1 /**
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "module_constant_analyzer.h"
17 #include "bytecode_optimizer/constant_propagation/constant_value.h"
18
19 namespace panda::bytecodeopt {
20
ModuleConstantAnalyzer(compiler::Graph * graph,const std::unordered_set<uint32_t> & const_local_export_slots,ModuleConstantAnalysisResult & analysis_result,const BytecodeOptIrInterface * iface)21 ModuleConstantAnalyzer::ModuleConstantAnalyzer(compiler::Graph *graph,
22 const std::unordered_set<uint32_t> &const_local_export_slots,
23 ModuleConstantAnalysisResult &analysis_result,
24 const BytecodeOptIrInterface *iface)
25 : Analysis(graph),
26 const_local_export_slots_(const_local_export_slots),
27 analysis_result_(analysis_result),
28 ir_interface_(iface)
29 {
30 }
31
RunImpl()32 bool ModuleConstantAnalyzer::RunImpl()
33 {
34 VisitGraph();
35 return true;
36 }
37
VisitIntrinsic(compiler::GraphVisitor * visitor,compiler::Inst * inst)38 void ModuleConstantAnalyzer::VisitIntrinsic(compiler::GraphVisitor *visitor, compiler::Inst *inst)
39 {
40 constexpr int STMODULEVAR_VALUE_INPUT_INDEX = 0;
41 constexpr int STMODULEVAR_SLOT_NUMBER_IMM_INDEX = 0;
42 auto module_constant_analyzer = static_cast<ModuleConstantAnalyzer *>(visitor);
43 auto intrinsic_inst = inst->CastToIntrinsic();
44 auto id = intrinsic_inst->GetIntrinsicId();
45 switch (id) {
46 case RuntimeInterface::IntrinsicId::STMODULEVAR_IMM8:
47 case RuntimeInterface::IntrinsicId::WIDE_STMODULEVAR_PREF_IMM16: {
48 int module_var_slot = intrinsic_inst->GetImms()[STMODULEVAR_SLOT_NUMBER_IMM_INDEX];
49 if (!module_constant_analyzer->IsConstModuleVar(module_var_slot)) {
50 break;
51 }
52 auto input_inst = inst->GetDataFlowInput(STMODULEVAR_VALUE_INPUT_INDEX);
53 auto input_const_value = module_constant_analyzer->GetInstConstValue(input_inst);
54 if (input_const_value != nullptr) {
55 module_constant_analyzer->RecordModuleConstValue(module_var_slot, input_const_value);
56 }
57 break;
58 }
59 default:
60 break;
61 }
62 }
63
GetInstConstValue(Inst * inst)64 ConstantValue *ModuleConstantAnalyzer::GetInstConstValue(Inst *inst)
65 {
66 switch (inst->GetOpcode()) {
67 case Opcode::Constant:
68 return GetConstantInstConstValue(inst->CastToConstant());
69 case Opcode::Intrinsic:
70 return GetIntrinsicInstConstValue(inst->CastToIntrinsic());
71 case Opcode::LoadString:
72 return GetLoadStringInstConstValue(inst->CastToLoadString());
73 case Opcode::CastValueToAnyType:
74 // According to inst_builder.cpp:
75 // 1. the fldai bytecode generates Constant(double) -> CastValueToAnyType,
76 // 1. the lda.str bytecode generates LoadString -> CastValueToAnyType,
77 // We handle such case here. 0 stands for the DataFlowInput corresponding to the Constant/LoadString
78 if (inst->GetDataFlowInput(0)->IsConst() ||
79 inst->GetDataFlowInput(0)->GetOpcode() == compiler::Opcode::LoadString) {
80 return GetInstConstValue(inst->GetDataFlowInput(0));
81 }
82 return nullptr;
83 default:
84 return nullptr;
85 }
86 }
87
GetConstantInstConstValue(compiler::ConstantInst * const_inst)88 ConstantValue *ModuleConstantAnalyzer::GetConstantInstConstValue(compiler::ConstantInst *const_inst)
89 {
90 switch (const_inst->GetType()) {
91 case compiler::DataType::INT32: {
92 auto val = static_cast<int32_t>(const_inst->GetInt32Value());
93 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
94 }
95 case compiler::DataType::INT64: {
96 auto val = static_cast<int64_t>(const_inst->GetRawValue());
97 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
98 }
99 case compiler::DataType::FLOAT64: {
100 auto val = const_inst->GetDoubleValue();
101 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
102 }
103 default:
104 UNREACHABLE();
105 }
106 }
107
GetIntrinsicInstConstValue(compiler::IntrinsicInst * intrinsic_inst)108 ConstantValue *ModuleConstantAnalyzer::GetIntrinsicInstConstValue(compiler::IntrinsicInst *intrinsic_inst)
109 {
110 switch (intrinsic_inst->GetIntrinsicId()) {
111 case RuntimeInterface::IntrinsicId::LDTRUE:
112 case RuntimeInterface::IntrinsicId::LDFALSE: {
113 bool is_true = intrinsic_inst->GetIntrinsicId() == RuntimeInterface::IntrinsicId::LDTRUE;
114 return GetGraph()->GetAllocator()->New<ConstantValue>(is_true);
115 }
116 default:
117 return nullptr;
118 }
119 }
120
GetLoadStringInstConstValue(compiler::LoadFromPool * inst)121 ConstantValue *ModuleConstantAnalyzer::GetLoadStringInstConstValue(compiler::LoadFromPool *inst)
122 {
123 return GetGraph()->GetAllocator()->New<ConstantValue>(
124 ir_interface_->GetStringIdByOffset(inst->GetTypeId()));
125 }
126
IsConstModuleVar(uint32_t slot)127 bool ModuleConstantAnalyzer::IsConstModuleVar(uint32_t slot)
128 {
129 return const_local_export_slots_.count(slot) == 1;
130 }
131
RecordModuleConstValue(uint32_t slot,ConstantValue * value)132 void ModuleConstantAnalyzer::RecordModuleConstValue(uint32_t slot, ConstantValue *value)
133 {
134 analysis_result_.emplace(slot, value);
135 }
136
137 } // namespace panda::bytecodeopt