1 /* 2 * Copyright (c) 2021-2023 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 /// Build IR from panda bytecode 32 class IrBuilder : public Optimization { 33 struct Boundaries { 34 uint32_t beginPc; 35 uint32_t endPc; 36 }; 37 38 struct CatchCodeBlock { 39 uint32_t pc {}; 40 uint32_t typeId {}; 41 }; 42 43 struct TryCodeBlock { 44 Boundaries boundaries {}; // NOLINT(misc-non-private-member-variables-in-classes) 45 BasicBlock *beginBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 46 BasicBlock *endBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 47 ArenaVector<CatchCodeBlock> *catches {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 48 ArenaVector<BasicBlock *> *basicBlocks {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 49 uint32_t id {INVALID_ID}; // NOLINT(misc-non-private-member-variables-in-classes) 50 bool containsThrowableInst {false}; // NOLINT(misc-non-private-member-variables-in-classes) 51 InitTryCodeBlock52 void Init(Graph *graph, uint32_t tryId) 53 { 54 id = tryId; 55 auto allocator = graph->GetLocalAllocator(); 56 catches = allocator->New<ArenaVector<CatchCodeBlock>>(allocator->Adapter()); 57 beginBb = graph->CreateEmptyBlock(boundaries.beginPc); 58 beginBb->SetTryBegin(true); 59 endBb = graph->CreateEmptyBlock(boundaries.endPc); 60 endBb->SetTryEnd(true); 61 // Order of try-blocks should be saved in the graph to restore it in the generated bytecode 62 graph->AppendTryBeginBlock(beginBb); 63 } 64 }; 65 66 public: IrBuilder(Graph * graph)67 explicit IrBuilder(Graph *graph) : IrBuilder(graph, graph->GetMethod(), nullptr, 0) {} 68 IrBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * callerInst,uint32_t inliningDepth)69 IrBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth) 70 : Optimization(graph), 71 blocks_(graph->GetLocalAllocator()->Adapter()), 72 catchesPc_(graph->GetLocalAllocator()->Adapter()), 73 tryBlocks_(graph->GetLocalAllocator()->Adapter()), 74 openedTryBlocks_(graph->GetLocalAllocator()->Adapter()), 75 catchHandlers_(graph->GetLocalAllocator()->Adapter()), 76 instDefs_(graph->GetLocalAllocator()->Adapter()), 77 method_(method), 78 isInlinedGraph_(callerInst != nullptr), 79 callerInst_(callerInst), 80 inliningDepth_(inliningDepth) 81 { 82 } 83 84 NO_COPY_SEMANTIC(IrBuilder); 85 NO_MOVE_SEMANTIC(IrBuilder); 86 ~IrBuilder() override = default; 87 88 bool RunImpl() override; 89 GetPassName()90 const char *GetPassName() const override 91 { 92 return "IrBuilder"; 93 } 94 GetMethod()95 auto GetMethod() const 96 { 97 return method_; 98 } 99 100 private: CreateBlock(size_t pc)101 void CreateBlock(size_t pc) 102 { 103 if (blocks_[pc] == nullptr) { 104 blocks_[pc] = GetGraph()->CreateEmptyBlock(); 105 blocks_[pc]->SetGuestPc(pc); 106 } 107 } 108 GetBlockForPc(size_t pc)109 BasicBlock *GetBlockForPc(size_t pc) 110 { 111 return blocks_[pc]; 112 } 113 GetPrevBlockForPc(size_t pc)114 BasicBlock *GetPrevBlockForPc(size_t pc) 115 { 116 do { 117 ASSERT(pc > 0); 118 pc--; 119 } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr); 120 return blocks_[pc]; 121 } 122 123 bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregsCount); 124 void BuildBasicBlocks(const BytecodeInstructions &instructions); 125 bool BuildBasicBlock(BasicBlock *bb, InstBuilder *instBuilder, const uint8_t *instructionsBuf); 126 template <bool NEED_SS_DEOPT> 127 bool BuildInstructionsForBB(BasicBlock *bb, InstBuilder *instBuilder, const uint8_t *instructionsBuf); 128 void SplitConstant(ConstantInst *constInst); 129 void ConnectBasicBlocks(const BytecodeInstructions &instructions); 130 void CreateTryCatchBoundariesBlocks(); 131 void ResolveTryCatchBlocks(); 132 void ConnectTryCatchBlocks(); 133 IrBuilder::TryCodeBlock *InsertTryBlockInfo(const Boundaries &tryBoundaries); 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 SetMemoryBarrierFlag(); 141 void ConnectTryCodeBlock(const TryCodeBlock &tryBlock, const ArenaMap<uint32_t, BasicBlock *> &catchBlocks); 142 void ProcessThrowableInstructions(InstBuilder *instBuilder, Inst *throwableInst); 143 void RestoreTryEnd(const TryCodeBlock &tryBlock); 144 145 private: 146 ArenaVector<BasicBlock *> blocks_; 147 ArenaSet<uint32_t> catchesPc_; 148 ArenaMultiMap<uint32_t, TryCodeBlock> tryBlocks_; 149 ArenaList<TryCodeBlock *> openedTryBlocks_; 150 ArenaUnorderedSet<BasicBlock *> catchHandlers_; 151 InstVector instDefs_; 152 RuntimeInterface::MethodPtr method_ = nullptr; 153 bool isInlinedGraph_ {false}; 154 CallInst *callerInst_ {nullptr}; 155 uint32_t inliningDepth_ {0}; 156 }; 157 158 class IrBuilderInliningAnalysis : public Analysis { 159 public: IrBuilderInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)160 IrBuilderInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method) : Analysis(graph), method_(method) {} 161 ~IrBuilderInliningAnalysis() override = default; 162 NO_COPY_SEMANTIC(IrBuilderInliningAnalysis); 163 NO_MOVE_SEMANTIC(IrBuilderInliningAnalysis); 164 165 bool RunImpl() override; 166 GetPassName()167 const char *GetPassName() const override 168 { 169 return "IrBuilderInlineAnalysis"; 170 } 171 GetMethod()172 auto GetMethod() const 173 { 174 return method_; 175 } 176 HasRuntimeCalls()177 auto HasRuntimeCalls() const 178 { 179 return hasRuntimeCalls_; 180 } 181 182 private: 183 virtual bool IsSuitableForInline(const BytecodeInstruction *inst); 184 185 private: 186 RuntimeInterface::MethodPtr method_; 187 bool hasRuntimeCalls_ {false}; 188 }; 189 190 class IrBuilderExternalInliningAnalysis : public IrBuilderInliningAnalysis { 191 public: IrBuilderExternalInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)192 IrBuilderExternalInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method) 193 : IrBuilderInliningAnalysis(graph, method) 194 { 195 } 196 197 NO_COPY_SEMANTIC(IrBuilderExternalInliningAnalysis); 198 NO_MOVE_SEMANTIC(IrBuilderExternalInliningAnalysis); 199 ~IrBuilderExternalInliningAnalysis() override = default; 200 GetPassName()201 const char *GetPassName() const override 202 { 203 return "IrBuilderExternalInliningAnalysis"; 204 } 205 206 private: 207 bool IsSuitableForInline(const BytecodeInstruction *inst) override; 208 }; 209 210 } // namespace panda::compiler 211 212 #endif // PANDA_IR_BUILDER_H 213