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_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_stub_csigns.h" 29 #include "ecmascript/compiler/interpreter_stub.h" 30 #include "ecmascript/compiler/rt_call_signature.h" 31 #include "ecmascript/compiler/ir_module.h" 32 #include "ecmascript/compiler/ir_builder.h" 33 #include "ecmascript/jspandafile/method_literal.h" 34 #include "llvm-c/DebugInfo.h" 35 #include "llvm-c/Core.h" 36 37 namespace panda::ecmascript::kungfu { 38 class BasicBlock; 39 class DebugInfo; 40 using BasicBlockMap = std::map<int, std::unique_ptr<BasicBlock>>; 41 class LLVMIRBuilder; 42 using HandleType = void(LLVMIRBuilder::*)(GateRef gate); 43 44 class BasicBlock { 45 public: BasicBlock(int id)46 explicit BasicBlock(int id) : id_(id) 47 { 48 predecessors_ = {}; 49 successors_ = {}; 50 impl_ = nullptr; 51 } 52 GetId()53 int GetId() const 54 { 55 return id_; 56 } 57 58 template<class T> GetImpl()59 inline T *GetImpl() const 60 { 61 return static_cast<T *>(impl_); 62 } 63 SetImpl(void * impl)64 inline void SetImpl(void *impl) 65 { 66 impl_ = impl; 67 } 68 69 template<class T> ResetImpl()70 inline void ResetImpl() 71 { 72 if (impl_) { 73 delete GetImpl<T>(); 74 impl_ = nullptr; 75 } 76 } 77 ~BasicBlock() = default; 78 79 private: 80 std::vector<BasicBlock *> predecessors_ {}; 81 std::vector<BasicBlock *> successors_ {}; 82 int id_ {-1}; 83 void *impl_ {nullptr}; 84 }; 85 86 struct NotMergedPhiDesc { 87 int predBBId; 88 GateRef operand; 89 LLVMValueRef phi; 90 }; 91 92 struct BasicBlockImpl { 93 LLVMBasicBlockRef lBB_ = nullptr; 94 LLVMBasicBlockRef continuation = nullptr; 95 bool started = false; 96 bool ended = false; 97 std::vector<NotMergedPhiDesc> unmergedPhis_; 98 }; 99 100 class LLVMModule : public IRModule { 101 public: 102 LLVMModule(NativeAreaAllocator* allocator, const std::string &name, bool logDbg, const std::string &triple); 103 ~LLVMModule(); 104 void SetUpForCommonStubs(); 105 void SetUpForBytecodeHandlerStubs(); 106 void SetUpForBuiltinsStubs(); 107 void SetUpForBaselineStubs(); 108 109 LLVMValueRef AddFunc(const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile); GetModule()110 LLVMModuleRef GetModule() const 111 { 112 return module_; 113 } 114 LLVMTypeRef GetFuncType(const CallSignature *stubDescriptor); 115 116 LLVMTypeRef GenerateFuncType(const std::vector<LLVMValueRef> ¶ms, const CallSignature *stubDescriptor); 117 SetFunction(size_t index,LLVMValueRef func,bool isFastCall)118 void SetFunction(size_t index, LLVMValueRef func, bool isFastCall) 119 { 120 funcIndexMap_.emplace_back(std::make_tuple(index, func, isFastCall)); 121 } 122 GetModuleKind()123 ModuleKind GetModuleKind() const override 124 { 125 return MODULE_LLVM; 126 } 127 GetFunction(size_t index)128 LLVMValueRef GetFunction(size_t index) 129 { 130 // next optimization can be performed 131 for (auto &it: funcIndexMap_) { 132 if (std::get<0>(it) == index) { 133 return std::get<1>(it); 134 } 135 } 136 return nullptr; 137 } 138 GetFuncCount()139 size_t GetFuncCount() const 140 { 141 return funcIndexMap_.size(); 142 } 143 144 template<class Callback> IteratefuncIndexMap(const Callback & cb)145 void IteratefuncIndexMap(const Callback &cb) const 146 { 147 for (auto record : funcIndexMap_) { 148 // 2: 3nd param 149 cb(std::get<0>(record), std::get<1>(record), std::get<2>(record)); 150 } 151 } 152 GetCSign(size_t index)153 const CallSignature *GetCSign(size_t index) const 154 { 155 return callSigns_[index]; 156 } 157 GetCSigns()158 const std::vector<const CallSignature*> &GetCSigns() const 159 { 160 return callSigns_; 161 } 162 GetContext()163 LLVMContextRef GetContext() const 164 { 165 return context_; 166 } 167 GetDFileMD()168 LLVMMetadataRef GetDFileMD() const 169 { 170 return dFileMD_; 171 } 172 GetDIBuilder()173 LLVMDIBuilderRef GetDIBuilder() const 174 { 175 return dBuilder_; 176 } 177 178 LLVMValueRef GetDeoptFunction(); 179 180 static constexpr int kDeoptEntryOffset = 0; 181 GetVoidT()182 LLVMTypeRef GetVoidT() const 183 { 184 return voidT_; 185 } 186 GetInt1T()187 LLVMTypeRef GetInt1T() const 188 { 189 return int1T_; 190 } 191 GetInt8T()192 LLVMTypeRef GetInt8T() const 193 { 194 return int8T_; 195 } 196 GetInt16T()197 LLVMTypeRef GetInt16T() const 198 { 199 return int16T_; 200 } 201 GetInt32T()202 LLVMTypeRef GetInt32T() const 203 { 204 return int32T_; 205 } 206 GetInt64T()207 LLVMTypeRef GetInt64T() const 208 { 209 return int64T_; 210 } 211 GetFloatT()212 LLVMTypeRef GetFloatT() const 213 { 214 return floatT_; 215 } 216 GetDoubleT()217 LLVMTypeRef GetDoubleT() const 218 { 219 return doubleT_; 220 } 221 GetTaggedPtrT()222 LLVMTypeRef GetTaggedPtrT() const 223 { 224 return taggedPtrT_; 225 } 226 GetTaggedHPtrT()227 LLVMTypeRef GetTaggedHPtrT() const 228 { 229 return taggedHPtrT_; 230 } 231 GetRawPtrT()232 LLVMTypeRef GetRawPtrT() const 233 { 234 return rawPtrT_; 235 } 236 237 LLVMTypeRef ConvertLLVMTypeFromVariableType(VariableType type); 238 private: 239 LLVMValueRef AddAndGetFunc(const CallSignature *stubDescriptor); 240 void InitialLLVMFuncTypeAndFuncByModuleCSigns(); 241 LLVMTypeRef NewLType(MachineType machineType, GateType gateType); 242 // index: 243 // stub scenario - sequence of function adding to llvmModule 244 // aot scenario - method Id of function generated by panda files 245 std::vector<std::tuple<size_t, LLVMValueRef, bool>> funcIndexMap_; 246 std::vector<const CallSignature *> callSigns_; 247 LLVMModuleRef module_ {nullptr}; 248 LLVMContextRef context_ {nullptr}; 249 LLVMMetadataRef dFileMD_ {nullptr}; 250 LLVMMetadataRef dUnitMD_ {nullptr}; 251 LLVMDIBuilderRef dBuilder_ {nullptr}; 252 253 LLVMTypeRef voidT_ {nullptr}; 254 LLVMTypeRef int1T_ {nullptr}; 255 LLVMTypeRef int8T_ {nullptr}; 256 LLVMTypeRef int16T_ {nullptr}; 257 LLVMTypeRef int32T_ {nullptr}; 258 LLVMTypeRef int64T_ {nullptr}; 259 LLVMTypeRef floatT_ {nullptr}; 260 LLVMTypeRef doubleT_ {nullptr}; 261 LLVMTypeRef taggedHPtrT_ {nullptr}; 262 LLVMTypeRef taggedPtrT_ {nullptr}; 263 LLVMTypeRef rawPtrT_ {nullptr}; 264 }; 265 266 // runtime/common stub ID, opcodeOffset for bc stub 267 using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>; 268 269 class LLVMTargetBuilder { 270 public: 271 virtual ~LLVMTargetBuilder() = default; 272 virtual LLVMValueRef GetASMBarrierCall(LLVMModule *llvmModule_) = 0; 273 }; 274 275 class LLVMIRBuilder { 276 public: 277 LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit, 278 LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg, 279 CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot, const std::string &funcName, 280 bool enableOptInlining = false, bool enableOptBranchProfiling = true); 281 ~LLVMIRBuilder(); 282 void Build(); 283 RegisterTargetBuilder(const std::string & triple,const std::function<LLVMTargetBuilder * ()> & creator)284 static void RegisterTargetBuilder(const std::string& triple, const std::function<LLVMTargetBuilder*()>& creator) 285 { 286 GlobalTargetBuilders().emplace(triple, creator); 287 }; 288 private: 289 #define DECLAREVISITOPCODE(name, signature) void Visit##name signature; OPCODES(DECLAREVISITOPCODE)290 OPCODES(DECLAREVISITOPCODE) 291 #undef DECLAREVISITOPCODE 292 #define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(GateRef gate); 293 OPCODES(DECLAREHANDLEOPCODE) 294 #undef DECLAREHANDLEOPCODE 295 296 bool IsPrologue(int bbId) const 297 { 298 return bbId == 0; 299 } 300 void LinkToLLVMCfg(int bbId, const OperandsVector &predecessors); 301 BasicBlock *EnsureBB(int id); 302 LLVMValueRef CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller); 303 LLVMValueRef GetCurrentSP(); 304 LLVMValueRef ReadRegister(LLVMModuleRef &module, LLVMBuilderRef &builder, LLVMMetadataRef meta); 305 void GenPrologue(); 306 void AssistGenPrologue(const size_t reservedSlotsSize, FrameType frameType); 307 LLVMBasicBlockRef EnsureLBB(BasicBlock *bb) const; 308 BasicBlockImpl *EnsureBBImpl(BasicBlock *bb) const; 309 void SetToCfg(BasicBlock *bb) const; 310 311 LLVMTypeRef GetMachineRepType(MachineRep rep) const; 312 int FindBasicBlock(GateRef gate) const; 313 void EndCurrentBlock() const; 314 void Finish(); 315 316 void ProcessPhiWorkList(); 317 void InitializeHandlers(); 318 std::string LLVMValueToString(LLVMValueRef val) const; 319 320 LLVMTypeRef ConvertLLVMTypeFromGate(GateRef gate) const; 321 int64_t GetBitWidthFromMachineType(MachineType machineType) const; 322 LLVMValueRef PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offsetInByte, LLVMTypeRef rep); 323 LLVMValueRef CanonicalizeToInt(LLVMValueRef value) const; 324 LLVMValueRef CanonicalizeToPtr(LLVMValueRef value) const; 325 LLVMValueRef CanonicalizeToPtr(LLVMValueRef value, LLVMTypeRef ptrType) const; 326 LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr); 327 void SetFunctionCallConv(); 328 template<typename... Ts> 329 void VisitIntrinsic(GateRef gate, unsigned llvmId, Ts... inputs); 330 IsLogEnabled()331 bool IsLogEnabled() const 332 { 333 return enableLog_; 334 } 335 LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset, 336 const std::string &realName = "") const; 337 LLVMValueRef GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature, 338 const std::string &realName = ""); 339 void CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset, 340 GateRef frameState); 341 LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature, 342 LLVMValueRef reloc) const; 343 bool IsInterpreted() const; 344 bool IsBaselineBuiltin() const; 345 bool IsOptimized() const; 346 bool IsOptimizedJSFunction() const; 347 void SetGCLeafFunction(LLVMValueRef call); 348 void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call); 349 bool IsHeapPointerType(LLVMTypeRef valueType); 350 GetVoidT()351 LLVMTypeRef GetVoidT() const 352 { 353 return llvmModule_->GetVoidT(); 354 } 355 GetInt1T()356 LLVMTypeRef GetInt1T() const 357 { 358 return llvmModule_->GetInt1T(); 359 } 360 GetInt8T()361 LLVMTypeRef GetInt8T() const 362 { 363 return llvmModule_->GetInt8T(); 364 } 365 GetInt16T()366 LLVMTypeRef GetInt16T() const 367 { 368 return llvmModule_->GetInt16T(); 369 } 370 GetInt32T()371 LLVMTypeRef GetInt32T() const 372 { 373 return llvmModule_->GetInt32T(); 374 } 375 GetInt64T()376 LLVMTypeRef GetInt64T() const 377 { 378 return llvmModule_->GetInt64T(); 379 } 380 GetFloatT()381 LLVMTypeRef GetFloatT() const 382 { 383 return llvmModule_->GetFloatT(); 384 } 385 GetDoubleT()386 LLVMTypeRef GetDoubleT() const 387 { 388 return llvmModule_->GetDoubleT(); 389 } 390 GetTaggedPtrT()391 LLVMTypeRef GetTaggedPtrT() const 392 { 393 return llvmModule_->GetTaggedPtrT(); 394 } 395 GetTaggedHPtrT()396 LLVMTypeRef GetTaggedHPtrT() const 397 { 398 return llvmModule_->GetTaggedHPtrT(); 399 } 400 GetRawPtrT()401 LLVMTypeRef GetRawPtrT() const 402 { 403 return llvmModule_->GetRawPtrT(); 404 } 405 406 private: GetDIBuilder()407 LLVMDIBuilderRef GetDIBuilder() const 408 { 409 return llvmModule_ == nullptr ? nullptr : llvmModule_->GetDIBuilder(); 410 } 411 412 unsigned GetPtrAddressSpace(LLVMValueRef v) const; 413 bool IsLInteger(LLVMValueRef v) const; 414 bool IsLPointer(LLVMValueRef v) const; 415 LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond); 416 LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond); 417 LLVMValueRef GetGlue(const std::vector<GateRef> &inList); 418 LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue); 419 LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index); 420 LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index); 421 LLVMValueRef GetBaselineStubOffset(LLVMValueRef glue, int index); 422 LLVMValueRef GetBCStubOffset(LLVMValueRef glue); 423 LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue); 424 LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue); 425 LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue); 426 CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const; 427 void ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs, 428 const std::vector<GateRef> &inList, CallExceptionKind kind); 429 void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value); 430 void SaveByteCodePcOnOptJSFuncFrame(LLVMValueRef value); 431 void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value); 432 void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder); 433 void UpdateLeaveFrame(LLVMValueRef glue); 434 LLVMTypeRef GetExperimentalDeoptTy(); 435 LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module); 436 void GenDeoptEntry(LLVMModuleRef &module); 437 LLVMMetadataRef GetFunctionTypeMD(LLVMMetadataRef dFile); 438 bool SetDebugInfo(GateRef g, LLVMValueRef r); 439 LLVMValueRef ConvertToTagged(GateRef gate); 440 LLVMValueRef ConvertBoolToTaggedBoolean(GateRef gate); 441 LLVMValueRef ConvertInt32ToTaggedInt(GateRef gate); 442 LLVMValueRef ConvertInt32ToTaggedInt(LLVMValueRef value); 443 LLVMValueRef ConvertFloat64ToTaggedDouble(GateRef gate); 444 void SaveDeoptVregInfo(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift, 445 GateRef gate); 446 void SaveDeoptVregInfoWithI64(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift, 447 GateRef gate); 448 int LookupPredBB(GateRef start, int bbID); GetLValue(const GateRef g)449 LLVMValueRef GetLValue(const GateRef g) 450 { 451 return gate2LValue_[g]; 452 } Bind(const GateRef g,const LLVMValueRef lv)453 void Bind(const GateRef g, const LLVMValueRef lv) 454 { 455 gate2LValue_[g] = lv; 456 } 457 using TargetBuilderMap = std::unordered_map<std::string, std::function<LLVMTargetBuilder*()>>; GlobalTargetBuilders()458 static TargetBuilderMap& GlobalTargetBuilders() 459 { 460 static TargetBuilderMap targetBuilderCreators; 461 return targetBuilderCreators; 462 } 463 464 const CompilationConfig *compCfg_ {nullptr}; 465 const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr}; 466 Circuit *circuit_ {nullptr}; 467 GateAccessor acc_; 468 BasicBlock *currentBb_ {nullptr}; 469 int lineNumber_ {0}; 470 471 LLVMModuleRef module_ {nullptr}; 472 LLVMContextRef context_ {nullptr}; 473 LLVMValueRef function_ {nullptr}; 474 LLVMBuilderRef builder_ {nullptr}; 475 std::map<GateId, int> instID2bbID_; 476 BasicBlockMap bbID2BB_; 477 478 std::vector<BasicBlock *> phiRebuildWorklist_; 479 LLVMModule *llvmModule_ {nullptr}; 480 std::unordered_map<GateRef, LLVMValueRef> gate2LValue_; 481 std::unordered_map<OpCode, HandleType> opHandlers_; 482 std::set<OpCode> illegalOpHandlers_; 483 int slotSize_ {-1}; 484 LLVMTypeRef slotType_ {nullptr}; 485 CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv; 486 bool enableLog_ {false}; 487 bool isFastCallAot_ {false}; 488 LLVMMetadataRef dFuncMD_ {nullptr}; 489 bool enableOptInlining_ {false}; 490 bool enableOptBranchProfiling_ {true}; 491 LLVMValueRef ASMBarrierCall_ {nullptr}; 492 LLVMTargetBuilder* targetBuilder_ {nullptr}; 493 static constexpr std::string_view COLD_ATTR = "cold"; 494 }; 495 } // namespace panda::ecmascript::kungfu 496 #endif // ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H 497