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, ¬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}, 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(¬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 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, ¬Int);
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(¬Int);
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