181ad6265SDimitry Andric //===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // SPIRVGlobalRegistry is used to maintain rich type information required for 1081ad6265SDimitry Andric // SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type 1181ad6265SDimitry Andric // into an OpTypeXXX instruction, and map it to a virtual register. Also it 1281ad6265SDimitry Andric // builds and supports consistency of constants and global variables. 1381ad6265SDimitry Andric // 1481ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1581ad6265SDimitry Andric 1681ad6265SDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 1781ad6265SDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 1881ad6265SDimitry Andric 1981ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h" 20753f127fSDimitry Andric #include "SPIRVDuplicatesTracker.h" 2181ad6265SDimitry Andric #include "SPIRVInstrInfo.h" 2281ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 23*0fca6ea1SDimitry Andric #include "llvm/IR/Constant.h" 24*0fca6ea1SDimitry Andric #include "llvm/IR/TypedPointerType.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric namespace llvm { 27*0fca6ea1SDimitry Andric class SPIRVSubtarget; 2881ad6265SDimitry Andric using SPIRVType = const MachineInstr; 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric class SPIRVGlobalRegistry { 3181ad6265SDimitry Andric // Registers holding values which have types associated with them. 3281ad6265SDimitry Andric // Initialized upon VReg definition in IRTranslator. 3381ad6265SDimitry Andric // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg> 3481ad6265SDimitry Andric // where Reg = OpType... 3581ad6265SDimitry Andric // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not 36fcaf7f86SDimitry Andric // type-declaring ones). 37753f127fSDimitry Andric DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>> 38753f127fSDimitry Andric VRegToTypeMap; 39753f127fSDimitry Andric 40*0fca6ea1SDimitry Andric // Map LLVM Type* to <MF, Reg> 41753f127fSDimitry Andric SPIRVGeneralDuplicatesTracker DT; 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType; 4481ad6265SDimitry Andric 45*0fca6ea1SDimitry Andric // map a Function to its definition (as a machine instruction operand) 46*0fca6ea1SDimitry Andric DenseMap<const Function *, const MachineOperand *> FunctionToInstr; 47*0fca6ea1SDimitry Andric DenseMap<const MachineInstr *, const Function *> FunctionToInstrRev; 48*0fca6ea1SDimitry Andric // map function pointer (as a machine instruction operand) to the used 49*0fca6ea1SDimitry Andric // Function 50*0fca6ea1SDimitry Andric DenseMap<const MachineOperand *, const Function *> InstrToFunction; 51*0fca6ea1SDimitry Andric // Maps Functions to their calls (in a form of the machine instruction, 52*0fca6ea1SDimitry Andric // OpFunctionCall) that happened before the definition is available 53*0fca6ea1SDimitry Andric DenseMap<const Function *, SmallPtrSet<MachineInstr *, 8>> ForwardCalls; 54*0fca6ea1SDimitry Andric // map a Function to its original return type before the clone function was 55*0fca6ea1SDimitry Andric // created during substitution of aggregate arguments 56*0fca6ea1SDimitry Andric // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`) 57*0fca6ea1SDimitry Andric DenseMap<Value *, Type *> MutatedAggRet; 58*0fca6ea1SDimitry Andric 59bdd1243dSDimitry Andric // Look for an equivalent of the newType in the map. Return the equivalent 60bdd1243dSDimitry Andric // if it's found, otherwise insert newType to the map and return the type. 61bdd1243dSDimitry Andric const MachineInstr *checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD, 62bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder); 63bdd1243dSDimitry Andric 64fcaf7f86SDimitry Andric SmallPtrSet<const Type *, 4> TypesInProcessing; 65fcaf7f86SDimitry Andric DenseMap<const Type *, SPIRVType *> ForwardPointerTypes; 66fcaf7f86SDimitry Andric 67*0fca6ea1SDimitry Andric // if a function returns a pointer, this is to map it into TypedPointerType 68*0fca6ea1SDimitry Andric DenseMap<const Function *, TypedPointerType *> FunResPointerTypes; 69*0fca6ea1SDimitry Andric 7081ad6265SDimitry Andric // Number of bits pointers and size_t integers require. 7181ad6265SDimitry Andric const unsigned PointerSize; 7281ad6265SDimitry Andric 73*0fca6ea1SDimitry Andric // Holds the maximum ID we have in the module. 74*0fca6ea1SDimitry Andric unsigned Bound; 75*0fca6ea1SDimitry Andric 76*0fca6ea1SDimitry Andric // Maps values associated with untyped pointers into deduced element types of 77*0fca6ea1SDimitry Andric // untyped pointers. 78*0fca6ea1SDimitry Andric DenseMap<Value *, Type *> DeducedElTys; 79*0fca6ea1SDimitry Andric // Maps composite values to deduced types where untyped pointers are replaced 80*0fca6ea1SDimitry Andric // with typed ones. 81*0fca6ea1SDimitry Andric DenseMap<Value *, Type *> DeducedNestedTys; 82*0fca6ea1SDimitry Andric // Maps values to "assign type" calls, thus being a registry of created 83*0fca6ea1SDimitry Andric // Intrinsic::spv_assign_ptr_type instructions. 84*0fca6ea1SDimitry Andric DenseMap<Value *, CallInst *> AssignPtrTypeInstr; 85*0fca6ea1SDimitry Andric 8681ad6265SDimitry Andric // Add a new OpTypeXXX instruction without checking for duplicates. 87bdd1243dSDimitry Andric SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, 88bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AQ = 89bdd1243dSDimitry Andric SPIRV::AccessQualifier::ReadWrite, 90bdd1243dSDimitry Andric bool EmitIR = true); 91bdd1243dSDimitry Andric SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder, 92bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier accessQual = 93bdd1243dSDimitry Andric SPIRV::AccessQualifier::ReadWrite, 94bdd1243dSDimitry Andric bool EmitIR = true); 9581ad6265SDimitry Andric SPIRVType * 96bdd1243dSDimitry Andric restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, 97bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AccessQual, 98fcaf7f86SDimitry Andric bool EmitIR); 9981ad6265SDimitry Andric 10081ad6265SDimitry Andric public: 10181ad6265SDimitry Andric SPIRVGlobalRegistry(unsigned PointerSize); 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric MachineFunction *CurMF; 10481ad6265SDimitry Andric 105753f127fSDimitry Andric void add(const Constant *C, MachineFunction *MF, Register R) { 106753f127fSDimitry Andric DT.add(C, MF, R); 107753f127fSDimitry Andric } 108753f127fSDimitry Andric 109753f127fSDimitry Andric void add(const GlobalVariable *GV, MachineFunction *MF, Register R) { 110753f127fSDimitry Andric DT.add(GV, MF, R); 111753f127fSDimitry Andric } 112753f127fSDimitry Andric 113753f127fSDimitry Andric void add(const Function *F, MachineFunction *MF, Register R) { 114753f127fSDimitry Andric DT.add(F, MF, R); 115753f127fSDimitry Andric } 116753f127fSDimitry Andric 117753f127fSDimitry Andric void add(const Argument *Arg, MachineFunction *MF, Register R) { 118753f127fSDimitry Andric DT.add(Arg, MF, R); 119753f127fSDimitry Andric } 120753f127fSDimitry Andric 121*0fca6ea1SDimitry Andric void add(const MachineInstr *MI, MachineFunction *MF, Register R) { 122*0fca6ea1SDimitry Andric DT.add(MI, MF, R); 123*0fca6ea1SDimitry Andric } 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric Register find(const MachineInstr *MI, MachineFunction *MF) { 126*0fca6ea1SDimitry Andric return DT.find(MI, MF); 127*0fca6ea1SDimitry Andric } 128*0fca6ea1SDimitry Andric 129753f127fSDimitry Andric Register find(const Constant *C, MachineFunction *MF) { 130753f127fSDimitry Andric return DT.find(C, MF); 131753f127fSDimitry Andric } 132753f127fSDimitry Andric 133753f127fSDimitry Andric Register find(const GlobalVariable *GV, MachineFunction *MF) { 134753f127fSDimitry Andric return DT.find(GV, MF); 135753f127fSDimitry Andric } 136753f127fSDimitry Andric 137753f127fSDimitry Andric Register find(const Function *F, MachineFunction *MF) { 138753f127fSDimitry Andric return DT.find(F, MF); 139753f127fSDimitry Andric } 140753f127fSDimitry Andric 141753f127fSDimitry Andric void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph, 142753f127fSDimitry Andric MachineModuleInfo *MMI = nullptr) { 143753f127fSDimitry Andric DT.buildDepsGraph(Graph, MMI); 144753f127fSDimitry Andric } 145753f127fSDimitry Andric 146*0fca6ea1SDimitry Andric void setBound(unsigned V) { Bound = V; } 147*0fca6ea1SDimitry Andric unsigned getBound() { return Bound; } 148*0fca6ea1SDimitry Andric 149*0fca6ea1SDimitry Andric // Add a record to the map of function return pointer types. 150*0fca6ea1SDimitry Andric void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy) { 151*0fca6ea1SDimitry Andric FunResPointerTypes[ArgF] = DerivedTy; 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric // Find a record in the map of function return pointer types. 154*0fca6ea1SDimitry Andric const TypedPointerType *findReturnType(const Function *ArgF) { 155*0fca6ea1SDimitry Andric auto It = FunResPointerTypes.find(ArgF); 156*0fca6ea1SDimitry Andric return It == FunResPointerTypes.end() ? nullptr : It->second; 157*0fca6ea1SDimitry Andric } 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric // A registry of "assign type" records: 160*0fca6ea1SDimitry Andric // - Add a record. 161*0fca6ea1SDimitry Andric void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) { 162*0fca6ea1SDimitry Andric AssignPtrTypeInstr[Val] = AssignPtrTyCI; 163*0fca6ea1SDimitry Andric } 164*0fca6ea1SDimitry Andric // - Find a record. 165*0fca6ea1SDimitry Andric CallInst *findAssignPtrTypeInstr(const Value *Val) { 166*0fca6ea1SDimitry Andric auto It = AssignPtrTypeInstr.find(Val); 167*0fca6ea1SDimitry Andric return It == AssignPtrTypeInstr.end() ? nullptr : It->second; 168*0fca6ea1SDimitry Andric } 169*0fca6ea1SDimitry Andric 170*0fca6ea1SDimitry Andric // A registry of mutated values 171*0fca6ea1SDimitry Andric // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`): 172*0fca6ea1SDimitry Andric // - Add a record. 173*0fca6ea1SDimitry Andric void addMutated(Value *Val, Type *Ty) { MutatedAggRet[Val] = Ty; } 174*0fca6ea1SDimitry Andric // - Find a record. 175*0fca6ea1SDimitry Andric Type *findMutated(const Value *Val) { 176*0fca6ea1SDimitry Andric auto It = MutatedAggRet.find(Val); 177*0fca6ea1SDimitry Andric return It == MutatedAggRet.end() ? nullptr : It->second; 178*0fca6ea1SDimitry Andric } 179*0fca6ea1SDimitry Andric 180*0fca6ea1SDimitry Andric // Deduced element types of untyped pointers and composites: 181*0fca6ea1SDimitry Andric // - Add a record to the map of deduced element types. 182*0fca6ea1SDimitry Andric void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; } 183*0fca6ea1SDimitry Andric // - Find a record in the map of deduced element types. 184*0fca6ea1SDimitry Andric Type *findDeducedElementType(const Value *Val) { 185*0fca6ea1SDimitry Andric auto It = DeducedElTys.find(Val); 186*0fca6ea1SDimitry Andric return It == DeducedElTys.end() ? nullptr : It->second; 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric // - Add a record to the map of deduced composite types. 189*0fca6ea1SDimitry Andric void addDeducedCompositeType(Value *Val, Type *Ty) { 190*0fca6ea1SDimitry Andric DeducedNestedTys[Val] = Ty; 191*0fca6ea1SDimitry Andric } 192*0fca6ea1SDimitry Andric // - Find a record in the map of deduced composite types. 193*0fca6ea1SDimitry Andric Type *findDeducedCompositeType(const Value *Val) { 194*0fca6ea1SDimitry Andric auto It = DeducedNestedTys.find(Val); 195*0fca6ea1SDimitry Andric return It == DeducedNestedTys.end() ? nullptr : It->second; 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric // - Find a type of the given Global value 198*0fca6ea1SDimitry Andric Type *getDeducedGlobalValueType(const GlobalValue *Global) { 199*0fca6ea1SDimitry Andric // we may know element type if it was deduced earlier 200*0fca6ea1SDimitry Andric Type *ElementTy = findDeducedElementType(Global); 201*0fca6ea1SDimitry Andric if (!ElementTy) { 202*0fca6ea1SDimitry Andric // or we may know element type if it's associated with a composite 203*0fca6ea1SDimitry Andric // value 204*0fca6ea1SDimitry Andric if (Value *GlobalElem = 205*0fca6ea1SDimitry Andric Global->getNumOperands() > 0 ? Global->getOperand(0) : nullptr) 206*0fca6ea1SDimitry Andric ElementTy = findDeducedCompositeType(GlobalElem); 207*0fca6ea1SDimitry Andric } 208*0fca6ea1SDimitry Andric return ElementTy ? ElementTy : Global->getValueType(); 209*0fca6ea1SDimitry Andric } 210*0fca6ea1SDimitry Andric 211*0fca6ea1SDimitry Andric // Map a machine operand that represents a use of a function via function 212*0fca6ea1SDimitry Andric // pointer to a machine operand that represents the function definition. 213*0fca6ea1SDimitry Andric // Return either the register or invalid value, because we have no context for 214*0fca6ea1SDimitry Andric // a good diagnostic message in case of unexpectedly missing references. 215*0fca6ea1SDimitry Andric const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) { 216*0fca6ea1SDimitry Andric auto ResF = InstrToFunction.find(Use); 217*0fca6ea1SDimitry Andric if (ResF == InstrToFunction.end()) 218*0fca6ea1SDimitry Andric return nullptr; 219*0fca6ea1SDimitry Andric auto ResReg = FunctionToInstr.find(ResF->second); 220*0fca6ea1SDimitry Andric return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second; 221*0fca6ea1SDimitry Andric } 222*0fca6ea1SDimitry Andric 223*0fca6ea1SDimitry Andric // Map a Function to a machine instruction that represents the function 224*0fca6ea1SDimitry Andric // definition. 225*0fca6ea1SDimitry Andric const MachineInstr *getFunctionDefinition(const Function *F) { 226*0fca6ea1SDimitry Andric if (!F) 227*0fca6ea1SDimitry Andric return nullptr; 228*0fca6ea1SDimitry Andric auto MOIt = FunctionToInstr.find(F); 229*0fca6ea1SDimitry Andric return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent(); 230*0fca6ea1SDimitry Andric } 231*0fca6ea1SDimitry Andric 232*0fca6ea1SDimitry Andric // Map a Function to a machine instruction that represents the function 233*0fca6ea1SDimitry Andric // definition. 234*0fca6ea1SDimitry Andric const Function *getFunctionByDefinition(const MachineInstr *MI) { 235*0fca6ea1SDimitry Andric if (!MI) 236*0fca6ea1SDimitry Andric return nullptr; 237*0fca6ea1SDimitry Andric auto FIt = FunctionToInstrRev.find(MI); 238*0fca6ea1SDimitry Andric return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second; 239*0fca6ea1SDimitry Andric } 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric // map function pointer (as a machine instruction operand) to the used 242*0fca6ea1SDimitry Andric // Function 243*0fca6ea1SDimitry Andric void recordFunctionPointer(const MachineOperand *MO, const Function *F) { 244*0fca6ea1SDimitry Andric InstrToFunction[MO] = F; 245*0fca6ea1SDimitry Andric } 246*0fca6ea1SDimitry Andric 247*0fca6ea1SDimitry Andric // map a Function to its definition (as a machine instruction) 248*0fca6ea1SDimitry Andric void recordFunctionDefinition(const Function *F, const MachineOperand *MO) { 249*0fca6ea1SDimitry Andric FunctionToInstr[F] = MO; 250*0fca6ea1SDimitry Andric FunctionToInstrRev[MO->getParent()] = F; 251*0fca6ea1SDimitry Andric } 252*0fca6ea1SDimitry Andric 253*0fca6ea1SDimitry Andric // Return true if any OpConstantFunctionPointerINTEL were generated 254*0fca6ea1SDimitry Andric bool hasConstFunPtr() { return !InstrToFunction.empty(); } 255*0fca6ea1SDimitry Andric 256*0fca6ea1SDimitry Andric // Add a record about forward function call. 257*0fca6ea1SDimitry Andric void addForwardCall(const Function *F, MachineInstr *MI) { 258*0fca6ea1SDimitry Andric auto It = ForwardCalls.find(F); 259*0fca6ea1SDimitry Andric if (It == ForwardCalls.end()) 260*0fca6ea1SDimitry Andric ForwardCalls[F] = {MI}; 261*0fca6ea1SDimitry Andric else 262*0fca6ea1SDimitry Andric It->second.insert(MI); 263*0fca6ea1SDimitry Andric } 264*0fca6ea1SDimitry Andric 265*0fca6ea1SDimitry Andric // Map a Function to the vector of machine instructions that represents 266*0fca6ea1SDimitry Andric // forward function calls or to nullptr if not found. 267*0fca6ea1SDimitry Andric SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) { 268*0fca6ea1SDimitry Andric auto It = ForwardCalls.find(F); 269*0fca6ea1SDimitry Andric return It == ForwardCalls.end() ? nullptr : &It->second; 270*0fca6ea1SDimitry Andric } 271*0fca6ea1SDimitry Andric 27281ad6265SDimitry Andric // Get or create a SPIR-V type corresponding the given LLVM IR type, 27381ad6265SDimitry Andric // and map it to the given VReg by creating an ASSIGN_TYPE instruction. 274bdd1243dSDimitry Andric SPIRVType *assignTypeToVReg(const Type *Type, Register VReg, 275bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 276bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AQ = 277bdd1243dSDimitry Andric SPIRV::AccessQualifier::ReadWrite, 27881ad6265SDimitry Andric bool EmitIR = true); 279fcaf7f86SDimitry Andric SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, 280fcaf7f86SDimitry Andric MachineInstr &I, const SPIRVInstrInfo &TII); 281*0fca6ea1SDimitry Andric SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg, 282*0fca6ea1SDimitry Andric MachineInstr &I, const SPIRVInstrInfo &TII); 283fcaf7f86SDimitry Andric SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, 284fcaf7f86SDimitry Andric Register VReg, MachineInstr &I, 285fcaf7f86SDimitry Andric const SPIRVInstrInfo &TII); 28681ad6265SDimitry Andric 28781ad6265SDimitry Andric // In cases where the SPIR-V type is already known, this function can be 28881ad6265SDimitry Andric // used to map it to the given VReg via an ASSIGN_TYPE instruction. 28981ad6265SDimitry Andric void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, 29081ad6265SDimitry Andric MachineFunction &MF); 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric // Either generate a new OpTypeXXX instruction or return an existing one 29381ad6265SDimitry Andric // corresponding to the given LLVM IR type. 29481ad6265SDimitry Andric // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) 29581ad6265SDimitry Andric // because this method may be called from InstructionSelector and we don't 29681ad6265SDimitry Andric // want to emit extra IR instructions there. 297bdd1243dSDimitry Andric SPIRVType *getOrCreateSPIRVType(const Type *Type, 298bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 299bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AQ = 300bdd1243dSDimitry Andric SPIRV::AccessQualifier::ReadWrite, 30181ad6265SDimitry Andric bool EmitIR = true); 30281ad6265SDimitry Andric 30381ad6265SDimitry Andric const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { 30481ad6265SDimitry Andric auto Res = SPIRVToLLVMType.find(Ty); 30581ad6265SDimitry Andric assert(Res != SPIRVToLLVMType.end()); 30681ad6265SDimitry Andric return Res->second; 30781ad6265SDimitry Andric } 30881ad6265SDimitry Andric 309*0fca6ea1SDimitry Andric // Return a pointee's type, or nullptr otherwise. 310*0fca6ea1SDimitry Andric SPIRVType *getPointeeType(SPIRVType *PtrType); 311*0fca6ea1SDimitry Andric // Return a pointee's type op code, or 0 otherwise. 312*0fca6ea1SDimitry Andric unsigned getPointeeTypeOp(Register PtrReg); 313*0fca6ea1SDimitry Andric 314bdd1243dSDimitry Andric // Either generate a new OpTypeXXX instruction or return an existing one 315bdd1243dSDimitry Andric // corresponding to the given string containing the name of the builtin type. 316*0fca6ea1SDimitry Andric // Return nullptr if unable to recognize SPIRV type name from `TypeStr`. 3175f757f3fSDimitry Andric SPIRVType *getOrCreateSPIRVTypeByName( 3185f757f3fSDimitry Andric StringRef TypeStr, MachineIRBuilder &MIRBuilder, 3195f757f3fSDimitry Andric SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function, 3205f757f3fSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AQ = 3215f757f3fSDimitry Andric SPIRV::AccessQualifier::ReadWrite); 322bdd1243dSDimitry Andric 32381ad6265SDimitry Andric // Return the SPIR-V type instruction corresponding to the given VReg, or 324*0fca6ea1SDimitry Andric // nullptr if no such type instruction exists. The second argument MF 325*0fca6ea1SDimitry Andric // allows to search for the association in a context of the machine functions 326*0fca6ea1SDimitry Andric // than the current one, without switching between different "current" machine 327*0fca6ea1SDimitry Andric // functions. 328*0fca6ea1SDimitry Andric SPIRVType *getSPIRVTypeForVReg(Register VReg, 329*0fca6ea1SDimitry Andric const MachineFunction *MF = nullptr) const; 33081ad6265SDimitry Andric 33181ad6265SDimitry Andric // Whether the given VReg has a SPIR-V type mapped to it yet. 33281ad6265SDimitry Andric bool hasSPIRVTypeForVReg(Register VReg) const { 33381ad6265SDimitry Andric return getSPIRVTypeForVReg(VReg) != nullptr; 33481ad6265SDimitry Andric } 33581ad6265SDimitry Andric 33681ad6265SDimitry Andric // Return the VReg holding the result of the given OpTypeXXX instruction. 337fcaf7f86SDimitry Andric Register getSPIRVTypeID(const SPIRVType *SpirvType) const; 33881ad6265SDimitry Andric 339*0fca6ea1SDimitry Andric // Return previous value of the current machine function 340*0fca6ea1SDimitry Andric MachineFunction *setCurrentFunc(MachineFunction &MF) { 341*0fca6ea1SDimitry Andric MachineFunction *Ret = CurMF; 342*0fca6ea1SDimitry Andric CurMF = &MF; 343*0fca6ea1SDimitry Andric return Ret; 344*0fca6ea1SDimitry Andric } 345*0fca6ea1SDimitry Andric 346*0fca6ea1SDimitry Andric // Return true if the type is an aggregate type. 347*0fca6ea1SDimitry Andric bool isAggregateType(SPIRVType *Type) const { 348*0fca6ea1SDimitry Andric return Type && (Type->getOpcode() == SPIRV::OpTypeStruct && 349*0fca6ea1SDimitry Andric Type->getOpcode() == SPIRV::OpTypeArray); 350*0fca6ea1SDimitry Andric } 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric // Whether the given VReg has an OpTypeXXX instruction mapped to it with the 35381ad6265SDimitry Andric // given opcode (e.g. OpTypeFloat). 35481ad6265SDimitry Andric bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; 35581ad6265SDimitry Andric 35681ad6265SDimitry Andric // Return true if the given VReg's assigned SPIR-V type is either a scalar 35781ad6265SDimitry Andric // matching the given opcode, or a vector with an element type matching that 35881ad6265SDimitry Andric // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). 35981ad6265SDimitry Andric bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; 36081ad6265SDimitry Andric 361*0fca6ea1SDimitry Andric // Return number of elements in a vector if the argument is associated with 362*0fca6ea1SDimitry Andric // a vector type. Return 1 for a scalar type, and 0 for a missing type. 363*0fca6ea1SDimitry Andric unsigned getScalarOrVectorComponentCount(Register VReg) const; 364*0fca6ea1SDimitry Andric unsigned getScalarOrVectorComponentCount(SPIRVType *Type) const; 365*0fca6ea1SDimitry Andric 366*0fca6ea1SDimitry Andric // For vectors or scalars of booleans, integers and floats, return the scalar 367*0fca6ea1SDimitry Andric // type's bitwidth. Otherwise calls llvm_unreachable(). 36881ad6265SDimitry Andric unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; 36981ad6265SDimitry Andric 370*0fca6ea1SDimitry Andric // For vectors or scalars of integers and floats, return total bitwidth of the 371*0fca6ea1SDimitry Andric // argument. Otherwise returns 0. 372*0fca6ea1SDimitry Andric unsigned getNumScalarOrVectorTotalBitWidth(const SPIRVType *Type) const; 373*0fca6ea1SDimitry Andric 374*0fca6ea1SDimitry Andric // Returns either pointer to integer type, that may be a type of vector 375*0fca6ea1SDimitry Andric // elements or an original type, or nullptr if the argument is niether 376*0fca6ea1SDimitry Andric // an integer scalar, nor an integer vector 377*0fca6ea1SDimitry Andric const SPIRVType *retrieveScalarOrVectorIntType(const SPIRVType *Type) const; 378*0fca6ea1SDimitry Andric 37981ad6265SDimitry Andric // For integer vectors or scalars, return whether the integers are signed. 38081ad6265SDimitry Andric bool isScalarOrVectorSigned(const SPIRVType *Type) const; 38181ad6265SDimitry Andric 38281ad6265SDimitry Andric // Gets the storage class of the pointer type assigned to this vreg. 383bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const; 38481ad6265SDimitry Andric 38581ad6265SDimitry Andric // Return the number of bits SPIR-V pointers and size_t variables require. 38681ad6265SDimitry Andric unsigned getPointerSize() const { return PointerSize; } 38781ad6265SDimitry Andric 388*0fca6ea1SDimitry Andric // Returns true if two types are defined and are compatible in a sense of 389*0fca6ea1SDimitry Andric // OpBitcast instruction 390*0fca6ea1SDimitry Andric bool isBitcastCompatible(const SPIRVType *Type1, 391*0fca6ea1SDimitry Andric const SPIRVType *Type2) const; 392*0fca6ea1SDimitry Andric 39381ad6265SDimitry Andric private: 39481ad6265SDimitry Andric SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); 39581ad6265SDimitry Andric 396*0fca6ea1SDimitry Andric const Type *adjustIntTypeByWidth(const Type *Ty) const; 397*0fca6ea1SDimitry Andric unsigned adjustOpTypeIntWidth(unsigned Width) const; 398*0fca6ea1SDimitry Andric 399*0fca6ea1SDimitry Andric SPIRVType *getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder, 40081ad6265SDimitry Andric bool IsSigned = false); 40181ad6265SDimitry Andric 40281ad6265SDimitry Andric SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); 40381ad6265SDimitry Andric 40481ad6265SDimitry Andric SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); 40581ad6265SDimitry Andric 40681ad6265SDimitry Andric SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, 40781ad6265SDimitry Andric MachineIRBuilder &MIRBuilder); 40881ad6265SDimitry Andric 40981ad6265SDimitry Andric SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, 41081ad6265SDimitry Andric MachineIRBuilder &MIRBuilder, bool EmitIR = true); 41181ad6265SDimitry Andric 412fcaf7f86SDimitry Andric SPIRVType *getOpTypeOpaque(const StructType *Ty, 413fcaf7f86SDimitry Andric MachineIRBuilder &MIRBuilder); 414fcaf7f86SDimitry Andric 415fcaf7f86SDimitry Andric SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, 416fcaf7f86SDimitry Andric bool EmitIR = true); 417fcaf7f86SDimitry Andric 418bdd1243dSDimitry Andric SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC, 419bdd1243dSDimitry Andric SPIRVType *ElemType, MachineIRBuilder &MIRBuilder, 420bdd1243dSDimitry Andric Register Reg); 421fcaf7f86SDimitry Andric 422bdd1243dSDimitry Andric SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC, 42381ad6265SDimitry Andric MachineIRBuilder &MIRBuilder); 42481ad6265SDimitry Andric 42581ad6265SDimitry Andric SPIRVType *getOpTypeFunction(SPIRVType *RetType, 42681ad6265SDimitry Andric const SmallVectorImpl<SPIRVType *> &ArgTypes, 42781ad6265SDimitry Andric MachineIRBuilder &MIRBuilder); 428bdd1243dSDimitry Andric 429bdd1243dSDimitry Andric SPIRVType * 430bdd1243dSDimitry Andric getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder, 431bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AccQual); 432bdd1243dSDimitry Andric 433fcaf7f86SDimitry Andric std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg( 434fcaf7f86SDimitry Andric uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder, 435fcaf7f86SDimitry Andric MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr); 436*0fca6ea1SDimitry Andric std::tuple<Register, ConstantFP *, bool, unsigned> getOrCreateConstFloatReg( 437*0fca6ea1SDimitry Andric APFloat Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder, 438*0fca6ea1SDimitry Andric MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr); 439fcaf7f86SDimitry Andric SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); 440*0fca6ea1SDimitry Andric Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I, 441bdd1243dSDimitry Andric SPIRVType *SpvType, 442bdd1243dSDimitry Andric const SPIRVInstrInfo &TII, 443*0fca6ea1SDimitry Andric unsigned BitWidth); 444*0fca6ea1SDimitry Andric Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I, 445*0fca6ea1SDimitry Andric SPIRVType *SpvType, 446*0fca6ea1SDimitry Andric const SPIRVInstrInfo &TII, Constant *CA, 447*0fca6ea1SDimitry Andric unsigned BitWidth, unsigned ElemCnt, 448*0fca6ea1SDimitry Andric bool ZeroAsNull = true); 449*0fca6ea1SDimitry Andric 450bdd1243dSDimitry Andric Register getOrCreateIntCompositeOrNull(uint64_t Val, 451bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 452bdd1243dSDimitry Andric SPIRVType *SpvType, bool EmitIR, 453bdd1243dSDimitry Andric Constant *CA, unsigned BitWidth, 454bdd1243dSDimitry Andric unsigned ElemCnt); 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric public: 45781ad6265SDimitry Andric Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, 45881ad6265SDimitry Andric SPIRVType *SpvType = nullptr, bool EmitIR = true); 459fcaf7f86SDimitry Andric Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, 460*0fca6ea1SDimitry Andric SPIRVType *SpvType, const SPIRVInstrInfo &TII, 461*0fca6ea1SDimitry Andric bool ZeroAsNull = true); 462*0fca6ea1SDimitry Andric Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType, 463*0fca6ea1SDimitry Andric const SPIRVInstrInfo &TII, 464*0fca6ea1SDimitry Andric bool ZeroAsNull = true); 46581ad6265SDimitry Andric Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, 46681ad6265SDimitry Andric SPIRVType *SpvType = nullptr); 467*0fca6ea1SDimitry Andric 468*0fca6ea1SDimitry Andric Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, 469*0fca6ea1SDimitry Andric SPIRVType *SpvType, const SPIRVInstrInfo &TII, 470*0fca6ea1SDimitry Andric bool ZeroAsNull = true); 471*0fca6ea1SDimitry Andric Register getOrCreateConstVector(APFloat Val, MachineInstr &I, 472*0fca6ea1SDimitry Andric SPIRVType *SpvType, const SPIRVInstrInfo &TII, 473*0fca6ea1SDimitry Andric bool ZeroAsNull = true); 474*0fca6ea1SDimitry Andric Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, 475bdd1243dSDimitry Andric SPIRVType *SpvType, 476bdd1243dSDimitry Andric const SPIRVInstrInfo &TII); 477bdd1243dSDimitry Andric Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, 478bdd1243dSDimitry Andric SPIRVType *SpvType, bool EmitIR = true); 479bdd1243dSDimitry Andric Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, 480bdd1243dSDimitry Andric SPIRVType *SpvType); 481bdd1243dSDimitry Andric Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, 482bdd1243dSDimitry Andric unsigned FilerMode, 483bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 484bdd1243dSDimitry Andric SPIRVType *SpvType); 485fcaf7f86SDimitry Andric Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, 486fcaf7f86SDimitry Andric const SPIRVInstrInfo &TII); 487bdd1243dSDimitry Andric Register buildGlobalVariable(Register Reg, SPIRVType *BaseType, 488bdd1243dSDimitry Andric StringRef Name, const GlobalValue *GV, 489bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass Storage, 490bdd1243dSDimitry Andric const MachineInstr *Init, bool IsConst, 491bdd1243dSDimitry Andric bool HasLinkageTy, 492bdd1243dSDimitry Andric SPIRV::LinkageType::LinkageType LinkageType, 493bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 494bdd1243dSDimitry Andric bool IsInstSelector); 49581ad6265SDimitry Andric 49681ad6265SDimitry Andric // Convenient helpers for getting types with check for duplicates. 49781ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, 49881ad6265SDimitry Andric MachineIRBuilder &MIRBuilder); 49981ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, 50081ad6265SDimitry Andric const SPIRVInstrInfo &TII); 501*0fca6ea1SDimitry Andric SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I, 502*0fca6ea1SDimitry Andric const SPIRVInstrInfo &TII, 503*0fca6ea1SDimitry Andric unsigned SPIRVOPcode, Type *LLVMTy); 504*0fca6ea1SDimitry Andric SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, 505*0fca6ea1SDimitry Andric const SPIRVInstrInfo &TII); 50681ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder); 507fcaf7f86SDimitry Andric SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, 508fcaf7f86SDimitry Andric const SPIRVInstrInfo &TII); 50981ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 51081ad6265SDimitry Andric unsigned NumElements, 51181ad6265SDimitry Andric MachineIRBuilder &MIRBuilder); 51281ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 51381ad6265SDimitry Andric unsigned NumElements, MachineInstr &I, 51481ad6265SDimitry Andric const SPIRVInstrInfo &TII); 515bdd1243dSDimitry Andric SPIRVType *getOrCreateSPIRVArrayType(SPIRVType *BaseType, 516bdd1243dSDimitry Andric unsigned NumElements, MachineInstr &I, 517bdd1243dSDimitry Andric const SPIRVInstrInfo &TII); 518bdd1243dSDimitry Andric 51981ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVPointerType( 52081ad6265SDimitry Andric SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, 521bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function); 52281ad6265SDimitry Andric SPIRVType *getOrCreateSPIRVPointerType( 52381ad6265SDimitry Andric SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII, 524bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function); 525bdd1243dSDimitry Andric 526bdd1243dSDimitry Andric SPIRVType * 527bdd1243dSDimitry Andric getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, 528bdd1243dSDimitry Andric SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, 529bdd1243dSDimitry Andric uint32_t Multisampled, uint32_t Sampled, 530bdd1243dSDimitry Andric SPIRV::ImageFormat::ImageFormat ImageFormat, 531bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AccQual); 532bdd1243dSDimitry Andric 533bdd1243dSDimitry Andric SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder); 534bdd1243dSDimitry Andric 535bdd1243dSDimitry Andric SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType, 536bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder); 537*0fca6ea1SDimitry Andric SPIRVType *getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder, 538*0fca6ea1SDimitry Andric const TargetExtType *ExtensionType, 539*0fca6ea1SDimitry Andric const SPIRVType *ElemType, 540*0fca6ea1SDimitry Andric uint32_t Scope, uint32_t Rows, 541*0fca6ea1SDimitry Andric uint32_t Columns, uint32_t Use); 542bdd1243dSDimitry Andric SPIRVType * 543bdd1243dSDimitry Andric getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, 544bdd1243dSDimitry Andric SPIRV::AccessQualifier::AccessQualifier AccQual); 545bdd1243dSDimitry Andric SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder); 546fcaf7f86SDimitry Andric SPIRVType *getOrCreateOpTypeFunctionWithArgs( 547fcaf7f86SDimitry Andric const Type *Ty, SPIRVType *RetType, 548fcaf7f86SDimitry Andric const SmallVectorImpl<SPIRVType *> &ArgTypes, 549fcaf7f86SDimitry Andric MachineIRBuilder &MIRBuilder); 550bdd1243dSDimitry Andric SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty, 551bdd1243dSDimitry Andric MachineIRBuilder &MIRBuilder, 552bdd1243dSDimitry Andric unsigned Opcode); 55381ad6265SDimitry Andric }; 55481ad6265SDimitry Andric } // end namespace llvm 55581ad6265SDimitry Andric #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 556