/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H #define COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H #include "compiler_options.h" #include "optimizer/ir/graph.h" #include "optimizer/ir/basicblock.h" #include "optimizer/analysis/loop_analyzer.h" #include "code_data_accessor.h" #include "file_items.h" #include "compiler_logger.h" #include "bytecode_instruction.h" namespace panda::compiler { constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max(); class InstBuilder { public: InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method) : graph_(graph), runtime_(graph->GetRuntime()), defs_(graph->GetLocalAllocator()->Adapter()), method_(method), VREGS_AND_ARGS_COUNT(graph->GetRuntime()->GetMethodRegistersCount(method) + graph->GetRuntime()->GetMethodTotalArgumentsCount(method)), instructions_buf_(GetGraph()->GetRuntime()->GetMethodCode(GetGraph()->GetMethod())), class_id_ {runtime_->GetClassIdForMethod(method_)} { no_type_marker_ = GetGraph()->NewMarker(); visited_block_marker_ = GetGraph()->NewMarker(); defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph->GetLocalAllocator()->Adapter())); for (auto &v : defs_) { v.resize(VREGS_AND_ARGS_COUNT + 1); } for (auto bb : graph->GetBlocksRPO()) { if (bb->IsCatchBegin()) { for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) { auto catch_phi = GetGraph()->CreateInstCatchPhi(); catch_phi->SetPc(bb->GetGuestPc()); catch_phi->SetMarker(GetNoTypeMarker()); bb->AppendInst(catch_phi); if (vreg == VREGS_AND_ARGS_COUNT) { catch_phi->SetIsAcc(); } } } } } NO_COPY_SEMANTIC(InstBuilder); NO_MOVE_SEMANTIC(InstBuilder); ~InstBuilder() { GetGraph()->EraseMarker(no_type_marker_); GetGraph()->EraseMarker(visited_block_marker_); } /** * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file * @param instruction Pointer to bytecode instruction */ void BuildInstruction(const BytecodeInstruction *instruction); bool IsFailed() const { return failed_; } /** * Return jump offset for instruction `inst`, 0 if it is not jump instruction. */ static int64_t GetInstructionJumpOffset(const BytecodeInstruction *inst); void SetCurrentBlock(BasicBlock *bb) { current_bb_ = bb; current_defs_ = &defs_[bb->GetId()]; } void Prepare(); void FixInstructions(); void ResolveConstants(); void SplitConstant(ConstantInst *const_inst); void CleanupCatchPhis(); static void RemoveNotDominateInputs(SaveStateInst *save_state); size_t GetPc(const uint8_t *inst_ptr) const; void UpdateDefs(); const auto &GetCurrentDefs() { ASSERT(current_defs_ != nullptr); return *current_defs_; } void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catch_handlers, const InstVector &defs, Inst *throwable_inst); SaveStateInst *CreateSaveState(Opcode opc, size_t pc); static void SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i, DataType::Type type); void TryFillInstIdTypePair(size_t id, int32_t pc) { ASSERT(GetGraph()->IsBytecodeOptimizer()); ASSERT(GetGraph()->IsDynamicMethod()); GetGraph()->GetRuntime()->FillInstIdTypePairByPc(id, pc); } private: void UpdateDefsForCatch(); void UpdateDefsForLoopHead(); size_t GetVRegsCount() const { return VREGS_AND_ARGS_COUNT + 1; } void AddInstruction(Inst *inst) { ASSERT(current_bb_); current_bb_->AppendInst(inst); COMPILER_LOG(DEBUG, IR_BUILDER) << *inst; } void UpdateDefinition(size_t vreg, Inst *inst) { ASSERT(vreg < current_defs_->size()); COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from " << ((*current_defs_)[vreg] != nullptr ? std::to_string((*current_defs_)[vreg]->GetId()) : "null") << " to " << inst->GetId(); (*current_defs_)[vreg] = inst; } void UpdateDefinitionAcc(Inst *inst) { if (inst == nullptr) { COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition"; } else { COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from " << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId()) : "null") << " to " << inst->GetId(); } (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst; } Inst *GetDefinition(size_t vreg) { ASSERT(vreg < current_defs_->size()); ASSERT((*current_defs_)[vreg] != nullptr); if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) { failed_ = true; COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg; return nullptr; } return (*current_defs_)[vreg]; } Inst *GetDefinitionAcc() { auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT]; ASSERT(acc_inst != nullptr); if (acc_inst == nullptr) { failed_ = true; COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed"; } return acc_inst; } auto FindOrCreate32BitConstant(uint32_t value) { auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value); if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); } return inst; } auto FindOrCreateConstant(uint64_t value) { auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value); if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); } return inst; } auto FindOrCreateDoubleConstant(double value) { auto inst = GetGraph()->FindOrCreateConstant<double>(value); if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) { COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId(); } return inst; } void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst); template <bool with_speculative = false> void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst); template <Opcode opcode> void BuildLoadFromPool(const BytecodeInstruction *bc_inst); void BuildCastToAnyString(const BytecodeInstruction *bc_inst); void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst); Graph *GetGraph() { return graph_; } const Graph *GetGraph() const { return graph_; } const RuntimeInterface *GetRuntime() const { return runtime_; } RuntimeInterface *GetRuntime() { return runtime_; } auto GetMethod() const { return method_; } auto GetClassId() const { return class_id_; } Marker GetNoTypeMarker() const { return no_type_marker_; } Marker GetVisitedBlockMarker() const { return visited_block_marker_; } void SetTypeRec(Inst *inst, DataType::Type type); size_t GetMethodArgumentsCount(uintptr_t id) const; private: static constexpr size_t INPUT_2 = 2; static constexpr size_t INPUT_3 = 3; static constexpr size_t TWO_INPUTS = 2; Graph *graph_ {nullptr}; RuntimeInterface *runtime_ {nullptr}; BasicBlock *current_bb_ {nullptr}; // Definitions vector of currently processed basic block InstVector *current_defs_ {nullptr}; // Contains definitions of the virtual registers in all basic blocks ArenaVector<InstVector> defs_; RuntimeInterface::MethodPtr method_ {nullptr}; // Set to true if builder failed to build IR bool failed_ {false}; // Number of virtual registers and method arguments const size_t VREGS_AND_ARGS_COUNT; // Marker for instructions with undefined type in the building phase Marker no_type_marker_; Marker visited_block_marker_; // Pointer to start position of bytecode instructions buffer const uint8_t *instructions_buf_ {nullptr}; size_t class_id_; #include "intrinsics_ir_build.inl.h" }; } // namespace panda::compiler #endif // COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H