• 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 #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