• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
17 #define ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
18 
19 #include <map>
20 #include <memory>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include "ecmascript/compiler/circuit.h"
25 #include "ecmascript/compiler/gate.h"
26 #include "ecmascript/compiler/stub_builder.h"
27 #include "ecmascript/compiler/call_signature.h"
28 #include "ecmascript/compiler/common_stubs.h"
29 #include "ecmascript/compiler/interpreter_stub.h"
30 #include "ecmascript/compiler/rt_call_signature.h"
31 #include "ecmascript/jspandafile/method_literal.h"
32 
33 #include "llvm-c/Core.h"
34 
35 namespace panda::ecmascript::kungfu {
36 using OperandsVector = std::set<int>;
37 class BasicBlock;
38 using BasicBlockMap = std::map<int, std::unique_ptr<BasicBlock>>;
39 class LLVMIRBuilder;
40 using HandleType = void(LLVMIRBuilder::*)(GateRef gate);
41 
42 enum class MachineRep {
43     K_NONE,
44     K_BIT,
45     K_WORD8,
46     K_WORD16,
47     K_WORD32,
48     K_WORD64,
49     // FP representations must be last, and in order of increasing size.
50     K_FLOAT32,
51     K_FLOAT64,
52     K_SIMD128,
53     K_PTR_1, // Tagged Pointer
54     K_META,
55 };
56 
57 class BasicBlock {
58 public:
BasicBlock(int id)59     explicit BasicBlock(int id) : id_(id)
60     {
61         predecessors_ = {};
62         successors_ = {};
63         impl_ = nullptr;
64     }
65 
GetId()66     int GetId() const
67     {
68         return id_;
69     }
70 
71     template<class T>
GetImpl()72     inline T *GetImpl() const
73     {
74         return static_cast<T *>(impl_);
75     }
76 
SetImpl(void * impl)77     inline void SetImpl(void *impl)
78     {
79         impl_ = impl;
80     }
81 
82     template<class T>
ResetImpl()83     inline void ResetImpl()
84     {
85         if (impl_) {
86             delete GetImpl<T>();
87             impl_ = nullptr;
88         }
89     }
90     ~BasicBlock() = default;
91 
92 private:
93     std::vector<BasicBlock *> predecessors_ {};
94     std::vector<BasicBlock *> successors_ {};
95     int id_ {-1};
96     void *impl_ {nullptr};
97 };
98 
99 struct NotMergedPhiDesc {
100     BasicBlock *pred;
101     GateRef operand;
102     LLVMValueRef phi;
103 };
104 
105 struct BasicBlockImpl {
106     LLVMBasicBlockRef lBB_ = nullptr;
107     LLVMBasicBlockRef continuation = nullptr;
108     bool started = false;
109     bool ended = false;
110     std::vector<NotMergedPhiDesc> unmergedPhis_;
111 };
112 
113 class LLVMModule {
114 public:
115     LLVMModule(const std::string &name, const std::string &triple, bool enablePGOProfiler = false);
116     ~LLVMModule();
117     void SetUpForCommonStubs();
118     void SetUpForBytecodeHandlerStubs();
119     void SetUpForBuiltinsStubs();
120     LLVMValueRef AddFunc(const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile);
GetModule()121     LLVMModuleRef GetModule() const
122     {
123         return module_;
124     }
125     LLVMTypeRef GetFuncType(const CallSignature *stubDescriptor);
126 
127     LLVMTypeRef GenerateFuncType(const std::vector<LLVMValueRef> &params, const CallSignature *stubDescriptor);
128 
SetFunction(size_t index,LLVMValueRef func)129     void SetFunction(size_t index, LLVMValueRef func)
130     {
131         funcIndexMap_.emplace_back(std::make_pair(index, func));
132     }
133 
GetFunction(size_t index)134     LLVMValueRef GetFunction(size_t index)
135     {
136         // next optimization can be performed
137         for (auto &it: funcIndexMap_) {
138             if (it.first == index) {
139                 return it.second;
140             }
141         }
142         return nullptr;
143     }
144 
GetFuncCount()145     size_t GetFuncCount() const
146     {
147         return funcIndexMap_.size();
148     }
149 
150     template<class Callback>
IteratefuncIndexMap(const Callback & cb)151     void IteratefuncIndexMap(const Callback &cb) const
152     {
153         for (auto record : funcIndexMap_) {
154             cb(record.first, record.second);
155         }
156     }
157 
GetCSign(size_t index)158     const CallSignature *GetCSign(size_t index) const
159     {
160         return callSigns_[index];
161     }
162 
GetCompilationConfig()163     const CompilationConfig *GetCompilationConfig() const
164     {
165         return &cfg_;
166     }
167 
GetCSigns()168     const std::vector<const CallSignature*> &GetCSigns() const
169     {
170         return callSigns_;
171     }
172 private:
173     LLVMValueRef AddAndGetFunc(const CallSignature *stubDescriptor);
174     void InitialLLVMFuncTypeAndFuncByModuleCSigns();
175     LLVMTypeRef ConvertLLVMTypeFromVariableType(VariableType type);
176     LLVMTypeRef NewLType(MachineType machineType, GateType gateType);
177     // index:
178     //     stub scenario - sequence of function adding to llvmModule
179     //     aot scenario - method Id of function generated by panda files
180     std::vector<std::pair<size_t, LLVMValueRef>> funcIndexMap_;
181     std::vector<const CallSignature *> callSigns_;
182     LLVMModuleRef module_;
183     CompilationConfig cfg_;
184 };
185 
186 
187 #define OPCODES(V)                                                                        \
188     V(Call, (GateRef gate, const std::vector<GateRef> &inList, OpCode op))                \
189     V(RuntimeCall, (GateRef gate, const std::vector<GateRef> &inList))                    \
190     V(RuntimeCallWithArgv, (GateRef gate, const std::vector<GateRef> &inList))            \
191     V(NoGcRuntimeCall, (GateRef gate, const std::vector<GateRef> &inList))                \
192     V(BytecodeCall, (GateRef gate, const std::vector<GateRef> &inList))                   \
193     V(Alloca, (GateRef gate))                                                             \
194     V(Block, (int id, const OperandsVector &predecessors))                                \
195     V(Goto, (int block, int bbout))                                                       \
196     V(Parameter, (GateRef gate))                                                          \
197     V(Constant, (GateRef gate, std::bitset<64> value))                                    \
198     V(RelocatableData, (GateRef gate, uint64_t value))                                    \
199     V(ZExtInt, (GateRef gate, GateRef e1))                                                \
200     V(SExtInt, (GateRef gate, GateRef e1))                                                \
201     V(FPExt, (GateRef gate, GateRef e1))                                                  \
202     V(FPTrunc, (GateRef gate, GateRef e1))                                                \
203     V(Load, (GateRef gate, GateRef base))                                                 \
204     V(Store, (GateRef gate, GateRef base, GateRef value))                                 \
205     V(IntRev, (GateRef gate, GateRef e1))                                                 \
206     V(Add, (GateRef gate, GateRef e1, GateRef e2))                                        \
207     V(Sub, (GateRef gate, GateRef e1, GateRef e2))                                        \
208     V(Mul, (GateRef gate, GateRef e1, GateRef e2))                                        \
209     V(FloatDiv, (GateRef gate, GateRef e1, GateRef e2))                                   \
210     V(IntDiv, (GateRef gate, GateRef e1, GateRef e2))                                     \
211     V(UDiv, (GateRef gate, GateRef e1, GateRef e2))                                       \
212     V(IntOr, (GateRef gate, GateRef e1, GateRef e2))                                      \
213     V(IntAnd, (GateRef gate, GateRef e1, GateRef e2))                                     \
214     V(IntXor, (GateRef gate, GateRef e1, GateRef e2))                                     \
215     V(IntLsr, (GateRef gate, GateRef e1, GateRef e2))                                     \
216     V(IntAsr, (GateRef gate, GateRef e1, GateRef e2))                                     \
217     V(Int32LessThanOrEqual, (GateRef gate, GateRef e1, GateRef e2))                       \
218     V(Cmp, (GateRef gate, GateRef e1, GateRef e2))                                        \
219     V(Branch, (GateRef gate, GateRef cmp, GateRef btrue, GateRef bfalse))                 \
220     V(Switch, (GateRef gate, GateRef input, const std::vector<GateRef> &outList))         \
221     V(SwitchCase, (GateRef gate, GateRef switchBranch, GateRef out))                      \
222     V(Phi, (GateRef gate, const std::vector<GateRef> &srcGates))                          \
223     V(Return, (GateRef gate, GateRef popCount, const std::vector<GateRef> &operands))     \
224     V(ReturnVoid, (GateRef gate))                                                         \
225     V(CastIntXToIntY, (GateRef gate, GateRef e1))                                         \
226     V(ChangeInt32ToDouble, (GateRef gate, GateRef e1))                                    \
227     V(ChangeUInt32ToDouble, (GateRef gate, GateRef e1))                                   \
228     V(ChangeDoubleToInt32, (GateRef gate, GateRef e1))                                    \
229     V(BitCast, (GateRef gate, GateRef e1))                                                \
230     V(IntLsl, (GateRef gate, GateRef e1, GateRef e2))                                     \
231     V(Mod, (GateRef gate, GateRef e1, GateRef e2))                                        \
232     V(ChangeTaggedPointerToInt64, (GateRef gate, GateRef e1))                             \
233     V(ChangeInt64ToTagged, (GateRef gate, GateRef e1))                                    \
234     V(Deopt, (GateRef gate))                                                              \
235     V(TruncFloatToInt, (GateRef gate, GateRef e1))                                        \
236 
237 // runtime/common stub ID, opcodeOffset for bc stub
238 using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>;
239 class LLVMIRBuilder {
240 public:
241     explicit LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
242                            LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg,
243                            CallSignature::CallConv callConv, bool enableLog = false);
244     ~LLVMIRBuilder();
245     void Build();
246 
247 private:
248     #define DECLAREVISITOPCODE(name, signature) void Visit##name signature;
OPCODES(DECLAREVISITOPCODE)249         OPCODES(DECLAREVISITOPCODE)
250     #undef DECLAREVISITOPCODE
251     #define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(GateRef gate);
252         OPCODES(DECLAREHANDLEOPCODE)
253     #undef DECLAREHANDLEOPCODE
254 
255     bool isPrologue(int bbId) const
256     {
257         return bbId == 0;
258     }
259     void LinkToLLVMCfg(int bbId, const OperandsVector &predecessors);
260     BasicBlock *EnsureBB(int id);
261     LLVMValueRef CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller);
262     LLVMValueRef GetCurrentSP();
263     LLVMValueRef ReadRegister(LLVMModuleRef &module, LLVMBuilderRef &builder,
264         LLVMMetadataRef meta);
265     void GenPrologue();
266     LLVMBasicBlockRef EnsureLBB(BasicBlock *bb) const;
267     BasicBlockImpl *EnsureBBImpl(BasicBlock *bb) const;
268     void SetToCfg(BasicBlock *bb) const;
269 
270     LLVMTypeRef GetMachineRepType(MachineRep rep) const;
271     int FindBasicBlock(GateRef gate) const;
272     void EndCurrentBlock() const;
273     void Finish();
274 
275     void ProcessPhiWorkList();
276     void InitializeHandlers();
277     std::string LLVMValueToString(LLVMValueRef val) const;
278 
GetIntPtr()279     LLVMTypeRef GetIntPtr() const
280     {
281         if (compCfg_->Is32Bit()) {
282             return LLVMInt32Type();
283         }
284         return LLVMInt64Type();
285     }
286     LLVMTypeRef ConvertLLVMTypeFromGate(GateRef gate) const;
287     int64_t GetBitWidthFromMachineType(MachineType machineType) const;
288     LLVMValueRef PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offset, LLVMTypeRef rep);
289     LLVMValueRef VectorAdd(LLVMValueRef e1Value, LLVMValueRef e2Value, LLVMTypeRef rep);
290     LLVMValueRef CanonicalizeToInt(LLVMValueRef value);
291     LLVMValueRef CanonicalizeToPtr(LLVMValueRef value);
292     LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr);
293     void SetFunctionCallConv();
294 
IsLogEnabled()295     bool IsLogEnabled() const
296     {
297         return enableLog_;
298     }
299     LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset,
300                              const std::string &realName = "") const;
301     LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature,
302         LLVMValueRef reloc) const;
303     bool IsInterpreted();
304     bool IsOptimized();
305     void SetGCLeafFunction(LLVMValueRef call);
306     void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call);
307     bool IsHeapPointerType(LLVMTypeRef valueType);
308 
309 private:
310     enum class CallInputs : size_t {
311         DEPEND = 0,
312         TARGET,
313         GLUE,
314         FIRST_PARAMETER
315     };
316     enum class CallExceptionKind : bool {
317         HAS_BC_OFFSET = true,
318         NO_BC_OFFSET = false
319     };
320     LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond);
321     LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond);
322     LLVMValueRef GetGlue(const std::vector<GateRef> &inList);
323     LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue);
324     LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index);
325     LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index);
326     LLVMValueRef GetBCStubOffset(LLVMValueRef glue);
327     LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue);
328     LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue);
329     LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue);
330     CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const;
331     void ComputeArgCountAndBCOffset(size_t &actualNumArgs, LLVMValueRef &bcOffset, const std::vector<GateRef> &inList,
332                                     CallExceptionKind kind);
333     void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value);
334     void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value);
335     void SaveFrameTypeOnFrame(FrameType frameType);
336     void UpdateLeaveFrame(LLVMValueRef glue);
337     LLVMTypeRef GetExperimentalDeoptTy();
338     LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module);
339     const CompilationConfig *compCfg_ {nullptr};
340     const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
341     const Circuit *circuit_ {nullptr};
342     GateAccessor acc_;
343     BasicBlock *currentBb_ {nullptr};
344     int lineNumber_ {0};
345 
346     LLVMModuleRef module_ {nullptr};
347     LLVMContextRef context_;
348     LLVMValueRef function_ {nullptr};
349     LLVMBuilderRef builder_ {nullptr};
350     std::map<GateId, int> instID2bbID_;
351     BasicBlockMap bbID2BB_;
352 
353     std::vector<BasicBlock *> phiRebuildWorklist_;
354     LLVMModule *llvmModule_ {nullptr};
355     std::unordered_map<GateRef, LLVMValueRef> gate2LValue_;
356     std::unordered_map<OpCode, HandleType> opHandlers_;
357     std::set<OpCode> illegalOpHandlers_;
358     int slotSize_;
359     LLVMTypeRef slotType_;
360     CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv;
361     bool enableLog_ {false};
362 };
363 }  // namespace panda::ecmascript::kungfu
364 #endif  // PANDA_RUNTIME_ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
365