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 #include "compiler/optimizer/ir/graph.h"
19 #include "compiler/optimizer/ir/runtime_interface.h"
20
21 namespace panda::bytecodeopt {
22
ModuleConstantAnalyzer(compiler::Graph * graph,const std::unordered_set<uint32_t> & const_local_export_slots,ModuleConstantAnalysisResult & analysis_result,const BytecodeOptIrInterface * iface)23 ModuleConstantAnalyzer::ModuleConstantAnalyzer(compiler::Graph *graph,
24 const std::unordered_set<uint32_t> &const_local_export_slots,
25 ModuleConstantAnalysisResult &analysis_result,
26 const BytecodeOptIrInterface *iface)
27 : Analysis(graph),
28 const_local_export_slots_(const_local_export_slots),
29 analysis_result_(analysis_result),
30 ir_interface_(iface)
31 {
32 }
33
RunImpl()34 bool ModuleConstantAnalyzer::RunImpl()
35 {
36 VisitGraph();
37 return true;
38 }
39
VisitIntrinsic(compiler::GraphVisitor * visitor,compiler::Inst * inst)40 void ModuleConstantAnalyzer::VisitIntrinsic(compiler::GraphVisitor *visitor, compiler::Inst *inst)
41 {
42 constexpr int STMODULEVAR_VALUE_INPUT_INDEX = 0;
43 constexpr int STMODULEVAR_SLOT_NUMBER_IMM_INDEX = 0;
44 auto module_constant_analyzer = static_cast<ModuleConstantAnalyzer *>(visitor);
45 auto intrinsic_inst = inst->CastToIntrinsic();
46 auto id = intrinsic_inst->GetIntrinsicId();
47 switch (id) {
48 case RuntimeInterface::IntrinsicId::STMODULEVAR_IMM8:
49 case RuntimeInterface::IntrinsicId::WIDE_STMODULEVAR_PREF_IMM16: {
50 int module_var_slot = intrinsic_inst->GetImms()[STMODULEVAR_SLOT_NUMBER_IMM_INDEX];
51 if (!module_constant_analyzer->IsConstModuleVar(module_var_slot)) {
52 break;
53 }
54 auto input_inst = inst->GetDataFlowInput(STMODULEVAR_VALUE_INPUT_INDEX);
55 auto input_const_value = module_constant_analyzer->GetInstConstValue(input_inst);
56 if (input_const_value != nullptr) {
57 module_constant_analyzer->RecordModuleConstValue(module_var_slot, input_const_value);
58 }
59 break;
60 }
61 default:
62 break;
63 }
64 }
65
GetInstConstValue(Inst * inst)66 ConstantValue *ModuleConstantAnalyzer::GetInstConstValue(Inst *inst)
67 {
68 switch (inst->GetOpcode()) {
69 case Opcode::Constant:
70 return GetConstantInstConstValue(inst->CastToConstant());
71 case Opcode::Intrinsic:
72 return GetIntrinsicInstConstValue(inst->CastToIntrinsic());
73 case Opcode::LoadString:
74 return GetLoadStringInstConstValue(inst->CastToLoadString());
75 case Opcode::CastValueToAnyType:
76 // According to inst_builder.cpp:
77 // 1. the fldai bytecode generates Constant(double) -> CastValueToAnyType,
78 // 1. the lda.str bytecode generates LoadString -> CastValueToAnyType,
79 // We handle such case here. 0 stands for the DataFlowInput corresponding to the Constant/LoadString
80 if (inst->GetDataFlowInput(0)->IsConst() ||
81 inst->GetDataFlowInput(0)->GetOpcode() == compiler::Opcode::LoadString) {
82 return GetInstConstValue(inst->GetDataFlowInput(0));
83 }
84 return nullptr;
85 default:
86 return nullptr;
87 }
88 }
89
GetConstantInstConstValue(compiler::ConstantInst * const_inst)90 ConstantValue *ModuleConstantAnalyzer::GetConstantInstConstValue(compiler::ConstantInst *const_inst)
91 {
92 switch (const_inst->GetType()) {
93 case compiler::DataType::INT32: {
94 auto val = static_cast<int32_t>(const_inst->GetInt32Value());
95 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
96 }
97 case compiler::DataType::INT64: {
98 auto val = static_cast<int64_t>(const_inst->GetRawValue());
99 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
100 }
101 case compiler::DataType::FLOAT64: {
102 auto val = const_inst->GetDoubleValue();
103 return GetGraph()->GetAllocator()->New<ConstantValue>(val);
104 }
105 default:
106 UNREACHABLE();
107 }
108 }
109
GetIntrinsicInstConstValue(compiler::IntrinsicInst * intrinsic_inst)110 ConstantValue *ModuleConstantAnalyzer::GetIntrinsicInstConstValue(compiler::IntrinsicInst *intrinsic_inst)
111 {
112 switch (intrinsic_inst->GetIntrinsicId()) {
113 case RuntimeInterface::IntrinsicId::LDTRUE:
114 case RuntimeInterface::IntrinsicId::LDFALSE: {
115 bool is_true = intrinsic_inst->GetIntrinsicId() == RuntimeInterface::IntrinsicId::LDTRUE;
116 return GetGraph()->GetAllocator()->New<ConstantValue>(is_true);
117 }
118 default:
119 return nullptr;
120 }
121 }
122
GetLoadStringInstConstValue(compiler::LoadFromPool * inst)123 ConstantValue *ModuleConstantAnalyzer::GetLoadStringInstConstValue(compiler::LoadFromPool *inst)
124 {
125 return GetGraph()->GetAllocator()->New<ConstantValue>(
126 ir_interface_->GetStringIdByOffset(inst->GetTypeId()));
127 }
128
IsConstModuleVar(uint32_t slot)129 bool ModuleConstantAnalyzer::IsConstModuleVar(uint32_t slot)
130 {
131 return const_local_export_slots_.count(slot) == 1;
132 }
133
RecordModuleConstValue(uint32_t slot,ConstantValue * value)134 void ModuleConstantAnalyzer::RecordModuleConstValue(uint32_t slot, ConstantValue *value)
135 {
136 analysis_result_.emplace(slot, value);
137 }
138
139 } // namespace panda::bytecodeopt