1 /*
2 * Copyright (c) 2022 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/builtins_lowering.h"
17
18 namespace panda::ecmascript::kungfu {
LowerTypedCallBuitin(GateRef gate)19 void BuiltinLowering::LowerTypedCallBuitin(GateRef gate)
20 {
21 Environment env(gate, circuit_, &builder_);
22 auto valuesIn = acc_.GetNumValueIn(gate);
23 auto idGate = acc_.GetValueIn(gate, valuesIn - 1);
24 auto id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
25 switch (id) {
26 case BUILTINS_STUB_ID(SQRT):
27 LowerTypedSqrt(gate);
28 break;
29 case BUILTINS_STUB_ID(ABS):
30 LowerTypedAbs(gate);
31 break;
32 case BUILTINS_STUB_ID(FLOOR):
33 case BUILTINS_STUB_ID(COS):
34 case BUILTINS_STUB_ID(SIN):
35 case BUILTINS_STUB_ID(ACOS):
36 case BUILTINS_STUB_ID(ATAN):
37 LowerTypedTrigonometric(gate, id);
38 break;
39 default:
40 break;
41 }
42 }
43
LowerTypedTrigonometric(GateRef gate,BuiltinsStubCSigns::ID id)44 void BuiltinLowering::LowerTypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id)
45 {
46 auto ret = TypedTrigonometric(gate, id);
47 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
48 }
49
TypedTrigonometric(GateRef gate,BuiltinsStubCSigns::ID id)50 GateRef BuiltinLowering::TypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id)
51 {
52 auto env = builder_.GetCurrentEnvironment();
53 Label entry(&builder_);
54 env->SubCfgEntry(&entry);
55
56 Label numberBranch(&builder_);
57 Label notNumberBranch(&builder_);
58 Label exit(&builder_);
59
60 GateRef para1 = acc_.GetValueIn(gate, 0);
61 DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
62
63 builder_.Branch(builder_.TaggedIsNumber(para1), &numberBranch, ¬NumberBranch);
64 builder_.Bind(&numberBranch);
65 {
66 GateRef value = builder_.GetDoubleOfTNumber(para1);
67 Label IsNan(&builder_);
68 Label NotNan(&builder_);
69 GateRef condition = builder_.DoubleIsNAN(value);
70 builder_.Branch(condition, &IsNan, &NotNan);
71 builder_.Bind(&NotNan);
72 {
73 GateRef glue = acc_.GetGlueFromArgList();
74 int index = RTSTUB_ID(FloatCos);
75 switch (id) {
76 case BUILTINS_STUB_ID(FLOOR):
77 index = RTSTUB_ID(FloatFloor);
78 break;
79 case BUILTINS_STUB_ID(ACOS):
80 index = RTSTUB_ID(FloatACos);
81 break;
82 case BUILTINS_STUB_ID(ATAN):
83 index = RTSTUB_ID(FloatATan);
84 break;
85 case BUILTINS_STUB_ID(COS):
86 index = RTSTUB_ID(FloatCos);
87 break;
88 case BUILTINS_STUB_ID(SIN):
89 index = RTSTUB_ID(FloatSin);
90 break;
91 default:
92 LOG_ECMA(FATAL) << "this branch is unreachable";
93 UNREACHABLE();
94 }
95 result = builder_.CallNGCRuntime(glue, index, Gate::InvalidGateRef, {value});
96 builder_.Jump(&exit);
97 }
98 builder_.Bind(&IsNan);
99 {
100 result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
101 builder_.Jump(&exit);
102 }
103 }
104 builder_.Bind(¬NumberBranch);
105 {
106 builder_.Jump(&exit);
107 }
108
109 builder_.Bind(&exit);
110 auto ret = *result;
111 env->SubCfgExit();
112 return ret;
113 }
114
LowerTypedSqrt(GateRef gate)115 void BuiltinLowering::LowerTypedSqrt(GateRef gate)
116 {
117 auto ret = TypedSqrt(gate);
118 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
119 }
120
LowerTypedAbs(GateRef gate)121 void BuiltinLowering::LowerTypedAbs(GateRef gate)
122 {
123 auto ret = TypedAbs(gate);
124 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
125 }
126
IntToTaggedIntPtr(GateRef x)127 GateRef BuiltinLowering::IntToTaggedIntPtr(GateRef x)
128 {
129 GateRef val = builder_.SExtInt32ToInt64(x);
130 return builder_.ToTaggedIntPtr(val);
131 }
132
TypedSqrt(GateRef gate)133 GateRef BuiltinLowering::TypedSqrt(GateRef gate)
134 {
135 auto env = builder_.GetCurrentEnvironment();
136 Label entry(&builder_);
137 env->SubCfgEntry(&entry);
138
139 Label numberBranch(&builder_);
140 Label notNumberBranch(&builder_);
141 Label exit(&builder_);
142 GateRef para1 = acc_.GetValueIn(gate, 0);
143 DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
144
145 builder_.Branch(builder_.TaggedIsNumber(para1), &numberBranch, ¬NumberBranch);
146 builder_.Bind(&numberBranch);
147 {
148 Label isInt(&builder_);
149 Label notInt(&builder_);
150 Label calc(&builder_);
151 DEFVAlUE(value, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
152 builder_.Branch(builder_.TaggedIsInt(para1), &isInt, ¬Int);
153 builder_.Bind(&isInt);
154 {
155 value = builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(para1));
156 builder_.Jump(&calc);
157 }
158 builder_.Bind(¬Int);
159 {
160 value = builder_.GetDoubleOfTDouble(para1);
161 builder_.Jump(&calc);
162 }
163 builder_.Bind(&calc);
164 {
165 Label signbit(&builder_);
166 Label notSignbit(&builder_);
167 GateRef negativeInfinity = builder_.Double(-base::POSITIVE_INFINITY);
168 GateRef isNegativeInfinity = builder_.Equal(*value, negativeInfinity);
169 isNegativeInfinity = builder_.Equal(builder_.SExtInt1ToInt32(isNegativeInfinity), builder_.Int32(1));
170 GateRef negativeNan = builder_.Double(-base::NAN_VALUE);
171 GateRef isNegativeNan = builder_.Equal(*value, negativeNan);
172 isNegativeNan = builder_.Equal(builder_.SExtInt1ToInt32(isNegativeNan), builder_.Int32(1));
173 GateRef negativeZero = builder_.Double(-0.0);
174 GateRef isNegativeZero = builder_.Equal(*value, negativeZero);
175 // If value is negative, include -NaN and -Infinity but not -0.0, the result is NaN
176 GateRef negNanOrInfinityNotZero = builder_.BoolOr(isNegativeNan, isNegativeInfinity);
177 negNanOrInfinityNotZero = builder_.BoolAnd(negNanOrInfinityNotZero, builder_.BoolNot(isNegativeZero));
178 builder_.Branch(negNanOrInfinityNotZero, &signbit, ¬Signbit);
179 builder_.Bind(&signbit);
180 {
181 result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
182 builder_.Jump(&exit);
183 }
184 builder_.Bind(¬Signbit);
185 {
186 Label naN(&builder_);
187 Label notNan(&builder_);
188 GateRef condition = builder_.DoubleIsNAN(*value);
189 builder_.Branch(condition, &naN, ¬Nan);
190 builder_.Bind(¬Nan);
191 {
192 GateRef glue = acc_.GetGlueFromArgList();
193 result = builder_.CallNGCRuntime(
194 glue, RTSTUB_ID(FloatSqrt), Gate::InvalidGateRef, {*value});
195 builder_.Jump(&exit);
196 }
197 // If value is NaN, the result is NaN
198 builder_.Bind(&naN);
199 {
200 result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
201 builder_.Jump(&exit);
202 }
203 }
204 }
205 }
206 builder_.Bind(¬NumberBranch);
207 {
208 builder_.Jump(&exit);
209 }
210
211 builder_.Bind(&exit);
212 auto ret = *result;
213 env->SubCfgExit();
214 return ret;
215 }
216
217 // Int abs : The internal representation of an integer is inverse code,
218 // The absolute value of a negative number can be found by inverting it by adding one.
219
220 // Float abs : A floating-point number is composed of mantissa and exponent.
221 // The length of mantissa will affect the precision of the number, and its sign will determine the sign of the number.
222 // The absolute value of a floating-point number can be found by setting mantissa sign bit to 0.
TypedAbs(GateRef gate)223 GateRef BuiltinLowering::TypedAbs(GateRef gate)
224 {
225 auto env = builder_.GetCurrentEnvironment();
226 Label entry(&builder_);
227 env->SubCfgEntry(&entry);
228
229 Label exit(&builder_);
230 GateRef para1 = acc_.GetValueIn(gate, 0);
231 DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
232
233 Label isInt(&builder_);
234 Label notInt(&builder_);
235 builder_.Branch(builder_.TaggedIsInt(para1), &isInt, ¬Int);
236 builder_.Bind(&isInt);
237 {
238 auto value = builder_.GetInt32OfTInt(para1);
239 auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
240 auto res = builder_.Int32Xor(value, temp);
241 result = IntToTaggedIntPtr(builder_.Int32Sub(res, temp));
242 builder_.Jump(&exit);
243 }
244 builder_.Bind(¬Int);
245 {
246 auto value = builder_.GetDoubleOfTDouble(para1);
247 // set the sign bit to 0 by shift left then right.
248 auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1));
249 auto res = builder_.Int64LSR(temp, builder_.Int64(1));
250 result = builder_.DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(res));
251 builder_.Jump(&exit);
252 }
253 builder_.Bind(&exit);
254 auto ret = *result;
255 env->SubCfgExit();
256 return ret;
257 }
258
LowerCallTargetCheck(Environment * env,GateRef gate)259 GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate)
260 {
261 builder_.SetEnvironment(env);
262 Label entry(&builder_);
263 env->SubCfgEntry(&entry);
264
265 GateRef function = acc_.GetValueIn(gate, 0); // 0: function
266 GateRef id = acc_.GetValueIn(gate, 1); // 1: buitin id
267 Label isHeapObject(&builder_);
268 Label funcIsCallable(&builder_);
269 Label exit(&builder_);
270 GateRef isObject = builder_.TaggedIsHeapObject(function);
271 DEFVAlUE(result, (&builder_), VariableType::BOOL(), builder_.False());
272 builder_.Branch(isObject, &isHeapObject, &exit);
273 builder_.Bind(&isHeapObject);
274 {
275 GateRef callable = builder_.IsCallable(function);
276 builder_.Branch(callable, &funcIsCallable, &exit);
277 builder_.Bind(&funcIsCallable);
278 {
279 GateRef method = builder_.Load(VariableType::JS_ANY(), function,
280 builder_.IntPtr(JSFunctionBase::METHOD_OFFSET));
281 GateRef builtinId = builder_.GetCallBuiltinId(method);
282 result = builder_.Int64Equal(builtinId, id);
283 builder_.Jump(&exit);
284 }
285 }
286 builder_.Bind(&exit);
287 auto ret = *result;
288 env->SubCfgExit();
289 return ret;
290 }
291
GetBuiltinId(std::string idStr)292 BuiltinsStubCSigns::ID BuiltinLowering::GetBuiltinId(std::string idStr)
293 {
294 const std::map<std::string, BuiltinsStubCSigns::ID> str2BuiltinId = {
295 {"sqrt", BUILTINS_STUB_ID(SQRT)},
296 {"cos", BUILTINS_STUB_ID(COS)},
297 {"sin", BUILTINS_STUB_ID(SIN)},
298 {"acos", BUILTINS_STUB_ID(ACOS)},
299 {"atan", BUILTINS_STUB_ID(ATAN)},
300 {"abs", BUILTINS_STUB_ID(ABS)},
301 {"floor", BUILTINS_STUB_ID(FLOOR)},
302 };
303 if (str2BuiltinId.count(idStr) > 0) {
304 return str2BuiltinId.at(idStr);
305 }
306 return BUILTINS_STUB_ID(NONE);
307 }
308
CheckPara(GateRef gate)309 GateRef BuiltinLowering::CheckPara(GateRef gate)
310 {
311 GateRef idGate = acc_.GetValueIn(gate, 1);
312 BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
313 GateRef para1 = acc_.GetValueIn(gate, 2);
314 GateRef paracheck = builder_.TaggedIsNumber(para1);
315 switch (id) {
316 case BuiltinsStubCSigns::ID::SQRT:
317 case BuiltinsStubCSigns::ID::COS:
318 case BuiltinsStubCSigns::ID::SIN:
319 case BuiltinsStubCSigns::ID::ACOS:
320 case BuiltinsStubCSigns::ID::ATAN:
321 case BuiltinsStubCSigns::ID::ABS:
322 case BuiltinsStubCSigns::ID::FLOOR: {
323 break;
324 }
325 default: {
326 LOG_COMPILER(FATAL) << "this branch is unreachable";
327 UNREACHABLE();
328 }
329 }
330 return paracheck;
331 }
332 } // namespace panda::ecmascript::kungfu