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 COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H 17 #define COMPILER_OPTIMIZER_IR_BUILDER_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)34 InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method) 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 class_id_ {runtime_->GetClassIdForMethod(method_)} 43 { 44 no_type_marker_ = GetGraph()->NewMarker(); 45 visited_block_marker_ = GetGraph()->NewMarker(); 46 47 defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph->GetLocalAllocator()->Adapter())); 48 for (auto &v : defs_) { 49 v.resize(VREGS_AND_ARGS_COUNT + 1); 50 } 51 52 for (auto bb : graph->GetBlocksRPO()) { 53 if (bb->IsCatchBegin()) { 54 for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) { 55 auto catch_phi = GetGraph()->CreateInstCatchPhi(); 56 catch_phi->SetPc(bb->GetGuestPc()); 57 catch_phi->SetMarker(GetNoTypeMarker()); 58 bb->AppendInst(catch_phi); 59 if (vreg == VREGS_AND_ARGS_COUNT) { 60 catch_phi->SetIsAcc(); 61 } 62 } 63 } 64 } 65 } 66 67 NO_COPY_SEMANTIC(InstBuilder); 68 NO_MOVE_SEMANTIC(InstBuilder); ~InstBuilder()69 ~InstBuilder() 70 { 71 GetGraph()->EraseMarker(no_type_marker_); 72 GetGraph()->EraseMarker(visited_block_marker_); 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 BytecodeInstruction *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 BytecodeInstruction *inst); 90 SetCurrentBlock(BasicBlock * bb)91 void SetCurrentBlock(BasicBlock *bb) 92 { 93 current_bb_ = bb; 94 current_defs_ = &defs_[bb->GetId()]; 95 } 96 97 void Prepare(); 98 99 void FixInstructions(); 100 void ResolveConstants(); 101 void SplitConstant(ConstantInst *const_inst); 102 void CleanupCatchPhis(); 103 104 static void RemoveNotDominateInputs(SaveStateInst *save_state); 105 106 size_t GetPc(const uint8_t *inst_ptr) const; 107 108 void UpdateDefs(); 109 GetCurrentDefs()110 const auto &GetCurrentDefs() 111 { 112 ASSERT(current_defs_ != nullptr); 113 return *current_defs_; 114 } 115 116 void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catch_handlers, const InstVector &defs, 117 Inst *throwable_inst); 118 119 SaveStateInst *CreateSaveState(Opcode opc, size_t pc); 120 121 static void SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i, 122 DataType::Type type); 123 TryFillInstIdTypePair(size_t id,int32_t pc)124 void TryFillInstIdTypePair(size_t id, int32_t pc) 125 { 126 ASSERT(GetGraph()->IsBytecodeOptimizer()); 127 ASSERT(GetGraph()->IsDynamicMethod()); 128 GetGraph()->GetRuntime()->FillInstIdTypePairByPc(id, pc); 129 } 130 private: 131 void UpdateDefsForCatch(); 132 void UpdateDefsForLoopHead(); 133 GetVRegsCount()134 size_t GetVRegsCount() const 135 { 136 return VREGS_AND_ARGS_COUNT + 1; 137 } 138 AddInstruction(Inst * inst)139 void AddInstruction(Inst *inst) 140 { 141 ASSERT(current_bb_); 142 current_bb_->AppendInst(inst); 143 COMPILER_LOG(DEBUG, IR_BUILDER) 144 145 << *inst; 146 } 147 UpdateDefinition(size_t vreg,Inst * inst)148 void UpdateDefinition(size_t vreg, Inst *inst) 149 { 150 ASSERT(vreg < current_defs_->size()); 151 COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from " 152 << ((*current_defs_)[vreg] != nullptr 153 ? std::to_string((*current_defs_)[vreg]->GetId()) 154 : "null") 155 << " to " << inst->GetId(); 156 (*current_defs_)[vreg] = inst; 157 } 158 UpdateDefinitionAcc(Inst * inst)159 void UpdateDefinitionAcc(Inst *inst) 160 { 161 if (inst == nullptr) { 162 COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition"; 163 } else { 164 COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from " 165 << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr 166 ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId()) 167 : "null") 168 << " to " << inst->GetId(); 169 } 170 (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst; 171 } 172 GetDefinition(size_t vreg)173 Inst *GetDefinition(size_t vreg) 174 { 175 ASSERT(vreg < current_defs_->size()); 176 ASSERT((*current_defs_)[vreg] != nullptr); 177 178 if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) { 179 failed_ = true; 180 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg; 181 return nullptr; 182 } 183 return (*current_defs_)[vreg]; 184 } 185 GetDefinitionAcc()186 Inst *GetDefinitionAcc() 187 { 188 auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT]; 189 ASSERT(acc_inst != nullptr); 190 191 if (acc_inst == nullptr) { 192 failed_ = true; 193 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed"; 194 } 195 return acc_inst; 196 } 197 FindOrCreate32BitConstant(uint32_t value)198 auto FindOrCreate32BitConstant(uint32_t value) 199 { 200 auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value); 201 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 202 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 203 } 204 return inst; 205 } 206 FindOrCreateConstant(uint64_t value)207 auto FindOrCreateConstant(uint64_t value) 208 { 209 auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value); 210 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 211 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 212 } 213 return inst; 214 } 215 FindOrCreateDoubleConstant(double value)216 auto FindOrCreateDoubleConstant(double value) 217 { 218 auto inst = GetGraph()->FindOrCreateConstant<double>(value); 219 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 220 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 221 } 222 return inst; 223 } 224 225 void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst); 226 template <bool with_speculative = false> 227 void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst); 228 229 template <Opcode opcode> 230 void BuildLoadFromPool(const BytecodeInstruction *bc_inst); 231 void BuildCastToAnyString(const BytecodeInstruction *bc_inst); 232 void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst); 233 GetGraph()234 Graph *GetGraph() 235 { 236 return graph_; 237 } 238 GetGraph()239 const Graph *GetGraph() const 240 { 241 return graph_; 242 } 243 GetRuntime()244 const RuntimeInterface *GetRuntime() const 245 { 246 return runtime_; 247 } 248 GetRuntime()249 RuntimeInterface *GetRuntime() 250 { 251 return runtime_; 252 } 253 GetMethod()254 auto GetMethod() const 255 { 256 return method_; 257 } 258 GetClassId()259 auto GetClassId() const 260 { 261 return class_id_; 262 } 263 GetNoTypeMarker()264 Marker GetNoTypeMarker() const 265 { 266 return no_type_marker_; 267 } 268 GetVisitedBlockMarker()269 Marker GetVisitedBlockMarker() const 270 { 271 return visited_block_marker_; 272 } 273 274 void SetTypeRec(Inst *inst, DataType::Type type); 275 276 size_t GetMethodArgumentsCount(uintptr_t id) const; 277 278 private: 279 static constexpr size_t INPUT_2 = 2; 280 static constexpr size_t INPUT_3 = 3; 281 static constexpr size_t TWO_INPUTS = 2; 282 283 Graph *graph_ {nullptr}; 284 RuntimeInterface *runtime_ {nullptr}; 285 BasicBlock *current_bb_ {nullptr}; 286 287 // Definitions vector of currently processed basic block 288 InstVector *current_defs_ {nullptr}; 289 // Contains definitions of the virtual registers in all basic blocks 290 ArenaVector<InstVector> defs_; 291 292 RuntimeInterface::MethodPtr method_ {nullptr}; 293 // Set to true if builder failed to build IR 294 bool failed_ {false}; 295 // Number of virtual registers and method arguments 296 const size_t VREGS_AND_ARGS_COUNT; 297 // Marker for instructions with undefined type in the building phase 298 Marker no_type_marker_; 299 Marker visited_block_marker_; 300 301 // Pointer to start position of bytecode instructions buffer 302 const uint8_t *instructions_buf_ {nullptr}; 303 304 size_t class_id_; 305 #include "intrinsics_ir_build.inl.h" 306 }; 307 } // namespace panda::compiler 308 309 #endif // COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H 310