1 /*
2 * Copyright (c) 2023 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/constant_folding.h"
17
18 namespace panda::ecmascript::kungfu {
19
VisitGate(GateRef gate)20 GateRef ConstantFolding::VisitGate(GateRef gate)
21 {
22 auto op = acc_.GetOpCode(gate);
23 switch (op) {
24 BINARY_OP_LIST(GEN_SWITCH_CASE)
25 UNARY_OP_LIST(GEN_SWITCH_CASE)
26 default:
27 return Circuit::NullGate();
28 }
29 }
30
BinaryInt32Calculate(GateRef gate,std::function<GateRef (int,int)> op)31 GateRef ConstantFolding::BinaryInt32Calculate(GateRef gate, std::function<GateRef(int, int)> op)
32 {
33 auto left = acc_.GetValueIn(gate, 0);
34 auto right = acc_.GetValueIn(gate, 1);
35 if (!IsInt32Type(gate) || !IsInt32Type(left) || !IsInt32Type(right)) {
36 return Circuit::NullGate();
37 }
38
39 GateRef result = Circuit::NullGate();
40 if (acc_.IsConstant(left) && acc_.IsConstant(right)) {
41 AddFoldingCount();
42 int lvalue = acc_.GetInt32FromConstant(left);
43 int rvalue = acc_.GetInt32FromConstant(right);
44 result = op(lvalue, rvalue);
45 }
46 return result;
47 }
48
UnaryInt32Calculate(GateRef gate,std::function<GateRef (int)> op)49 GateRef ConstantFolding::UnaryInt32Calculate(GateRef gate, std::function<GateRef(int)> op)
50 {
51 auto valueIn = acc_.GetValueIn(gate, 0);
52 if (!IsInt32Type(gate) || !IsInt32Type(valueIn)) {
53 return Circuit::NullGate();
54 }
55
56 GateRef result = Circuit::NullGate();
57 if (acc_.IsConstant(valueIn)) {
58 AddFoldingCount();
59 int value = acc_.GetInt32FromConstant(valueIn);
60 result = op(value);
61 }
62 return result;
63 }
64
BinaryF64Calculate(GateRef gate,std::function<GateRef (double,double)> op)65 GateRef ConstantFolding::BinaryF64Calculate(GateRef gate, std::function<GateRef(double, double)> op)
66 {
67 auto left = acc_.GetValueIn(gate, 0);
68 auto right = acc_.GetValueIn(gate, 1);
69 if (!IsF64Type(gate) || !IsF64Type(left) || !IsF64Type(right)) {
70 return Circuit::NullGate();
71 }
72
73 GateRef result = Circuit::NullGate();
74 if (acc_.IsConstant(left) && acc_.IsConstant(right)) {
75 AddFoldingCount();
76 double lvalue = acc_.GetFloat64FromConstant(left);
77 double rvalue = acc_.GetFloat64FromConstant(right);
78 if (!std::isnan(lvalue) && !std::isnan(rvalue)) {
79 result = op(lvalue, rvalue);
80 }
81 }
82 return result;
83 }
84
UnaryF64Calculate(GateRef gate,std::function<GateRef (double)> op)85 GateRef ConstantFolding::UnaryF64Calculate(GateRef gate, std::function<GateRef(double)> op)
86 {
87 auto valueIn = acc_.GetValueIn(gate, 0);
88 if (!IsF64Type(gate) || !IsF64Type(valueIn)) {
89 return Circuit::NullGate();
90 }
91
92 GateRef result = Circuit::NullGate();
93 if (acc_.IsConstant(valueIn)) {
94 AddFoldingCount();
95 double value = acc_.GetFloat64FromConstant(valueIn);
96 if (!std::isnan(value)) {
97 result = op(value);
98 }
99 }
100 return result;
101 }
102
VisitADD(GateRef gate)103 GateRef ConstantFolding::VisitADD(GateRef gate)
104 {
105 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) {
106 if (lvalue > 0 && rvalue > INT_MAX - lvalue) {
107 return Circuit::NullGate();
108 }
109 if (lvalue < 0 && rvalue < INT_MIN - lvalue) {
110 return Circuit::NullGate();
111 }
112 return Int32Constant(lvalue + rvalue);
113 });
114 }
115
VisitSUB(GateRef gate)116 GateRef ConstantFolding::VisitSUB(GateRef gate)
117 {
118 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) {
119 if (rvalue > 0 && lvalue < INT_MIN + rvalue) {
120 return Circuit::NullGate();
121 }
122 if (rvalue < 0 && lvalue > INT_MAX + rvalue) {
123 return Circuit::NullGate();
124 }
125 return Int32Constant(lvalue - rvalue);
126 });
127 }
128
VisitMUL(GateRef gate)129 GateRef ConstantFolding::VisitMUL(GateRef gate)
130 {
131 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) {
132 if (lvalue > 0 && rvalue > 0 && lvalue > INT_MAX / rvalue) {
133 return Circuit::NullGate();
134 }
135 if (lvalue < 0 && rvalue < 0 && lvalue < INT_MAX / rvalue) {
136 return Circuit::NullGate();
137 }
138 if (lvalue > 0 && rvalue < 0 && rvalue < INT_MIN / lvalue) {
139 return Circuit::NullGate();
140 }
141 if (lvalue < 0 && rvalue > 0 && lvalue < INT_MIN / rvalue) {
142 return Circuit::NullGate();
143 }
144 return Int32Constant(lvalue * rvalue);
145 });
146 }
147
VisitAND(GateRef gate)148 GateRef ConstantFolding::VisitAND(GateRef gate)
149 {
150 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) { return Int32Constant(lvalue & rvalue); });
151 }
152
VisitOR(GateRef gate)153 GateRef ConstantFolding::VisitOR(GateRef gate)
154 {
155 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) { return Int32Constant(lvalue | rvalue); });
156 }
157
VisitXOR(GateRef gate)158 GateRef ConstantFolding::VisitXOR(GateRef gate)
159 {
160 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) { return Int32Constant(lvalue ^ rvalue); });
161 }
162
VisitMAX(GateRef gate)163 GateRef ConstantFolding::VisitMAX(GateRef gate)
164 {
165 if (IsInt32Type(gate)) {
166 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) {
167 return Int32Constant(std::max(lvalue, rvalue));
168 });
169 }
170 return BinaryF64Calculate(gate, [this](double lvalue, double rvalue) {
171 return DoubleConstant(std::max(lvalue, rvalue));
172 });
173 }
174
VisitMIN(GateRef gate)175 GateRef ConstantFolding::VisitMIN(GateRef gate)
176 {
177 if (IsInt32Type(gate)) {
178 return BinaryInt32Calculate(gate, [this](int lvalue, int rvalue) {
179 return Int32Constant(std::min(lvalue, rvalue));
180 });
181 }
182 return BinaryF64Calculate(gate, [this](double lvalue, double rvalue) {
183 return DoubleConstant(std::min(lvalue, rvalue));
184 });
185 }
186
VisitABS(GateRef gate)187 GateRef ConstantFolding::VisitABS(GateRef gate)
188 {
189 return UnaryInt32Calculate(gate, [this](int value) { return Int32Constant(std::abs(value)); });
190 }
191
VisitSQRT(GateRef gate)192 GateRef ConstantFolding::VisitSQRT(GateRef gate)
193 {
194 return UnaryF64Calculate(gate, [this](double value) { return DoubleConstant(std::sqrt(value)); });
195 }
196
VisitCEIL(GateRef gate)197 GateRef ConstantFolding::VisitCEIL(GateRef gate)
198 {
199 return UnaryF64Calculate(gate, [this](double value) { return DoubleConstant(std::ceil(value)); });
200 }
201
VisitFLOOR(GateRef gate)202 GateRef ConstantFolding::VisitFLOOR(GateRef gate)
203 {
204 return UnaryF64Calculate(gate, [this](double value) { return DoubleConstant(std::floor(value)); });
205 }
206
VisitSMOD(GateRef gate)207 GateRef ConstantFolding::VisitSMOD(GateRef gate)
208 {
209 auto left = acc_.GetValueIn(gate, 0);
210 auto right = acc_.GetValueIn(gate, 1);
211 if (!IsInt32Type(gate) || !IsInt32Type(left) || !IsInt32Type(right)) {
212 return Circuit::NullGate();
213 }
214
215 GateRef result = Circuit::NullGate();
216 if (acc_.IsConstant(left) && acc_.IsConstant(right)) {
217 AddFoldingCount();
218 int lvalue = acc_.GetInt32FromConstant(left);
219 int rvalue = acc_.GetInt32FromConstant(right);
220 if (rvalue != 0) {
221 result = Int32Constant(lvalue % rvalue);
222 }
223 }
224 return result;
225 }
226
VisitUMOD(GateRef gate)227 GateRef ConstantFolding::VisitUMOD(GateRef gate)
228 {
229 auto left = acc_.GetValueIn(gate, 0);
230 auto right = acc_.GetValueIn(gate, 1);
231 if (!IsInt32Type(gate) || !IsInt32Type(left) || !IsInt32Type(right)) {
232 return Circuit::NullGate();
233 }
234
235 GateRef result = Circuit::NullGate();
236 if (acc_.IsConstant(left) && acc_.IsConstant(right)) {
237 AddFoldingCount();
238 int lvalue = acc_.GetInt32FromConstant(left);
239 int rvalue = acc_.GetInt32FromConstant(right);
240 if (rvalue != 0) {
241 result = Int32Constant(bit_cast<uint32_t>(lvalue) % rvalue);
242 }
243 }
244 return result;
245 }
246
VisitREV(GateRef gate)247 GateRef ConstantFolding::VisitREV(GateRef gate)
248 {
249 auto input = acc_.GetValueIn(gate);
250 if (!IsBoolType(gate) || !acc_.IsConstant(input) || !IsBoolType(input)) {
251 return Circuit::NullGate();
252 }
253
254 GateRef result = Circuit::NullGate();
255 uint64_t rawValue = acc_.GetConstantValue(input);
256 if (acc_.GetGateType(gate).IsNJSValueType()) {
257 AddFoldingCount();
258 result = BoolConstant(rawValue == 0);
259 }
260 return result;
261 }
262
VisitZEXT(GateRef gate)263 GateRef ConstantFolding::VisitZEXT(GateRef gate)
264 {
265 auto input = acc_.GetValueIn(gate, 0);
266 if (acc_.GetMachineType(gate) == acc_.GetMachineType(input)) {
267 AddFoldingCount();
268 return input;
269 }
270
271 GateRef result = Circuit::NullGate();
272 if (acc_.IsConstant(input) && IsInt32Type(input)) {
273 AddFoldingCount();
274 int value = acc_.GetInt32FromConstant(input);
275 auto machineType = acc_.GetMachineType(gate);
276 switch (machineType) {
277 case MachineType::I32:
278 result = Int32Constant(value);
279 break;
280 case MachineType::ARCH:
281 case MachineType::I64:
282 result = Int64Constant(value);
283 break;
284 default:
285 break;
286 }
287 }
288 return result;
289 }
290
Print() const291 void ConstantFolding::Print() const
292 {
293 if (IsLogEnabled()) {
294 LOG_COMPILER(INFO) << "";
295 LOG_COMPILER(INFO) << "\033[34m"
296 << "===================="
297 << " After constant folding "
298 << "[" << GetMethodName() << "]"
299 << "===================="
300 << "\033[0m";
301 circuit_->PrintAllGatesWithBytecode();
302 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
303
304 LOG_COMPILER(INFO) << "Folding Count : " << GetFoldingCount();
305 }
306 }
307 } // namespace panda::ecmascript::kungfu