• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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             ASSERT(beginBb != nullptr);
68             beginBb->SetTryBegin(true);
69             endBb = graph->CreateEmptyBlock(boundaries.endPc);
70             ASSERT(endBb != nullptr);
71             endBb->SetTryEnd(true);
72             // Order of try-blocks should be saved in the graph to restore it in the generated bytecode
73             graph->AppendTryBeginBlock(beginBb);
74         }
75     };
76 
77 public:
IrBuilder(Graph * graph)78     explicit IrBuilder(Graph *graph) : IrBuilder(graph, graph->GetMethod(), nullptr, 0) {}
79 
IrBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * callerInst,uint32_t inliningDepth)80     IrBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth)
81         : Optimization(graph),
82           blocks_(graph->GetLocalAllocator()->Adapter()),
83           catchesPc_(graph->GetLocalAllocator()->Adapter()),
84           tryBlocks_(graph->GetLocalAllocator()->Adapter()),
85           openedTryBlocks_(graph->GetLocalAllocator()->Adapter()),
86           catchHandlers_(graph->GetLocalAllocator()->Adapter()),
87           instDefs_(graph->GetLocalAllocator()->Adapter()),
88           method_(method),
89           isInlinedGraph_(callerInst != nullptr),
90           callerInst_(callerInst),
91           inliningDepth_(inliningDepth)
92     {
93     }
94 
95     NO_COPY_SEMANTIC(IrBuilder);
96     NO_MOVE_SEMANTIC(IrBuilder);
97     ~IrBuilder() override = default;
98 
99     bool RunImpl() override;
100 
GetPassName()101     const char *GetPassName() const override
102     {
103         return "IrBuilder";
104     }
105 
GetMethod()106     auto GetMethod() const
107     {
108         return method_;
109     }
110 
111 private:
CreateBlock(size_t pc)112     void CreateBlock(size_t pc)
113     {
114         if (blocks_[pc] == nullptr) {
115             blocks_[pc] = GetGraph()->CreateEmptyBlock();
116             blocks_[pc]->SetGuestPc(pc);
117         }
118     }
119 
GetBlockForPc(size_t pc)120     BasicBlock *GetBlockForPc(size_t pc)
121     {
122         return blocks_[pc];
123     }
124 
GetPrevBlockForPc(size_t pc)125     BasicBlock *GetPrevBlockForPc(size_t pc)
126     {
127         do {
128             ASSERT(pc > 0);
129             pc--;
130         } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr);
131         return blocks_[pc];
132     }
133 
134     bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregsCount);
135     void BuildBasicBlocks(const BytecodeInstructions &instructions);
136     bool CreateSaveStateForLoopBlocks(BasicBlock *bb);
137     bool BuildBasicBlock(BasicBlock *bb, const uint8_t *instructionsBuf);
138     template <bool NEED_SS_DEOPT>
139     bool AddInstructionToBB(BasicBlock *bb, BytecodeInstruction &inst, size_t pc, bool *ssDeoptWasBuilded);
140     template <bool NEED_SS_DEOPT>
141     bool BuildInstructionsForBB(BasicBlock *bb, const uint8_t *instructionsBuf);
142     void SplitConstant(ConstantInst *constInst);
143     void ConnectBasicBlocks(const BytecodeInstructions &instructions);
144     void CreateTryCatchBoundariesBlocks();
145     void ResolveTryCatchBlocks();
146     void ConnectTryCatchBlocks();
147     IrBuilder::TryCodeBlock *InsertTryBlockInfo(const Boundaries &tryBoundaries);
148     void TrackTryBoundaries(size_t pc, const BytecodeInstruction &inst, BasicBlock *targetBb,
149                             BlocksConnectorInfo &info);
150     BasicBlock *GetBlockToJump(BytecodeInstruction *inst, size_t pc);
151     BasicBlock *GetBlockForSaveStateDeoptimize(BasicBlock *block);
152     void MarkTryCatchBlocks(Marker marker);
153     template <class Callback>
154     void EnumerateTryBlocksCoveredPc(uint32_t pc, const Callback &callback);
155     void SetMemoryBarrierFlag();
156     void ConnectTryCodeBlock(const TryCodeBlock &tryBlock, const ArenaMap<uint32_t, BasicBlock *> &catchBlocks);
157     void ProcessThrowableInstructions(Inst *throwableInst);
158     void RestoreTryEnd(const TryCodeBlock &tryBlock);
159     uint32_t FindCatchBlockInPandaFile(Class *cls, uint32_t pc) const;
160     void ConnectThrowBlock(BasicBlock *throwBlock, const TryCodeBlock &tryBlock);
161     void ConnectThrowBlocks();
162     bool BuildIrImpl(size_t vregsCount);
163     bool BuildIr(size_t vregsCount);
164     RuntimeInterface::ClassPtr FindExceptionClass(BasicBlock *throwBlock, int32_t *throwPc);
165     bool FindAppropriateCatchBlock(const TryCodeBlock &tryBlock, BasicBlock *throwBlock, uint32_t catchPc);
166     BasicBlock *FindCatchBegin(BasicBlock *bb);
167 
SetInstBuilder(InstBuilder * instBuilder)168     void SetInstBuilder(InstBuilder *instBuilder)
169     {
170         instBuilder_ = instBuilder;
171         instBuilder_->Prepare(isInlinedGraph_);
172     }
GetInstBuilder()173     InstBuilder *GetInstBuilder() const
174     {
175         return instBuilder_;
176     }
177 
178 private:
179     ArenaVector<BasicBlock *> blocks_;
180     ArenaSet<uint32_t> catchesPc_;
181     ArenaMultiMap<uint32_t, TryCodeBlock> tryBlocks_;
182     ArenaList<TryCodeBlock *> openedTryBlocks_;
183     ArenaUnorderedSet<BasicBlock *> catchHandlers_;
184     InstVector instDefs_;
185     RuntimeInterface::MethodPtr method_ = nullptr;
186     bool isInlinedGraph_ {false};
187     CallInst *callerInst_ {nullptr};
188     uint32_t inliningDepth_ {0};
189     InstBuilder *instBuilder_ {nullptr};
190 };
191 
192 class IrBuilderInliningAnalysis : public Analysis {
193 public:
IrBuilderInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)194     IrBuilderInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method) : Analysis(graph), method_(method) {}
195     ~IrBuilderInliningAnalysis() override = default;
196     NO_COPY_SEMANTIC(IrBuilderInliningAnalysis);
197     NO_MOVE_SEMANTIC(IrBuilderInliningAnalysis);
198 
199     bool RunImpl() override;
200 
GetPassName()201     const char *GetPassName() const override
202     {
203         return "IrBuilderInlineAnalysis";
204     }
205 
GetMethod()206     auto GetMethod() const
207     {
208         return method_;
209     }
210 
HasRuntimeCalls()211     auto HasRuntimeCalls() const
212     {
213         return hasRuntimeCalls_;
214     }
215 
216 private:
217     virtual bool IsSuitableForInline(const BytecodeInstruction *inst);
218 
219 private:
220     RuntimeInterface::MethodPtr method_;
221     bool hasRuntimeCalls_ {false};
222 };
223 
224 class IrBuilderExternalInliningAnalysis : public IrBuilderInliningAnalysis {
225 public:
IrBuilderExternalInliningAnalysis(Graph * graph,RuntimeInterface::MethodPtr method)226     IrBuilderExternalInliningAnalysis(Graph *graph, RuntimeInterface::MethodPtr method)
227         : IrBuilderInliningAnalysis(graph, method)
228     {
229     }
230 
231     NO_COPY_SEMANTIC(IrBuilderExternalInliningAnalysis);
232     NO_MOVE_SEMANTIC(IrBuilderExternalInliningAnalysis);
233     ~IrBuilderExternalInliningAnalysis() override = default;
234 
GetPassName()235     const char *GetPassName() const override
236     {
237         return "IrBuilderExternalInliningAnalysis";
238     }
239 
240 private:
241     bool IsSuitableForInline(const BytecodeInstruction *inst) override;
242 };
243 
244 }  // namespace ark::compiler
245 
246 #endif  // PANDA_IR_BUILDER_H
247