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