• 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 ArenaSet<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 
124 private:
125     void UpdateDefsForCatch();
126     void UpdateDefsForLoopHead();
127 
GetVRegsCount()128     size_t GetVRegsCount() const
129     {
130         return VREGS_AND_ARGS_COUNT + 1;
131     }
132 
AddInstruction(Inst * inst)133     void AddInstruction(Inst *inst)
134     {
135         ASSERT(current_bb_);
136         current_bb_->AppendInst(inst);
137         COMPILER_LOG(DEBUG, IR_BUILDER)
138 
139             << *inst;
140     }
141 
UpdateDefinition(size_t vreg,Inst * inst)142     void UpdateDefinition(size_t vreg, Inst *inst)
143     {
144         ASSERT(vreg < current_defs_->size());
145         COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from "
146                                         << ((*current_defs_)[vreg] != nullptr
147                                                 ? std::to_string((*current_defs_)[vreg]->GetId())
148                                                 : "null")
149                                         << " to " << inst->GetId();
150         (*current_defs_)[vreg] = inst;
151     }
152 
UpdateDefinitionAcc(Inst * inst)153     void UpdateDefinitionAcc(Inst *inst)
154     {
155         if (inst == nullptr) {
156             COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition";
157         } else {
158             COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from "
159                                             << ((*current_defs_)[VREGS_AND_ARGS_COUNT] != nullptr
160                                                     ? std::to_string((*current_defs_)[VREGS_AND_ARGS_COUNT]->GetId())
161                                                     : "null")
162                                             << " to " << inst->GetId();
163         }
164         (*current_defs_)[VREGS_AND_ARGS_COUNT] = inst;
165     }
166 
GetDefinition(size_t vreg)167     Inst *GetDefinition(size_t vreg)
168     {
169         ASSERT(vreg < current_defs_->size());
170         ASSERT((*current_defs_)[vreg] != nullptr);
171 
172         if (vreg >= current_defs_->size() || (*current_defs_)[vreg] == nullptr) {
173             failed_ = true;
174             COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg;
175             return nullptr;
176         }
177         return (*current_defs_)[vreg];
178     }
179 
GetDefinitionAcc()180     Inst *GetDefinitionAcc()
181     {
182         auto *acc_inst = (*current_defs_)[VREGS_AND_ARGS_COUNT];
183         ASSERT(acc_inst != nullptr);
184 
185         if (acc_inst == nullptr) {
186             failed_ = true;
187             COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed";
188         }
189         return acc_inst;
190     }
191 
FindOrCreate32BitConstant(uint32_t value)192     auto FindOrCreate32BitConstant(uint32_t value)
193     {
194         auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value);
195         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
196             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
197         }
198         return inst;
199     }
200 
FindOrCreateConstant(uint64_t value)201     auto FindOrCreateConstant(uint64_t value)
202     {
203         auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value);
204         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
205             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
206         }
207         return inst;
208     }
209 
FindOrCreateDoubleConstant(double value)210     auto FindOrCreateDoubleConstant(double value)
211     {
212         auto inst = GetGraph()->FindOrCreateConstant<double>(value);
213         if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
214             COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
215         }
216         return inst;
217     }
218 
219     void BuildEcma([[maybe_unused]] const BytecodeInstruction *bc_inst);
220     template <bool with_speculative = false>
221     void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst);
222 
223     template <Opcode opcode>
224     void BuildLoadFromPool(const BytecodeInstruction *bc_inst);
225     void BuildCastToAnyString(const BytecodeInstruction *bc_inst);
226     void BuildCastToAnyNumber(const BytecodeInstruction *bc_inst);
227 
GetGraph()228     Graph *GetGraph()
229     {
230         return graph_;
231     }
232 
GetGraph()233     const Graph *GetGraph() const
234     {
235         return graph_;
236     }
237 
GetRuntime()238     const RuntimeInterface *GetRuntime() const
239     {
240         return runtime_;
241     }
242 
GetRuntime()243     RuntimeInterface *GetRuntime()
244     {
245         return runtime_;
246     }
247 
GetMethod()248     auto GetMethod() const
249     {
250         return method_;
251     }
252 
GetClassId()253     auto GetClassId() const
254     {
255         return class_id_;
256     }
257 
GetNoTypeMarker()258     Marker GetNoTypeMarker() const
259     {
260         return no_type_marker_;
261     }
262 
GetVisitedBlockMarker()263     Marker GetVisitedBlockMarker() const
264     {
265         return visited_block_marker_;
266     }
267 
268     void SetTypeRec(Inst *inst, DataType::Type type);
269 
270     size_t GetMethodArgumentsCount(uintptr_t id) const;
271 
272 private:
273     static constexpr size_t INPUT_2 = 2;
274     static constexpr size_t INPUT_3 = 3;
275     static constexpr size_t TWO_INPUTS = 2;
276 
277     Graph *graph_ {nullptr};
278     RuntimeInterface *runtime_ {nullptr};
279     BasicBlock *current_bb_ {nullptr};
280 
281     // Definitions vector of currently processed basic block
282     InstVector *current_defs_ {nullptr};
283     // Contains definitions of the virtual registers in all basic blocks
284     ArenaVector<InstVector> defs_;
285 
286     RuntimeInterface::MethodPtr method_ {nullptr};
287     // Set to true if builder failed to build IR
288     bool failed_ {false};
289     // Number of virtual registers and method arguments
290     const size_t VREGS_AND_ARGS_COUNT;
291     // Marker for instructions with undefined type in the building phase
292     Marker no_type_marker_;
293     Marker visited_block_marker_;
294 
295     // Pointer to start position of bytecode instructions buffer
296     const uint8_t *instructions_buf_ {nullptr};
297 
298     size_t class_id_;
299 #include "intrinsics_ir_build.inl.h"
300 };
301 }  // namespace panda::compiler
302 
303 #endif  // COMPILER_OPTIMIZER_IR_BUILDER_INST_BUILDER_H
304