| 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 | } |
| 218 | return ElementTy ? ElementTy : Global->getValueType(); |
| 219 | } |
| 220 | |
| 221 | // Map a machine operand that represents a use of a function via function |
| 222 | // pointer to a machine operand that represents the function definition. |
| 223 | // Return either the register or invalid value, because we have no context for |
| 224 | // a good diagnostic message in case of unexpectedly missing references. |
| 225 | const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) { |
| 226 | auto ResF = InstrToFunction.find(Val: Use); |
| 227 | if (ResF == InstrToFunction.end()) |
| 228 | return nullptr; |
| 229 | auto ResReg = FunctionToInstr.find(Val: ResF->second); |
| 230 | return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second; |
| 231 | } |
| 232 | |
| 233 | // Map a Function to a machine instruction that represents the function |
| 234 | // definition. |
| 235 | const MachineInstr *getFunctionDefinition(const Function *F) { |
| 236 | if (!F) |
| 237 | return nullptr; |
| 238 | auto MOIt = FunctionToInstr.find(Val: F); |
| 239 | return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent(); |
| 240 | } |
| 241 | |
| 242 | // Map a Function to a machine instruction that represents the function |
| 243 | // definition. |
| 244 | const Function *getFunctionByDefinition(const MachineInstr *MI) { |
| 245 | if (!MI) |
| 246 | return nullptr; |
| 247 | auto FIt = FunctionToInstrRev.find(Val: MI); |
| 248 | return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second; |
| 249 | } |
| 250 | |
| 251 | // map function pointer (as a machine instruction operand) to the used |
| 252 | // Function |
| 253 | void recordFunctionPointer(const MachineOperand *MO, const Function *F) { |
| 254 | InstrToFunction[MO] = F; |
| 255 | } |
| 256 | |
| 257 | // map a Function to its definition (as a machine instruction) |
| 258 | void recordFunctionDefinition(const Function *F, const MachineOperand *MO) { |
| 259 | FunctionToInstr[F] = MO; |
| 260 | FunctionToInstrRev[MO->getParent()] = F; |
| 261 | } |
| 262 | |
| 263 | // Return true if any OpConstantFunctionPointerINTEL were generated |
| 264 | bool hasConstFunPtr() { return !InstrToFunction.empty(); } |
| 265 | |
| 266 | // Add a record about forward function call. |
| 267 | void addForwardCall(const Function *F, MachineInstr *MI) { |
| 268 | ForwardCalls[F].insert(Ptr: MI); |
| 269 | } |
| 270 | |
| 271 | // Map a Function to the vector of machine instructions that represents |
| 272 | // forward function calls or to nullptr if not found. |
| 273 | SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) { |
| 274 | auto It = ForwardCalls.find(Val: F); |
| 275 | return It == ForwardCalls.end() ? nullptr : &It->second; |
| 276 | } |
| 277 | |
| 278 | // Get or create a SPIR-V type corresponding the given LLVM IR type, |
| 279 | // and map it to the given VReg by creating an ASSIGN_TYPE instruction. |
| 280 | SPIRVType *assignTypeToVReg(const Type *Type, Register VReg, |
| 281 | MachineIRBuilder &MIRBuilder, |
| 282 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 283 | bool EmitIR); |
| 284 | SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, |
| 285 | MachineInstr &I, const SPIRVInstrInfo &TII); |
| 286 | SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg, |
| 287 | MachineInstr &I, const SPIRVInstrInfo &TII); |
| 288 | SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, |
| 289 | Register VReg, MachineInstr &I, |
| 290 | const SPIRVInstrInfo &TII); |
| 291 | |
| 292 | // In cases where the SPIR-V type is already known, this function can be |
| 293 | // used to map it to the given VReg via an ASSIGN_TYPE instruction. |
| 294 | void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, |
| 295 | const MachineFunction &MF); |
| 296 | |
| 297 | // Either generate a new OpTypeXXX instruction or return an existing one |
| 298 | // corresponding to the given LLVM IR type. |
| 299 | // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) |
| 300 | // because this method may be called from InstructionSelector and we don't |
| 301 | // want to emit extra IR instructions there. |
| 302 | SPIRVType *getOrCreateSPIRVType(const Type *Type, MachineInstr &I, |
| 303 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 304 | bool EmitIR) { |
| 305 | MachineIRBuilder MIRBuilder(I); |
| 306 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, EmitIR); |
| 307 | } |
| 308 | |
| 309 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
| 310 | MachineIRBuilder &MIRBuilder, |
| 311 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 312 | bool EmitIR) { |
| 313 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, ExplicitLayoutRequired: false, EmitIR); |
| 314 | } |
| 315 | |
| 316 | const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { |
| 317 | auto Res = SPIRVToLLVMType.find(Val: Ty); |
| 318 | assert(Res != SPIRVToLLVMType.end()); |
| 319 | return Res->second; |
| 320 | } |
| 321 | |
| 322 | // Return a pointee's type, or nullptr otherwise. |
| 323 | SPIRVType *getPointeeType(SPIRVType *PtrType); |
| 324 | // Return a pointee's type op code, or 0 otherwise. |
| 325 | unsigned getPointeeTypeOp(Register PtrReg); |
| 326 | |
| 327 | // Either generate a new OpTypeXXX instruction or return an existing one |
| 328 | // corresponding to the given string containing the name of the builtin type. |
| 329 | // Return nullptr if unable to recognize SPIRV type name from `TypeStr`. |
| 330 | SPIRVType *getOrCreateSPIRVTypeByName( |
| 331 | StringRef TypeStr, MachineIRBuilder &MIRBuilder, bool EmitIR, |
| 332 | SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function, |
| 333 | SPIRV::AccessQualifier::AccessQualifier AQ = |
| 334 | SPIRV::AccessQualifier::ReadWrite); |
| 335 | |
| 336 | // Return the SPIR-V type instruction corresponding to the given VReg, or |
| 337 | // nullptr if no such type instruction exists. The second argument MF |
| 338 | // allows to search for the association in a context of the machine functions |
| 339 | // than the current one, without switching between different "current" machine |
| 340 | // functions. |
| 341 | SPIRVType *getSPIRVTypeForVReg(Register VReg, |
| 342 | const MachineFunction *MF = nullptr) const; |
| 343 | |
| 344 | // Return the result type of the instruction defining the register. |
| 345 | SPIRVType *getResultType(Register VReg, MachineFunction *MF = nullptr); |
| 346 | |
| 347 | // Whether the given VReg has a SPIR-V type mapped to it yet. |
| 348 | bool hasSPIRVTypeForVReg(Register VReg) const { |
| 349 | return getSPIRVTypeForVReg(VReg) != nullptr; |
| 350 | } |
| 351 | |
| 352 | // Return the VReg holding the result of the given OpTypeXXX instruction. |
| 353 | Register getSPIRVTypeID(const SPIRVType *SpirvType) const; |
| 354 | |
| 355 | // Return previous value of the current machine function |
| 356 | MachineFunction *setCurrentFunc(MachineFunction &MF) { |
| 357 | MachineFunction *Ret = CurMF; |
| 358 | CurMF = &MF; |
| 359 | return Ret; |
| 360 | } |
| 361 | |
| 362 | // Return true if the type is an aggregate type. |
| 363 | bool isAggregateType(SPIRVType *Type) const { |
| 364 | return Type && (Type->getOpcode() == SPIRV::OpTypeStruct && |
| 365 | Type->getOpcode() == SPIRV::OpTypeArray); |
| 366 | } |
| 367 | |
| 368 | // Whether the given VReg has an OpTypeXXX instruction mapped to it with the |
| 369 | // given opcode (e.g. OpTypeFloat). |
| 370 | bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; |
| 371 | |
| 372 | // Return true if the given VReg's assigned SPIR-V type is either a scalar |
| 373 | // matching the given opcode, or a vector with an element type matching that |
| 374 | // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). |
| 375 | bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; |
| 376 | |
| 377 | // Returns true if `Type` is a resource type. This could be an image type |
| 378 | // or a struct for a buffer decorated with the block decoration. |
| 379 | bool isResourceType(SPIRVType *Type) const; |
| 380 | |
| 381 | // Return number of elements in a vector if the argument is associated with |
| 382 | // a vector type. Return 1 for a scalar type, and 0 for a missing type. |
| 383 | unsigned getScalarOrVectorComponentCount(Register VReg) const; |
| 384 | unsigned getScalarOrVectorComponentCount(SPIRVType *Type) const; |
| 385 | |
| 386 | // Return the component type in a vector if the argument is associated with |
| 387 | // a vector type. Returns the argument itself for other types, and nullptr |
| 388 | // for a missing type. |
| 389 | SPIRVType *getScalarOrVectorComponentType(Register VReg) const; |
| 390 | SPIRVType *getScalarOrVectorComponentType(SPIRVType *Type) const; |
| 391 | |
| 392 | // For vectors or scalars of booleans, integers and floats, return the scalar |
| 393 | // type's bitwidth. Otherwise calls llvm_unreachable(). |
| 394 | unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; |
| 395 | |
| 396 | // For vectors or scalars of integers and floats, return total bitwidth of the |
| 397 | // argument. Otherwise returns 0. |
| 398 | unsigned getNumScalarOrVectorTotalBitWidth(const SPIRVType *Type) const; |
| 399 | |
| 400 | // Returns either pointer to integer type, that may be a type of vector |
| 401 | // elements or an original type, or nullptr if the argument is niether |
| 402 | // an integer scalar, nor an integer vector |
| 403 | const SPIRVType *retrieveScalarOrVectorIntType(const SPIRVType *Type) const; |
| 404 | |
| 405 | // For integer vectors or scalars, return whether the integers are signed. |
| 406 | bool isScalarOrVectorSigned(const SPIRVType *Type) const; |
| 407 | |
| 408 | // Gets the storage class of the pointer type assigned to this vreg. |
| 409 | SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const; |
| 410 | SPIRV::StorageClass::StorageClass |
| 411 | getPointerStorageClass(const SPIRVType *Type) const; |
| 412 | |
| 413 | // Return the number of bits SPIR-V pointers and size_t variables require. |
| 414 | unsigned getPointerSize() const { return PointerSize; } |
| 415 | |
| 416 | // Returns true if two types are defined and are compatible in a sense of |
| 417 | // OpBitcast instruction |
| 418 | bool isBitcastCompatible(const SPIRVType *Type1, |
| 419 | const SPIRVType *Type2) const; |
| 420 | |
| 421 | // Informs about removal of the machine instruction and invalidates data |
| 422 | // structures referring this instruction. |
| 423 | void invalidateMachineInstr(MachineInstr *MI); |
| 424 | |
| 425 | private: |
| 426 | SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); |
| 427 | |
| 428 | const Type *adjustIntTypeByWidth(const Type *Ty) const; |
| 429 | unsigned adjustOpTypeIntWidth(unsigned Width) const; |
| 430 | |
| 431 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
| 432 | MachineIRBuilder &MIRBuilder, |
| 433 | SPIRV::AccessQualifier::AccessQualifier AQ, |
| 434 | bool ExplicitLayoutRequired, bool EmitIR); |
| 435 | |
| 436 | SPIRVType *getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder, |
| 437 | bool IsSigned = false); |
| 438 | |
| 439 | SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); |
| 440 | |
| 441 | SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); |
| 442 | |
| 443 | SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, |
| 444 | MachineIRBuilder &MIRBuilder); |
| 445 | |
| 446 | SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, |
| 447 | MachineIRBuilder &MIRBuilder, |
| 448 | bool ExplicitLayoutRequired, bool EmitIR); |
| 449 | |
| 450 | SPIRVType *getOpTypeOpaque(const StructType *Ty, |
| 451 | MachineIRBuilder &MIRBuilder); |
| 452 | |
| 453 | SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, |
| 454 | SPIRV::AccessQualifier::AccessQualifier AccQual, |
| 455 | StructOffsetDecorator Decorator, bool EmitIR); |
| 456 | |
| 457 | SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC, |
| 458 | SPIRVType *ElemType, MachineIRBuilder &MIRBuilder, |
| 459 | Register Reg); |
| 460 | |
| 461 | SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC, |
| 462 | MachineIRBuilder &MIRBuilder); |
| 463 | |
| 464 | SPIRVType *getOpTypeFunction(SPIRVType *RetType, |
| 465 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
| 466 | MachineIRBuilder &MIRBuilder); |
| 467 | |
| 468 | SPIRVType * |
| 469 | getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder, |
| 470 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 471 | |
| 472 | SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); |
| 473 | Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I, |
| 474 | SPIRVType *SpvType, |
| 475 | const SPIRVInstrInfo &TII, unsigned BitWidth, |
| 476 | bool ZeroAsNull); |
| 477 | Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I, |
| 478 | SPIRVType *SpvType, |
| 479 | const SPIRVInstrInfo &TII, Constant *CA, |
| 480 | unsigned BitWidth, unsigned ElemCnt, |
| 481 | bool ZeroAsNull = true); |
| 482 | |
| 483 | Register getOrCreateIntCompositeOrNull(uint64_t Val, |
| 484 | MachineIRBuilder &MIRBuilder, |
| 485 | SPIRVType *SpvType, bool EmitIR, |
| 486 | Constant *CA, unsigned BitWidth, |
| 487 | unsigned ElemCnt); |
| 488 | |
| 489 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 490 | // storage class. It is the responsibility of the caller to make sure the |
| 491 | // decorations on the base type are valid for the given storage class. For |
| 492 | // example, it has the correct offset and stride decorations. |
| 493 | SPIRVType * |
| 494 | getOrCreateSPIRVPointerTypeInternal(SPIRVType *BaseType, |
| 495 | MachineIRBuilder &MIRBuilder, |
| 496 | SPIRV::StorageClass::StorageClass SC); |
| 497 | |
| 498 | void addStructOffsetDecorations(Register Reg, StructType *Ty, |
| 499 | MachineIRBuilder &MIRBuilder); |
| 500 | void addArrayStrideDecorations(Register Reg, Type *ElementType, |
| 501 | MachineIRBuilder &MIRBuilder); |
| 502 | bool hasBlockDecoration(SPIRVType *Type) const; |
| 503 | |
| 504 | SPIRVType * |
| 505 | getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, |
| 506 | SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, |
| 507 | uint32_t Multisampled, uint32_t Sampled, |
| 508 | SPIRV::ImageFormat::ImageFormat ImageFormat, |
| 509 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 510 | |
| 511 | public: |
| 512 | Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, |
| 513 | SPIRVType *SpvType, bool EmitIR, |
| 514 | bool ZeroAsNull = true); |
| 515 | Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, |
| 516 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 517 | bool ZeroAsNull = true); |
| 518 | Register createConstInt(const ConstantInt *CI, MachineInstr &I, |
| 519 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 520 | bool ZeroAsNull); |
| 521 | Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType, |
| 522 | const SPIRVInstrInfo &TII, |
| 523 | bool ZeroAsNull = true); |
| 524 | Register createConstFP(const ConstantFP *CF, MachineInstr &I, |
| 525 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 526 | bool ZeroAsNull); |
| 527 | Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, |
| 528 | SPIRVType *SpvType = nullptr); |
| 529 | |
| 530 | Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, |
| 531 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 532 | bool ZeroAsNull = true); |
| 533 | Register getOrCreateConstVector(APFloat Val, MachineInstr &I, |
| 534 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
| 535 | bool ZeroAsNull = true); |
| 536 | Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, |
| 537 | SPIRVType *SpvType, |
| 538 | const SPIRVInstrInfo &TII); |
| 539 | Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, |
| 540 | SPIRVType *SpvType, bool EmitIR); |
| 541 | Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, |
| 542 | SPIRVType *SpvType); |
| 543 | Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, |
| 544 | unsigned FilerMode, |
| 545 | MachineIRBuilder &MIRBuilder); |
| 546 | Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, |
| 547 | const SPIRVInstrInfo &TII); |
| 548 | Register buildGlobalVariable(Register Reg, SPIRVType *BaseType, |
| 549 | StringRef Name, const GlobalValue *GV, |
| 550 | SPIRV::StorageClass::StorageClass Storage, |
| 551 | const MachineInstr *Init, bool IsConst, |
| 552 | bool HasLinkageTy, |
| 553 | SPIRV::LinkageType::LinkageType LinkageType, |
| 554 | MachineIRBuilder &MIRBuilder, |
| 555 | bool IsInstSelector); |
| 556 | Register getOrCreateGlobalVariableWithBinding(const SPIRVType *VarType, |
| 557 | uint32_t Set, uint32_t Binding, |
| 558 | StringRef Name, |
| 559 | MachineIRBuilder &MIRBuilder); |
| 560 | |
| 561 | // Convenient helpers for getting types with check for duplicates. |
| 562 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, |
| 563 | MachineIRBuilder &MIRBuilder); |
| 564 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, |
| 565 | const SPIRVInstrInfo &TII); |
| 566 | SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I, |
| 567 | const SPIRVInstrInfo &TII, |
| 568 | unsigned SPIRVOPcode, Type *LLVMTy); |
| 569 | SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, |
| 570 | const SPIRVInstrInfo &TII); |
| 571 | SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder, |
| 572 | bool EmitIR); |
| 573 | SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, |
| 574 | const SPIRVInstrInfo &TII); |
| 575 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
| 576 | unsigned NumElements, |
| 577 | MachineIRBuilder &MIRBuilder, |
| 578 | bool EmitIR); |
| 579 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
| 580 | unsigned NumElements, MachineInstr &I, |
| 581 | const SPIRVInstrInfo &TII); |
| 582 | |
| 583 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 584 | // storage class. The base type will be translated to a SPIR-V type, and the |
| 585 | // appropriate layout decorations will be added to the base type. |
| 586 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, |
| 587 | MachineIRBuilder &MIRBuilder, |
| 588 | SPIRV::StorageClass::StorageClass SC); |
| 589 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, MachineInstr &I, |
| 590 | SPIRV::StorageClass::StorageClass SC); |
| 591 | |
| 592 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
| 593 | // storage class. It is the responsibility of the caller to make sure the |
| 594 | // decorations on the base type are valid for the given storage class. For |
| 595 | // example, it has the correct offset and stride decorations. |
| 596 | SPIRVType *getOrCreateSPIRVPointerType(SPIRVType *BaseType, |
| 597 | MachineIRBuilder &MIRBuilder, |
| 598 | SPIRV::StorageClass::StorageClass SC); |
| 599 | |
| 600 | // Returns a pointer to a SPIR-V pointer type that is the same as `PtrType` |
| 601 | // except the stroage class has been changed to `SC`. It is the responsibility |
| 602 | // of the caller to be sure that the original and new storage class have the |
| 603 | // same layout requirements. |
| 604 | SPIRVType *changePointerStorageClass(SPIRVType *PtrType, |
| 605 | SPIRV::StorageClass::StorageClass SC, |
| 606 | MachineInstr &I); |
| 607 | |
| 608 | SPIRVType *getOrCreateVulkanBufferType(MachineIRBuilder &MIRBuilder, |
| 609 | Type *ElemType, |
| 610 | SPIRV::StorageClass::StorageClass SC, |
| 611 | bool IsWritable, bool EmitIr = false); |
| 612 | |
| 613 | SPIRVType *getOrCreateLayoutType(MachineIRBuilder &MIRBuilder, |
| 614 | const TargetExtType *T, bool EmitIr = false); |
| 615 | |
| 616 | SPIRVType * |
| 617 | getImageType(const TargetExtType *ExtensionType, |
| 618 | const SPIRV::AccessQualifier::AccessQualifier Qualifier, |
| 619 | MachineIRBuilder &MIRBuilder); |
| 620 | |
| 621 | SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder); |
| 622 | |
| 623 | SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType, |
| 624 | MachineIRBuilder &MIRBuilder); |
| 625 | SPIRVType *getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder, |
| 626 | const TargetExtType *ExtensionType, |
| 627 | const SPIRVType *ElemType, |
| 628 | uint32_t Scope, uint32_t Rows, |
| 629 | uint32_t Columns, uint32_t Use, |
| 630 | bool EmitIR); |
| 631 | SPIRVType * |
| 632 | getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, |
| 633 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
| 634 | SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder); |
| 635 | SPIRVType *getOrCreateOpTypeFunctionWithArgs( |
| 636 | const Type *Ty, SPIRVType *RetType, |
| 637 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
| 638 | MachineIRBuilder &MIRBuilder); |
| 639 | SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty, |
| 640 | MachineIRBuilder &MIRBuilder, |
| 641 | unsigned Opcode); |
| 642 | |
| 643 | SPIRVType *getOrCreateUnknownType(const Type *Ty, |
| 644 | MachineIRBuilder &MIRBuilder, |
| 645 | unsigned Opcode, |
| 646 | const ArrayRef<MCOperand> Operands); |
| 647 | |
| 648 | const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const; |
| 649 | LLT getRegType(SPIRVType *SpvType) const; |
| 650 | |
| 651 | MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, |
| 652 | const MDNode *AliasingListMD); |
| 653 | void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, |
| 654 | uint32_t Dec, const MDNode *GVarMD); |
| 655 | // Replace all uses of a |Old| with |New| updates the global registry type |
| 656 | // mappings. |
| 657 | void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true); |
| 658 | |
| 659 | void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg); |
| 660 | void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg); |
| 661 | void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType); |
| 662 | }; |
| 663 | } // end namespace llvm |
| 664 | #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
| 665 | |