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