• 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_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_info/vreg_info.h"
24 #include "code_data_accessor.h"
25 #include "file_items.h"
26 #include "compiler_logger.h"
27 
28 #include "bytecode_instruction.h"
29 
30 namespace ark::compiler {
31 constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max();
32 
33 class InstBuilder {
34 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
35 #define ENV_IDX(ENV_TYPE) \
36     static constexpr uint8_t ENV_TYPE##_IDX = VRegInfo::VRegType::ENV_TYPE - VRegInfo::VRegType::ENV_BEGIN;
37     VREGS_ENV_TYPE_DEFS(ENV_IDX)
38 #undef ENV_IDX
39 public:
40     InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth);
41 
42     NO_COPY_SEMANTIC(InstBuilder);
43     NO_MOVE_SEMANTIC(InstBuilder);
~InstBuilder()44     ~InstBuilder()
45     {
46         GetGraph()->EraseMarker(noTypeMarker_);
47         GetGraph()->EraseMarker(visitedBlockMarker_);
48     }
49 
50     /**
51      * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file
52      * @param instruction Pointer to bytecode instruction
53      */
54     void BuildInstruction(const BytecodeInstruction *instruction);
55 
56     void InitEnv(BasicBlock *bb);
57 
IsFailed()58     bool IsFailed() const
59     {
60         return failed_;
61     }
62 
63     /// Return jump offset for instruction `inst`, 0 if it is not jump instruction.
64     static int64_t GetInstructionJumpOffset(const BytecodeInstruction *inst);
65 
66     void SetCurrentBlock(BasicBlock *bb);
67 
GetCurrentBlock()68     BasicBlock *GetCurrentBlock() const
69     {
70         return currentBb_;
71     }
72 
73     void Prepare(bool isInlinedGraph);
74 
75     void FixType(PhiInst *inst, BasicBlock *bb);
76     void FixType(Inst *inst);
77     void FixInstructions();
78     void ResolveConstants();
79     void SplitConstant(ConstantInst *constInst);
80 
81     static void RemoveNotDominateInputs(SaveStateInst *saveState);
82 
83     size_t GetPc(const uint8_t *instPtr) const;
84 
CreateSafePoint(BasicBlock * bb)85     auto CreateSafePoint(BasicBlock *bb)
86     {
87 #ifndef NDEBUG
88         ResetSafepointDistance();
89 #endif
90         return CreateSaveState(Opcode::SafePoint, bb->GetGuestPc());
91     }
92 
CreateSaveStateOsr(BasicBlock * bb)93     auto CreateSaveStateOsr(BasicBlock *bb)
94     {
95         return CreateSaveState(Opcode::SaveStateOsr, bb->GetGuestPc());
96     }
97 
CreateSaveStateDeoptimize(uint32_t pc)98     auto CreateSaveStateDeoptimize(uint32_t pc)
99     {
100         return CreateSaveState(Opcode::SaveStateDeoptimize, pc);
101     }
102 
103     void UpdateDefs();
104     bool UpdateDefsForPreds(size_t vreg, std::optional<Inst *> &value);
105 
GetCurrentDefs()106     const auto &GetCurrentDefs()
107     {
108         ASSERT(currentDefs_ != nullptr);
109         return *currentDefs_;
110     }
111 
112     void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catchHandlers, const InstVector &defs,
113                            Inst *throwableInst);
114 
115     SaveStateInst *CreateSaveState(Opcode opc, size_t pc);
116 
117     static void SetParamSpillFill(Graph *graph, ParameterInst *paramInst, size_t numArgs, size_t i,
118                                   DataType::Type type);
119 
120 #ifndef NDEBUG
121     void TryInsertSafepoint(BasicBlock *bb = nullptr, bool insertSP = false)
122     {
123         auto curBb = bb != nullptr ? bb : currentBb_;
124         if (GetGraph()->IsBytecodeOptimizer() || curBb->IsOsrEntry() ||
125             !g_options.IsCompilerEnforceSafepointPlacement()) {
126             return;
127         }
128         if ((curBb->GetLastInst() == nullptr || curBb->GetLastInst()->GetOpcode() != Opcode::SafePoint) &&
129             (insertSP || --safepointDistance_ <= 0)) {
130             auto *sp = CreateSafePoint(curBb);
131             currentBb_->AppendInst(sp);
132 #ifdef PANDA_COMPILER_DEBUG_INFO
133             if (sp->GetPc() != INVALID_PC) {
134                 sp->SetCurrentMethod(method_);
135             }
136 #endif
137             COMPILER_LOG(DEBUG, IR_BUILDER) << *sp;
138         }
139     }
140 #endif
141 
142 private:
143     void SyncWithGraph();
144 
145     void UpdateDefsForCatch();
146     void UpdateDefsForLoopHead();
147 
GetVRegsCount()148     size_t GetVRegsCount() const
149     {
150         return vregsAndArgsCount_ + 1 + GetGraph()->GetEnvCount();
151     }
152 
153     template <typename T>
AddInstruction(T inst)154     void AddInstruction(T inst)
155     {
156         ASSERT(currentBb_);
157         currentBb_->AppendInst(inst);
158 #ifdef PANDA_COMPILER_DEBUG_INFO
159         if (inst->GetPc() != INVALID_PC) {
160             inst->SetCurrentMethod(method_);
161         }
162 #endif
163         COMPILER_LOG(DEBUG, IR_BUILDER) << *inst;
164     }
165 
166     template <typename T, typename... Ts>
AddInstruction(T inst,Ts...insts)167     void AddInstruction(T inst, Ts... insts)
168     {
169         AddInstruction(inst);
170         AddInstruction(insts...);
171     }
172 
173     void UpdateDefinition(size_t vreg, Inst *inst);
174     void UpdateDefinitionAcc(Inst *inst);
175     void UpdateDefinitionLexEnv(Inst *inst);
176     Inst *GetDefinition(size_t vreg);
177     Inst *GetDefinitionAcc();
178     Inst *GetEnvDefinition(uint8_t envIdx);
179 
180     ConstantInst *FindOrCreate32BitConstant(uint32_t value);
181     ConstantInst *FindOrCreateConstant(uint64_t value);
182     ConstantInst *FindOrCreateAnyConstant(DataType::Any value);
183     ConstantInst *FindOrCreateDoubleConstant(double value);
184     ConstantInst *FindOrCreateFloatConstant(float value);
185 
186     enum SaveStateType {
187         CHECK = 0,  // side_exit = true,  move_to_side_exit = true
188         CALL,       // side_exit = false,  move_to_side_exit = false
189         VIRT_CALL   // side_exit = true,  move_to_side_exit = false
190     };
191 
192     ClassInst *CreateLoadAndInitClassGeneric(uint32_t classId, size_t pc);
193 
CreateCast(Inst * input,DataType::Type type,DataType::Type operandsType,size_t pc)194     Inst *CreateCast(Inst *input, DataType::Type type, DataType::Type operandsType, size_t pc)
195     {
196         auto cast = GetGraph()->CreateInstCast(type, pc, input, operandsType);
197         if (!input->HasType()) {
198             input->SetType(operandsType);
199         }
200         return cast;
201     }
202 
CreateNewObjectInst(size_t pc,uint32_t typeId,SaveStateInst * saveState,Inst * initClass)203     NewObjectInst *CreateNewObjectInst(size_t pc, uint32_t typeId, SaveStateInst *saveState, Inst *initClass)
204     {
205         auto newObj = graph_->CreateInstNewObject(DataType::REFERENCE, pc, initClass, saveState,
206                                                   TypeIdMixin {typeId, graph_->GetMethod()});
207         return newObj;
208     }
209 
210     template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ>
211     class BuildCallHelper {
212     public:
213         BuildCallHelper(const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput = nullptr);
214 
215         void BuildIntrinsic();
216         void BuildDefaultIntrinsic(RuntimeInterface::IntrinsicId intrinsicId, bool isVirtual);
217         void BuildDefaultStaticIntrinsic(RuntimeInterface::IntrinsicId intrinsicId);
218         void BuildDefaultVirtualCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId);
219         void BuildMonitorIntrinsic(bool isEnter);
220 
221         void BuildStaticCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId);
222         void BuildVirtualCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId);
223 
224         void BuildCallInst(uint32_t classId);
225         void BuildCallStaticInst(uint32_t classId);
226         void BuildInitClassInstForCallStatic(uint32_t classId);
227 
228         void BuildCallVirtualInst();
229         void SetCallArgs(Inst *additionalInput = nullptr);
GetGraph()230         auto GetGraph()
231         {
232             return builder_->GetGraph();
233         }
GetRuntime()234         auto GetRuntime()
235         {
236             return builder_->GetRuntime();
237         }
GetMethod()238         auto GetMethod()
239         {
240             return builder_->GetMethod();
241         }
Builder()242         auto Builder()
243         {
244             return builder_;
245         }
246 
247     private:
248         InstBuilder *builder_ {};
249         const BytecodeInstruction *bcInst_ {};
250         RuntimeInterface::MethodPtr method_ {};
251         uint32_t methodId_ {};
252         uint32_t pc_ {};
253         InputTypesMixin<DynamicInputsInst> *call_ {};
254         Inst *resolver_ {};
255         Inst *nullCheck_ {};
256         SaveStateInst *saveState_ {};
257         bool hasImplicitArg_ {};
258     };
259     Inst *GetArgDefinition(const BytecodeInstruction *bcInst, size_t idx, bool accRead, bool isRange = false);
260     Inst *GetArgDefinitionRange(const BytecodeInstruction *bcInst, size_t idx);
261     template <bool IS_VIRTUAL>
262     void AddArgNullcheckIfNeeded(RuntimeInterface::IntrinsicId intrinsic, Inst *inst, Inst *saveState, size_t bcAddr);
263     void BuildMonitor(const BytecodeInstruction *bcInst, Inst *def, bool isEnter);
264     Inst *BuildFloatInst(const BytecodeInstruction *bcInst);
265     template <bool IS_RANGE, bool ACC_READ>
266     void BuildIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead);
267     template <bool IS_RANGE, bool ACC_READ>
268     void BuildDefaultIntrinsic(bool isVirtual, const BytecodeInstruction *bcInst);
269     void BuildAbsIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
270     template <Opcode OPCODE>
271     void BuildBinaryOperationIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
272     void BuildSqrtIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
273     void BuildIsNanIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
274     void BuildStringLengthIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
275     void BuildStringIsEmptyIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
276     void BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
277     void BuildCharToUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
278     void BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
279     void BuildCharToLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
280     void BuildMonitorIntrinsic(const BytecodeInstruction *bcInst, bool isEnter, bool accRead);
281     void BuildThrow(const BytecodeInstruction *bcInst);
282     void BuildLenArray(const BytecodeInstruction *bcInst);
283     void BuildNewArray(const BytecodeInstruction *bcInst);
284     void BuildNewObject(const BytecodeInstruction *bcInst);
285     void BuildLoadConstArray(const BytecodeInstruction *bcInst);
286     void BuildLoadConstStringArray(const BytecodeInstruction *bcInst);
287     template <typename T>
288     void BuildUnfoldLoadConstArray(const BytecodeInstruction *bcInst, DataType::Type type,
289                                    const pandasm::LiteralArray &litArray);
290     template <typename T>
291     void BuildUnfoldLoadConstPrimitiveArray(const BytecodeInstruction *bcInst, DataType::Type type,
292                                             const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst);
293     template <typename T>
294     void BuildUnfoldLoadConstStringArray(const BytecodeInstruction *bcInst, DataType::Type type,
295                                          const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst);
296     void BuildInitString(const BytecodeInstruction *bcInst);
297     void BuildInitObject(const BytecodeInstruction *bcInst, bool isRange);
298     CallInst *BuildCallStaticForInitObject(const BytecodeInstruction *bcInst, uint32_t methodId, Inst **resolver);
299     void BuildMultiDimensionalArrayObject(const BytecodeInstruction *bcInst, bool isRange);
300     void BuildInitObjectMultiDimensionalArray(const BytecodeInstruction *bcInst, bool isRange);
301     template <bool IS_ACC_WRITE>
302     void BuildLoadObject(const BytecodeInstruction *bcInst, DataType::Type type);
303     template <bool IS_ACC_READ>
304     void BuildStoreObject(const BytecodeInstruction *bcInst, DataType::Type type);
305     Inst *BuildStoreObjectInst(const BytecodeInstruction *bcInst, DataType::Type type, RuntimeInterface::FieldPtr field,
306                                uint32_t fieldId, Inst **resolveInst);
307     void BuildLoadStatic(const BytecodeInstruction *bcInst, DataType::Type type);
308     Inst *BuildLoadStaticInst(size_t pc, DataType::Type type, uint32_t typeId, Inst *saveState);
309     void BuildStoreStatic(const BytecodeInstruction *bcInst, DataType::Type type);
310     Inst *BuildStoreStaticInst(const BytecodeInstruction *bcInst, DataType::Type type, uint32_t typeId,
311                                Inst *storeInput, Inst *saveState);
312     void BuildCheckCast(const BytecodeInstruction *bcInst);
313     void BuildIsInstance(const BytecodeInstruction *bcInst);
314     Inst *BuildLoadClass(RuntimeInterface::IdType typeId, size_t pc, Inst *saveState);
315     void BuildLoadArray(const BytecodeInstruction *bcInst, DataType::Type type);
316     void BuildStoreArray(const BytecodeInstruction *bcInst, DataType::Type type);
317     template <bool CREATE_REF_CHECK>
318     void BuildStoreArrayInst(const BytecodeInstruction *bcInst, DataType::Type type, Inst *arrayRef, Inst *index,
319                              Inst *value);
320     std::tuple<SaveStateInst *, Inst *, LengthMethodInst *, BoundsCheckInst *> BuildChecksBeforeArray(
321         size_t pc, Inst *arrayRef, bool withNullcheck = true);
322     template <Opcode OPCODE>
323     void BuildLoadFromPool(const BytecodeInstruction *bcInst);
324     void BuildCastToAnyString(const BytecodeInstruction *bcInst);
325     void BuildCastToAnyNumber(const BytecodeInstruction *bcInst);
326     AnyTypeCheckInst *BuildAnyTypeCheckInst(size_t bcAddr, Inst *input, Inst *saveState,
327                                             AnyBaseType type = AnyBaseType::UNDEFINED_TYPE);
328     void InitAnyTypeCheckInst(AnyTypeCheckInst *anyCheck, bool typeWasProfiled = false,
329                               profiling::AnyInputType allowedInputType = {})
330     {
331         anyCheck->SetAllowedInputType(allowedInputType);
332         anyCheck->SetIsTypeWasProfiled(typeWasProfiled);
333     }
334 
335     bool TryBuildStringCharAtIntrinsic(const BytecodeInstruction *bcInst, bool accRead);
336 #include "inst_builder_extensions.inl.h"
337 
GetGraph()338     Graph *GetGraph()
339     {
340         return graph_;
341     }
342 
GetGraph()343     const Graph *GetGraph() const
344     {
345         return graph_;
346     }
347 
GetRuntime()348     const RuntimeInterface *GetRuntime() const
349     {
350         return runtime_;
351     }
352 
GetRuntime()353     RuntimeInterface *GetRuntime()
354     {
355         return runtime_;
356     }
357 
GetMethod()358     RuntimeInterface::MethodPtr GetMethod() const
359     {
360         return method_;
361     }
362 
GetClassId()363     auto GetClassId() const
364     {
365         return classId_;
366     }
367 
GetNoTypeMarker()368     Marker GetNoTypeMarker() const
369     {
370         return noTypeMarker_;
371     }
372 
GetVisitedBlockMarker()373     Marker GetVisitedBlockMarker() const
374     {
375         return visitedBlockMarker_;
376     }
377 
ForceUnresolved()378     bool ForceUnresolved() const
379     {
380 #ifndef NDEBUG
381         return g_options.IsCompilerForceUnresolved() && !graph_->IsBytecodeOptimizer();
382 #else
383         return false;
384 #endif
385     }
386 
387     void SetTypeRec(Inst *inst, DataType::Type type);
388 
389     /// Convert Panda bytecode type to COMPILER IR type
390     static DataType::Type ConvertPbcType(panda_file::Type type);
391 
392     /// Get return type of the method specified by id
393     DataType::Type GetMethodReturnType(uintptr_t id) const;
394     /// Get type of argument of the method specified by id
395     DataType::Type GetMethodArgumentType(uintptr_t id, size_t index) const;
396     /// Get count of arguments for the method specified by id
397     size_t GetMethodArgumentsCount(uintptr_t id) const;
398     /// Get return type of currently compiling method
399     DataType::Type GetCurrentMethodReturnType() const;
400     /// Get type of argument of currently compiling method
401     DataType::Type GetCurrentMethodArgumentType(size_t index) const;
402     /// Get count of arguments of currently compiling method
403     size_t GetCurrentMethodArgumentsCount() const;
404 
405     template <bool IS_STATIC>
406     bool IsInConstructor() const;
407 
408 #ifndef PANDA_ETS_INTEROP_JS
TryBuildInteropCall(const BytecodeInstruction * bcInst,bool isRange,bool accRead)409     bool TryBuildInteropCall([[maybe_unused]] const BytecodeInstruction *bcInst, [[maybe_unused]] bool isRange,
410                              [[maybe_unused]] bool accRead)
411     {
412         return false;
413     }
414 #endif
415 
416 #ifndef NDEBUG
ResetSafepointDistance()417     void ResetSafepointDistance()
418     {
419         safepointDistance_ = static_cast<int32_t>(g_options.GetCompilerSafepointDistanceLimit());
420     }
421 #endif
422 
423 private:
424     static constexpr size_t ONE_FOR_OBJECT = 1;
425     static constexpr size_t ONE_FOR_SSTATE = 1;
426 
427     Graph *graph_ {nullptr};
428     RuntimeInterface *runtime_ {nullptr};
429     BasicBlock *currentBb_ {nullptr};
430 
431     RuntimeInterface::MethodProfile methodProfile_ {};
432 
433     // Definitions vector of currently processed basic block
434     InstVector *currentDefs_ {nullptr};
435     // Result of LoadFromConstantPool which will be added to SaveState inputs
436     Inst *additionalDef_ {nullptr};
437     // Contains definitions of the virtual registers in all basic blocks
438     ArenaVector<InstVector> defs_;
439 
440     RuntimeInterface::MethodPtr method_ {nullptr};
441     // Set to true if builder failed to build IR
442     bool failed_ {false};
443     // Number of virtual registers and method arguments
444     const size_t vregsAndArgsCount_;
445     // Marker for instructions with undefined type in the building phase
446     Marker noTypeMarker_;
447     Marker visitedBlockMarker_;
448 
449     // Pointer to start position of bytecode instructions buffer
450     const uint8_t *instructionsBuf_ {nullptr};
451 
452     CallInst *callerInst_ {nullptr};
453     uint32_t inliningDepth_ {0};
454     size_t classId_;
455 #ifndef NDEBUG
456     int32_t safepointDistance_ {0};
457 #endif
458 #include "intrinsics_ir_build.inl.h"
459 };
460 }  // namespace ark::compiler
461 
462 #endif  // PANDA_INST_BUILDER_H
463