1/* 2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/lcr_circuit_builder.h" 17 18#include "ecmascript/compiler/circuit_builder-inl.h" 19#include "ecmascript/compiler/rt_call_signature.h" 20#include "ecmascript/compiler/circuit_builder_helper.h" 21 22namespace panda::ecmascript::kungfu { 23 24GateRef CircuitBuilder::BinaryCmp(const GateMetaData* meta, GateRef left, GateRef right, const char* comment) 25{ 26 return GetCircuit()->NewGate(meta, MachineType::I1, { left, right }, GateType::NJSValue(), comment); 27} 28 29MachineType CircuitBuilder::GetMachineTypeFromVariableType(VariableType type) 30{ 31 return type.GetMachineType(); 32} 33 34GateRef CircuitBuilder::Sqrt(GateRef param) 35{ 36 return GetCircuit()->NewGate(circuit_->Sqrt(), MachineType::F64, {param}, GateType::DoubleType()); 37} 38 39GateRef CircuitBuilder::AddWithOverflow(GateRef left, GateRef right) 40{ 41 return GetCircuit()->NewGate(circuit_->AddWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType()); 42} 43 44GateRef CircuitBuilder::SubWithOverflow(GateRef left, GateRef right) 45{ 46 return GetCircuit()->NewGate(circuit_->SubWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType()); 47} 48 49GateRef CircuitBuilder::MulWithOverflow(GateRef left, GateRef right) 50{ 51 return GetCircuit()->NewGate(circuit_->MulWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType()); 52} 53 54GateRef CircuitBuilder::ExtractValue(MachineType mt, GateRef pointer, GateRef index) 55{ 56 ASSERT(acc_.GetOpCode(index) == OpCode::CONSTANT); 57 ASSERT(acc_.GetMachineType(index) == MachineType::I32); 58 return GetCircuit()->NewGate(circuit_->ExtractValue(), mt, {pointer, index}, GateType::NJSValue()); 59} 60 61GateRef CircuitBuilder::ReadSp() 62{ 63 return circuit_->NewGate(circuit_->ReadSp(), MachineType::I64, GateType::NJSValue()); 64} 65 66MachineType CircuitBuilder::GetMachineTypeOfValueType(ValueType type) 67{ 68 switch (type) { 69 case ValueType::BOOL: 70 return MachineType::I1; 71 case ValueType::INT32: 72 case ValueType::UINT32: 73 return MachineType::I32; 74 case ValueType::FLOAT64: 75 return MachineType::F64; 76 case ValueType::TAGGED_BOOLEAN: 77 case ValueType::TAGGED_INT: 78 case ValueType::TAGGED_DOUBLE: 79 case ValueType::TAGGED_NUMBER: 80 case ValueType::TAGGED_NULL: 81 case ValueType::CHAR: 82 case ValueType::ECMA_STRING: 83 case ValueType::UNDEFINED: 84 case ValueType::HOLE_INT: 85 case ValueType::HOLE_DOUBLE: 86 return MachineType::I64; 87 default: 88 UNREACHABLE(); 89 break; 90 } 91 return MachineType::NOVALUE; 92} 93 94GateRef CircuitBuilder::BinaryArithmetic(const GateMetaData* meta, MachineType machineType, 95 GateRef left, GateRef right, GateType gateType, const char* comment) 96{ 97 auto circuit = GetCircuit(); 98 if (gateType == GateType::Empty()) { 99 gateType = acc_.GetGateType(left); 100 } 101 return circuit->NewGate(meta, machineType, { left, right }, gateType, comment); 102} 103 104GateRef CircuitBuilder::Alloca(size_t size) 105{ 106 return GetCircuit()->NewGate(circuit_->Alloca(size), MachineType::ARCH, GateType::NJSValue()); 107} 108 109// memory 110void CircuitBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value, 111 MemoryAttribute mAttr) 112{ 113 auto label = GetCurrentLabel(); 114 auto depend = label->GetDepend(); 115 if (mAttr.GetBarrier() == MemoryAttribute::Barrier::UNKNOWN_BARRIER && acc_.IsConstant(value)) { 116 mAttr.SetBarrier(MemoryAttribute::Barrier::NO_BARRIER); 117 } 118 auto bit = LoadStoreAccessor::ToValue(mAttr); 119 GateRef result = GetCircuit()->NewGate(circuit_->Store(bit), 120 MachineType::NOVALUE, { depend, glue, base, offset, value }, type.GetGateType()); 121 label->SetDepend(result); 122} 123 124void CircuitBuilder::StoreWithoutBarrier(VariableType type, GateRef addr, GateRef value, MemoryAttribute mAttr) 125{ 126 auto label = GetCurrentLabel(); 127 auto depend = label->GetDepend(); 128 auto bit = LoadStoreAccessor::ToValue(mAttr); 129 GateRef result = GetCircuit()->NewGate(circuit_->StoreWithoutBarrier(bit), 130 MachineType::NOVALUE, { depend, addr, value }, type.GetGateType()); 131 label->SetDepend(result); 132} 133 134// memory 135GateRef CircuitBuilder::Load(VariableType type, GateRef base, GateRef offset, MemoryAttribute mAttr) 136{ 137 auto label = GetCurrentLabel(); 138 auto depend = label->GetDepend(); 139 GateRef val = PtrAdd(base, offset); 140 auto bits = LoadStoreAccessor::ToValue(mAttr); 141 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(), 142 { depend, val }, type.GetGateType()); 143 label->SetDepend(result); 144 return result; 145} 146 147GateRef CircuitBuilder::Load(VariableType type, GateRef base, GateRef offset, GateRef depend, 148 MemoryAttribute mAttr) 149{ 150 GateRef val = PtrAdd(base, offset); 151 auto bits = LoadStoreAccessor::ToValue(mAttr); 152 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(), 153 { depend, val }, type.GetGateType()); 154 return result; 155} 156 157GateRef CircuitBuilder::Load(VariableType type, GateRef addr, MemoryAttribute mAttr) 158{ 159 auto label = GetCurrentLabel(); 160 auto depend = label->GetDepend(); 161 auto bits = LoadStoreAccessor::ToValue(mAttr); 162 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(), 163 { depend, addr }, type.GetGateType()); 164 label->SetDepend(result); 165 return result; 166} 167 168GateRef CircuitBuilder::DoubleTrunc(GateRef gate, GateRef value, const char* comment) 169{ 170 if (GetCompilationConfig()->IsAArch64()) { 171 return DoubleTrunc(value, comment); 172 } 173 174 GateRef glue = acc_.GetGlueFromArgList(); 175 return CallNGCRuntime(glue, RTSTUB_ID(FloatTrunc), Gate::InvalidGateRef, {value}, gate, comment); 176} 177 178GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x) 179{ 180 Label subentry(env_); 181 SubCfgEntry(&subentry); 182 Label isInt(env_); 183 Label isDouble(env_); 184 Label exit(env_); 185 DEFVALUE(result, env_, VariableType::FLOAT64(), Double(0)); 186 BRANCH_CIR2(TaggedIsInt(x), &isInt, &isDouble); 187 Bind(&isInt); 188 { 189 result = ChangeInt32ToFloat64(GetInt32OfTInt(x)); 190 Jump(&exit); 191 } 192 Bind(&isDouble); 193 { 194 result = GetDoubleOfTDouble(x); 195 Jump(&exit); 196 } 197 Bind(&exit); 198 GateRef ret = *result; 199 SubCfgExit(); 200 return ret; 201} 202 203GateRef CircuitBuilder::DoubleToInt(GateRef x, Label *exit) 204{ 205 Label overflow(env_); 206 207 GateRef xInt = ChangeFloat64ToInt32(x); 208 DEFVALUE(result, env_, VariableType::INT32(), xInt); 209 210 GateRef xInt64 = CastDoubleToInt64(x); 211 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS 212 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK)); 213 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE))); 214 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS)); 215 GateRef bits = Int32(base::INT32_BITS - 1); 216 // exp < 32 - 1 217 BRANCH_CIR2(Int32LessThan(exp, bits), exit, &overflow); 218 219 Bind(&overflow); 220 { 221 result = CallNGCRuntime(acc_.GetGlueFromArgList(), RTSTUB_ID(DoubleToInt), 222 Circuit::NullGate(), { x, IntPtr(base::INT32_BITS) }, Circuit::NullGate()); 223 Jump(exit); 224 } 225 Bind(exit); 226 auto ret = *result; 227 return ret; 228} 229 230GateRef CircuitBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits) 231{ 232 Label entry(env_); 233 env_->SubCfgEntry(&entry); 234 Label exit(env_); 235 Label overflow(env_); 236 237 GateRef xInt = ChangeFloat64ToInt32(x); 238 DEFVALUE(result, env_, VariableType::INT32(), xInt); 239 240 if (env_->IsAmd64()) { 241 // 0x80000000: amd64 overflow return value 242 BRANCH_CIR2(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit); 243 } else { 244 GateRef xInt64 = CastDoubleToInt64(x); 245 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS 246 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK)); 247 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE))); 248 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS)); 249 GateRef bits = Int32(typeBits - 1); 250 // exp < 32 - 1 251 BRANCH_CIR2(Int32LessThan(exp, bits), &exit, &overflow); 252 } 253 Bind(&overflow); 254 { 255 result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), Circuit::NullGate(), { x, IntPtr(typeBits) }, 256 Circuit::NullGate()); 257 Jump(&exit); 258 } 259 Bind(&exit); 260 auto ret = *result; 261 env_->SubCfgExit(); 262 return ret; 263} 264 265GateRef CircuitBuilder::DoubleCheckINFInRangeInt32(GateRef x) 266{ 267 Label entry(env_); 268 env_->SubCfgEntry(&entry); 269 Label exit(env_); 270 Label isInfinity(env_); 271 Label positiveInf(env_); 272 Label negativeInf(env_); 273 274 DEFVALUE(result, env_, VariableType::INT32(), DoubleInRangeInt32(x)); 275 GateRef Max = Double(INT32_MAX); 276 GateRef Min = Double(INT32_MIN); 277 GateRef pInfinity = Double(base::POSITIVE_INFINITY); 278 Branch(DoubleIsINF(x), &isInfinity, &exit); 279 Bind(&isInfinity); 280 { 281 Branch(DoubleEqual(x, pInfinity), &positiveInf, &negativeInf); 282 Bind(&positiveInf); 283 { 284 result = ChangeFloat64ToInt32(Max); 285 Jump(&exit); 286 } 287 Bind(&negativeInf); 288 { 289 result = ChangeFloat64ToInt32(Min); 290 Jump(&exit); 291 } 292 } 293 Bind(&exit); 294 auto ret = *result; 295 env_->SubCfgExit(); 296 return ret; 297} 298 299GateRef CircuitBuilder::DoubleInRangeInt32(GateRef x) 300{ 301 Label entry(env_); 302 env_->SubCfgEntry(&entry); 303 Label exit(env_); 304 Label overflow(env_); 305 Label checkUnderflow(env_); 306 Label underflow(env_); 307 308 DEFVALUE(result, env_, VariableType::INT32(), ChangeFloat64ToInt32(x)); 309 GateRef Max = Double(INT32_MAX); 310 GateRef Min = Double(INT32_MIN); 311 Branch(DoubleGreaterThan(x, Max), &overflow, &checkUnderflow); 312 Bind(&overflow); 313 { 314 result = ChangeFloat64ToInt32(Max); 315 Jump(&exit); 316 } 317 Bind(&checkUnderflow); 318 { 319 Branch(DoubleLessThan(x, Min), &underflow, &exit); 320 Bind(&underflow); 321 { 322 result = ChangeFloat64ToInt32(Min); 323 Jump(&exit); 324 } 325 } 326 Bind(&exit); 327 auto ret = *result; 328 env_->SubCfgExit(); 329 return ret; 330} 331} 332