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 #ifndef LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_INST_BUILDER_H 17 #define LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_INST_BUILDER_H 18 19 #include "static_core/compiler/optimizer/ir/graph.h" 20 #include "static_core/compiler/optimizer/ir/basicblock.h" 21 #include "static_core/compiler/optimizer/analysis/loop_analyzer.h" 22 23 #include "libabckit/src/adapter_dynamic/runtime_adapter_dynamic.h" 24 #include "libabckit/src/irbuilder_dynamic/bytecode_inst.h" 25 26 namespace libabckit { 27 28 constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max(); 29 using ark::BytecodeInstruction; 30 31 class InstBuilder { 32 public: InstBuilder(ark::compiler::Graph * graph,AbckitRuntimeAdapterDynamic::MethodPtr method)33 InstBuilder(ark::compiler::Graph *graph, AbckitRuntimeAdapterDynamic::MethodPtr method) 34 : graph_(graph), 35 runtime_(graph->GetRuntime()), 36 defs_(graph->GetLocalAllocator()->Adapter()), 37 method_(method), 38 vregsAndArgsCount_(graph->GetRuntime()->GetMethodRegistersCount(method) + 39 graph->GetRuntime()->GetMethodTotalArgumentsCount(method)), 40 instructionsBuf_(GetGraph()->GetRuntime()->GetMethodCode(GetGraph()->GetMethod())), 41 classId_ {runtime_->GetClassIdForMethod(method_)} 42 { 43 noTypeMarker_ = GetGraph()->NewMarker(); 44 visitedBlockMarker_ = GetGraph()->NewMarker(); 45 46 defs_.resize(graph_->GetVectorBlocks().size(), 47 ark::compiler::InstVector(graph->GetLocalAllocator()->Adapter())); 48 for (auto &v : defs_) { 49 v.resize(vregsAndArgsCount_ + 1); 50 } 51 52 for (auto bb : graph->GetBlocksRPO()) { 53 if (bb->IsCatchBegin()) { 54 for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) { 55 auto catchPhi = GetGraph()->CreateInstCatchPhi(); 56 catchPhi->SetPc(bb->GetGuestPc()); 57 catchPhi->SetMarker(GetNoTypeMarker()); 58 bb->AppendInst(catchPhi); 59 if (vreg == vregsAndArgsCount_) { 60 catchPhi->SetIsAcc(); 61 } 62 } 63 } 64 } 65 } 66 67 NO_COPY_SEMANTIC(InstBuilder); 68 NO_MOVE_SEMANTIC(InstBuilder); ~InstBuilder()69 ~InstBuilder() 70 { 71 GetGraph()->EraseMarker(noTypeMarker_); 72 GetGraph()->EraseMarker(visitedBlockMarker_); 73 } 74 75 /** 76 * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file 77 * @param instruction Pointer to bytecode instruction 78 */ 79 void BuildInstruction(const BytecodeInst *instruction); 80 IsFailed()81 bool IsFailed() const 82 { 83 return failed_; 84 } 85 86 /** 87 * Return jump offset for instruction `inst`, 0 if it is not jump instruction. 88 */ 89 static int64_t GetInstructionJumpOffset(const BytecodeInst *inst); 90 SetCurrentBlock(ark::compiler::BasicBlock * bb)91 void SetCurrentBlock(ark::compiler::BasicBlock *bb) 92 { 93 currentBb_ = bb; 94 currentDefs_ = &defs_[bb->GetId()]; 95 } 96 97 void Prepare(); 98 99 void UpdatePreds(ark::compiler::BasicBlock *bb, ark::compiler::Inst *inst); 100 void SetType(ark::compiler::Inst *inst); 101 void FixInstructions(); 102 void CheckInstructions(ark::compiler::Inst *inst); 103 void ResolveConstants(); 104 void SplitConstant(ark::compiler::ConstantInst *constInst); 105 void CleanupInst(ark::compiler::BasicBlock *block, ark::compiler::Inst *inst); 106 void CleanupCatchPhis(); 107 void AddPhiToDifferent(); 108 109 static void RemoveNotDominateInputs(ark::compiler::SaveStateInst *saveState); 110 111 size_t GetPc(const uint8_t *instPtr) const; 112 113 void UpdateDefs(); 114 GetCurrentDefs()115 const auto &GetCurrentDefs() 116 { 117 ASSERT(currentDefs_ != nullptr); 118 return *currentDefs_; 119 } 120 121 void AddCatchPhiInputs(const ark::ArenaUnorderedSet<ark::compiler::BasicBlock *> &catchHandlers, 122 const ark::compiler::InstVector &defs, ark::compiler::Inst *throwableInst); 123 124 ark::compiler::SaveStateInst *CreateSaveState(ark::compiler::Opcode opc, size_t pc); 125 126 static void SetParamSpillFill(ark::compiler::Graph *graph, ark::compiler::ParameterInst *paramInst, size_t numArgs, 127 size_t i, ark::compiler::DataType::Type type); 128 129 private: 130 void UpdateDefsForCatch(); 131 void UpdateDefsForLoopHead(); 132 GetVRegsCount()133 size_t GetVRegsCount() const 134 { 135 return vregsAndArgsCount_ + 1; 136 } 137 AddInstruction(ark::compiler::Inst * inst)138 void AddInstruction(ark::compiler::Inst *inst) 139 { 140 ASSERT(currentBb_); 141 currentBb_->AppendInst(inst); 142 LIBABCKIT_LOG(DEBUG) << *inst << std::endl; 143 } 144 UpdateDefinition(size_t vreg,ark::compiler::Inst * inst)145 void UpdateDefinition(size_t vreg, ark::compiler::Inst *inst) 146 { 147 ASSERT(vreg < currentDefs_->size()); 148 (*currentDefs_)[vreg] = inst; 149 } 150 UpdateDefinitionAcc(ark::compiler::Inst * inst)151 void UpdateDefinitionAcc(ark::compiler::Inst *inst) 152 { 153 (*currentDefs_)[vregsAndArgsCount_] = inst; 154 } 155 GetDefinition(size_t vreg)156 ark::compiler::Inst *GetDefinition(size_t vreg) 157 { 158 ASSERT(vreg < currentDefs_->size()); 159 ASSERT((*currentDefs_)[vreg] != nullptr); 160 161 if (vreg >= currentDefs_->size() || (*currentDefs_)[vreg] == nullptr) { 162 failed_ = true; 163 LIBABCKIT_LOG(DEBUG) << "GetDefinition failed for verg " << vreg << std::endl; 164 return nullptr; 165 } 166 return (*currentDefs_)[vreg]; 167 } 168 GetDefinitionAcc()169 ark::compiler::Inst *GetDefinitionAcc() 170 { 171 auto *accInst = (*currentDefs_)[vregsAndArgsCount_]; 172 ASSERT(accInst != nullptr); 173 174 if (accInst == nullptr) { 175 failed_ = true; 176 LIBABCKIT_LOG(DEBUG) << "GetDefinitionAcc failed\n"; 177 } 178 return accInst; 179 } 180 FindOrCreate32BitConstant(uint32_t value)181 auto FindOrCreate32BitConstant(uint32_t value) 182 { 183 auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value); 184 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 185 LIBABCKIT_LOG(DEBUG) << "create new constant: value=" << value << ", inst=" << inst->GetId() << std::endl; 186 } 187 return inst; 188 } 189 FindOrCreateConstant(uint64_t value)190 auto FindOrCreateConstant(uint64_t value) 191 { 192 auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value); 193 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 194 LIBABCKIT_LOG(DEBUG) << "create new constant: value=" << value << ", inst=" << inst->GetId() << std::endl; 195 } 196 return inst; 197 } 198 FindOrCreateDoubleConstant(double value)199 auto FindOrCreateDoubleConstant(double value) 200 { 201 auto inst = GetGraph()->FindOrCreateConstant<double>(value); 202 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 203 LIBABCKIT_LOG(DEBUG) << "create new constant: value=" << value << ", inst=" << inst->GetId() << std::endl; 204 } 205 return inst; 206 } 207 208 void BuildEcma([[maybe_unused]] const BytecodeInst *bcInst); 209 template <bool WITH_SPECULATIVE = false> 210 void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInst *bcInst); 211 void BuildAbcKitLoadStringIntrinsic(const BytecodeInst *bcInst); 212 213 template <ark::compiler::Opcode OPCODE> 214 void BuildLoadFromPool(const BytecodeInst *bcInst); 215 GetGraph()216 ark::compiler::Graph *GetGraph() 217 { 218 return graph_; 219 } 220 GetGraph()221 const ark::compiler::Graph *GetGraph() const 222 { 223 return graph_; 224 } 225 GetRuntime()226 const ark::compiler::RuntimeInterface *GetRuntime() const 227 { 228 return runtime_; 229 } 230 GetRuntime()231 ark::compiler::RuntimeInterface *GetRuntime() 232 { 233 return runtime_; 234 } 235 GetMethod()236 auto GetMethod() const 237 { 238 return method_; 239 } 240 GetClassId()241 auto GetClassId() const 242 { 243 return classId_; 244 } 245 GetNoTypeMarker()246 ark::compiler::Marker GetNoTypeMarker() const 247 { 248 return noTypeMarker_; 249 } 250 GetVisitedBlockMarker()251 ark::compiler::Marker GetVisitedBlockMarker() const 252 { 253 return visitedBlockMarker_; 254 } 255 256 void SetTypeRec(ark::compiler::Inst *inst, ark::compiler::DataType::Type type); 257 258 size_t GetMethodArgumentsCount(uintptr_t id) const; 259 260 private: 261 static constexpr size_t INPUT_2 = 2; 262 static constexpr size_t INPUT_3 = 3; 263 static constexpr size_t TWO_INPUTS = 2; 264 265 ark::compiler::Graph *graph_ {nullptr}; 266 ark::compiler::RuntimeInterface *runtime_ {nullptr}; 267 ark::compiler::BasicBlock *currentBb_ {nullptr}; 268 269 // Definitions vector of currently processed basic block 270 ark::compiler::InstVector *currentDefs_ {nullptr}; 271 // Contains definitions of the virtual registers in all basic blocks 272 ark::ArenaVector<ark::compiler::InstVector> defs_; 273 274 AbckitRuntimeAdapterDynamic::MethodPtr method_ {nullptr}; 275 // Set to true if builder failed to build IR 276 bool failed_ {false}; 277 // Number of virtual registers and method arguments 278 const size_t vregsAndArgsCount_; 279 // Marker for instructions with undefined type in the building phase 280 ark::compiler::Marker noTypeMarker_; 281 ark::compiler::Marker visitedBlockMarker_; 282 283 // Pointer to start position of bytecode instructions buffer 284 const uint8_t *instructionsBuf_ {nullptr}; 285 286 size_t classId_; 287 288 #include "intrinsics_ir_build.inl.h" 289 }; 290 291 } // namespace libabckit 292 293 #endif // LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_INST_BUILDER_H 294