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_, bool isDirectCall) = 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 enableOptDirectCall, 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 GetOrDeclareFunction(const CallSignature *signature) const; 338 LLVMValueRef GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature, 339 const std::string &realName = ""); 340 void CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset, 341 GateRef frameState); 342 LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature, 343 LLVMValueRef reloc) const; 344 bool IsInterpreted() const; 345 bool IsBaselineBuiltin() const; 346 bool IsOptimized() const; 347 bool IsOptimizedJSFunction() const; 348 void SetGCLeafFunction(LLVMValueRef call); 349 void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call); 350 bool IsHeapPointerType(LLVMTypeRef valueType); 351 GetVoidT()352 LLVMTypeRef GetVoidT() const 353 { 354 return llvmModule_->GetVoidT(); 355 } 356 GetInt1T()357 LLVMTypeRef GetInt1T() const 358 { 359 return llvmModule_->GetInt1T(); 360 } 361 GetInt8T()362 LLVMTypeRef GetInt8T() const 363 { 364 return llvmModule_->GetInt8T(); 365 } 366 GetInt16T()367 LLVMTypeRef GetInt16T() const 368 { 369 return llvmModule_->GetInt16T(); 370 } 371 GetInt32T()372 LLVMTypeRef GetInt32T() const 373 { 374 return llvmModule_->GetInt32T(); 375 } 376 GetInt64T()377 LLVMTypeRef GetInt64T() const 378 { 379 return llvmModule_->GetInt64T(); 380 } 381 GetFloatT()382 LLVMTypeRef GetFloatT() const 383 { 384 return llvmModule_->GetFloatT(); 385 } 386 GetDoubleT()387 LLVMTypeRef GetDoubleT() const 388 { 389 return llvmModule_->GetDoubleT(); 390 } 391 GetTaggedPtrT()392 LLVMTypeRef GetTaggedPtrT() const 393 { 394 return llvmModule_->GetTaggedPtrT(); 395 } 396 GetTaggedHPtrT()397 LLVMTypeRef GetTaggedHPtrT() const 398 { 399 return llvmModule_->GetTaggedHPtrT(); 400 } 401 GetRawPtrT()402 LLVMTypeRef GetRawPtrT() const 403 { 404 return llvmModule_->GetRawPtrT(); 405 } 406 407 private: GetDIBuilder()408 LLVMDIBuilderRef GetDIBuilder() const 409 { 410 return llvmModule_ == nullptr ? nullptr : llvmModule_->GetDIBuilder(); 411 } 412 413 unsigned GetPtrAddressSpace(LLVMValueRef v) const; 414 bool IsLInteger(LLVMValueRef v) const; 415 bool IsLPointer(LLVMValueRef v) const; 416 LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond); 417 LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond); 418 LLVMValueRef GetGlue(const std::vector<GateRef> &inList); 419 LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue); 420 LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index); 421 LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index); 422 LLVMValueRef GetBaselineStubOffset(LLVMValueRef glue, int index); 423 LLVMValueRef GetBCStubOffset(LLVMValueRef glue); 424 LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue); 425 LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue); 426 LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue); 427 CallExceptionKind GetCallExceptionKind(OpCode op, size_t index = SIZE_MAX) const; 428 void ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs, 429 const std::vector<GateRef> &inList, CallExceptionKind kind); 430 void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value); 431 void SaveByteCodePcOnOptJSFuncFrame(LLVMValueRef value); 432 void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value); 433 void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder); 434 void UpdateLeaveFrame(LLVMValueRef glue); 435 LLVMTypeRef GetExperimentalDeoptTy(); 436 LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module); 437 void GenDeoptEntry(LLVMModuleRef &module); 438 LLVMMetadataRef GetFunctionTypeMD(LLVMMetadataRef dFile); 439 bool SetDebugInfo(GateRef g, LLVMValueRef r); 440 LLVMValueRef ConvertToTagged(GateRef gate); 441 LLVMValueRef ConvertBoolToTaggedBoolean(GateRef gate); 442 LLVMValueRef ConvertInt32ToTaggedInt(GateRef gate); 443 LLVMValueRef ConvertInt32ToTaggedInt(LLVMValueRef value); 444 LLVMValueRef ConvertFloat64ToTaggedDouble(GateRef gate); 445 void SaveDeoptVregInfo(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift, 446 GateRef gate); 447 void SaveDeoptVregInfoWithI64(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift, 448 GateRef gate); 449 int LookupPredBB(GateRef start, int bbID); GetLValue(const GateRef g)450 LLVMValueRef GetLValue(const GateRef g) 451 { 452 return gate2LValue_[g]; 453 } Bind(const GateRef g,const LLVMValueRef lv)454 void Bind(const GateRef g, const LLVMValueRef lv) 455 { 456 gate2LValue_[g] = lv; 457 } 458 using TargetBuilderMap = std::unordered_map<std::string, std::function<LLVMTargetBuilder*()>>; GlobalTargetBuilders()459 static TargetBuilderMap& GlobalTargetBuilders() 460 { 461 static TargetBuilderMap targetBuilderCreators; 462 return targetBuilderCreators; 463 } 464 465 const CompilationConfig *compCfg_ {nullptr}; 466 const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr}; 467 Circuit *circuit_ {nullptr}; 468 GateAccessor acc_; 469 BasicBlock *currentBb_ {nullptr}; 470 int lineNumber_ {0}; 471 472 LLVMModuleRef module_ {nullptr}; 473 LLVMContextRef context_ {nullptr}; 474 LLVMValueRef function_ {nullptr}; 475 LLVMBuilderRef builder_ {nullptr}; 476 std::map<GateId, int> instID2bbID_; 477 BasicBlockMap bbID2BB_; 478 479 std::vector<BasicBlock *> phiRebuildWorklist_; 480 LLVMModule *llvmModule_ {nullptr}; 481 std::unordered_map<GateRef, LLVMValueRef> gate2LValue_; 482 std::unordered_map<OpCode, HandleType> opHandlers_; 483 std::set<OpCode> illegalOpHandlers_; 484 int slotSize_ {-1}; 485 LLVMTypeRef slotType_ {nullptr}; 486 CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv; 487 bool enableLog_ {false}; 488 bool isFastCallAot_ {false}; 489 LLVMMetadataRef dFuncMD_ {nullptr}; 490 bool enableOptDirectCall_ {false}; 491 bool enableOptInlining_ {false}; 492 bool enableOptBranchProfiling_ {true}; 493 LLVMValueRef ASMBarrierCall_ {nullptr}; 494 LLVMTargetBuilder* targetBuilder_ {nullptr}; 495 static constexpr std::string_view COLD_ATTR = "cold"; 496 }; 497 } // namespace panda::ecmascript::kungfu 498 #endif // ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H 499