• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notNumberBranch);
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(&notNumberBranch);
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, &notNumberBranch);
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, &notInt);
153         builder_.Bind(&isInt);
154         {
155             value = builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(para1));
156             builder_.Jump(&calc);
157         }
158         builder_.Bind(&notInt);
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, &notSignbit);
179             builder_.Bind(&signbit);
180             {
181                 result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
182                 builder_.Jump(&exit);
183             }
184             builder_.Bind(&notSignbit);
185             {
186                 Label naN(&builder_);
187                 Label notNan(&builder_);
188                 GateRef condition = builder_.DoubleIsNAN(*value);
189                 builder_.Branch(condition, &naN, &notNan);
190                 builder_.Bind(&notNan);
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(&notNumberBranch);
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, &notInt);
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(&notInt);
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