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