1 /** 2 * Copyright (c) 2021-2022 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 PANDA_INST_BUILDER_H 17 #define PANDA_INST_BUILDER_H 18 19 #include "compiler_options.h" 20 #include "optimizer/ir/graph.h" 21 #include "optimizer/ir/basicblock.h" 22 #include "optimizer/analysis/loop_analyzer.h" 23 #include "code_data_accessor.h" 24 #include "file_items.h" 25 #include "compiler_logger.h" 26 27 #include "bytecode_instruction.h" 28 29 namespace panda::compiler { 30 constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max(); 31 32 class InstBuilder { 33 public: InstBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * caller_inst)34 InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *caller_inst) 35 : graph_(graph), 36 runtime_(graph->GetRuntime()), 37 defs_(graph->GetLocalAllocator()->Adapter()), 38 method_(method), 39 VREGS_AND_ARGS_COUNT(graph->GetRuntime()->GetMethodRegistersCount(method) + 40 graph->GetRuntime()->GetMethodTotalArgumentsCount(method)), 41 instructions_buf_(GetGraph()->GetRuntime()->GetMethodCode(GetGraph()->GetMethod())), 42 caller_inst_(caller_inst), 43 class_id_ {runtime_->GetClassIdForMethod(method_)} 44 { 45 no_type_marker_ = GetGraph()->NewMarker(); 46 visited_block_marker_ = GetGraph()->NewMarker(); 47 48 defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph->GetLocalAllocator()->Adapter())); 49 for (auto &v : defs_) { 50 v.resize(VREGS_AND_ARGS_COUNT + 1); 51 } 52 53 for (auto bb : graph->GetBlocksRPO()) { 54 if (bb->IsCatchBegin()) { 55 for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) { 56 auto catch_phi = GetGraph()->CreateInstCatchPhi(); 57 catch_phi->SetPc(bb->GetGuestPc()); 58 catch_phi->SetMarker(GetNoTypeMarker()); 59 bb->AppendInst(catch_phi); 60 if (vreg == VREGS_AND_ARGS_COUNT) { 61 catch_phi->SetIsAcc(); 62 } 63 } 64 } 65 } 66 } 67 68 NO_COPY_SEMANTIC(InstBuilder); 69 NO_MOVE_SEMANTIC(InstBuilder); ~InstBuilder()70 ~InstBuilder() 71 { 72 GetGraph()->EraseMarker(no_type_marker_); 73 GetGraph()->EraseMarker(visited_block_marker_); 74 } 75 76 /** 77 * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file 78 * @param instruction Pointer to bytecode instruction 79 */ 80 void BuildInstruction(const BytecodeInstruction *instruction); 81 IsFailed()82 bool IsFailed() const 83 { 84 return failed_; 85 } 86 87 /** 88 * Return jump offset for instruction `inst`, 0 if it is not jump instruction. 89 */ 90 static int64_t GetInstructionJumpOffset(const BytecodeInstruction *inst); 91 SetCurrentBlock(BasicBlock * bb)92 void SetCurrentBlock(BasicBlock *bb) 93 { 94 current_bb_ = bb; 95 current_defs_ = &defs_[bb->GetId()]; 96 } 97 98 void Prepare(bool is_inlined_graph); 99 100 void FixInstructions(); 101 void ResolveConstants(); 102 void SplitConstant(ConstantInst *const_inst); 103 void CleanupCatchPhis(); 104 105 static void RemoveNotDominateInputs(SaveStateInst *save_state); 106 107 size_t GetPc(const uint8_t *inst_ptr) const; 108 CreateSaveStateDeoptimize(uint32_t pc)109 auto CreateSaveStateDeoptimize(uint32_t pc) 110 { 111 return CreateSaveState(Opcode::SaveStateDeoptimize, pc); 112 } 113 114 void UpdateDefs(); 115 GetCurrentDefs()116 const auto &GetCurrentDefs() 117 { 118 ASSERT(current_defs_ != nullptr); 119 return *current_defs_; 120 } 121 122 void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catch_handlers, const InstVector &defs, 123 Inst *throwable_inst); 124 125 SaveStateInst *CreateSaveState(Opcode opc, size_t pc); 126 127 static void SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i, 128 DataType::Type type); 129 TryFillInstIdTypePair(size_t id,int32_t pc)130 void TryFillInstIdTypePair(size_t id, int32_t pc) 131 { 132 ASSERT(GetGraph()->IsBytecodeOptimizer()); 133 ASSERT(GetGraph()->IsDynamicMethod()); 134 GetGraph()->GetRuntime()->FillInstIdTypePairByPc(id, pc); 135 } 136 private: 137 void UpdateDefsForCatch(); 138 void UpdateDefsForLoopHead(); 139 GetVRegsCount()140 size_t GetVRegsCount() const 141 { 142 return VREGS_AND_ARGS_COUNT + 1; 143 } 144 AddInstruction(Inst * inst)145 void AddInstruction(Inst *inst) 146 { 147 ASSERT(current_bb_); 148 current_bb_->AppendInst(inst); 149 COMPILER_LOG(DEBUG, IR_BUILDER) 150 151 << *inst; 152 } 153 UpdateDefinition(size_t vreg,Inst * inst)154 void UpdateDefinition(size_t vreg, Inst *inst) 155 { 156 ASSERT(vreg < current_defs_->size()); 157 COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from " 158 << ((*current_defs_)[vreg] != nullptr 159 ? std::to_string((*current_defs_)[vreg]->GetId()) 160 : "null") 161 << " to " << inst->GetId(); 162 (*current_defs_)[vreg] = inst; 163 } 164 UpdateDefinitionAcc(Inst * inst)165 void UpdateDefinitionAcc(Inst *inst) 166 { 167 if (inst == nullptr) { 168 COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition"; 169 } else { 170 COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from " 171 << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr 172 ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId()) 173 : "null") 174 << " to " << inst->GetId(); 175 } 176 (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst; 177 } 178 GetDefinition(size_t vreg)179 Inst *GetDefinition(size_t vreg) 180 { 181 ASSERT(vreg < current_defs_->size()); 182 ASSERT((*current_defs_)[vreg] != nullptr); 183 184 if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) { 185 failed_ = true; 186 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg; 187 return nullptr; 188 } 189 return (*current_defs_)[vreg]; 190 } 191 GetDefinitionAcc()192 Inst *GetDefinitionAcc() 193 { 194 auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT]; 195 ASSERT(acc_inst != nullptr); 196 197 if (acc_inst == nullptr) { 198 failed_ = true; 199 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed"; 200 } 201 return acc_inst; 202 } 203 FindOrCreate32BitConstant(uint32_t value)204 auto FindOrCreate32BitConstant(uint32_t value) 205 { 206 auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value); 207 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 208 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 209 } 210 return inst; 211 } 212 FindOrCreateConstant(uint64_t value)213 auto FindOrCreateConstant(uint64_t value) 214 { 215 auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value); 216 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 217 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 218 } 219 return inst; 220 } 221 FindOrCreateDoubleConstant(double value)222 auto FindOrCreateDoubleConstant(double value) 223 { 224 auto inst = GetGraph()->FindOrCreateConstant<double>(value); 225 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 226 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 227 } 228 return inst; 229 } 230 CreateCast(Inst * input,DataType::Type type,DataType::Type operands_type,size_t pc)231 Inst *CreateCast(Inst *input, DataType::Type type, DataType::Type operands_type, size_t pc) 232 { 233 auto cast = GetGraph()->CreateInstCast(type, pc); 234 cast->CastToCast()->SetOperandsType(operands_type); 235 cast->SetInput(0, input); 236 if (!input->HasType()) { 237 input->SetType(operands_type); 238 } 239 return cast; 240 } 241 242 void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst); 243 template <bool with_speculative = false> 244 void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst); 245 246 template <Opcode opcode> 247 void BuildLoadFromPool(const BytecodeInstruction *bc_inst); 248 void BuildCastToAnyString(const BytecodeInstruction *bc_inst); 249 void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst); 250 Inst *BuildAnyTypeCheckInst(size_t bc_addr, Inst *input, Inst *save_state, 251 AnyBaseType type = AnyBaseType::UNDEFINED_TYPE); 252 GetGraph()253 Graph *GetGraph() 254 { 255 return graph_; 256 } 257 GetGraph()258 const Graph *GetGraph() const 259 { 260 return graph_; 261 } 262 GetRuntime()263 const RuntimeInterface *GetRuntime() const 264 { 265 return runtime_; 266 } 267 GetRuntime()268 RuntimeInterface *GetRuntime() 269 { 270 return runtime_; 271 } 272 GetMethod()273 auto GetMethod() const 274 { 275 return method_; 276 } 277 GetClassId()278 auto GetClassId() const 279 { 280 return class_id_; 281 } 282 GetNoTypeMarker()283 Marker GetNoTypeMarker() const 284 { 285 return no_type_marker_; 286 } 287 GetVisitedBlockMarker()288 Marker GetVisitedBlockMarker() const 289 { 290 return visited_block_marker_; 291 } 292 293 void SetTypeRec(Inst *inst, DataType::Type type); 294 295 /// Get return type of the method specified by id 296 DataType::Type GetMethodReturnType(uintptr_t id) const; 297 /// Get type of argument of the method specified by id 298 DataType::Type GetMethodArgumentType(uintptr_t id, size_t index) const; 299 /// Get count of arguments for the method specified by id 300 size_t GetMethodArgumentsCount(uintptr_t id) const; 301 /// Get return type of currently compiling method 302 DataType::Type GetCurrentMethodReturnType() const; 303 /// Get type of argument of currently compiling method 304 DataType::Type GetCurrentMethodArgumentType(size_t index) const; 305 /// Get count of arguments of currently compiling method 306 size_t GetCurrentMethodArgumentsCount() const; 307 308 private: 309 static constexpr size_t INPUT_2 = 2; 310 static constexpr size_t INPUT_3 = 3; 311 static constexpr size_t TWO_INPUTS = 2; 312 313 Graph *graph_ {nullptr}; 314 RuntimeInterface *runtime_ {nullptr}; 315 BasicBlock *current_bb_ {nullptr}; 316 317 // Definitions vector of currently processed basic block 318 InstVector *current_defs_ {nullptr}; 319 // Contains definitions of the virtual registers in all basic blocks 320 ArenaVector<InstVector> defs_; 321 322 RuntimeInterface::MethodPtr method_ {nullptr}; 323 // Set to true if builder failed to build IR 324 bool failed_ {false}; 325 // Number of virtual registers and method arguments 326 const size_t VREGS_AND_ARGS_COUNT; 327 // Marker for instructions with undefined type in the building phase 328 Marker no_type_marker_; 329 Marker visited_block_marker_; 330 331 // Pointer to start position of bytecode instructions buffer 332 const uint8_t *instructions_buf_ {nullptr}; 333 334 CallInst *caller_inst_ {nullptr}; 335 size_t class_id_; 336 #include "intrinsics_ir_build.inl.h" 337 }; 338 } // namespace panda::compiler 339 340 #endif // PANDA_INST_BUILDER_H 341