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