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