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