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 #ifndef ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
17 #define ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
18
19 #include "ecmascript/compiler/circuit_builder.h"
20 #include "ecmascript/compiler/circuit_builder_helper.h"
21 #include "ecmascript/compiler/share_gate_meta_data.h"
22
23 namespace panda::ecmascript::kungfu {
24
Int8Equal(GateRef x, GateRef y)25 GateRef CircuitBuilder::Int8Equal(GateRef x, GateRef y)
26 {
27 return Equal(x, y);
28 }
29
Int32NotEqual(GateRef x, GateRef y)30 GateRef CircuitBuilder::Int32NotEqual(GateRef x, GateRef y)
31 {
32 return NotEqual(x, y);
33 }
34
Int64NotEqual(GateRef x, GateRef y)35 GateRef CircuitBuilder::Int64NotEqual(GateRef x, GateRef y)
36 {
37 return NotEqual(x, y);
38 }
39
Int64Equal(GateRef x, GateRef y)40 GateRef CircuitBuilder::Int64Equal(GateRef x, GateRef y)
41 {
42 return Equal(x, y);
43 }
44
Int32Equal(GateRef x, GateRef y)45 GateRef CircuitBuilder::Int32Equal(GateRef x, GateRef y)
46 {
47 return Equal(x, y);
48 }
49
IntPtrGreaterThan(GateRef x, GateRef y)50 GateRef CircuitBuilder::IntPtrGreaterThan(GateRef x, GateRef y)
51 {
52 return env_->Is32Bit() ? Int32GreaterThan(x, y) : Int64GreaterThan(x, y);
53 }
54
IntPtrAnd(GateRef x, GateRef y)55 GateRef CircuitBuilder::IntPtrAnd(GateRef x, GateRef y)
56 {
57 return env_->Is32Bit() ? Int32And(x, y) : Int64And(x, y);
58 }
59
IntPtrNot(GateRef x)60 GateRef CircuitBuilder::IntPtrNot(GateRef x)
61 {
62 return env_->Is32Bit() ? Int32Not(x) : Int64Not(x);
63 }
64
IntPtrEqual(GateRef x, GateRef y)65 GateRef CircuitBuilder::IntPtrEqual(GateRef x, GateRef y)
66 {
67 return env_->Is32Bit() ? Int32Equal(x, y) : Int64Equal(x, y);
68 }
69
IntPtrLSR(GateRef x, GateRef y)70 GateRef CircuitBuilder::IntPtrLSR(GateRef x, GateRef y)
71 {
72 auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
73 return BinaryArithmetic(circuit_->Lsr(), ptrSize, x, y);
74 }
75
IntPtrLSL(GateRef x, GateRef y)76 GateRef CircuitBuilder::IntPtrLSL(GateRef x, GateRef y)
77 {
78 auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
79 return BinaryArithmetic(circuit_->Lsl(), ptrSize, x, y);
80 }
81
Int16ToBigEndianInt16(GateRef x)82 GateRef CircuitBuilder::Int16ToBigEndianInt16(GateRef x)
83 {
84 GateRef int16toint32 = ZExtInt16ToInt32(x);
85 GateRef high8bits = Int32LSL(Int32And(int16toint32, Int32(0x00FF)), Int32(8));
86 GateRef low8bits = Int32LSR(Int32And(int16toint32, Int32(0xFF00)), Int32(8));
87 return TruncInt32ToInt16(Int32Add(high8bits, low8bits));
88 }
89
Int32ToBigEndianInt32(GateRef x)90 GateRef CircuitBuilder::Int32ToBigEndianInt32(GateRef x)
91 {
92 GateRef first8bits = Int32LSL(Int32And(x, Int32(0x000000FF)), Int32(24));
93 GateRef second8bits = Int32LSL(Int32And(x, Int32(0x0000FF00)), Int32(8));
94 GateRef third8bits = Int32LSR(Int32And(x, Int32(0x00FF0000)), Int32(8));
95 GateRef fourth8bits = Int32LSR(Int32And(x, Int32(0xFF000000)), Int32(24));
96 GateRef firstHalf = Int32Add(first8bits, second8bits);
97 GateRef secondHalf = Int32Add(third8bits, fourth8bits);
98 return Int32Add(firstHalf, secondHalf);
99 }
100
Int64ToBigEndianInt64(GateRef x)101 GateRef CircuitBuilder::Int64ToBigEndianInt64(GateRef x)
102 {
103 GateRef first8bits = Int64LSL(Int64And(x, Int64(0x00000000000000FF)), Int64(56));
104 GateRef second8bits = Int64LSL(Int64And(x, Int64(0x000000000000FF00)), Int64(40));
105 // 0-16bits
106 GateRef first16bits = Int64Add(first8bits, second8bits);
107 GateRef third8bits = Int64LSL(Int64And(x, Int64(0x0000000000FF0000)), Int64(24));
108 GateRef fourth8bits = Int64LSL(Int64And(x, Int64(0x00000000FF000000)), Int64(8));
109 // 16-32bits
110 GateRef second16bits = Int64Add(third8bits, fourth8bits);
111 // 0-32bits
112 GateRef firstHalf = Int64Add(first16bits, second16bits);
113 GateRef fifth8bits = Int64LSR(Int64And(x, Int64(0x000000FF00000000)), Int64(8));
114 GateRef sixth8bits = Int64LSR(Int64And(x, Int64(0x0000FF0000000000)), Int64(24));
115 //32-48bits
116 GateRef third16bits = Int64Add(fifth8bits, sixth8bits);
117 GateRef seventh8bits = Int64LSR(Int64And(x, Int64(0x00FF000000000000)), Int64(40));
118 GateRef eighth8bits = Int64LSR(Int64And(x, Int64(0xFF00000000000000)), Int64(56));
119 //48-64bits
120 GateRef fourth16bits = Int64Add(seventh8bits, eighth8bits);
121 //32-64bits
122 GateRef secondHalf = Int64Add(third16bits, fourth16bits);
123 //0-64bits
124 return Int64Add(firstHalf, secondHalf);
125 }
126
IntPtrOr(GateRef x, GateRef y)127 GateRef CircuitBuilder::IntPtrOr(GateRef x, GateRef y)
128 {
129 auto ptrsize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
130 return BinaryArithmetic(circuit_->Or(), ptrsize, x, y);
131 }
132
IntPtrDiv(GateRef x, GateRef y)133 GateRef CircuitBuilder::IntPtrDiv(GateRef x, GateRef y)
134 {
135 return env_->Is32Bit() ? Int32Div(x, y) : Int64Div(x, y);
136 }
137
GetInt64OfTInt(GateRef x)138 GateRef CircuitBuilder::GetInt64OfTInt(GateRef x)
139 {
140 GateRef tagged = ChangeTaggedPointerToInt64(x);
141 return Int64And(tagged, Int64(~JSTaggedValue::TAG_MARK));
142 }
143
GetInt32OfTInt(GateRef x)144 GateRef CircuitBuilder::GetInt32OfTInt(GateRef x)
145 {
146 GateRef tagged = ChangeTaggedPointerToInt64(x);
147 return TruncInt64ToInt32(tagged);
148 }
149
GetInt32OfTNumber(GateRef x)150 GateRef CircuitBuilder::GetInt32OfTNumber(GateRef x)
151 {
152 Label subentry(env_);
153 SubCfgEntry(&subentry);
154 Label isInt(env_);
155 Label isDouble(env_);
156 Label exit(env_);
157 DEFVALUE(result, env_, VariableType::INT32(), Int32(0));
158 BRANCH_CIR2(TaggedIsInt(x), &isInt, &isDouble);
159 Bind(&isInt);
160 {
161 result = GetInt32OfTInt(x);
162 Jump(&exit);
163 }
164 Bind(&isDouble);
165 {
166 result = DoubleCheckINFInRangeInt32(GetDoubleOfTDouble(x));
167 Jump(&exit);
168 }
169 Bind(&exit);
170 GateRef ret = *result;
171 SubCfgExit();
172 return ret;
173 }
174
TaggedCastToIntPtr(GateRef x)175 GateRef CircuitBuilder::TaggedCastToIntPtr(GateRef x)
176 {
177 return env_->Is32Bit() ? GetInt32OfTInt(x) : GetInt64OfTInt(x);
178 }
179
GetDoubleOfTInt(GateRef x)180 GateRef CircuitBuilder::GetDoubleOfTInt(GateRef x)
181 {
182 return ChangeInt32ToFloat64(GetInt32OfTInt(x));
183 }
184
GetDoubleOfTDouble(GateRef x)185 GateRef CircuitBuilder::GetDoubleOfTDouble(GateRef x)
186 {
187 GateRef tagged = ChangeTaggedPointerToInt64(x);
188 GateRef val = Int64Sub(tagged, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
189 return CastInt64ToFloat64(val);
190 }
191
GetBooleanOfTBoolean(GateRef x)192 GateRef CircuitBuilder::GetBooleanOfTBoolean(GateRef x)
193 {
194 GateRef tagged = ChangeTaggedPointerToInt64(x);
195 return TruncInt64ToInt1(tagged);
196 }
197
Int32ToTaggedInt(GateRef x)198 GateRef CircuitBuilder::Int32ToTaggedInt(GateRef x)
199 {
200 GateRef val = SExtInt32ToInt64(x);
201 return Int64Or(val, Int64(JSTaggedValue::TAG_INT));
202 }
203
Int32ToTaggedPtr(GateRef x)204 GateRef CircuitBuilder::Int32ToTaggedPtr(GateRef x)
205 {
206 GateRef val = SExtInt32ToInt64(x);
207 return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_INT)));
208 }
209
Int64ToTaggedPtr(GateRef x)210 GateRef CircuitBuilder::Int64ToTaggedPtr(GateRef x)
211 {
212 return GetCircuit()->NewGate(circuit_->Int64ToTagged(),
213 MachineType::I64, { x }, GateType::TaggedValue());
214 }
215
ToTaggedInt(GateRef x)216 GateRef CircuitBuilder::ToTaggedInt(GateRef x)
217 {
218 return Int64Or(x, Int64(JSTaggedValue::TAG_INT));
219 }
220
ToTaggedIntPtr(GateRef x)221 GateRef CircuitBuilder::ToTaggedIntPtr(GateRef x)
222 {
223 return Int64ToTaggedPtr(Int64Or(x, Int64(JSTaggedValue::TAG_INT)));
224 }
225
DoubleToTaggedDoublePtr(GateRef x)226 GateRef CircuitBuilder::DoubleToTaggedDoublePtr(GateRef x)
227 {
228 GateRef val = CastDoubleToInt64(x);
229 return Int64ToTaggedPtr(Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET)));
230 }
231
DoubleIsImpureNaN(GateRef x)232 GateRef CircuitBuilder::DoubleIsImpureNaN(GateRef x)
233 {
234 GateRef impureNaN = Int64(JSTaggedValue::TAG_INT - JSTaggedValue::DOUBLE_ENCODE_OFFSET);
235 GateRef val = CastDoubleToInt64(x);
236 return Int64UnsignedGreaterThanOrEqual(val, impureNaN);
237 }
238
BooleanToTaggedBooleanPtr(GateRef x)239 GateRef CircuitBuilder::BooleanToTaggedBooleanPtr(GateRef x)
240 {
241 auto val = ZExtInt1ToInt64(x);
242 return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_BOOLEAN_MASK)));
243 }
244
BooleanToInt32(GateRef x)245 GateRef CircuitBuilder::BooleanToInt32(GateRef x)
246 {
247 return ZExtInt1ToInt32(x);
248 }
249
BooleanToFloat64(GateRef x)250 GateRef CircuitBuilder::BooleanToFloat64(GateRef x)
251 {
252 return ChangeInt32ToFloat64(ZExtInt1ToInt32(x));
253 }
254
Float32ToTaggedDoublePtr(GateRef x)255 GateRef CircuitBuilder::Float32ToTaggedDoublePtr(GateRef x)
256 {
257 GateRef val = ExtFloat32ToDouble(x);
258 return DoubleToTaggedDoublePtr(val);
259 }
260
TaggedDoublePtrToFloat32(GateRef x)261 GateRef CircuitBuilder::TaggedDoublePtrToFloat32(GateRef x)
262 {
263 GateRef val = GetDoubleOfTDouble(x);
264 return TruncDoubleToFloat32(val);
265 }
266
TaggedIntPtrToFloat32(GateRef x)267 GateRef CircuitBuilder::TaggedIntPtrToFloat32(GateRef x)
268 {
269 GateRef val = GetInt32OfTInt(x);
270 return ChangeInt32ToFloat32(val);
271 }
272
DoubleToTaggedDouble(GateRef x)273 GateRef CircuitBuilder::DoubleToTaggedDouble(GateRef x)
274 {
275 GateRef val = CastDoubleToInt64(x);
276 return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
277 }
278
DoubleIsNAN(GateRef x)279 GateRef CircuitBuilder::DoubleIsNAN(GateRef x)
280 {
281 GateRef diff = DoubleEqual(x, x);
282 return Equal(SExtInt1ToInt32(diff), Int32(0));
283 }
284
DoubleToTagged(GateRef x)285 GateRef CircuitBuilder::DoubleToTagged(GateRef x)
286 {
287 GateRef val = CastDoubleToInt64(x);
288 acc_.SetGateType(val, GateType::TaggedValue());
289 return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
290 }
291
292 template<OpCode Op, MachineType Type>
BinaryOp(GateRef x, GateRef y)293 GateRef CircuitBuilder::BinaryOp(GateRef x, GateRef y)
294 {
295 if (Op == OpCode::ADD) {
296 return BinaryArithmetic(circuit_->Add(), Type, x, y);
297 } else if (Op == OpCode::SUB) {
298 return BinaryArithmetic(circuit_->Sub(), Type, x, y);
299 } else if (Op == OpCode::MUL) {
300 return BinaryArithmetic(circuit_->Mul(), Type, x, y);
301 }
302 UNREACHABLE();
303 return Circuit::NullGate();
304 }
305
306 template<OpCode Op, MachineType Type>
BinaryOpWithOverflow(GateRef x, GateRef y)307 GateRef CircuitBuilder::BinaryOpWithOverflow(GateRef x, GateRef y)
308 {
309 if (Op == OpCode::ADD) {
310 return BinaryArithmetic(circuit_->AddWithOverflow(), Type, x, y);
311 } else if (Op == OpCode::SUB) {
312 return BinaryArithmetic(circuit_->SubWithOverflow(), Type, x, y);
313 } else if (Op == OpCode::MUL) {
314 return BinaryArithmetic(circuit_->MulWithOverflow(), Type, x, y);
315 }
316 UNREACHABLE();
317 return Circuit::NullGate();
318 }
319
Equal(GateRef x, GateRef y, const char* comment)320 GateRef CircuitBuilder::Equal(GateRef x, GateRef y, const char* comment)
321 {
322 auto xType = acc_.GetMachineType(x);
323 switch (xType) {
324 case ARCH:
325 case FLEX:
326 case I1:
327 case I8:
328 case I16:
329 case I32:
330 case I64:
331 return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::EQ)), x, y, comment);
332 case F32:
333 case F64:
334 return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::OEQ)), x, y, comment);
335 default:
336 LOG_ECMA(FATAL) << "this branch is unreachable";
337 UNREACHABLE();
338 }
339 }
340
NotEqual(GateRef x, GateRef y, const char* comment)341 GateRef CircuitBuilder::NotEqual(GateRef x, GateRef y, const char* comment)
342 {
343 auto xType = acc_.GetMachineType(x);
344 switch (xType) {
345 case ARCH:
346 case FLEX:
347 case I1:
348 case I8:
349 case I16:
350 case I32:
351 case I64:
352 return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::NE)), x, y, comment);
353 case F32:
354 case F64:
355 return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::ONE)), x, y, comment);
356 default:
357 LOG_ECMA(FATAL) << "this branch is unreachable";
358 UNREACHABLE();
359 }
360 }
361
362 }
363
364 #endif // ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
365