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