• 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(ABS):
27             LowerTypedAbs(gate);
28             break;
29         case BUILTINS_STUB_ID(FLOOR):
30         case BUILTINS_STUB_ID(COS):
31         case BUILTINS_STUB_ID(SIN):
32         case BUILTINS_STUB_ID(ACOS):
33         case BUILTINS_STUB_ID(ATAN):
34             LowerTypedTrigonometric(gate, id);
35             break;
36         case BUILTINS_STUB_ID(LocaleCompare):
37             LowerTypedLocaleCompare(gate);
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}, gate);
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     Environment env(gate, circuit_, &builder_);
118     GateRef param = acc_.GetValueIn(gate, 0);
119     // 20.2.2.32
120     // If value is NAN or negative, include -NaN and -Infinity but not -0.0, the result is NaN
121     // Assembly instruction support NAN and negative
122     auto ret = builder_.Sqrt(param);
123     acc_.SetMachineType(gate, MachineType::F64);
124     acc_.SetGateType(gate, GateType::NJSValue());
125     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
126 }
127 
LowerTypedAbs(GateRef gate)128 void BuiltinLowering::LowerTypedAbs(GateRef gate)
129 {
130     auto ret = TypedAbs(gate);
131     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
132 }
133 
IntToTaggedIntPtr(GateRef x)134 GateRef BuiltinLowering::IntToTaggedIntPtr(GateRef x)
135 {
136     GateRef val = builder_.SExtInt32ToInt64(x);
137     return builder_.ToTaggedIntPtr(val);
138 }
139 
140 //  Int abs : The internal representation of an integer is inverse code,
141 //  The absolute value of a negative number can be found by inverting it by adding one.
142 
143 //  Float abs : A floating-point number is composed of mantissa and exponent.
144 //  The length of mantissa will affect the precision of the number, and its sign will determine the sign of the number.
145 //  The absolute value of a floating-point number can be found by setting mantissa sign bit to 0.
TypedAbs(GateRef gate)146 GateRef BuiltinLowering::TypedAbs(GateRef gate)
147 {
148     auto env = builder_.GetCurrentEnvironment();
149     Label entry(&builder_);
150     env->SubCfgEntry(&entry);
151 
152     Label exit(&builder_);
153     GateRef para1 = acc_.GetValueIn(gate, 0);
154     DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
155 
156     Label isInt(&builder_);
157     Label notInt(&builder_);
158     builder_.Branch(builder_.TaggedIsInt(para1), &isInt, &notInt);
159     builder_.Bind(&isInt);
160     {
161         auto value = builder_.GetInt32OfTInt(para1);
162         auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
163         auto res = builder_.Int32Xor(value, temp);
164         result = IntToTaggedIntPtr(builder_.Int32Sub(res, temp));
165         builder_.Jump(&exit);
166     }
167     builder_.Bind(&notInt);
168     {
169         auto value = builder_.GetDoubleOfTDouble(para1);
170         // set the sign bit to 0 by shift left then right.
171         auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1));
172         auto res = builder_.Int64LSR(temp, builder_.Int64(1));
173         result = builder_.DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(res));
174         builder_.Jump(&exit);
175     }
176     builder_.Bind(&exit);
177     auto ret = *result;
178     env->SubCfgExit();
179     return ret;
180 }
181 
LowerCallRuntime(GateRef glue,GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)182 GateRef BuiltinLowering::LowerCallRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
183                                           bool useLabel)
184 {
185     const std::string name = RuntimeStubCSigns::GetRTName(index);
186     if (useLabel) {
187         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
188         return result;
189     } else {
190         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
191         GateRef target = builder_.IntPtr(index);
192         GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate, name.c_str());
193         return result;
194     }
195 }
196 
ReplaceHirWithValue(GateRef hirGate,GateRef value,bool noThrow)197 void BuiltinLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow)
198 {
199     if (!noThrow) {
200         GateRef state = builder_.GetState();
201         // copy depend-wire of hirGate to value
202         GateRef depend = builder_.GetDepend();
203         // exception value
204         GateRef exceptionVal = builder_.ExceptionConstant();
205         // compare with trampolines result
206         GateRef equal = builder_.Equal(value, exceptionVal);
207         auto ifBranch = builder_.Branch(state, equal);
208 
209         GateRef ifTrue = builder_.IfTrue(ifBranch);
210         GateRef ifFalse = builder_.IfFalse(ifBranch);
211         GateRef eDepend = builder_.DependRelay(ifTrue, depend);
212         GateRef sDepend = builder_.DependRelay(ifFalse, depend);
213         StateDepend success(ifFalse, sDepend);
214         StateDepend exception(ifTrue, eDepend);
215         acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
216     } else {
217         acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
218     }
219 }
220 
LowerTypedLocaleCompare(GateRef gate)221 void BuiltinLowering::LowerTypedLocaleCompare(GateRef gate)
222 {
223     GateRef glue = acc_.GetGlueFromArgList();
224     uint32_t index = 0;
225     GateRef thisObj = acc_.GetValueIn(gate, index++);
226     GateRef a0 = acc_.GetValueIn(gate, index++);
227     GateRef a1 = acc_.GetValueIn(gate, index++);
228     GateRef a2 = acc_.GetValueIn(gate, index++);
229 
230     std::vector<GateRef> args;
231     args.reserve(index);
232     args.emplace_back(thisObj);
233     args.emplace_back(a0);
234     args.emplace_back(a1);
235     args.emplace_back(a2);
236     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(LocaleCompare), args);
237     ReplaceHirWithValue(gate, result);
238 }
239 
LowerCallTargetCheck(Environment * env,GateRef gate)240 GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate)
241 {
242     builder_.SetEnvironment(env);
243     GateRef idGate = acc_.GetValueIn(gate, 1);
244     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
245     GateRef constantFunction = builder_.GetGlobalConstantValue(GET_TYPED_CONSTANT_INDEX(id));
246 
247     GateRef function = acc_.GetValueIn(gate, 0); // 0: function
248     return builder_.Equal(function, constantFunction);
249 }
250 
CheckPara(GateRef gate,GateRef funcCheck)251 GateRef BuiltinLowering::CheckPara(GateRef gate, GateRef funcCheck)
252 {
253     GateRef idGate = acc_.GetValueIn(gate, 1);
254     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
255     switch (id) {
256         case BuiltinsStubCSigns::ID::COS:
257         case BuiltinsStubCSigns::ID::SIN:
258         case BuiltinsStubCSigns::ID::ACOS:
259         case BuiltinsStubCSigns::ID::ATAN:
260         case BuiltinsStubCSigns::ID::ABS:
261         case BuiltinsStubCSigns::ID::FLOOR: {
262             GateRef para = acc_.GetValueIn(gate, 2);
263             GateRef paracheck = builder_.TaggedIsNumber(para);
264             return builder_.BoolAnd(paracheck, funcCheck);
265         }
266         case BuiltinsStubCSigns::ID::SQRT:
267             // NumberSpeculativeRetype is checked
268             return funcCheck;
269         default: {
270             LOG_COMPILER(FATAL) << "this branch is unreachable";
271             UNREACHABLE();
272         }
273     }
274 }
275 }  // namespace panda::ecmascript::kungfu
276