1 /*
2 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 * Copyright (c) 2024 Huawei Device Co., Ltd.
16 * Licensed under the Apache License, Version 2.0 (the "License");
17 * you may not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28
29 #include "constant_propagation.h"
30 #include "bytecode_optimizer/bytecode_analysis_results.h"
31 #include "compiler_logger.h"
32 #include "compiler/optimizer/optimizations/lowering.h"
33 #include "optimizer/ir/graph.h"
34 #include "optimizer/ir/inst.h"
35
36 namespace panda::bytecodeopt {
37
38 enum class InputCount {
39 NONE_INPUT,
40 ONE_INPUT,
41 TWO_INPUT,
42 };
43
ConstantPropagation(compiler::Graph * graph,const BytecodeOptIrInterface * iface)44 ConstantPropagation::ConstantPropagation(compiler::Graph *graph, const BytecodeOptIrInterface *iface)
45 : Optimization(graph),
46 lattices_(graph->GetLocalAllocator()->Adapter()),
47 flow_edges_(graph->GetLocalAllocator()->Adapter()),
48 ssa_edges_(graph->GetLocalAllocator()->Adapter()),
49 executable_flag_(graph->GetLocalAllocator()->Adapter()),
50 executed_node_(graph->GetLocalAllocator()->Adapter()),
51 ir_interface_(iface)
52 {
53 std::string classname = GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod());
54 record_name_ = pandasm::Type::FromDescriptor(classname).GetName();
55 }
56
RunImpl()57 bool ConstantPropagation::RunImpl()
58 {
59 auto entry = GetGraph()->GetStartBlock();
60 AddUntraversedFlowEdges(nullptr, entry);
61 while (!flow_edges_.empty() || !ssa_edges_.empty()) {
62 RunFlowEdge();
63 RunSsaEdge();
64 };
65 ReWriteInst();
66 return true;
67 }
68
RunFlowEdge()69 void ConstantPropagation::RunFlowEdge()
70 {
71 while (!flow_edges_.empty()) {
72 auto &edge = flow_edges_.front();
73 flow_edges_.pop();
74
75 if (executable_flag_.count(edge) != 0) {
76 continue;
77 }
78 executable_flag_.insert(edge);
79 auto dest = edge.second;
80 for (auto phi : dest->PhiInstsSafe()) {
81 VisitInstruction(phi);
82 }
83 // If the destination basic block (BB) has already been visited, there is no need to process its non-phi
84 // instructions.
85 if (executed_node_.count(dest->GetId()) != 0) {
86 continue;
87 }
88 executed_node_.insert(dest->GetId());
89 VisitInsts(dest);
90 }
91 }
92
RunSsaEdge()93 void ConstantPropagation::RunSsaEdge()
94 {
95 while (!ssa_edges_.empty()) {
96 auto inst = ssa_edges_.front();
97 ssa_edges_.pop();
98 for (auto &user : inst->GetUsers()) {
99 if (user.GetInst()->IsPhi()) {
100 VisitInstruction(user.GetInst()->CastToPhi());
101 } else if (executed_node_.count(user.GetInst()->GetBasicBlock()->GetId()) != 0) {
102 VisitInstruction(user.GetInst());
103 }
104 }
105 }
106 }
107
ReWriteInst()108 void ConstantPropagation::ReWriteInst()
109 {
110 for (auto &pair : lattices_) {
111 ASSERT(pair.second != nullptr);
112 if (!pair.second->IsConstantElement() || pair.first->IsConst()) {
113 continue;
114 }
115 // Skip the CastValueToAnyType instruction to preserve the original IR structure of
116 // "LoadString/Constant(double) -> CastValueToAnyType".
117 // This structure is necessary for certain GraphChecker checks.
118 if (pair.first->GetOpcode() == compiler::Opcode::CastValueToAnyType) {
119 continue;
120 }
121 // Skip generate replacement inst for string constants for now, since it requires generating
122 // a string with a unique offset
123 if (pair.second->AsConstant()->GetType() == ConstantValue::CONSTANT_STRING) {
124 continue;
125 }
126 if (pair.first->IsIntrinsic()) {
127 auto id = pair.first->CastToIntrinsic()->GetIntrinsicId();
128 // Skip Intrinsic.ldtrue and Intrinsic.ldfalse since replacing them would create the same instruction.
129 // Skip ldlocal/externalmodulevar and ldobjbyname in case of possible side effects when accessing module
130 // constants.
131 switch (id) {
132 case compiler::RuntimeInterface::IntrinsicId::LDFALSE:
133 case compiler::RuntimeInterface::IntrinsicId::LDTRUE:
134 pair.first->ClearFlag(compiler::inst_flags::NO_DCE);
135 continue;
136 case RuntimeInterface::IntrinsicId::LDLOCALMODULEVAR_IMM8:
137 case RuntimeInterface::IntrinsicId::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
138 case RuntimeInterface::IntrinsicId::LDEXTERNALMODULEVAR_IMM8:
139 case RuntimeInterface::IntrinsicId::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
140 case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM8_ID16:
141 case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM16_ID16:
142 continue;
143 default:
144 break;
145 }
146 }
147 auto replace_inst = CreateReplaceInst(pair.first, pair.second->AsConstant());
148 // This should never happen, but left here as a precaution for unexpected scenarios.
149 if (replace_inst == nullptr) {
150 continue;
151 }
152 pair.first->ReplaceUsers(replace_inst);
153 pair.first->ClearFlag(compiler::inst_flags::NO_DCE);
154 }
155 }
156
VisitInsts(BasicBlock * bb)157 void ConstantPropagation::VisitInsts(BasicBlock *bb)
158 {
159 for (auto inst : bb->AllInsts()) {
160 if (inst->IsPhi()) {
161 continue;
162 }
163 VisitInstruction(inst);
164 }
165 // If branch
166 Inst *lastInst = bb->GetLastInst();
167 if (lastInst && lastInst->GetOpcode() == Opcode::IfImm) {
168 return;
169 }
170 auto &succs = bb->GetSuccsBlocks();
171 for (auto succ : succs) {
172 AddUntraversedFlowEdges(bb, succ);
173 }
174 }
175
VisitDefault(Inst * inst)176 void ConstantPropagation::VisitDefault(Inst *inst)
177 {
178 auto current = GetOrCreateDefaultLattice(inst);
179 if (current->IsBottomElement()) {
180 return;
181 }
182 CheckAndAddToSsaEdge(inst, current, BottomElement::GetInstance());
183 }
184
VisitIfImm(GraphVisitor * v,Inst * inst)185 void ConstantPropagation::VisitIfImm(GraphVisitor *v, Inst *inst)
186 {
187 ASSERT(v);
188 ASSERT(inst && inst->GetOpcode() == Opcode::IfImm);
189 auto propagation = static_cast<ConstantPropagation *>(v);
190 auto input_inst = inst->GetDataFlowInput(inst->GetInput(0).GetInst());
191 auto input_lattice = propagation->GetOrCreateDefaultLattice(input_inst);
192 auto bb = inst->GetBasicBlock();
193 // According to inst_builder_gen.cpp.erb, the input of the IfImm IR is always a Compare IR generates DataType::BOOL.
194 if (input_lattice->IsConstantElement() &&
195 input_lattice->AsConstant()->GetType() == ConstantValue::CONSTANT_BOOL) {
196 auto cst = static_cast<uint64_t>(input_lattice->AsConstant()->GetValue<bool>());
197 auto dstBlock =
198 propagation->GetIfTargetBlock(inst->CastToIfImm(), cst) ? bb->GetTrueSuccessor() : bb->GetFalseSuccessor();
199 propagation->AddUntraversedFlowEdges(bb, dstBlock);
200 } else {
201 propagation->AddUntraversedFlowEdges(bb, bb->GetTrueSuccessor());
202 propagation->AddUntraversedFlowEdges(bb, bb->GetFalseSuccessor());
203 }
204 }
205
VisitCompare(GraphVisitor * v,Inst * inst)206 void ConstantPropagation::VisitCompare(GraphVisitor *v, Inst *inst)
207 {
208 ASSERT(v);
209 ASSERT(inst && inst->GetOpcode() == Opcode::Compare);
210 auto propagation = static_cast<ConstantPropagation *>(v);
211 auto current = propagation->GetOrCreateDefaultLattice(inst);
212 if (current->IsBottomElement()) {
213 return;
214 }
215 auto input0 = inst->GetDataFlowInput(inst->GetInput(0).GetInst());
216 auto input1 = inst->GetDataFlowInput(inst->GetInput(1).GetInst());
217 auto lattices0 = propagation->GetOrCreateDefaultLattice(input0);
218 auto lattices1 = propagation->GetOrCreateDefaultLattice(input1);
219 LatticeElement *element = BottomElement::GetInstance();
220 if (lattices0->IsConstantElement() && lattices1->IsConstantElement()) {
221 element = propagation->FoldingCompare(lattices0->AsConstant(), lattices1->AsConstant(),
222 inst->CastToCompare()->GetCc());
223 }
224 propagation->CheckAndAddToSsaEdge(inst, current, element);
225 }
226
VisitIntrinsic(GraphVisitor * v,Inst * inst)227 void ConstantPropagation::VisitIntrinsic(GraphVisitor *v, Inst *inst)
228 {
229 ASSERT(v);
230 ASSERT(inst && inst->IsIntrinsic());
231 auto propagation = static_cast<ConstantPropagation *>(v);
232 auto current = propagation->GetOrCreateDefaultLattice(inst);
233 if (current->IsBottomElement()) {
234 return;
235 }
236 auto id = inst->CastToIntrinsic()->GetIntrinsicId();
237 LatticeElement *element = propagation->FoldingModuleOperation(inst->CastToIntrinsic());
238 if (element != nullptr) {
239 propagation->CheckAndAddToSsaEdge(inst, current, element);
240 return;
241 }
242 element = BottomElement::GetInstance();
243 auto count = inst->GetInputsCount();
244 if (inst->RequireState()) {
245 count--;
246 }
247 auto input_count = static_cast<InputCount>(count);
248 switch (input_count) {
249 case InputCount::TWO_INPUT: {
250 auto input0 = inst->GetDataFlowInput(inst->GetInput(0).GetInst());
251 auto input1 = inst->GetDataFlowInput(inst->GetInput(1).GetInst());
252 auto lattices0 = propagation->GetOrCreateDefaultLattice(input0);
253 auto lattices1 = propagation->GetOrCreateDefaultLattice(input1);
254 if (lattices0->IsConstantElement() && lattices1->IsConstantElement()) {
255 element = propagation->FoldingConstant(lattices0->AsConstant(), lattices1->AsConstant(), id);
256 }
257 break;
258 }
259 case InputCount::ONE_INPUT: {
260 auto input = inst->GetDataFlowInput(inst->GetInput(0).GetInst());
261 auto lattice = propagation->GetOrCreateDefaultLattice(input);
262 if (lattice->IsConstantElement()) {
263 element = propagation->FoldingConstant(lattice->AsConstant(), id);
264 }
265 break;
266 }
267 case InputCount::NONE_INPUT: {
268 element = propagation->FoldingConstant(id);
269 break;
270 }
271 default:
272 break;
273 }
274 propagation->CheckAndAddToSsaEdge(inst, current, element);
275 }
276
VisitCastValueToAnyType(GraphVisitor * v,Inst * inst)277 void ConstantPropagation::VisitCastValueToAnyType(GraphVisitor *v, Inst *inst)
278 {
279 ASSERT(v);
280 ASSERT(inst && inst->GetOpcode() == Opcode::CastValueToAnyType);
281 auto propagation = static_cast<ConstantPropagation *>(v);
282 auto current = propagation->GetOrCreateDefaultLattice(inst);
283 if (current->IsBottomElement()) {
284 return;
285 }
286 LatticeElement *element = BottomElement::GetInstance();
287 auto type = inst->CastToCastValueToAnyType()->GetAnyType();
288 // According to inst_builder.cpp:
289 // 1. The fldai bytecode will generate: Constant(double) -> CastValueToAnyType(ECMASCRIPT_DOUBLE_TYPE).
290 // 2. The lda.str bytecode will generate: LoadString -> CastValueToAnyType(ECMASCRIPT_STRING_TYPE).
291 // We create the lattice value of the original constant here and leave the IR unchanged.
292 if (type == compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE) {
293 ASSERT(inst->GetDataFlowInput(0)->IsConst());
294 element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(
295 inst->GetDataFlowInput(0)->CastToConstant()->GetDoubleValue());
296 } else if (type == compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE) {
297 ASSERT(inst->GetDataFlowInput(0)->GetOpcode() == compiler::Opcode::LoadString);
298 auto load_string_inst = inst->GetDataFlowInput(0)->CastToLoadString();
299 element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(
300 propagation->ir_interface_->GetStringIdByOffset(load_string_inst->GetTypeId()));
301 }
302 propagation->CheckAndAddToSsaEdge(inst, current, element);
303 }
304
VisitConstant(GraphVisitor * v,Inst * inst)305 void ConstantPropagation::VisitConstant(GraphVisitor *v, Inst *inst)
306 {
307 ASSERT(v);
308 ASSERT(inst && inst->IsConst());
309 auto propagation = static_cast<ConstantPropagation *>(v);
310 auto const_inst = inst->CastToConstant();
311 auto current = propagation->GetOrCreateDefaultLattice(inst);
312 if (current->IsBottomElement()) {
313 return;
314 }
315 LatticeElement *element = BottomElement::GetInstance();
316 switch (const_inst->GetType()) {
317 case compiler::DataType::INT32: {
318 auto val = static_cast<int32_t>(const_inst->GetInt32Value());
319 element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
320 break;
321 }
322 case compiler::DataType::INT64: {
323 auto val = static_cast<int64_t>(const_inst->GetRawValue());
324 element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
325 break;
326 }
327 case compiler::DataType::FLOAT64: {
328 auto val = const_inst->GetDoubleValue();
329 element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
330 break;
331 }
332 default:
333 break;
334 }
335 propagation->CheckAndAddToSsaEdge(inst, current, element);
336 }
337
VisitLoadString(GraphVisitor * v,Inst * inst)338 void ConstantPropagation::VisitLoadString(GraphVisitor *v, Inst *inst)
339 {
340 ASSERT(v);
341 ASSERT(inst && inst->GetOpcode() == compiler::Opcode::LoadString);
342 auto propagation = static_cast<ConstantPropagation *>(v);
343 auto load_string_inst = inst->CastToLoadString();
344 auto current = propagation->GetOrCreateDefaultLattice(inst);
345 if (current->IsBottomElement()) {
346 return;
347 }
348 auto val = propagation->ir_interface_->GetStringIdByOffset(load_string_inst->GetTypeId());
349 LatticeElement *element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
350 propagation->CheckAndAddToSsaEdge(inst, current, element);
351 }
352
VisitPhi(GraphVisitor * v,Inst * inst)353 void ConstantPropagation::VisitPhi(GraphVisitor *v, Inst *inst)
354 {
355 ASSERT(v);
356 ASSERT(inst->IsPhi());
357 auto propagation = static_cast<ConstantPropagation *>(v);
358 auto current = propagation->GetOrCreateDefaultLattice(inst);
359 if (current->IsBottomElement()) {
360 return;
361 }
362 auto bb = inst->GetBasicBlock();
363 auto &pres = bb->GetPredsBlocks();
364 LatticeElement *element = TopElement::GetInstance();
365 for (size_t i = 0; i < pres.size(); i++) {
366 if (propagation->executable_flag_.count(Edge(pres[i], bb))) {
367 auto input_lattice = propagation->GetOrCreateDefaultLattice(inst->GetInput(i).GetInst());
368 element = element->Meet(input_lattice);
369 if (element->IsBottomElement()) {
370 break;
371 }
372 }
373 }
374 propagation->CheckAndAddToSsaEdge(inst, current, element);
375 }
376
AddUntraversedFlowEdges(BasicBlock * src,BasicBlock * dst)377 void ConstantPropagation::AddUntraversedFlowEdges(BasicBlock *src, BasicBlock *dst)
378 {
379 auto edge = Edge(src, dst);
380 if (executable_flag_.count(edge) != 0) {
381 return;
382 }
383 flow_edges_.push(edge);
384 }
385
GetIfTargetBlock(compiler::IfImmInst * inst,uint64_t val)386 bool ConstantPropagation::GetIfTargetBlock(compiler::IfImmInst *inst, uint64_t val)
387 {
388 auto imm = inst->GetImm();
389 auto cc = inst->GetCc();
390 switch (cc) {
391 case compiler::ConditionCode::CC_NE:
392 return imm != val;
393 case compiler::ConditionCode::CC_EQ:
394 return imm == val;
395 default:
396 UNREACHABLE();
397 }
398 return false;
399 }
400
GetOrCreateDefaultLattice(Inst * inst)401 LatticeElement *ConstantPropagation::GetOrCreateDefaultLattice(Inst *inst)
402 {
403 auto iter = lattices_.find(inst);
404 if (iter == lattices_.end()) {
405 lattices_.emplace(inst, TopElement::GetInstance());
406 return TopElement::GetInstance();
407 }
408 return iter->second;
409 }
410
FoldingConstant(ConstantElement * left,ConstantElement * right,RuntimeInterface::IntrinsicId id)411 LatticeElement *ConstantPropagation::FoldingConstant(ConstantElement *left, ConstantElement *right,
412 RuntimeInterface::IntrinsicId id)
413 {
414 switch (id) {
415 case RuntimeInterface::IntrinsicId::GREATER_IMM8_V8:
416 case RuntimeInterface::IntrinsicId::GREATEREQ_IMM8_V8: {
417 return FoldingGreater(left, right, id == RuntimeInterface::IntrinsicId::GREATEREQ_IMM8_V8);
418 }
419 case RuntimeInterface::IntrinsicId::LESS_IMM8_V8:
420 case RuntimeInterface::IntrinsicId::LESSEQ_IMM8_V8: {
421 return FoldingLess(left, right, id == RuntimeInterface::IntrinsicId::LESSEQ_IMM8_V8);
422 }
423 case RuntimeInterface::IntrinsicId::STRICTEQ_IMM8_V8:
424 case RuntimeInterface::IntrinsicId::EQ_IMM8_V8: {
425 return FoldingEq(left, right);
426 }
427 case RuntimeInterface::IntrinsicId::STRICTNOTEQ_IMM8_V8:
428 case RuntimeInterface::IntrinsicId::NOTEQ_IMM8_V8: {
429 return FoldingNotEq(left, right);
430 }
431 default:
432 return BottomElement::GetInstance();
433 }
434 }
435
FoldingModuleOperation(compiler::IntrinsicInst * inst)436 LatticeElement *ConstantPropagation::FoldingModuleOperation(compiler::IntrinsicInst *inst)
437 {
438 auto id = inst->GetIntrinsicId();
439 switch (id) {
440 case RuntimeInterface::IntrinsicId::LDLOCALMODULEVAR_IMM8:
441 case RuntimeInterface::IntrinsicId::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
442 return FoldingLdlocalmodulevar(inst);
443 case RuntimeInterface::IntrinsicId::LDEXTERNALMODULEVAR_IMM8:
444 case RuntimeInterface::IntrinsicId::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
445 return FoldingLdexternalmodulevar(inst);
446 case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM8_ID16:
447 case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM16_ID16:
448 return FoldingLdobjbyname(inst);
449 default:
450 return nullptr;
451 }
452 }
453
FoldingConstant(RuntimeInterface::IntrinsicId id)454 LatticeElement *ConstantPropagation::FoldingConstant(RuntimeInterface::IntrinsicId id)
455 {
456 switch (id) {
457 case RuntimeInterface::IntrinsicId::LDFALSE:
458 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(false);
459 case RuntimeInterface::IntrinsicId::LDTRUE:
460 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(true);
461 default:
462 return BottomElement::GetInstance();
463 }
464 }
465
FoldingConstant(ConstantElement * lattice,RuntimeInterface::IntrinsicId id)466 LatticeElement *ConstantPropagation::FoldingConstant(ConstantElement *lattice, RuntimeInterface::IntrinsicId id)
467 {
468 switch (id) {
469 case RuntimeInterface::IntrinsicId::ISFALSE:
470 case RuntimeInterface::IntrinsicId::ISTRUE:
471 case RuntimeInterface::IntrinsicId::CALLRUNTIME_ISFALSE_PREF_IMM8:
472 case RuntimeInterface::IntrinsicId::CALLRUNTIME_ISTRUE_PREF_IMM8: {
473 if (lattice->GetType() != ConstantValue::CONSTANT_BOOL) {
474 return BottomElement::GetInstance();
475 }
476 auto cst = lattice->GetValue<bool>();
477 bool is_true_ins = (id == RuntimeInterface::IntrinsicId::ISTRUE) ||
478 (id == RuntimeInterface::IntrinsicId::CALLRUNTIME_ISTRUE_PREF_IMM8);
479 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(
480 is_true_ins ? cst : !cst);
481 }
482 default:
483 return BottomElement::GetInstance();
484 }
485 }
486
FoldingCompare(const ConstantElement * left,const ConstantElement * right,compiler::ConditionCode cc)487 LatticeElement *ConstantPropagation::FoldingCompare(const ConstantElement *left, const ConstantElement *right,
488 compiler::ConditionCode cc)
489 {
490 ASSERT(left);
491 ASSERT(right);
492 // According to inst_builder_gen.cpp.erb, the input of the Compare IR are always ISTRUE/ISFALSE and a zero of i64.
493 if (left->GetType() != ConstantValue::CONSTANT_BOOL || right->GetType() != ConstantValue::CONSTANT_INT64) {
494 return BottomElement::GetInstance();
495 }
496 auto left_value = left->GetValue<bool>();
497 auto right_value = right->GetValue<int64_t>();
498 if ((right_value != 0) && (right_value != 1)) {
499 return BottomElement::GetInstance();
500 }
501 switch (cc) {
502 case compiler::CC_EQ: {
503 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(left_value == right_value);
504 }
505 case compiler::CC_NE: {
506 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(left_value != right_value);
507 }
508 default:
509 return BottomElement::GetInstance();
510 }
511 }
512
FoldingGreater(const ConstantElement * left,const ConstantElement * right,bool equal)513 LatticeElement *ConstantPropagation::FoldingGreater(const ConstantElement *left, const ConstantElement *right,
514 bool equal)
515 {
516 if (left->GetType() != right->GetType() || left->GetType() == ConstantValue::CONSTANT_STRING) {
517 return BottomElement::GetInstance();
518 }
519 auto left_value = left->GetValue();
520 auto right_value = right->GetValue();
521 auto result = equal ? left_value >= right_value : left_value > right_value;
522 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(result);
523 }
524
FoldingLess(const ConstantElement * left,const ConstantElement * right,bool equal)525 LatticeElement *ConstantPropagation::FoldingLess(const ConstantElement *left, const ConstantElement *right, bool equal)
526 {
527 if (left->GetType() != right->GetType() || left->GetType() == ConstantValue::CONSTANT_STRING) {
528 return BottomElement::GetInstance();
529 }
530 auto left_value = left->GetValue();
531 auto right_value = right->GetValue();
532 auto result = equal ? left_value <= right_value : left_value < right_value;
533 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(result);
534 }
535
FoldingEq(const ConstantElement * left,const ConstantElement * right)536 LatticeElement *ConstantPropagation::FoldingEq(const ConstantElement *left, const ConstantElement *right)
537 {
538 if (left->GetType() != right->GetType()) {
539 return BottomElement::GetInstance();
540 }
541 auto left_value = left->GetValue();
542 auto right_value = right->GetValue();
543 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(left_value == right_value);
544 }
545
FoldingNotEq(const ConstantElement * left,const ConstantElement * right)546 LatticeElement *ConstantPropagation::FoldingNotEq(const ConstantElement *left, const ConstantElement *right)
547 {
548 if (left->GetType() != right->GetType()) {
549 return BottomElement::GetInstance();
550 }
551 auto left_value = left->GetValue();
552 auto right_value = right->GetValue();
553 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(left_value != right_value);
554 }
555
FoldingLdlocalmodulevar(compiler::IntrinsicInst * inst)556 LatticeElement *ConstantPropagation::FoldingLdlocalmodulevar(compiler::IntrinsicInst *inst)
557 {
558 constexpr uint32_t LOCAL_EXPORT_SLOT_IDX = 0;
559 uint32_t local_export_slot = inst->GetImms()[LOCAL_EXPORT_SLOT_IDX];
560 ConstantValue constant_value;
561 if (bytecodeopt::BytecodeAnalysisResults::GetLocalExportConstForRecord(record_name_,
562 local_export_slot,
563 constant_value)) {
564 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(constant_value);
565 }
566 return BottomElement::GetInstance();
567 }
568
FoldingLdexternalmodulevar(compiler::IntrinsicInst * inst)569 LatticeElement *ConstantPropagation::FoldingLdexternalmodulevar(compiler::IntrinsicInst *inst)
570 {
571 constexpr uint32_t REGULAR_IMPORT_SLOT_IDX = 0;
572 auto regular_import_slot = inst->GetImms()[REGULAR_IMPORT_SLOT_IDX];
573 ConstantValue constant_value;
574 if (bytecodeopt::BytecodeAnalysisResults::GetRegularImportConstForRecord(record_name_,
575 regular_import_slot,
576 constant_value)) {
577 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(constant_value);
578 }
579 return BottomElement::GetInstance();
580 }
581
FoldingLdobjbyname(compiler::IntrinsicInst * inst)582 LatticeElement *ConstantPropagation::FoldingLdobjbyname(compiler::IntrinsicInst *inst)
583 {
584 constexpr uint32_t PROPERTY_NAME_STRING_OFFSET_IDX = 1;
585 constexpr uint32_t MODULE_NAMESPACE_SLOT_IDX = 0;
586 constexpr uint32_t OBJECT_INPUT_IDX = 0;
587 Inst *object_inst = inst->GetDataFlowInput(OBJECT_INPUT_IDX);
588 if (object_inst->IsIntrinsic()) {
589 auto id = object_inst->CastToIntrinsic()->GetIntrinsicId();
590 if (id == RuntimeInterface::IntrinsicId::GETMODULENAMESPACE_IMM8 ||
591 id == RuntimeInterface::IntrinsicId::WIDE_GETMODULENAMESPACE_PREF_IMM16) {
592 uint32_t property_name_offset = inst->GetImms()[PROPERTY_NAME_STRING_OFFSET_IDX];
593 std::string property_name = ir_interface_->GetStringIdByOffset(property_name_offset);
594 uint32_t module_namespace_slot = object_inst->CastToIntrinsic()->GetImms()[MODULE_NAMESPACE_SLOT_IDX];
595 ConstantValue constant_value;
596 if (bytecodeopt::BytecodeAnalysisResults::GetModuleNamespaceConstForRecord(record_name_,
597 module_namespace_slot,
598 property_name,
599 constant_value)) {
600 return GetGraph()->GetLocalAllocator()->New<ConstantElement>(constant_value);
601 }
602 }
603 }
604 return BottomElement::GetInstance();
605 }
606
CreateReplaceInst(Inst * base_inst,ConstantElement * lattice)607 Inst *ConstantPropagation::CreateReplaceInst(Inst *base_inst, ConstantElement *lattice)
608 {
609 auto const_type = lattice->GetType();
610 Inst *replace_inst = nullptr;
611 switch (const_type) {
612 case ConstantValue::CONSTANT_BOOL: {
613 auto inst_intrinsic_id = lattice->GetValue<bool>() ? RuntimeInterface::IntrinsicId::LDTRUE
614 : RuntimeInterface::IntrinsicId::LDFALSE;
615 auto inst = GetGraph()->CreateInstIntrinsic(compiler::DataType::ANY, base_inst->GetPc(), inst_intrinsic_id);
616 size_t args_count {1U}; // 1: input count
617 inst->ReserveInputs(args_count);
618 inst->AllocateInputTypes(GetGraph()->GetAllocator(), args_count);
619 compiler::SaveStateInst *save_state_inst = GetGraph()->CreateInstSaveState();
620 save_state_inst->SetPc(base_inst->GetPc());
621 save_state_inst->SetMethod(GetGraph()->GetMethod());
622 save_state_inst->ReserveInputs(0);
623 inst->SetFlag(compiler::inst_flags::ACC_WRITE);
624 inst->ClearFlag(compiler::inst_flags::NO_DCE);
625 inst->AppendInput(save_state_inst);
626 inst->AddInputType(compiler::DataType::NO_TYPE);
627 InsertSaveState(base_inst, save_state_inst);
628 base_inst->GetBasicBlock()->InsertAfter(inst, save_state_inst);
629 replace_inst = inst;
630 break;
631 }
632 case ConstantValue::CONSTANT_INT32: {
633 replace_inst = GetGraph()->FindOrCreateConstant(static_cast<uint32_t>(lattice->GetValue<int32_t>()));
634 break;
635 }
636 case ConstantValue::CONSTANT_INT64: {
637 replace_inst = GetGraph()->FindOrCreateConstant(static_cast<uint64_t>(lattice->GetValue<int64_t>()));
638 break;
639 }
640 case ConstantValue::CONSTANT_DOUBLE: {
641 replace_inst = GetGraph()->FindOrCreateConstant(lattice->GetValue<double>());
642 break;
643 }
644 default:
645 UNREACHABLE();
646 }
647 ASSERT(replace_inst);
648 return replace_inst;
649 }
650
InsertSaveState(Inst * base_inst,Inst * save_state)651 void ConstantPropagation::InsertSaveState(Inst *base_inst, Inst *save_state)
652 {
653 auto bb = base_inst->GetBasicBlock();
654 if (!base_inst->IsPhi()) {
655 bb->InsertAfter(save_state, base_inst);
656 return;
657 }
658 auto first_inst = bb->Insts().begin();
659 if (first_inst != bb->Insts().end()) {
660 bb->InsertBefore(save_state, *first_inst);
661 } else {
662 bb->AppendInst(save_state);
663 }
664 }
665
CheckAndAddToSsaEdge(Inst * inst,LatticeElement * current,LatticeElement * new_lattice)666 void ConstantPropagation::CheckAndAddToSsaEdge(Inst *inst, LatticeElement *current, LatticeElement *new_lattice)
667 {
668 auto dst = current->Meet(new_lattice);
669 if (dst != current) {
670 ssa_edges_.push(inst);
671 lattices_[inst] = dst;
672 }
673 }
674
675 } // namespace panda::bytecodeopt
676