• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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