| 1 | //===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // SPIRVGlobalRegistry is used to maintain rich type information required for |
| 10 | // SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type |
| 11 | // into an OpTypeXXX instruction, and map it to a virtual register. Also it |
| 12 | // builds and supports consistency of constants and global variables. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
| 17 | #define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
| 18 | |
| 19 | #include "MCTargetDesc/SPIRVBaseInfo.h" |
| 20 | #include "SPIRVIRMapping.h" |
| 21 | #include "SPIRVInstrInfo.h" |
| 22 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
| 23 | #include "llvm/IR/Constant.h" |
| 24 | #include "llvm/IR/TypedPointerType.h" |
| 25 | |
| 26 | namespace llvm { |
| 27 | class SPIRVSubtarget; |
| 28 | using SPIRVType = const MachineInstr; |
| 29 | using StructOffsetDecorator = std::function<void(Register)>; |
| 30 | |
| 31 | class SPIRVGlobalRegistry : public SPIRVIRMapping { |
| 32 | // Registers holding values which have types associated with them. |
| 33 | // Initialized upon VReg definition in IRTranslator. |
| 34 | // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg> |
| 35 | // where Reg = OpType... |
| 36 | // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not |
| 37 | // type-declaring ones). |
| 38 | DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>> |
| 39 | VRegToTypeMap; |
| 40 | |
| 41 | DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType; |
| 42 | |
| 43 | // map a Function to its definition (as a machine instruction operand) |
| 44 | DenseMap<const Function *, const MachineOperand *> FunctionToInstr; |
| 45 | DenseMap<const MachineInstr *, const Function *> FunctionToInstrRev; |
| 46 | // map function pointer (as a machine instruction operand) to the used |
| 47 | // Function |
| 48 | DenseMap<const MachineOperand *, const Function *> InstrToFunction; |
| 49 | // Maps Functions to their calls (in a form of the machine instruction, |
| 50 | // OpFunctionCall) that happened before the definition is available |
| 51 | DenseMap<const Function *, SmallPtrSet<MachineInstr *, 8>> ForwardCalls; |
| 52 | // map a Function to its original return type before the clone function was |
| 53 | // created during substitution of aggregate arguments |
| 54 | // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`) |
| 55 | DenseMap<Value *, Type *> MutatedAggRet; |
| 56 | // map an instruction to its value's attributes (type, name) |
| 57 | DenseMap<MachineInstr *, std::pair<Type *, std::string>> ValueAttrs; |
| 58 | |
| 59 | SmallPtrSet<const Type *, 4> TypesInProcessing; |
| 60 | DenseMap<const Type *, SPIRVType *> ForwardPointerTypes; |
| 61 | |
| 62 | // Stores for each function the last inserted SPIR-V Type. |
| 63 | // See: SPIRVGlobalRegistry::createOpType. |
| 64 | DenseMap<const MachineFunction *, MachineInstr *> LastInsertedTypeMap; |
| 65 | |
| 66 | // if a function returns a pointer, this is to map it into TypedPointerType |
| 67 | DenseMap<const Function *, TypedPointerType *> FunResPointerTypes; |
| 68 | |
| 69 | // Number of bits pointers and size_t integers require. |
| 70 | const unsigned PointerSize; |
| 71 | |
| 72 | // Holds the maximum ID we have in the module. |
| 73 | unsigned Bound; |
| 74 | |
| 75 | // Maps values associated with untyped pointers into deduced element types of |
| 76 | // untyped pointers. |
| 77 | DenseMap<Value *, Type *> DeducedElTys; |
| 78 | // Maps composite values to deduced types where untyped pointers are replaced |
| 79 | // with typed ones. |
| 80 | DenseMap<Value *, Type *> DeducedNestedTys; |
| 81 | // Maps values to "assign type" calls, thus being a registry of created |
| 82 | // Intrinsic::spv_assign_ptr_type instructions. |
| 83 | DenseMap<Value *, CallInst *> AssignPtrTypeInstr; |
| 84 | |
| 85 | // Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition. |
| 86 | DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO; |
| 87 | |
| 88 | // map of aliasing decorations to aliasing metadata |
| 89 | std::unordered_map<const MDNode *, MachineInstr *> AliasInstMDMap; |
| 90 | |
| 91 | // Add a new OpTypeXXX instruction without checking for duplicates. |
| 92 | SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, |
| 93 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 94 | bool ExplicitLayoutRequired, bool EmitIR); |
| 95 | SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder, |
| 96 | SPIRV::AccessQualifier::AccessQualifier accessQual, |
| 97 | bool ExplicitLayoutRequired, bool EmitIR); |
| 98 | SPIRVType * |
| 99 | restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, |
| 100 | SPIRV::AccessQualifier::AccessQualifier AccessQual, |
| 101 | bool ExplicitLayoutRequired, bool EmitIR); |
| 102 | |
| 103 | // Internal function creating the an OpType at the correct position in the |
| 104 | // function by tweaking the passed "MIRBuilder" insertion point and restoring |
| 105 | // it to the correct position. "Op" should be the function creating the |
| 106 | // specific OpType you need, and should return the newly created instruction. |
| 107 | SPIRVType *createOpType(MachineIRBuilder &MIRBuilder, |
| 108 | std::function<MachineInstr *(MachineIRBuilder &)> Op); |
| 109 | |
| 110 | public: |
| 111 | SPIRVGlobalRegistry(unsigned PointerSize); |
| 112 | |
| 113 | MachineFunction *CurMF; |
| 114 | |
| 115 | void setBound(unsigned V) { Bound = V; } |
| 116 | unsigned getBound() { return Bound; } |
| 117 | |
| 118 | void addGlobalObject(const Value *V, const MachineFunction *MF, Register R) { |
| 119 | Reg2GO[std::make_pair(x&: MF, y&: R)] = V; |
| 120 | } |
| 121 | const Value *getGlobalObject(const MachineFunction *MF, Register R) { |
| 122 | auto It = Reg2GO.find(Val: std::make_pair(x&: MF, y&: R)); |
| 123 | return It == Reg2GO.end() ? nullptr : It->second; |
| 124 | } |
| 125 | |
| 126 | // Add a record to the map of function return pointer types. |
| 127 | void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy) { |
| 128 | FunResPointerTypes[ArgF] = DerivedTy; |
| 129 | } |
| 130 | // Find a record in the map of function return pointer types. |
| 131 | const TypedPointerType *findReturnType(const Function *ArgF) { |
| 132 | auto It = FunResPointerTypes.find(Val: ArgF); |
| 133 | return It == FunResPointerTypes.end() ? nullptr : It->second; |
| 134 | } |
| 135 | |
| 136 | // A registry of "assign type" records: |
| 137 | // - Add a record. |
| 138 | void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) { |
| 139 | AssignPtrTypeInstr[Val] = AssignPtrTyCI; |
| 140 | } |
| 141 | // - Find a record. |
| 142 | CallInst *findAssignPtrTypeInstr(const Value *Val) { |
| 143 | auto It = AssignPtrTypeInstr.find(Val); |
| 144 | return It == AssignPtrTypeInstr.end() ? nullptr : It->second; |
| 145 | } |
| 146 | // - Find a record and update its key or add a new record, if found. |
| 147 | void updateIfExistAssignPtrTypeInstr(Value *OldVal, Value *NewVal, |
| 148 | bool DeleteOld) { |
| 149 | if (CallInst *CI = findAssignPtrTypeInstr(Val: OldVal)) { |
| 150 | if (DeleteOld) |
| 151 | AssignPtrTypeInstr.erase(Val: OldVal); |
| 152 | AssignPtrTypeInstr[NewVal] = CI; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // A registry of mutated values |
| 157 | // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`): |
| 158 | // - Add a record. |
| 159 | void addMutated(Value *Val, Type *Ty) { MutatedAggRet[Val] = Ty; } |
| 160 | // - Find a record. |
| 161 | Type *findMutated(const Value *Val) { |
| 162 | auto It = MutatedAggRet.find(Val); |
| 163 | return It == MutatedAggRet.end() ? nullptr : It->second; |
| 164 | } |
| 165 | |
| 166 | // A registry of value's attributes (type, name) |
| 167 | // - Add a record. |
| 168 | void addValueAttrs(MachineInstr *Key, std::pair<Type *, std::string> Val) { |
| 169 | ValueAttrs[Key] = Val; |
| 170 | } |
| 171 | // - Find a record. |
| 172 | bool findValueAttrs(const MachineInstr *Key, Type *&Ty, StringRef &Name) { |
| 173 | auto It = ValueAttrs.find(Val: Key); |
| 174 | if (It == ValueAttrs.end()) |
| 175 | return false; |
| 176 | Ty = It->second.first; |
| 177 | Name = It->second.second; |
| 178 | return true; |
| 179 | } |
| 180 | |
| 181 | // Deduced element types of untyped pointers and composites: |
| 182 | // - Add a record to the map of deduced element types. |
| 183 | void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; } |
| 184 | // - Find a record in the map of deduced element types. |
| 185 | Type *findDeducedElementType(const Value *Val) { |
| 186 | auto It = DeducedElTys.find(Val); |
| 187 | return It == DeducedElTys.end() ? nullptr : It->second; |
| 188 | } |
| 189 | // - Find a record and update its key or add a new record, if found. |
| 190 | void updateIfExistDeducedElementType(Value *OldVal, Value *NewVal, |
| 191 | bool DeleteOld) { |
| 192 | if (Type *Ty = findDeducedElementType(Val: OldVal)) { |
| 193 | if (DeleteOld) |
| 194 | DeducedElTys.erase(Val: OldVal); |
| 195 | DeducedElTys[NewVal] = Ty; |
| 196 | } |
| 197 | } |
| 198 | // - Add a record to the map of deduced composite types. |
| 199 | void addDeducedCompositeType(Value *Val, Type *Ty) { |
| 200 | DeducedNestedTys[Val] = Ty; |
| 201 | } |
| 202 | // - Find a record in the map of deduced composite types. |
| 203 | Type *findDeducedCompositeType(const Value *Val) { |
| 204 | auto It = DeducedNestedTys.find(Val); |
| 205 | return It == DeducedNestedTys.end() ? nullptr : It->second; |
| 206 | } |
| 207 | // - Find a type of the given Global value |
| 208 | Type *getDeducedGlobalValueType(const GlobalValue *Global) { |
| 209 | // we may know element type if it was deduced earlier |
| 210 | Type *ElementTy = findDeducedElementType(Val: Global); |
| 211 | if (!ElementTy) { |
| 212 | // or we may know element type if it's associated with a composite |
| 213 | // value |
| 214 | if (Value *GlobalElem = |
| 215 | Global->getNumOperands() > 0 ? Global->getOperand(i: 0) : nullptr) |
| 216 | ElementTy = findDeducedCompositeType(Val: GlobalElem); |
| 217 | else if (const Function *Fn = dyn_cast<Function>(Val: Global)) |
| 218 | ElementTy = SPIRV::getOriginalFunctionType(F: *Fn); |
| 219 | } |
| 220 | return ElementTy ? ElementTy : Global->getValueType(); |
| 221 | } |
| 222 | |
| 223 | // Map a machine operand that represents a use of a function via function |
| 224 | // pointer to a machine operand that represents the function definition. |
| 225 | // Return either the register or invalid value, because we have no context for |
| 226 | // a good diagnostic message in case of unexpectedly missing references. |
| 227 | const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) { |
| 228 | auto ResF = InstrToFunction.find(Val: Use); |
| 229 | if (ResF == InstrToFunction.end()) |
| 230 | return nullptr; |
| 231 | auto ResReg = FunctionToInstr.find(Val: ResF->second); |
| 232 | return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second; |
| 233 | } |
| 234 | |
| 235 | // Map a Function to a machine instruction that represents the function |
| 236 | // definition. |
| 237 | const MachineInstr *getFunctionDefinition(const Function *F) { |
| 238 | if (!F) |
| 239 | return nullptr; |
| 240 | auto MOIt = FunctionToInstr.find(Val: F); |
| 241 | return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent(); |
| 242 | } |
| 243 | |
| 244 | // Map a Function to a machine instruction that represents the function |
| 245 | // definition. |
| 246 | const Function *getFunctionByDefinition(const MachineInstr *MI) { |
| 247 | if (!MI) |
| 248 | return nullptr; |
| 249 | auto FIt = FunctionToInstrRev.find(Val: MI); |
| 250 | return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second; |
| 251 | } |
| 252 | |
| 253 | // map function pointer (as a machine instruction operand) to the used |
| 254 | // Function |
| 255 | void recordFunctionPointer(const MachineOperand *MO, const Function *F) { |
| 256 | InstrToFunction[MO] = F; |
| 257 | } |
| 258 | |
| 259 | // map a Function to its definition (as a machine instruction) |
| 260 | void recordFunctionDefinition(const Function *F, const MachineOperand *MO) { |
| 261 | FunctionToInstr[F] = MO; |
| 262 | FunctionToInstrRev[MO->getParent()] = F; |
| 263 | } |
| 264 | |
| 265 | // Return true if any OpConstantFunctionPointerINTEL were generated |
| 266 | bool hasConstFunPtr() { return !InstrToFunction.empty(); } |
| 267 | |
| 268 | // Add a record about forward function call. |
| 269 | void addForwardCall(const Function *F, MachineInstr *MI) { |
| 270 | ForwardCalls[F].insert(Ptr: MI); |
| 271 | } |
| 272 | |
| 273 | // Map a Function to the vector of machine instructions that represents |
| 274 | // forward function calls or to nullptr if not found. |
| 275 | SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) { |
| 276 | auto It = ForwardCalls.find(Val: F); |
| 277 | return It == ForwardCalls.end() ? nullptr : &It->second; |
| 278 | } |
| 279 | |
| 280 | // Get or create a SPIR-V type corresponding the given LLVM IR type, |
| 281 | // and map it to the given VReg. |
| 282 | SPIRVType *assignTypeToVReg(const Type *Type, Register VReg, |
| 283 | MachineIRBuilder &MIRBuilder, |
| 284 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 285 | bool EmitIR); |
| 286 | SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, |
| 287 | MachineInstr &I, const SPIRVInstrInfo &TII); |
| 288 | SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg, |
| 289 | MachineInstr &I, const SPIRVInstrInfo &TII); |
| 290 | SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, |
| 291 | Register VReg, MachineInstr &I, |
| 292 | const SPIRVInstrInfo &TII); |
| 293 | |
| 294 | // In cases where the SPIR-V type is already known, this function can be |
| 295 | // used to map it to the given VReg. |
| 296 | void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, |
| 297 | const MachineFunction &MF); |
| 298 | |
| 299 | // Either generate a new OpTypeXXX instruction or return an existing one |
| 300 | // corresponding to the given LLVM IR type. |
| 301 | // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) |
| 302 | // because this method may be called from InstructionSelector and we don't |
| 303 | // want to emit extra IR instructions there. |
| 304 | SPIRVType *getOrCreateSPIRVType(const Type *Type, MachineInstr &I, |
| 305 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 306 | bool EmitIR) { |
| 307 | MachineIRBuilder MIRBuilder(I); |
| 308 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, EmitIR); |
| 309 | } |
| 310 | |
| 311 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
| 312 | MachineIRBuilder &MIRBuilder, |
| 313 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 314 | bool EmitIR) { |
| 315 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, ExplicitLayoutRequired: false, EmitIR); |
| 316 | } |
| 317 | |
| 318 | const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { |
| 319 | auto Res = SPIRVToLLVMType.find(Val: Ty); |
| 320 | assert(Res != SPIRVToLLVMType.end()); |
| 321 | return Res->second; |
| 322 | } |
| 323 | |
| 324 | // Return a pointee's type, or nullptr otherwise. |
| 325 | SPIRVType *getPointeeType(SPIRVType *PtrType); |
| 326 | // Return a pointee's type op code, or 0 otherwise. |
| 327 | unsigned getPointeeTypeOp(Register PtrReg); |
| 328 | |
| 329 | // Either generate a new OpTypeXXX instruction or return an existing one |
| 330 | // corresponding to the given string containing the name of the builtin type. |
| 331 | // Return nullptr if unable to recognize SPIRV type name from `TypeStr`. |
| 332 | SPIRVType *getOrCreateSPIRVTypeByName( |
| 333 | StringRef TypeStr, MachineIRBuilder &MIRBuilder, bool EmitIR, |
| 334 | SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function, |
| 335 | SPIRV::AccessQualifier::AccessQualifier AQ = |
| 336 | SPIRV::AccessQualifier::ReadWrite); |
| 337 | |
| 338 | // Return the SPIR-V type instruction corresponding to the given VReg, or |
| 339 | // nullptr if no such type instruction exists. The second argument MF |
| 340 | // allows to search for the association in a context of the machine functions |
| 341 | // than the current one, without switching between different "current" machine |
| 342 | // functions. |
| 343 | SPIRVType *getSPIRVTypeForVReg(Register VReg, |
| 344 | const MachineFunction *MF = nullptr) const; |
| 345 | |
| 346 | // Return the result type of the instruction defining the register. |
| 347 | SPIRVType *getResultType(Register VReg, MachineFunction *MF = nullptr); |
| 348 | |
| 349 | // Whether the given VReg has a SPIR-V type mapped to it yet. |
| 350 | bool hasSPIRVTypeForVReg(Register VReg) const { |
| 351 | return getSPIRVTypeForVReg(VReg) != nullptr; |
| 352 | } |
| 353 | |
| 354 | // Return the VReg holding the result of the given OpTypeXXX instruction. |
| 355 | Register getSPIRVTypeID(const SPIRVType *SpirvType) const; |
| 356 | |
| 357 | // Return previous value of the current machine function |
| 358 | MachineFunction *setCurrentFunc(MachineFunction &MF) { |
| 359 | MachineFunction *Ret = CurMF; |
| 360 | CurMF = &MF; |
| 361 | return Ret; |
| 362 | } |
| 363 | |
| 364 | // Return true if the type is an aggregate type. |
| 365 | bool isAggregateType(SPIRVType *Type) const { |
| 366 | return Type && (Type->getOpcode() == SPIRV::OpTypeStruct && |
| 367 | Type->getOpcode() == SPIRV::OpTypeArray); |
| 368 | } |
| 369 | |
| 370 | // Whether the given VReg has an OpTypeXXX instruction mapped to it with the |
| 371 | // given opcode (e.g. OpTypeFloat). |
| 372 | bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; |
| 373 | |
| 374 | // Return true if the given VReg's assigned SPIR-V type is either a scalar |
| 375 | // matching the given opcode, or a vector with an element type matching that |
| 376 | // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). |
| 377 | bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; |
| 378 | |
| 379 | // Returns true if `Type` is a resource type. This could be an image type |
| 380 | // or a struct for a buffer decorated with the block decoration. |
| 381 | bool isResourceType(SPIRVType *Type) const; |
| 382 | |
| 383 | // Return number of elements in a vector if the argument is associated with |
| 384 | // a vector type. Return 1 for a scalar type, and 0 for a missing type. |
| 385 | unsigned getScalarOrVectorComponentCount(Register VReg) const; |
| 386 | unsigned getScalarOrVectorComponentCount(SPIRVType *Type) const; |
| 387 | |
| 388 | // Return the component type in a vector if the argument is associated with |
| 389 | // a vector type. Returns the argument itself for other types, and nullptr |
| 390 | // for a missing type. |
| 391 | SPIRVType *getScalarOrVectorComponentType(Register VReg) const; |
| 392 | SPIRVType *getScalarOrVectorComponentType(SPIRVType *Type) const; |
| 393 | |
| 394 | // For vectors or scalars of booleans, integers and floats, return the scalar |
| 395 | // type's bitwidth. Otherwise calls llvm_unreachable(). |
| 396 | unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; |
| 397 | |
| 398 | // For vectors or scalars of integers and floats, return total bitwidth of the |
| 399 | // argument. Otherwise returns 0. |
| 400 | unsigned getNumScalarOrVectorTotalBitWidth(const SPIRVType *Type) const; |
| 401 | |
| 402 | // Returns either pointer to integer type, that may be a type of vector |
| 403 | // elements or an original type, or nullptr if the argument is niether |
| 404 | // an integer scalar, nor an integer vector |
| 405 | const SPIRVType *retrieveScalarOrVectorIntType(const SPIRVType *Type) const; |
| 406 | |
| 407 | // For integer vectors or scalars, return whether the integers are signed. |
| 408 | bool isScalarOrVectorSigned(const SPIRVType *Type) const; |
| 409 | |
| 410 | // Gets the storage class of the pointer type assigned to this vreg. |
| 411 | SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const; |
| 412 | SPIRV::StorageClass::StorageClass |
| 413 | getPointerStorageClass(const SPIRVType *Type) const; |
| 414 | |
| 415 | // Return the number of bits SPIR-V pointers and size_t variables require. |
| 416 | unsigned getPointerSize() const { return PointerSize; } |
| 417 | |
| 418 | // Returns true if two types are defined and are compatible in a sense of |
| 419 | // OpBitcast instruction |
| 420 | bool isBitcastCompatible(const SPIRVType *Type1, |
| 421 | const SPIRVType *Type2) const; |
| 422 | |
| 423 | // Informs about removal of the machine instruction and invalidates data |
| 424 | // structures referring this instruction. |
| 425 | void invalidateMachineInstr(MachineInstr *MI); |
| 426 | |
| 427 | private: |
| 428 | SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); |
| 429 | |
| 430 | const Type *adjustIntTypeByWidth(const Type *Ty) const; |
| 431 | unsigned adjustOpTypeIntWidth(unsigned Width) const; |
| 432 | |
| 433 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
| 434 | MachineIRBuilder &MIRBuilder, |
| 435 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 436 | bool ExplicitLayoutRequired, bool EmitIR); |
| 437 | |
| 438 | SPIRVType *getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder, |
| 439 | bool IsSigned = false); |
| 440 | |
| 441 | SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); |
| 442 | |
| 443 | SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder, |
| 444 | SPIRV::FPEncoding::FPEncoding FPEncode); |
| 445 | |
| 446 | SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); |
| 447 | |
| 448 | SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, |
| 449 | MachineIRBuilder &MIRBuilder); |
| 450 | |
| 451 | SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, |
| 452 | MachineIRBuilder &MIRBuilder, |
| 453 | bool ExplicitLayoutRequired, bool EmitIR); |
| 454 | |
| 455 | SPIRVType *getOpTypeOpaque(const StructType *Ty, |
| 456 | MachineIRBuilder &MIRBuilder); |
| 457 | |
| 458 | SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, |
| 459 | SPIRV::AccessQualifier::AccessQualifier AccQual, |
| 460 | StructOffsetDecorator Decorator, bool EmitIR); |
| 461 | |
| 462 | SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC, |
| 463 | SPIRVType *ElemType, MachineIRBuilder &MIRBuilder, |
| 464 | Register Reg); |
| 465 | |
| 466 | SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC, |
| 467 | MachineIRBuilder &MIRBuilder); |
| 468 | |
| 469 | SPIRVType *getOpTypeFunction(const FunctionType *Ty, SPIRVType *RetType, |
| 470 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
| 471 | MachineIRBuilder &MIRBuilder); |
| 472 | |
| 473 | SPIRVType * |
| 474 | getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder, |
| 475 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 476 | |
| 477 | SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); |
| 478 | Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I, |
| 479 | SPIRVType *SpvType, |
| 480 | const SPIRVInstrInfo &TII, unsigned BitWidth, |
| 481 | bool ZeroAsNull); |
| 482 | Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I, |
| 483 | SPIRVType *SpvType, |
| 484 | const SPIRVInstrInfo &TII, Constant *CA, |
| 485 | unsigned BitWidth, unsigned ElemCnt, |
| 486 | bool ZeroAsNull = true); |
| 487 | |
| 488 | Register getOrCreateIntCompositeOrNull(uint64_t Val, |
| 489 | MachineIRBuilder &MIRBuilder, |
| 490 | SPIRVType *SpvType, bool EmitIR, |
| 491 | Constant *CA, unsigned BitWidth, |
| 492 | unsigned ElemCnt); |
| 493 | |
| 494 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 495 | // storage class. It is the responsibility of the caller to make sure the |
| 496 | // decorations on the base type are valid for the given storage class. For |
| 497 | // example, it has the correct offset and stride decorations. |
| 498 | SPIRVType * |
| 499 | getOrCreateSPIRVPointerTypeInternal(SPIRVType *BaseType, |
| 500 | MachineIRBuilder &MIRBuilder, |
| 501 | SPIRV::StorageClass::StorageClass SC); |
| 502 | |
| 503 | void addStructOffsetDecorations(Register Reg, StructType *Ty, |
| 504 | MachineIRBuilder &MIRBuilder); |
| 505 | void addArrayStrideDecorations(Register Reg, Type *ElementType, |
| 506 | MachineIRBuilder &MIRBuilder); |
| 507 | bool hasBlockDecoration(SPIRVType *Type) const; |
| 508 | |
| 509 | SPIRVType * |
| 510 | getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, |
| 511 | SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, |
| 512 | uint32_t Multisampled, uint32_t Sampled, |
| 513 | SPIRV::ImageFormat::ImageFormat ImageFormat, |
| 514 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 515 | |
| 516 | public: |
| 517 | Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, |
| 518 | SPIRVType *SpvType, bool EmitIR, |
| 519 | bool ZeroAsNull = true); |
| 520 | Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, |
| 521 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 522 | bool ZeroAsNull = true); |
| 523 | Register createConstInt(const ConstantInt *CI, MachineInstr &I, |
| 524 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 525 | bool ZeroAsNull); |
| 526 | Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType, |
| 527 | const SPIRVInstrInfo &TII, |
| 528 | bool ZeroAsNull = true); |
| 529 | Register createConstFP(const ConstantFP *CF, MachineInstr &I, |
| 530 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 531 | bool ZeroAsNull); |
| 532 | Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, |
| 533 | SPIRVType *SpvType = nullptr); |
| 534 | |
| 535 | Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, |
| 536 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 537 | bool ZeroAsNull = true); |
| 538 | Register getOrCreateConstVector(APFloat Val, MachineInstr &I, |
| 539 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 540 | bool ZeroAsNull = true); |
| 541 | Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, |
| 542 | SPIRVType *SpvType, |
| 543 | const SPIRVInstrInfo &TII); |
| 544 | Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, |
| 545 | SPIRVType *SpvType, bool EmitIR); |
| 546 | Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, |
| 547 | SPIRVType *SpvType); |
| 548 | Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, |
| 549 | unsigned FilerMode, |
| 550 | MachineIRBuilder &MIRBuilder); |
| 551 | Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, |
| 552 | const SPIRVInstrInfo &TII); |
| 553 | Register buildGlobalVariable( |
| 554 | Register Reg, SPIRVType *BaseType, StringRef Name, const GlobalValue *GV, |
| 555 | SPIRV::StorageClass::StorageClass Storage, const MachineInstr *Init, |
| 556 | bool IsConst, |
| 557 | const std::optional<SPIRV::LinkageType::LinkageType> &LinkageType, |
| 558 | MachineIRBuilder &MIRBuilder, bool IsInstSelector); |
| 559 | Register getOrCreateGlobalVariableWithBinding(const SPIRVType *VarType, |
| 560 | uint32_t Set, uint32_t Binding, |
| 561 | StringRef Name, |
| 562 | MachineIRBuilder &MIRBuilder); |
| 563 | |
| 564 | // Convenient helpers for getting types with check for duplicates. |
| 565 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, |
| 566 | MachineIRBuilder &MIRBuilder); |
| 567 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, |
| 568 | const SPIRVInstrInfo &TII); |
| 569 | SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I, |
| 570 | const SPIRVInstrInfo &TII, |
| 571 | unsigned SPIRVOPcode, Type *LLVMTy); |
| 572 | SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, |
| 573 | const SPIRVInstrInfo &TII); |
| 574 | SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder, |
| 575 | bool EmitIR); |
| 576 | SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, |
| 577 | const SPIRVInstrInfo &TII); |
| 578 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
| 579 | unsigned NumElements, |
| 580 | MachineIRBuilder &MIRBuilder, |
| 581 | bool EmitIR); |
| 582 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
| 583 | unsigned NumElements, MachineInstr &I, |
| 584 | const SPIRVInstrInfo &TII); |
| 585 | |
| 586 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 587 | // storage class. The base type will be translated to a SPIR-V type, and the |
| 588 | // appropriate layout decorations will be added to the base type. |
| 589 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, |
| 590 | MachineIRBuilder &MIRBuilder, |
| 591 | SPIRV::StorageClass::StorageClass SC); |
| 592 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, MachineInstr &I, |
| 593 | SPIRV::StorageClass::StorageClass SC); |
| 594 | |
| 595 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 596 | // storage class. It is the responsibility of the caller to make sure the |
| 597 | // decorations on the base type are valid for the given storage class. For |
| 598 | // example, it has the correct offset and stride decorations. |
| 599 | SPIRVType *getOrCreateSPIRVPointerType(SPIRVType *BaseType, |
| 600 | MachineIRBuilder &MIRBuilder, |
| 601 | SPIRV::StorageClass::StorageClass SC); |
| 602 | |
| 603 | // Returns a pointer to a SPIR-V pointer type that is the same as `PtrType` |
| 604 | // except the stroage class has been changed to `SC`. It is the responsibility |
| 605 | // of the caller to be sure that the original and new storage class have the |
| 606 | // same layout requirements. |
| 607 | SPIRVType *changePointerStorageClass(SPIRVType *PtrType, |
| 608 | SPIRV::StorageClass::StorageClass SC, |
| 609 | MachineInstr &I); |
| 610 | |
| 611 | SPIRVType *getOrCreateVulkanBufferType(MachineIRBuilder &MIRBuilder, |
| 612 | Type *ElemType, |
| 613 | SPIRV::StorageClass::StorageClass SC, |
| 614 | bool IsWritable, bool EmitIr = false); |
| 615 | |
| 616 | SPIRVType *getOrCreatePaddingType(MachineIRBuilder &MIRBuilder); |
| 617 | |
| 618 | SPIRVType *getOrCreateVulkanPushConstantType(MachineIRBuilder &MIRBuilder, |
| 619 | Type *ElemType); |
| 620 | |
| 621 | SPIRVType *getOrCreateLayoutType(MachineIRBuilder &MIRBuilder, |
| 622 | const TargetExtType *T, bool EmitIr = false); |
| 623 | |
| 624 | SPIRVType * |
| 625 | getImageType(const TargetExtType *ExtensionType, |
| 626 | const SPIRV::AccessQualifier::AccessQualifier Qualifier, |
| 627 | MachineIRBuilder &MIRBuilder); |
| 628 | |
| 629 | SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder); |
| 630 | |
| 631 | SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType, |
| 632 | MachineIRBuilder &MIRBuilder); |
| 633 | SPIRVType *getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder, |
| 634 | const TargetExtType *ExtensionType, |
| 635 | const SPIRVType *ElemType, |
| 636 | uint32_t Scope, uint32_t Rows, |
| 637 | uint32_t Columns, uint32_t Use, |
| 638 | bool EmitIR); |
| 639 | SPIRVType * |
| 640 | getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, |
| 641 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 642 | SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder); |
| 643 | SPIRVType *getOrCreateOpTypeFunctionWithArgs( |
| 644 | const Type *Ty, SPIRVType *RetType, |
| 645 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
| 646 | MachineIRBuilder &MIRBuilder); |
| 647 | SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty, |
| 648 | MachineIRBuilder &MIRBuilder, |
| 649 | unsigned Opcode); |
| 650 | |
| 651 | SPIRVType *getOrCreateUnknownType(const Type *Ty, |
| 652 | MachineIRBuilder &MIRBuilder, |
| 653 | unsigned Opcode, |
| 654 | const ArrayRef<MCOperand> Operands); |
| 655 | |
| 656 | const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const; |
| 657 | LLT getRegType(SPIRVType *SpvType) const; |
| 658 | |
| 659 | MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, |
| 660 | const MDNode *AliasingListMD); |
| 661 | void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, |
| 662 | uint32_t Dec, const MDNode *GVarMD); |
| 663 | // Replace all uses of a |Old| with |New| updates the global registry type |
| 664 | // mappings. |
| 665 | void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true); |
| 666 | |
| 667 | void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg); |
| 668 | void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg); |
| 669 | void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType); |
| 670 | }; |
| 671 | } // end namespace llvm |
| 672 | #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
| 673 | |