• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H
17 #define COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H
18 
19 #include "compiler_options.h"
20 #include "optimizer/ir/graph.h"
21 #include "optimizer/ir/basicblock.h"
22 #include "optimizer/analysis/loop_analyzer.h"
23 #include "code_data_accessor.h"
24 #include "file_items.h"
25 #include "compiler_logger.h"
26 
27 #include "bytecode_instruction.h"
28 
29 namespace panda::compiler {
30 constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max();
31 
32 class InstBuilder {
33 public:
InstBuilder(Graph * graph,RuntimeInterface::MethodPtr method)34     InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method)
35         : graph_(graph),
36           runtime_(graph->GetRuntime()),
37           defs_(graph->GetLocalAllocator()->Adapter()),
38           method_(method),
39           VREGS_AND_ARGS_COUNT(graph->GetRuntime()->GetMethodRegistersCount(method) +
40                                graph->GetRuntime()->GetMethodTotalArgumentsCount(method)),
41           instructions_buf_(GetGraph()->GetRuntime()->GetMethodCode(GetGraph()->GetMethod())),
42           class_id_ {runtime_->GetClassIdForMethod(method_)}
43     {
44         no_type_marker_ = GetGraph()->NewMarker();
45         visited_block_marker_ = GetGraph()->NewMarker();
46 
47         defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph->GetLocalAllocator()->Adapter()));
48         for (auto &v : defs_) {
49             v.resize(VREGS_AND_ARGS_COUNT + 1);
50         }
51 
52         for (auto bb : graph->GetBlocksRPO()) {
53             if (bb->IsCatchBegin()) {
54                 for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
55                     auto catch_phi = GetGraph()->CreateInstCatchPhi();
56                     catch_phi->SetPc(bb->GetGuestPc());
57                     catch_phi->SetMarker(GetNoTypeMarker());
58                     bb->AppendInst(catch_phi);
59                     if (vreg == VREGS_AND_ARGS_COUNT) {
60                         catch_phi->SetIsAcc();
61                     }
62                 }
63             }
64         }
65     }
66 
67     NO_COPY_SEMANTIC(InstBuilder);
68     NO_MOVE_SEMANTIC(InstBuilder);
~InstBuilder()69     ~InstBuilder()
70     {
71         GetGraph()->EraseMarker(no_type_marker_);
72         GetGraph()->EraseMarker(visited_block_marker_);
73     }
74 
75     /**
76      * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file
77      * @param instruction Pointer to bytecode instruction
78      */
79     void BuildInstruction(const BytecodeInstruction *instruction);
80 
IsFailed()81     bool IsFailed() const
82     {
83         return failed_;
84     }
85 
86     /**
87      * Return jump offset for instruction `inst`, 0 if it is not jump instruction.
88      */
89     static int64_t GetInstructionJumpOffset(const BytecodeInstruction *inst);
90 
SetCurrentBlock(BasicBlock * bb)91     void SetCurrentBlock(BasicBlock *bb)
92     {
93         current_bb_ = bb;
94         current_defs_ = &defs_[bb->GetId()];
95     }
96 
97     void Prepare();
98 
99     void FixInstructions();
100     void ResolveConstants();
101     void SplitConstant(ConstantInst *const_inst);
102     void CleanupCatchPhis();
103 
104     static void RemoveNotDominateInputs(SaveStateInst *save_state);
105 
106     size_t GetPc(const uint8_t *inst_ptr) const;
107 
108     void UpdateDefs();
109 
GetCurrentDefs()110     const auto &GetCurrentDefs()
111     {
112         ASSERT(current_defs_ != nullptr);
113         return *current_defs_;
114     }
115 
116     void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catch_handlers, const InstVector &defs,
117                            Inst *throwable_inst);
118 
119     SaveStateInst *CreateSaveState(Opcode opc, size_t pc);
120 
121     static void SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i,
122                                   DataType::Type type);
123 
TryFillInstIdTypePair(size_t id,int32_t pc)124     void TryFillInstIdTypePair(size_t id, int32_t pc)
125     {
126         ASSERT(GetGraph()->IsBytecodeOptimizer());
127         ASSERT(GetGraph()->IsDynamicMethod());
128         GetGraph()->GetRuntime()->FillInstIdTypePairByPc(id, pc);
129     }
130 private:
131     void UpdateDefsForCatch();
132     void UpdateDefsForLoopHead();
133 
GetVRegsCount()134     size_t GetVRegsCount() const
135     {
136         return VREGS_AND_ARGS_COUNT + 1;
137     }
138 
AddInstruction(Inst * inst)139     void AddInstruction(Inst *inst)
140     {
141         ASSERT(current_bb_);
142         current_bb_->AppendInst(inst);
143         COMPILER_LOG(DEBUG, IR_BUILDER)
144 
145             << *inst;
146     }
147 
UpdateDefinition(size_t vreg,Inst * inst)148     void UpdateDefinition(size_t vreg, Inst *inst)
149     {
150         ASSERT(vreg < current_defs_->size());
151         COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from "
152                                         << ((*current_defs_)[vreg] != nullptr
153                                                 ? std::to_string((*current_defs_)[vreg]->GetId())
154                                                 : "null")
155                                         << " to " << inst->GetId();
156         (*current_defs_)[vreg] = inst;
157     }
158 
UpdateDefinitionAcc(Inst * inst)159     void UpdateDefinitionAcc(Inst *inst)
160     {
161         if (inst == nullptr) {
162             COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition";
163         } else {
164             COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from "
165                                             << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr
166                                                     ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId())
167                                                     : "null")
168                                             << " to " << inst->GetId();
169         }
170         (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst;
171     }
172 
GetDefinition(size_t vreg)173     Inst *GetDefinition(size_t vreg)
174     {
175         ASSERT(vreg < current_defs_->size());
176         ASSERT((*current_defs_)[vreg] != nullptr);
177 
178         if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) {
179             failed_ = true;
180             COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg;
181             return nullptr;
182         }
183         return (*current_defs_)[vreg];
184     }
185 
GetDefinitionAcc()186     Inst *GetDefinitionAcc()
187     {
188         auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT];
189         ASSERT(acc_inst != nullptr);
190 
191         if (acc_inst == nullptr) {
192             failed_ = true;
193             COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed";
194         }
195         return acc_inst;
196     }
197 
FindOrCreate32BitConstant(uint32_t value)198     auto FindOrCreate32BitConstant(uint32_t value)
199     {
200         auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value);
201         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
202             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
203         }
204         return inst;
205     }
206 
FindOrCreateConstant(uint64_t value)207     auto FindOrCreateConstant(uint64_t value)
208     {
209         auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value);
210         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
211             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
212         }
213         return inst;
214     }
215 
FindOrCreateDoubleConstant(double value)216     auto FindOrCreateDoubleConstant(double value)
217     {
218         auto inst = GetGraph()->FindOrCreateConstant<double>(value);
219         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
220             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
221         }
222         return inst;
223     }
224 
225     void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst);
226     template <bool with_speculative = false>
227     void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst);
228 
229     template <Opcode opcode>
230     void BuildLoadFromPool(const BytecodeInstruction *bc_inst);
231     void BuildCastToAnyString(const BytecodeInstruction *bc_inst);
232     void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst);
233 
GetGraph()234     Graph *GetGraph()
235     {
236         return graph_;
237     }
238 
GetGraph()239     const Graph *GetGraph() const
240     {
241         return graph_;
242     }
243 
GetRuntime()244     const RuntimeInterface *GetRuntime() const
245     {
246         return runtime_;
247     }
248 
GetRuntime()249     RuntimeInterface *GetRuntime()
250     {
251         return runtime_;
252     }
253 
GetMethod()254     auto GetMethod() const
255     {
256         return method_;
257     }
258 
GetClassId()259     auto GetClassId() const
260     {
261         return class_id_;
262     }
263 
GetNoTypeMarker()264     Marker GetNoTypeMarker() const
265     {
266         return no_type_marker_;
267     }
268 
GetVisitedBlockMarker()269     Marker GetVisitedBlockMarker() const
270     {
271         return visited_block_marker_;
272     }
273 
274     void SetTypeRec(Inst *inst, DataType::Type type);
275 
276     size_t GetMethodArgumentsCount(uintptr_t id) const;
277 
278 private:
279     static constexpr size_t INPUT_2 = 2;
280     static constexpr size_t INPUT_3 = 3;
281     static constexpr size_t TWO_INPUTS = 2;
282 
283     Graph *graph_ {nullptr};
284     RuntimeInterface *runtime_ {nullptr};
285     BasicBlock *current_bb_ {nullptr};
286 
287     // Definitions vector of currently processed basic block
288     InstVector *current_defs_ {nullptr};
289     // Contains definitions of the virtual registers in all basic blocks
290     ArenaVector<InstVector> defs_;
291 
292     RuntimeInterface::MethodPtr method_ {nullptr};
293     // Set to true if builder failed to build IR
294     bool failed_ {false};
295     // Number of virtual registers and method arguments
296     const size_t VREGS_AND_ARGS_COUNT;
297     // Marker for instructions with undefined type in the building phase
298     Marker no_type_marker_;
299     Marker visited_block_marker_;
300 
301     // Pointer to start position of bytecode instructions buffer
302     const uint8_t *instructions_buf_ {nullptr};
303 
304     size_t class_id_;
305 #include "intrinsics_ir_build.inl.h"
306 };
307 }  // namespace panda::compiler
308 
309 #endif  // COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H
310