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 ECMASCRIPT_COMPILER_LITECG_IR_BUILDER_H
17 #define ECMASCRIPT_COMPILER_LITECG_IR_BUILDER_H
18 
19 #include <map>
20 #include <vector>
21 
22 #include "ecmascript/compiler/circuit.h"
23 #include "ecmascript/compiler/gate.h"
24 #include "ecmascript/compiler/stub_builder.h"
25 #include "ecmascript/compiler/call_signature.h"
26 #include "ecmascript/compiler/interpreter_stub.h"
27 #include "ecmascript/compiler/rt_call_signature.h"
28 #include "ecmascript/compiler/ir_builder.h"
29 #include "ecmascript/compiler/ir_module.h"
30 #include "ecmascript/jspandafile/method_literal.h"
31 #include "lmir_builder.h"
32 #include "constantfold.h"
33 
34 namespace panda::ecmascript::kungfu {
35 class LMIRModule : public IRModule {
36 public:
37     static constexpr int kDeoptEntryOffset = 0;
LMIRModule(NativeAreaAllocator *allocator, const std::string &name, bool logDbg, const std::string &triple, bool isJit)38     LMIRModule(NativeAreaAllocator *allocator, const std::string &name, bool logDbg, const std::string &triple,
39          bool isJit)
40         : IRModule(allocator, logDbg, triple)
41     {
42         moduleName = name;
43         module = isJit ? nullptr : maple::litecg::CreateModuleWithName(name);
44     }
45 
~LMIRModule()46     ~LMIRModule()
47     {
48         if (module != nullptr) {
49             maple::litecg::ReleaseModule(module);
50         }
51     }
52 
JitCreateLitecgModule()53     void JitCreateLitecgModule()
54     {
55         ASSERT(module == nullptr);
56         module = maple::litecg::CreateModuleWithName(moduleName);
57     }
58 
GetModule()59     maple::litecg::Module *GetModule()
60     {
61         ASSERT(module != nullptr);
62         return module;
63     }
64 
65     ModuleKind GetModuleKind() const override
66     {
67         return MODULE_LITECG;
68     }
69 
SetFunction(size_t index, std::string funcName, bool isFastCall)70     void SetFunction(size_t index, std::string funcName, bool isFastCall)
71     {
72         funcIndexMap_.emplace_back(std::make_tuple(index, funcName, isFastCall));
73     }
74 
75     template <class Callback>
IteratefuncIndexMap(const Callback &cb) const76     void IteratefuncIndexMap(const Callback &cb) const
77     {
78         for (auto record : funcIndexMap_) {
79             // 2: 3nd param
80             cb(std::get<0>(record), std::get<1>(record), std::get<2>(record));
81         }
82     }
83 
84 private:
85     std::string moduleName;
86     maple::litecg::Module *module;
87     std::vector<std::tuple<size_t, std::string, bool>> funcIndexMap_;
88 };
89 
90 class LiteCGIRBuilder {
91 public:
92     LiteCGIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit, LMIRModule *module,
93                     const CompilationConfig *cfg, CallSignature::CallConv callConv, bool enableLog,
94                     bool enableOptInlining, const panda::ecmascript::MethodLiteral *methodLiteral,
95                     const JSPandaFile *jsPandaFile, const std::string &funcName);
96     ~LiteCGIRBuilder();
97     void Build();
98 
99 private:
100     struct PhiDesc {
101         int predBBId;
102         GateRef operand;
103         maple::litecg::PregIdx phi;
104     };
105     enum DerivedStatus {
106         IS_DERIVED,
107         IS_BASE,
108         UNKNOW
109     };
110     const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
111     const Circuit *circuit_ {nullptr};
112     LMIRModule *lmirModule_ {nullptr};
113     const CompilationConfig *compCfg_ {nullptr};
114     CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv;
115     bool enableLog_ {false};
116     bool enableOptInlining_ {false};
117     const panda::ecmascript::MethodLiteral *methodLiteral_ {nullptr};
118     const JSPandaFile *jsPandaFile_ {nullptr};
119     std::string funcName_;
120     GateAccessor acc_;
121     maple::litecg::LMIRBuilder *lmirBuilder_ {nullptr};
122     std::unordered_map<GateRef, maple::litecg::LiteCGValue> gate2Expr_;
123     std::set<OpCode> illegalOpHandlers_;
124     std::map<GateId, int> instID2bbID_;
125     std::map<int, maple::litecg::BB *> bbID2BB_;
126     int slotSize_ {-1};
127     maple::litecg::Type *slotType_ {nullptr};
128     std::map<int, std::vector<PhiDesc>> bbID2unmergedPhis_;
129     std::map<int, std::vector<PhiDesc>> bbID2basePhis_; // use for collect all the base references
130     // derived phi reference gate to base phi preg map
131     std::map<GateRef, maple::litecg::PregIdx> derivedPhiGate2BasePhiPreg_;
132     std::map<GateRef, GateRef> derivedGate2BaseGate_; // derived reference gate to base reference gate map
133     std::map<GateRef, bool> derivedGateCache_; // cache whether the phi reference is derived, base or unknow
134     maple::ConstantFold cf_;
135 
136 #define DECLAREVISITLOWEROPCODE(name, signature) void Visit##name signature;
137     OPCODES(DECLAREVISITLOWEROPCODE)
138 #undef DECLAREVISITLOWEROPCODE
139 #define DECLAREHANDLELOWEROPCODE(name, ignore) void Handle##name(GateRef gate);
140     OPCODES(DECLAREHANDLELOWEROPCODE)
141 #undef DECLAREHANDLELOWEROPCODE
InsertUsedOpcodeSet(std::unordered_set<OpCode> &usedOpcodeSet, OpCode op)142     void InsertUsedOpcodeSet(std::unordered_set<OpCode> &usedOpcodeSet, OpCode op)
143     {
144         if (enableLog_) {
145             usedOpcodeSet.insert(op);
146         }
147     }
148     void SaveGate2Expr(GateRef gate, maple::litecg::Expr expr, bool isGlueAdd = false);
149     void SaveGate2Expr(GateRef gate, maple::litecg::PregIdx pregIdx1, maple::litecg::PregIdx pregIdx2);
150     maple::litecg::Expr GetExprFromGate(GateRef gate);
151     maple::litecg::Expr GetExprFromGate(GateRef gate, uint32_t index);
152     maple::litecg::Expr GetConstant(GateRef gate);
153     void BuildInstID2BBIDMap();
154     maple::litecg::BB &GetOrCreateBB(int bbID);
155     maple::litecg::BB &GetFirstBB();
156     maple::litecg::BB &CreateBB();
157     void AddPhiDesc(int bbID, PhiDesc &desc, std::map<int, std::vector<PhiDesc>> &bbID2Phis);
158     DerivedStatus CheckDerivedPhi(GateRef gate, std::set<GateRef> &vis);
159     void FindBaseRefForPhi(GateRef gate, const std::vector<GateRef> &phiIns);
160     maple::litecg::Type *ConvertLiteCGTypeFromGate(GateRef gate, bool isSigned = true) const;
161     maple::litecg::IntCmpCondition ConvertLiteCGPredicateFromICMP(ICmpCondition cond) const;
162     maple::litecg::FloatCmpCondition ConvertLiteCGPredicateFromFCMP(FCmpCondition cond) const;
163     void InitializeHandlers();
164     maple::litecg::Expr GetGlue(const std::vector<GateRef> &inList);
165     maple::litecg::Expr GetRTStubOffset(maple::litecg::Expr glue, int index);
166     maple::litecg::Type *ConvertLiteCGTypeFromVariableType(VariableType type) const;
167     maple::litecg::Type *GenerateFuncType(const std::vector<maple::litecg::Expr> &params,
168                                           const CallSignature *stubDescriptor);
169     maple::litecg::Type *GetFuncType(const CallSignature *stubDescriptor) const;
170     maple::litecg::Expr GetFunction(maple::litecg::BB &bb, maple::litecg::Expr glue, const CallSignature *signature,
171                                     maple::litecg::Expr rtbaseoffset, const std::string &realName = "") const;
172     bool IsOptimizedJSFunction() const;
173     bool IsOptimized() const;
174     CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const;
175     maple::litecg::Expr GetRTStubOffset(maple::litecg::Expr glue, int index) const;
176     maple::litecg::Expr GetCoStubOffset(maple::litecg::Expr glue, int index) const;
177     maple::litecg::Expr GetBaselineStubOffset(maple::litecg::Expr glue, int index) const;
178     maple::litecg::Expr GetCallee(maple::litecg::BB &bb, const std::vector<GateRef> &inList,
179                                   const CallSignature *signature, const std::string &realName);
180     maple::litecg::Expr CanonicalizeToPtr(maple::litecg::Expr expr, maple::litecg::Type *type);
181     maple::litecg::Expr CanonicalizeToInt(GateRef gate);
182     int64_t GetBitWidthFromMachineType(MachineType machineType) const;
183     int LookupPredBB(GateRef start, int bbID);
184     maple::litecg::Expr GetBuiltinsStubOffset(maple::litecg::Expr glue);
185     void UpdateLeaveFrame(maple::litecg::Expr glue);
186     maple::litecg::Expr GetLeaveFrameOffset(maple::litecg::Expr glue);
187     maple::litecg::Expr CallingFp(bool isCaller);
188     maple::litecg::Expr GetBaseOffset(GateRef gate, maple::litecg::Expr glue);
189     maple::litecg::Expr GetBCDebugStubOffset(maple::litecg::Expr glue);
190     maple::litecg::Expr GetBCStubOffset(maple::litecg::Expr glue);
191     maple::litecg::Type *GetExperimentalDeoptTy();
192     maple::litecg::Function *GetExperimentalDeopt();
193     void GenDeoptEntry(std::string funcName);
194     void SaveFrameTypeOnFrame(maple::litecg::BB &bb, FrameType frameType);
195     maple::litecg::Expr ConvertToTagged(GateRef gate);
196     maple::litecg::Expr ConvertInt32ToTaggedInt(maple::litecg::Expr value);
197     maple::litecg::Expr ConvertBoolToTaggedBoolean(GateRef gate);
198     maple::litecg::Expr ConvertFloat64ToTaggedDouble(GateRef gate);
199     void SaveDeoptVregInfo(std::unordered_map<int, maple::litecg::LiteCGValue> &deoptBundleInfo, maple::litecg::BB &bb,
200                            int32_t index, size_t curDepth, size_t shift, GateRef gate);
201     void SaveDeoptVregInfoWithI64(std::unordered_map<int, maple::litecg::LiteCGValue> &deoptBundleInfo,
202                                   maple::litecg::BB &bb, int32_t index, size_t curDepth, size_t shift, GateRef gate);
203 
204     maple::litecg::ConvAttr ConvertCallAttr(const CallSignature::CallConv callConv);
205     void CollectExraCallSiteInfo(std::unordered_map<int, maple::litecg::LiteCGValue> &deoptBundleInfo,
206                                  maple::litecg::Expr pcOffset, GateRef frameArgs);
207     void GenPrologue(maple::litecg::Function &function);
208     void AssistGenPrologue(const size_t reservedSlotsSize, FrameType frameType, maple::litecg::Function &function);
209     void SaveByteCodePcOnOptJSFuncFrame(maple::litecg::Var &value);
210     void SaveJSFuncOnOptJSFuncFrame(maple::litecg::Function &function, maple::litecg::Var &value, int funcIndex);
211     void SaveFrameTypeOnFrame(maple::litecg::Function &function, FrameType frameType);
212     bool IsInterpreted() const;
213     bool IsBaselineBuiltin() const;
214     void AddFunc();
215     void CollectDerivedRefInfo();
216     void HandleBB(const std::vector<GateRef> &bb, std::unordered_set<OpCode> &usedOpcodeSet);
IsLogEnabled() const217     bool IsLogEnabled() const
218     {
219         return enableLog_;
220     }
221     void VisitBinaryOpWithOverflow(GateRef gate, GateRef e1, GateRef e2, maple::litecg::IntrinsicId intrinsicId);
222 };
223 }  // namespace panda::ecmascript::kungfu
224 #endif  // ECMASCRIPT_COMPILER_LITECG_IR_BUILDER_H
225