1 /* 2 * Copyright (c) 2021-2024 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 "bytecode_instruction.h" 20 #include "optimizer/ir/graph.h" 21 #include "optimizer/ir/basicblock.h" 22 #include "optimizer/pass.h" 23 #include "utils/logger.h" 24 #include "pbc_iterator.h" 25 #include "inst_builder.h" 26 27 namespace ark { 28 class Method; 29 } // namespace ark 30 31 namespace ark::compiler { 32 33 struct BlocksConnectorInfo { 34 bool fallthrough {}; 35 bool deadInstructions {}; 36 BytecodeInstruction prevInst {nullptr}; 37 }; 38 39 /// Build IR from panda bytecode 40 class PANDA_PUBLIC_API IrBuilder : public Optimization { 41 struct Boundaries { 42 uint32_t beginPc; 43 uint32_t endPc; 44 }; 45 46 struct CatchCodeBlock { 47 uint32_t pc {}; 48 uint32_t typeId {}; 49 }; 50 51 struct TryCodeBlock { 52 Boundaries boundaries {}; // NOLINT(misc-non-private-member-variables-in-classes) 53 BasicBlock *beginBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 54 BasicBlock *endBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 55 ArenaVector<CatchCodeBlock> *catches {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 56 ArenaVector<BasicBlock *> *basicBlocks {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 57 uint32_t id {INVALID_ID}; // NOLINT(misc-non-private-member-variables-in-classes) 58 bool containsThrowableInst {false}; // NOLINT(misc-non-private-member-variables-in-classes) 59 ArenaSet<BasicBlock *> *throwBlocks {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 60 InitTryCodeBlock61 void Init(Graph *graph, uint32_t tryId) 62 { 63 id = tryId; 64 auto allocator = graph->GetLocalAllocator(); 65 catches = allocator->New<ArenaVector<CatchCodeBlock>>(allocator->Adapter()); 66 beginBb = graph->CreateEmptyBlock(boundaries.beginPc); 67 beginBb->SetTryBegin(true); 68 endBb = graph->CreateEmptyBlock(boundaries.endPc); 69 endBb->SetTryEnd(true); 70 // Order of try-blocks should be saved in the graph to restore it in the generated bytecode 71 graph->AppendTryBeginBlock(beginBb); 72 } 73 }; 74 75 public: IrBuilder(Graph * graph)76 explicit IrBuilder(Graph *graph) : IrBuilder(graph, graph->GetMethod(), nullptr, 0) {} 77 IrBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * callerInst,uint32_t inliningDepth)78 IrBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth) 79 : Optimization(graph), 80 blocks_(graph->GetLocalAllocator()->Adapter()), 81 catchesPc_(graph->GetLocalAllocator()->Adapter()), 82 tryBlocks_(graph->GetLocalAllocator()->Adapter()), 83 openedTryBlocks_(graph->GetLocalAllocator()->Adapter()), 84 catchHandlers_(graph->GetLocalAllocator()->Adapter()), 85 instDefs_(graph->GetLocalAllocator()->Adapter()), 86 method_(method), 87 isInlinedGraph_(callerInst != nullptr), 88 callerInst_(callerInst), 89 inliningDepth_(inliningDepth) 90 { 91 } 92 93 NO_COPY_SEMANTIC(IrBuilder); 94 NO_MOVE_SEMANTIC(IrBuilder); 95 ~IrBuilder() override = default; 96 97 bool RunImpl() override; 98 GetPassName()99 const char *GetPassName() const override 100 { 101 return "IrBuilder"; 102 } 103 GetMethod()104 auto GetMethod() const 105 { 106 return method_; 107 } 108 109 private: CreateBlock(size_t pc)110 void CreateBlock(size_t pc) 111 { 112 if (blocks_[pc] == nullptr) { 113 blocks_[pc] = GetGraph()->CreateEmptyBlock(); 114 blocks_[pc]->SetGuestPc(pc); 115 } 116 } 117 GetBlockForPc(size_t pc)118 BasicBlock *GetBlockForPc(size_t pc) 119 { 120 return blocks_[pc]; 121 } 122 GetPrevBlockForPc(size_t pc)123 BasicBlock *GetPrevBlockForPc(size_t pc) 124 { 125 do { 126 ASSERT(pc > 0); 127 pc--; 128 } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr); 129 return blocks_[pc]; 130 } 131 132 bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregsCount); 133 void BuildBasicBlocks(const BytecodeInstructions &instructions); 134 bool CreateSaveStateForLoopBlocks(BasicBlock *bb); 135 bool BuildBasicBlock(BasicBlock *bb, const uint8_t *instructionsBuf); 136 template <bool NEED_SS_DEOPT> 137 bool AddInstructionToBB(BasicBlock *bb, BytecodeInstruction &inst, size_t pc, bool *ssDeoptWasBuilded); 138 template <bool NEED_SS_DEOPT> 139 bool BuildInstructionsForBB(BasicBlock *bb, const uint8_t *instructionsBuf); 140 void SplitConstant(ConstantInst *constInst); 141 void ConnectBasicBlocks(const BytecodeInstructions &instructions); 142 void CreateTryCatchBoundariesBlocks(); 143 void ResolveTryCatchBlocks(); 144 void ConnectTryCatchBlocks(); 145 IrBuilder::TryCodeBlock *InsertTryBlockInfo(const Boundaries &tryBoundaries); 146 void TrackTryBoundaries(size_t pc, const BytecodeInstruction &inst, BasicBlock *targetBb, 147 BlocksConnectorInfo &info); 148 BasicBlock *GetBlockToJump(BytecodeInstruction *inst, size_t pc); 149 BasicBlock *GetBlockForSaveStateDeoptimize(BasicBlock *block); 150 void MarkTryCatchBlocks(Marker marker); 151 template <class Callback> 152 void EnumerateTryBlocksCoveredPc(uint32_t pc, const Callback &callback); 153 void SetMemoryBarrierFlag(); 154 void ConnectTryCodeBlock(const TryCodeBlock &tryBlock, const ArenaMap<uint32_t, BasicBlock *> &catchBlocks); 155 void ProcessThrowableInstructions(Inst *throwableInst); 156 void RestoreTryEnd(const TryCodeBlock &tryBlock); 157 uint32_t FindCatchBlockInPandaFile(Class *cls, uint32_t pc) const; 158 void ConnectThrowBlock(BasicBlock *throwBlock, const TryCodeBlock &tryBlock); 159 void ConnectThrowBlocks(); 160 bool BuildIrImpl(size_t vregsCount); 161 bool BuildIr(size_t vregsCount); 162 RuntimeInterface::ClassPtr FindExceptionClass(BasicBlock *throwBlock, int32_t *throwPc); 163 bool FindAppropriateCatchBlock(const TryCodeBlock &tryBlock, BasicBlock *throwBlock, uint32_t catchPc); 164 BasicBlock *FindCatchBegin(BasicBlock *bb); 165 SetInstBuilder(InstBuilder * instBuilder)166 void SetInstBuilder(InstBuilder *instBuilder) 167 { 168 instBuilder_ = instBuilder; 169 instBuilder_->Prepare(isInlinedGraph_); 170 } GetInstBuilder()171 InstBuilder *GetInstBuilder() const 172 { 173 return instBuilder_; 174 } 175 176 private: 177 ArenaVector<BasicBlock *> blocks_; 178 ArenaSet<uint32_t> catchesPc_; 179 ArenaMultiMap<uint32_t, TryCodeBlock> tryBlocks_; 180 ArenaList<TryCodeBlock *> openedTryBlocks_; 181 ArenaUnorderedSet<BasicBlock *> catchHandlers_; 182 InstVector instDefs_; 183 RuntimeInterface::MethodPtr method_ = nullptr; 184 bool isInlinedGraph_ {false}; 185 CallInst *callerInst_ {nullptr}; 186 uint32_t inliningDepth_ {0}; 187 InstBuilder *instBuilder_ {nullptr}; 188 }; 189 190 class IrBuilderInliningAnalysis : public Analysis { 191 public: IrBuilderInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)192 IrBuilderInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method) : Analysis(graph), method_(method) {} 193 ~IrBuilderInliningAnalysis() override = default; 194 NO_COPY_SEMANTIC(IrBuilderInliningAnalysis); 195 NO_MOVE_SEMANTIC(IrBuilderInliningAnalysis); 196 197 bool RunImpl() override; 198 GetPassName()199 const char *GetPassName() const override 200 { 201 return "IrBuilderInlineAnalysis"; 202 } 203 GetMethod()204 auto GetMethod() const 205 { 206 return method_; 207 } 208 HasRuntimeCalls()209 auto HasRuntimeCalls() const 210 { 211 return hasRuntimeCalls_; 212 } 213 214 private: 215 virtual bool IsSuitableForInline(const BytecodeInstruction *inst); 216 217 private: 218 RuntimeInterface::MethodPtr method_; 219 bool hasRuntimeCalls_ {false}; 220 }; 221 222 class IrBuilderExternalInliningAnalysis : public IrBuilderInliningAnalysis { 223 public: IrBuilderExternalInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)224 IrBuilderExternalInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method) 225 : IrBuilderInliningAnalysis(graph, method) 226 { 227 } 228 229 NO_COPY_SEMANTIC(IrBuilderExternalInliningAnalysis); 230 NO_MOVE_SEMANTIC(IrBuilderExternalInliningAnalysis); 231 ~IrBuilderExternalInliningAnalysis() override = default; 232 GetPassName()233 const char *GetPassName() const override 234 { 235 return "IrBuilderExternalInliningAnalysis"; 236 } 237 238 private: 239 bool IsSuitableForInline(const BytecodeInstruction *inst) override; 240 }; 241 242 } // namespace ark::compiler 243 244 #endif // PANDA_IR_BUILDER_H 245