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 ArenaSet<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 124 private: 125 void UpdateDefsForCatch(); 126 void UpdateDefsForLoopHead(); 127 GetVRegsCount()128 size_t GetVRegsCount() const 129 { 130 return VREGS_AND_ARGS_COUNT + 1; 131 } 132 AddInstruction(Inst * inst)133 void AddInstruction(Inst *inst) 134 { 135 ASSERT(current_bb_); 136 current_bb_->AppendInst(inst); 137 COMPILER_LOG(DEBUG, IR_BUILDER) 138 139 << *inst; 140 } 141 UpdateDefinition(size_t vreg,Inst * inst)142 void UpdateDefinition(size_t vreg, Inst *inst) 143 { 144 ASSERT(vreg < current_defs_->size()); 145 COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from " 146 << ((*current_defs_)[vreg] != nullptr 147 ? std::to_string((*current_defs_)[vreg]->GetId()) 148 : "null") 149 << " to " << inst->GetId(); 150 (*current_defs_)[vreg] = inst; 151 } 152 UpdateDefinitionAcc(Inst * inst)153 void UpdateDefinitionAcc(Inst *inst) 154 { 155 if (inst == nullptr) { 156 COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition"; 157 } else { 158 COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from " 159 << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr 160 ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId()) 161 : "null") 162 << " to " << inst->GetId(); 163 } 164 (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst; 165 } 166 GetDefinition(size_t vreg)167 Inst *GetDefinition(size_t vreg) 168 { 169 ASSERT(vreg < current_defs_->size()); 170 ASSERT((*current_defs_)[vreg] != nullptr); 171 172 if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) { 173 failed_ = true; 174 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg; 175 return nullptr; 176 } 177 return (*current_defs_)[vreg]; 178 } 179 GetDefinitionAcc()180 Inst *GetDefinitionAcc() 181 { 182 auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT]; 183 ASSERT(acc_inst != nullptr); 184 185 if (acc_inst == nullptr) { 186 failed_ = true; 187 COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed"; 188 } 189 return acc_inst; 190 } 191 FindOrCreate32BitConstant(uint32_t value)192 auto FindOrCreate32BitConstant(uint32_t value) 193 { 194 auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value); 195 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 196 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 197 } 198 return inst; 199 } 200 FindOrCreateConstant(uint64_t value)201 auto FindOrCreateConstant(uint64_t value) 202 { 203 auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value); 204 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 205 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 206 } 207 return inst; 208 } 209 FindOrCreateDoubleConstant(double value)210 auto FindOrCreateDoubleConstant(double value) 211 { 212 auto inst = GetGraph()->FindOrCreateConstant<double>(value); 213 if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { 214 COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); 215 } 216 return inst; 217 } 218 219 void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst); 220 template <bool with_speculative = false> 221 void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst); 222 223 template <Opcode opcode> 224 void BuildLoadFromPool(const BytecodeInstruction *bc_inst); 225 void BuildCastToAnyString(const BytecodeInstruction *bc_inst); 226 void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst); 227 GetGraph()228 Graph *GetGraph() 229 { 230 return graph_; 231 } 232 GetGraph()233 const Graph *GetGraph() const 234 { 235 return graph_; 236 } 237 GetRuntime()238 const RuntimeInterface *GetRuntime() const 239 { 240 return runtime_; 241 } 242 GetRuntime()243 RuntimeInterface *GetRuntime() 244 { 245 return runtime_; 246 } 247 GetMethod()248 auto GetMethod() const 249 { 250 return method_; 251 } 252 GetClassId()253 auto GetClassId() const 254 { 255 return class_id_; 256 } 257 GetNoTypeMarker()258 Marker GetNoTypeMarker() const 259 { 260 return no_type_marker_; 261 } 262 GetVisitedBlockMarker()263 Marker GetVisitedBlockMarker() const 264 { 265 return visited_block_marker_; 266 } 267 268 void SetTypeRec(Inst *inst, DataType::Type type); 269 270 size_t GetMethodArgumentsCount(uintptr_t id) const; 271 272 private: 273 static constexpr size_t INPUT_2 = 2; 274 static constexpr size_t INPUT_3 = 3; 275 static constexpr size_t TWO_INPUTS = 2; 276 277 Graph *graph_ {nullptr}; 278 RuntimeInterface *runtime_ {nullptr}; 279 BasicBlock *current_bb_ {nullptr}; 280 281 // Definitions vector of currently processed basic block 282 InstVector *current_defs_ {nullptr}; 283 // Contains definitions of the virtual registers in all basic blocks 284 ArenaVector<InstVector> defs_; 285 286 RuntimeInterface::MethodPtr method_ {nullptr}; 287 // Set to true if builder failed to build IR 288 bool failed_ {false}; 289 // Number of virtual registers and method arguments 290 const size_t VREGS_AND_ARGS_COUNT; 291 // Marker for instructions with undefined type in the building phase 292 Marker no_type_marker_; 293 Marker visited_block_marker_; 294 295 // Pointer to start position of bytecode instructions buffer 296 const uint8_t *instructions_buf_ {nullptr}; 297 298 size_t class_id_; 299 #include "intrinsics_ir_build.inl.h" 300 }; 301 } // namespace panda::compiler 302 303 #endif // COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H 304