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> ¶ms, 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 173 LLVMValueRef GetDeoptFunction() const; 174 175 static constexpr int kDeoptEntryOffset = 0; 176 private: 177 LLVMValueRef AddAndGetFunc(const CallSignature *stubDescriptor); 178 void InitialLLVMFuncTypeAndFuncByModuleCSigns(); 179 LLVMTypeRef ConvertLLVMTypeFromVariableType(VariableType type); 180 LLVMTypeRef NewLType(MachineType machineType, GateType gateType); 181 // index: 182 // stub scenario - sequence of function adding to llvmModule 183 // aot scenario - method Id of function generated by panda files 184 std::vector<std::pair<size_t, LLVMValueRef>> funcIndexMap_; 185 std::vector<const CallSignature *> callSigns_; 186 LLVMModuleRef module_; 187 CompilationConfig cfg_; 188 }; 189 190 191 #define OPCODES(V) \ 192 V(Call, (GateRef gate, const std::vector<GateRef> &inList, OpCode op)) \ 193 V(RuntimeCall, (GateRef gate, const std::vector<GateRef> &inList)) \ 194 V(RuntimeCallWithArgv, (GateRef gate, const std::vector<GateRef> &inList)) \ 195 V(NoGcRuntimeCall, (GateRef gate, const std::vector<GateRef> &inList)) \ 196 V(BytecodeCall, (GateRef gate, const std::vector<GateRef> &inList)) \ 197 V(Alloca, (GateRef gate)) \ 198 V(Block, (int id, const OperandsVector &predecessors)) \ 199 V(Goto, (int block, int bbout)) \ 200 V(Parameter, (GateRef gate)) \ 201 V(Constant, (GateRef gate, std::bitset<64> value)) \ 202 V(RelocatableData, (GateRef gate, uint64_t value)) \ 203 V(ZExtInt, (GateRef gate, GateRef e1)) \ 204 V(SExtInt, (GateRef gate, GateRef e1)) \ 205 V(FPExt, (GateRef gate, GateRef e1)) \ 206 V(FPTrunc, (GateRef gate, GateRef e1)) \ 207 V(Load, (GateRef gate, GateRef base)) \ 208 V(Store, (GateRef gate, GateRef base, GateRef value)) \ 209 V(IntRev, (GateRef gate, GateRef e1)) \ 210 V(Add, (GateRef gate, GateRef e1, GateRef e2)) \ 211 V(Sub, (GateRef gate, GateRef e1, GateRef e2)) \ 212 V(Mul, (GateRef gate, GateRef e1, GateRef e2)) \ 213 V(FloatDiv, (GateRef gate, GateRef e1, GateRef e2)) \ 214 V(IntDiv, (GateRef gate, GateRef e1, GateRef e2)) \ 215 V(UDiv, (GateRef gate, GateRef e1, GateRef e2)) \ 216 V(IntOr, (GateRef gate, GateRef e1, GateRef e2)) \ 217 V(IntAnd, (GateRef gate, GateRef e1, GateRef e2)) \ 218 V(IntXor, (GateRef gate, GateRef e1, GateRef e2)) \ 219 V(IntLsr, (GateRef gate, GateRef e1, GateRef e2)) \ 220 V(IntAsr, (GateRef gate, GateRef e1, GateRef e2)) \ 221 V(Int32LessThanOrEqual, (GateRef gate, GateRef e1, GateRef e2)) \ 222 V(Cmp, (GateRef gate, GateRef e1, GateRef e2)) \ 223 V(Branch, (GateRef gate, GateRef cmp, GateRef btrue, GateRef bfalse)) \ 224 V(Switch, (GateRef gate, GateRef input, const std::vector<GateRef> &outList)) \ 225 V(SwitchCase, (GateRef gate, GateRef switchBranch, GateRef out)) \ 226 V(Phi, (GateRef gate, const std::vector<GateRef> &srcGates)) \ 227 V(Return, (GateRef gate, GateRef popCount, const std::vector<GateRef> &operands)) \ 228 V(ReturnVoid, (GateRef gate)) \ 229 V(CastIntXToIntY, (GateRef gate, GateRef e1)) \ 230 V(ChangeInt32ToDouble, (GateRef gate, GateRef e1)) \ 231 V(ChangeUInt32ToDouble, (GateRef gate, GateRef e1)) \ 232 V(ChangeDoubleToInt32, (GateRef gate, GateRef e1)) \ 233 V(BitCast, (GateRef gate, GateRef e1)) \ 234 V(IntLsl, (GateRef gate, GateRef e1, GateRef e2)) \ 235 V(Mod, (GateRef gate, GateRef e1, GateRef e2)) \ 236 V(ChangeTaggedPointerToInt64, (GateRef gate, GateRef e1)) \ 237 V(ChangeInt64ToTagged, (GateRef gate, GateRef e1)) \ 238 V(Deopt, (GateRef gate)) \ 239 V(TruncFloatToInt, (GateRef gate, GateRef e1)) \ 240 241 // runtime/common stub ID, opcodeOffset for bc stub 242 using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>; 243 class LLVMIRBuilder { 244 public: 245 explicit LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit, 246 LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg, 247 CallSignature::CallConv callConv, bool enableLog = false); 248 ~LLVMIRBuilder(); 249 void Build(); 250 251 private: 252 #define DECLAREVISITOPCODE(name, signature) void Visit##name signature; OPCODES(DECLAREVISITOPCODE)253 OPCODES(DECLAREVISITOPCODE) 254 #undef DECLAREVISITOPCODE 255 #define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(GateRef gate); 256 OPCODES(DECLAREHANDLEOPCODE) 257 #undef DECLAREHANDLEOPCODE 258 259 bool isPrologue(int bbId) const 260 { 261 return bbId == 0; 262 } 263 void LinkToLLVMCfg(int bbId, const OperandsVector &predecessors); 264 BasicBlock *EnsureBB(int id); 265 LLVMValueRef CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller); 266 LLVMValueRef GetCurrentSP(); 267 LLVMValueRef ReadRegister(LLVMModuleRef &module, LLVMBuilderRef &builder, 268 LLVMMetadataRef meta); 269 void GenPrologue(); 270 LLVMBasicBlockRef EnsureLBB(BasicBlock *bb) const; 271 BasicBlockImpl *EnsureBBImpl(BasicBlock *bb) const; 272 void SetToCfg(BasicBlock *bb) const; 273 274 LLVMTypeRef GetMachineRepType(MachineRep rep) const; 275 int FindBasicBlock(GateRef gate) const; 276 void EndCurrentBlock() const; 277 void Finish(); 278 279 void ProcessPhiWorkList(); 280 void InitializeHandlers(); 281 std::string LLVMValueToString(LLVMValueRef val) const; 282 GetIntPtr()283 LLVMTypeRef GetIntPtr() const 284 { 285 if (compCfg_->Is32Bit()) { 286 return LLVMInt32Type(); 287 } 288 return LLVMInt64Type(); 289 } 290 LLVMTypeRef ConvertLLVMTypeFromGate(GateRef gate) const; 291 int64_t GetBitWidthFromMachineType(MachineType machineType) const; 292 LLVMValueRef PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offset, LLVMTypeRef rep); 293 LLVMValueRef VectorAdd(LLVMValueRef e1Value, LLVMValueRef e2Value, LLVMTypeRef rep); 294 LLVMValueRef CanonicalizeToInt(LLVMValueRef value); 295 LLVMValueRef CanonicalizeToPtr(LLVMValueRef value); 296 LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr); 297 void SetFunctionCallConv(); 298 IsLogEnabled()299 bool IsLogEnabled() const 300 { 301 return enableLog_; 302 } 303 LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset, 304 const std::string &realName = "") const; 305 LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature, 306 LLVMValueRef reloc) const; 307 bool IsInterpreted(); 308 bool IsOptimized(); 309 void SetGCLeafFunction(LLVMValueRef call); 310 void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call); 311 bool IsHeapPointerType(LLVMTypeRef valueType); 312 313 private: 314 enum class CallInputs : size_t { 315 DEPEND = 0, 316 TARGET, 317 GLUE, 318 FIRST_PARAMETER 319 }; 320 enum class CallExceptionKind : bool { 321 HAS_BC_OFFSET = true, 322 NO_BC_OFFSET = false 323 }; 324 LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond); 325 LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond); 326 LLVMValueRef GetGlue(const std::vector<GateRef> &inList); 327 LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue); 328 LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index); 329 LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index); 330 LLVMValueRef GetBCStubOffset(LLVMValueRef glue); 331 LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue); 332 LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue); 333 LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue); 334 CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const; 335 void ComputeArgCountAndBCOffset(size_t &actualNumArgs, LLVMValueRef &bcOffset, const std::vector<GateRef> &inList, 336 CallExceptionKind kind); 337 void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value); 338 void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value); 339 void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder); 340 void UpdateLeaveFrame(LLVMValueRef glue); 341 LLVMTypeRef GetExperimentalDeoptTy(); 342 LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module); 343 void GenDeoptEntry(LLVMModuleRef &module); 344 const CompilationConfig *compCfg_ {nullptr}; 345 const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr}; 346 const Circuit *circuit_ {nullptr}; 347 GateAccessor acc_; 348 BasicBlock *currentBb_ {nullptr}; 349 int lineNumber_ {0}; 350 351 LLVMModuleRef module_ {nullptr}; 352 LLVMContextRef context_; 353 LLVMValueRef function_ {nullptr}; 354 LLVMBuilderRef builder_ {nullptr}; 355 std::map<GateId, int> instID2bbID_; 356 BasicBlockMap bbID2BB_; 357 358 std::vector<BasicBlock *> phiRebuildWorklist_; 359 LLVMModule *llvmModule_ {nullptr}; 360 std::unordered_map<GateRef, LLVMValueRef> gate2LValue_; 361 std::unordered_map<OpCode, HandleType> opHandlers_; 362 std::set<OpCode> illegalOpHandlers_; 363 int slotSize_; 364 LLVMTypeRef slotType_; 365 CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv; 366 bool enableLog_ {false}; 367 }; 368 } // namespace panda::ecmascript::kungfu 369 #endif // PANDA_RUNTIME_ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H 370