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_IR_BUILDER_H 17 #define PANDA_IR_BUILDER_H 18 19 #include "optimizer/ir/graph.h" 20 #include "optimizer/ir/basicblock.h" 21 #include "optimizer/pass.h" 22 #include "utils/logger.h" 23 #include "pbc_iterator.h" 24 #include "inst_builder.h" 25 26 namespace panda { 27 class Method; 28 } // namespace panda 29 30 namespace panda::compiler { 31 /** 32 * Build IR from panda bytecode 33 */ 34 class IrBuilder : public Optimization { 35 struct Boundaries { 36 uint32_t begin_pc; 37 uint32_t end_pc; 38 }; 39 40 struct CatchCodeBlock { 41 uint32_t pc {}; 42 uint32_t type_id {}; 43 }; 44 45 struct TryCodeBlock { 46 Boundaries boundaries {}; // NOLINT(misc-non-private-member-variables-in-classes) 47 BasicBlock *begin_bb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 48 BasicBlock *end_bb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 49 ArenaVector<CatchCodeBlock> *catches {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 50 ArenaVector<BasicBlock *> *basic_blocks {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 51 uint32_t id {INVALID_ID}; // NOLINT(misc-non-private-member-variables-in-classes) 52 bool contains_throwable_inst {false}; // NOLINT(misc-non-private-member-variables-in-classes) 53 InitTryCodeBlock54 void Init(Graph *graph, uint32_t try_id) 55 { 56 id = try_id; 57 auto allocator = graph->GetLocalAllocator(); 58 catches = allocator->New<ArenaVector<CatchCodeBlock>>(allocator->Adapter()); 59 begin_bb = graph->CreateEmptyBlock(boundaries.begin_pc); 60 begin_bb->SetTryBegin(true); 61 end_bb = graph->CreateEmptyBlock(boundaries.end_pc); 62 end_bb->SetTryEnd(true); 63 // Order of try-blocks should be saved in the graph to restore it in the generated bytecode 64 graph->AppendTryBeginBlock(begin_bb); 65 } 66 }; 67 68 public: IrBuilder(Graph * graph)69 explicit IrBuilder(Graph *graph) : IrBuilder(graph, graph->GetMethod(), nullptr) {} 70 IrBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * caller_inst)71 IrBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *caller_inst) 72 : Optimization(graph), 73 blocks_(graph->GetLocalAllocator()->Adapter()), 74 catches_pc_(graph->GetLocalAllocator()->Adapter()), 75 try_blocks_(graph->GetLocalAllocator()->Adapter()), 76 opened_try_blocks_(graph->GetLocalAllocator()->Adapter()), 77 catch_handlers_(graph->GetLocalAllocator()->Adapter()), 78 inst_defs_(graph->GetLocalAllocator()->Adapter()), 79 method_(method), 80 is_inlined_graph_(caller_inst != nullptr), 81 caller_inst_(caller_inst) 82 { 83 } 84 85 NO_COPY_SEMANTIC(IrBuilder); 86 NO_MOVE_SEMANTIC(IrBuilder); 87 ~IrBuilder() override = default; 88 89 bool RunImpl() override; 90 GetPassName()91 const char *GetPassName() const override 92 { 93 return "IrBuilder"; 94 } 95 GetMethod()96 auto GetMethod() const 97 { 98 return method_; 99 } 100 101 private: CreateBlock(size_t pc)102 void CreateBlock(size_t pc) 103 { 104 if (blocks_[pc] == nullptr) { 105 blocks_[pc] = GetGraph()->CreateEmptyBlock(); 106 blocks_[pc]->SetGuestPc(pc); 107 } 108 } 109 GetBlockForPc(size_t pc)110 BasicBlock *GetBlockForPc(size_t pc) 111 { 112 return blocks_[pc]; 113 } 114 GetPrevBlockForPc(size_t pc)115 BasicBlock *GetPrevBlockForPc(size_t pc) 116 { 117 do { 118 ASSERT(pc > 0); 119 pc--; 120 } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr); 121 return blocks_[pc]; 122 } 123 124 bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregs_count); 125 void BuildBasicBlocks(const BytecodeInstructions &instructions); 126 bool BuildBasicBlock(BasicBlock *bb, InstBuilder *inst_builder, const uint8_t *instructions_buf); 127 bool BuildInstructionsForBB(BasicBlock *bb, InstBuilder *inst_builder, const uint8_t *instructions_buf); 128 void SplitConstant(ConstantInst *const_inst); 129 void ConnectBasicBlocks(const BytecodeInstructions &instructions); 130 void CreateTryCatchBoundariesBlocks(); 131 void ResolveTryCatchBlocks(); 132 void ConnectTryCatchBlocks(); 133 IrBuilder::TryCodeBlock *InsertTryBlockInfo(const Boundaries &try_boundaries); 134 void TrackTryBoundaries(size_t pc, const BytecodeInstruction &inst); 135 BasicBlock *GetBlockToJump(BytecodeInstruction *inst, size_t pc); 136 BasicBlock *GetBlockForSaveStateDeoptimize(BasicBlock *block); 137 void MarkTryCatchBlocks(Marker marker); 138 template <class Callback> 139 void EnumerateTryBlocksCoveredPc(uint32_t pc, const Callback &callback); 140 void ConnectTryCodeBlock(const TryCodeBlock &try_block, const ArenaMap<uint32_t, BasicBlock *> &catch_blocks); 141 void ProcessThrowableInstructions(InstBuilder *inst_builder, Inst *throwable_inst); 142 void RestoreTryEnd(const TryCodeBlock &try_block); 143 144 private: 145 ArenaVector<BasicBlock *> blocks_; 146 ArenaSet<uint32_t> catches_pc_; 147 ArenaMultiMap<uint32_t, TryCodeBlock> try_blocks_; 148 ArenaList<TryCodeBlock *> opened_try_blocks_; 149 ArenaUnorderedSet<BasicBlock *> catch_handlers_; 150 InstVector inst_defs_; 151 RuntimeInterface::MethodPtr method_ = nullptr; 152 bool is_inlined_graph_ {false}; 153 CallInst *caller_inst_ {nullptr}; 154 }; 155 156 } // namespace panda::compiler 157 158 #endif // PANDA_IR_BUILDER_H 159