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_IR_BUILDER_H 17 #define COMPILER_OPTIMIZER_IR_BUILDER_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()) {} 70 IrBuilder(Graph * graph,RuntimeInterface::MethodPtr method)71 IrBuilder(Graph *graph, RuntimeInterface::MethodPtr method) 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 { 81 } 82 83 NO_COPY_SEMANTIC(IrBuilder); 84 NO_MOVE_SEMANTIC(IrBuilder); 85 ~IrBuilder() override = default; 86 87 bool RunImpl() override; 88 GetPassName()89 const char *GetPassName() const override 90 { 91 return "IrBuilder"; 92 } 93 GetMethod()94 auto GetMethod() const 95 { 96 return method_; 97 } 98 99 private: CreateBlock(size_t pc)100 void CreateBlock(size_t pc) 101 { 102 if (blocks_[pc] == nullptr) { 103 blocks_[pc] = GetGraph()->CreateEmptyBlock(); 104 blocks_[pc]->SetGuestPc(pc); 105 } 106 } 107 GetBlockForPc(size_t pc)108 BasicBlock *GetBlockForPc(size_t pc) 109 { 110 return blocks_[pc]; 111 } 112 GetPrevBlockForPc(size_t pc)113 BasicBlock *GetPrevBlockForPc(size_t pc) 114 { 115 do { 116 ASSERT(pc > 0); 117 pc--; 118 } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr); 119 return blocks_[pc]; 120 } 121 122 bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregs_count); 123 void BuildBasicBlocks(const BytecodeInstructions &instructions); 124 bool BuildBasicBlock(BasicBlock *bb, InstBuilder *inst_builder, const uint8_t *instructions_buf); 125 bool BuildInstructionsForBB(BasicBlock *bb, InstBuilder *inst_builder, const uint8_t *instructions_buf); 126 void SplitConstant(ConstantInst *const_inst); 127 void ConnectBasicBlocks(const BytecodeInstructions &instructions); 128 void CreateTryCatchBoundariesBlocks(); 129 void ResolveTryCatchBlocks(); 130 void ConnectTryCatchBlocks(); 131 IrBuilder::TryCodeBlock *InsertTryBlockInfo(const Boundaries &try_boundaries); 132 void TrackTryBoundaries(size_t pc, const BytecodeInstruction &inst); 133 BasicBlock *GetBlockToJump(BytecodeInstruction *inst, size_t pc); 134 BasicBlock *GetBlockForSaveStateDeoptimize(BasicBlock *block); 135 void MarkTryCatchBlocks(Marker marker); 136 template <class Callback> 137 void EnumerateTryBlocksCoveredPc(uint32_t pc, const Callback &callback); 138 void ConnectTryCodeBlock(const TryCodeBlock &try_block, const ArenaMap<uint32_t, BasicBlock *> &catch_blocks); 139 void ProcessThrowableInstructions(InstBuilder *inst_builder, Inst *throwable_inst); 140 void RestoreTryEnd(const TryCodeBlock &try_block); 141 142 private: 143 ArenaVector<BasicBlock *> blocks_; 144 ArenaSet<uint32_t> catches_pc_; 145 ArenaMultiMap<uint32_t, TryCodeBlock> try_blocks_; 146 ArenaList<TryCodeBlock *> opened_try_blocks_; 147 ArenaUnorderedSet<BasicBlock *> catch_handlers_; 148 InstVector inst_defs_; 149 RuntimeInterface::MethodPtr method_ = nullptr; 150 }; 151 152 } // namespace panda::compiler 153 154 #endif // COMPILER_OPTIMIZER_IR_BUILDER_IR_BUILDER_H 155