1//===-- SPIRVGlobalRegistry.cpp - 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// This file contains the implementation of the SPIRVGlobalRegistry class,
10// which is used to maintain rich type information required for SPIR-V even
11// after lowering from LLVM IR to GMIR. It can convert an llvm::Type into
12// an OpTypeXXX instruction, and map it to a virtual register. Also it builds
13// and supports consistency of constants and global variables.
14//
15//===----------------------------------------------------------------------===//
16
17#include "SPIRVGlobalRegistry.h"
18#include "SPIRV.h"
19#include "SPIRVBuiltins.h"
20#include "SPIRVSubtarget.h"
21#include "SPIRVUtils.h"
22#include "llvm/ADT/APInt.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/DiagnosticInfo.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/IntrinsicInst.h"
27#include "llvm/IR/Intrinsics.h"
28#include "llvm/IR/IntrinsicsSPIRV.h"
29#include "llvm/IR/Type.h"
30#include "llvm/Support/Casting.h"
31#include "llvm/Support/MathExtras.h"
32#include <cassert>
33#include <functional>
34
35using namespace llvm;
36
37static bool allowEmitFakeUse(const Value *Arg) {
38 if (isSpvIntrinsic(Arg))
39 return false;
40 if (isa<AtomicCmpXchgInst, InsertValueInst, UndefValue>(Val: Arg))
41 return false;
42 if (const auto *LI = dyn_cast<LoadInst>(Val: Arg))
43 if (LI->getType()->isAggregateType())
44 return false;
45 return true;
46}
47
48static unsigned typeToAddressSpace(const Type *Ty) {
49 if (auto PType = dyn_cast<TypedPointerType>(Val: Ty))
50 return PType->getAddressSpace();
51 if (auto PType = dyn_cast<PointerType>(Val: Ty))
52 return PType->getAddressSpace();
53 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty);
54 ExtTy && isTypedPointerWrapper(ExtTy))
55 return ExtTy->getIntParameter(i: 0);
56 reportFatalInternalError(reason: "Unable to convert LLVM type to SPIRVType");
57}
58
59static bool
60storageClassRequiresExplictLayout(SPIRV::StorageClass::StorageClass SC) {
61 switch (SC) {
62 case SPIRV::StorageClass::Uniform:
63 case SPIRV::StorageClass::PushConstant:
64 case SPIRV::StorageClass::StorageBuffer:
65 case SPIRV::StorageClass::PhysicalStorageBufferEXT:
66 return true;
67 case SPIRV::StorageClass::UniformConstant:
68 case SPIRV::StorageClass::Input:
69 case SPIRV::StorageClass::Output:
70 case SPIRV::StorageClass::Workgroup:
71 case SPIRV::StorageClass::CrossWorkgroup:
72 case SPIRV::StorageClass::Private:
73 case SPIRV::StorageClass::Function:
74 case SPIRV::StorageClass::Generic:
75 case SPIRV::StorageClass::AtomicCounter:
76 case SPIRV::StorageClass::Image:
77 case SPIRV::StorageClass::CallableDataNV:
78 case SPIRV::StorageClass::IncomingCallableDataNV:
79 case SPIRV::StorageClass::RayPayloadNV:
80 case SPIRV::StorageClass::HitAttributeNV:
81 case SPIRV::StorageClass::IncomingRayPayloadNV:
82 case SPIRV::StorageClass::ShaderRecordBufferNV:
83 case SPIRV::StorageClass::CodeSectionINTEL:
84 case SPIRV::StorageClass::DeviceOnlyINTEL:
85 case SPIRV::StorageClass::HostOnlyINTEL:
86 return false;
87 }
88 llvm_unreachable("Unknown SPIRV::StorageClass enum");
89}
90
91SPIRVGlobalRegistry::SPIRVGlobalRegistry(DataLayout DL)
92 : DL(DL), Bound(0), CurMF(nullptr) {}
93
94void SPIRVGlobalRegistry::constrainSelectedInstRegOperands(
95 MachineInstrBuilder &MIB) const {
96 const auto &ST = CurMF->getSubtarget();
97 MIB.constrainAllUses(TII: *ST.getInstrInfo(), TRI: *ST.getRegisterInfo(),
98 RBI: *ST.getRegBankInfo());
99}
100
101SPIRVTypeInst
102SPIRVGlobalRegistry::assignIntTypeToVReg(unsigned BitWidth, Register VReg,
103 MachineInstr &I,
104 const SPIRVInstrInfo &TII) {
105 SPIRVTypeInst SpirvType = getOrCreateSPIRVIntegerType(BitWidth, I, TII);
106 assignSPIRVTypeToVReg(Type: SpirvType, VReg, MF: *CurMF);
107 return SpirvType;
108}
109
110SPIRVTypeInst SPIRVGlobalRegistry::assignTypeToVReg(
111 const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder,
112 SPIRV::AccessQualifier::AccessQualifier AccessQual, bool EmitIR) {
113 SPIRVTypeInst SpirvType =
114 getOrCreateSPIRVType(Type, MIRBuilder, AQ: AccessQual, EmitIR);
115 assignSPIRVTypeToVReg(Type: SpirvType, VReg, MF: MIRBuilder.getMF());
116 return SpirvType;
117}
118
119void SPIRVGlobalRegistry::assignSPIRVTypeToVReg(SPIRVTypeInst SpirvType,
120 Register VReg,
121 const MachineFunction &MF) {
122 VRegToTypeMap[&MF][VReg] = SpirvType;
123}
124
125static Register createTypeVReg(MachineRegisterInfo &MRI) {
126 auto Res = MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
127 MRI.setRegClass(Reg: Res, RC: &SPIRV::TYPERegClass);
128 return Res;
129}
130
131inline Register createTypeVReg(MachineIRBuilder &MIRBuilder) {
132 return createTypeVReg(MRI&: MIRBuilder.getMF().getRegInfo());
133}
134
135SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeBool(MachineIRBuilder &MIRBuilder) {
136 return createConstOrTypeAtFunctionEntry(
137 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
138 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeBool)
139 .addDef(RegNo: createTypeVReg(MIRBuilder));
140 });
141}
142
143unsigned SPIRVGlobalRegistry::adjustOpTypeIntWidth(unsigned Width) const {
144 const SPIRVSubtarget &ST = cast<SPIRVSubtarget>(Val: CurMF->getSubtarget());
145 if (ST.canUseExtension(
146 E: SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
147 (Width == 4 && ST.canUseExtension(E: SPIRV::Extension::SPV_INTEL_int4)))
148 return Width;
149 if (Width <= 8)
150 return 8;
151 else if (Width <= 16)
152 return 16;
153 else if (Width <= 32)
154 return 32;
155 else if (Width <= 64)
156 return 64;
157 else if (Width <= 128)
158 return 128;
159 reportFatalUsageError(reason: "Unsupported Integer width!");
160}
161
162SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeInt(unsigned Width,
163 MachineIRBuilder &MIRBuilder,
164 bool IsSigned) {
165 Width = adjustOpTypeIntWidth(Width);
166 const SPIRVSubtarget &ST =
167 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
168 return createConstOrTypeAtFunctionEntry(MIRBuilder, Op: [&](MachineIRBuilder
169 &MIRBuilder) {
170 if (Width == 4 && ST.canUseExtension(E: SPIRV::Extension::SPV_INTEL_int4)) {
171 MIRBuilder.buildInstr(Opcode: SPIRV::OpExtension)
172 .addImm(Val: SPIRV::Extension::SPV_INTEL_int4);
173 MIRBuilder.buildInstr(Opcode: SPIRV::OpCapability)
174 .addImm(Val: SPIRV::Capability::Int4TypeINTEL);
175 } else if ((!isPowerOf2_32(Value: Width) || Width < 8) &&
176 ST.canUseExtension(
177 E: SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers)) {
178 MIRBuilder.buildInstr(Opcode: SPIRV::OpExtension)
179 .addImm(Val: SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
180 MIRBuilder.buildInstr(Opcode: SPIRV::OpCapability)
181 .addImm(Val: SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
182 }
183 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeInt)
184 .addDef(RegNo: createTypeVReg(MIRBuilder))
185 .addImm(Val: Width)
186 .addImm(Val: IsSigned ? 1 : 0);
187 });
188}
189
190SPIRVTypeInst
191SPIRVGlobalRegistry::getOpTypeFloat(uint32_t Width,
192 MachineIRBuilder &MIRBuilder) {
193 return createConstOrTypeAtFunctionEntry(MIRBuilder, Op: [&](MachineIRBuilder
194 &MIRBuilder) {
195 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeFloat)
196 .addDef(RegNo: createTypeVReg(MIRBuilder))
197 .addImm(Val: Width);
198 });
199}
200
201SPIRVTypeInst
202SPIRVGlobalRegistry::getOpTypeFloat(uint32_t Width,
203 MachineIRBuilder &MIRBuilder,
204 SPIRV::FPEncoding::FPEncoding FPEncode) {
205 return createConstOrTypeAtFunctionEntry(MIRBuilder, Op: [&](MachineIRBuilder
206 &MIRBuilder) {
207 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeFloat)
208 .addDef(RegNo: createTypeVReg(MIRBuilder))
209 .addImm(Val: Width)
210 .addImm(Val: FPEncode);
211 });
212}
213
214SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeVoid(MachineIRBuilder &MIRBuilder) {
215 return createConstOrTypeAtFunctionEntry(
216 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
217 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeVoid)
218 .addDef(RegNo: createTypeVReg(MIRBuilder));
219 });
220}
221
222void SPIRVGlobalRegistry::invalidateMachineInstr(MachineInstr *MI) {
223 // Other maps that may hold MachineInstr*:
224 // - VRegToTypeMap: We cannot remove the definitions of `MI` from
225 // VRegToTypeMap because some calls to invalidateMachineInstr are replacing MI
226 // with another instruction defining the same register. We expect that if MI
227 // is a type instruction, and it is still referenced in VRegToTypeMap, then
228 // those registers are dead or the VRegToTypeMap is out-of-date. We do not
229 // expect passes to ask for the SPIR-V type of a dead register. If the
230 // VRegToTypeMap is out-of-date already, then there was an error before. We
231 // cannot add an assert to verify this because the VRegToTypeMap can be
232 // out-of-date.
233 // - FunctionToInstr & FunctionToInstrRev: At this point, we should not be
234 // deleting functions. No need to update.
235 // - AliasInstMDMap: Would require a linear search, and the Intel Alias
236 // instruction are not instructions instruction selection will be able to
237 // remove.
238
239 const SPIRVSubtarget &ST = MI->getMF()->getSubtarget<SPIRVSubtarget>();
240 [[maybe_unused]] const SPIRVInstrInfo *TII = ST.getInstrInfo();
241 assert(!TII->isAliasingInstr(*MI) &&
242 "Cannot invalidate aliasing instructions.");
243 assert(MI->getOpcode() != SPIRV::OpFunction &&
244 "Cannot invalidate OpFunction.");
245
246 if (MI->getOpcode() == SPIRV::OpFunctionCall) {
247 if (const auto *F = dyn_cast<Function>(Val: MI->getOperand(i: 2).getGlobal())) {
248 auto It = ForwardCalls.find(Val: F);
249 if (It != ForwardCalls.end()) {
250 It->second.erase(Ptr: MI);
251 if (It->second.empty())
252 ForwardCalls.erase(I: It);
253 }
254 }
255 }
256
257 const MachineFunction *MF = MI->getMF();
258 auto It = LastInsertedTypeMap.find(Val: MF);
259 if (It != LastInsertedTypeMap.end() && It->second == MI)
260 LastInsertedTypeMap.erase(Val: MF);
261 // remove from the duplicate tracker to avoid incorrect reuse
262 erase(MI);
263}
264
265const MachineInstr *SPIRVGlobalRegistry::createConstOrTypeAtFunctionEntry(
266 MachineIRBuilder &MIRBuilder,
267 std::function<MachineInstr *(MachineIRBuilder &)> Op) {
268 auto oldInsertPoint = MIRBuilder.getInsertPt();
269 MachineBasicBlock *OldMBB = &MIRBuilder.getMBB();
270 MachineBasicBlock *NewMBB = &*MIRBuilder.getMF().begin();
271
272 auto LastInsertedType = LastInsertedTypeMap.find(Val: CurMF);
273 if (LastInsertedType != LastInsertedTypeMap.end()) {
274 auto It = LastInsertedType->second->getIterator();
275 // It might happen that this instruction was removed from the first MBB,
276 // hence the Parent's check.
277 MachineBasicBlock::iterator InsertAt;
278 if (It->getParent() != NewMBB)
279 InsertAt = oldInsertPoint->getParent() == NewMBB
280 ? oldInsertPoint
281 : getInsertPtValidEnd(MBB: NewMBB);
282 else if (It->getNextNode())
283 InsertAt = It->getNextNode()->getIterator();
284 else
285 InsertAt = getInsertPtValidEnd(MBB: NewMBB);
286 MIRBuilder.setInsertPt(MBB&: *NewMBB, II: InsertAt);
287 } else {
288 MIRBuilder.setInsertPt(MBB&: *NewMBB, II: NewMBB->begin());
289 auto Result = LastInsertedTypeMap.try_emplace(Key: CurMF, Args: nullptr);
290 assert(Result.second);
291 LastInsertedType = Result.first;
292 }
293
294 MachineInstr *ConstOrType = Op(MIRBuilder);
295 // We expect all users of this function to insert definitions at the insertion
296 // point set above that is always the first MBB.
297 assert(ConstOrType->getParent() == NewMBB);
298 LastInsertedType->second = ConstOrType;
299 // Advance past any continued instructions so that the next type/constant
300 // is inserted after the full group, preserving required adjacency.
301 while (auto *Next = LastInsertedType->second->getNextNode()) {
302 unsigned Opc = Next->getOpcode();
303 if (Opc == SPIRV::OpTypeStructContinuedINTEL ||
304 Opc == SPIRV::OpConstantCompositeContinuedINTEL ||
305 Opc == SPIRV::OpSpecConstantCompositeContinuedINTEL ||
306 Opc == SPIRV::OpCompositeConstructContinuedINTEL)
307 LastInsertedType->second = Next;
308 else
309 break;
310 }
311
312 MIRBuilder.setInsertPt(MBB&: *OldMBB, II: oldInsertPoint);
313 return ConstOrType;
314}
315
316SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeVectorImpl(
317 uint32_t NumElems, SPIRVTypeInst ElemType, MachineIRBuilder &MIRBuilder,
318 bool IsLongVectorEXT) {
319 if (ElemType.isPointer()) {
320 if (!cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget())
321 .canUseExtension(
322 E: SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
323 const Function &F = MIRBuilder.getMF().getFunction();
324 F.getContext().diagnose(DI: DiagnosticInfoUnsupported(
325 F,
326 "Vector of pointers requires SPV_INTEL_masked_gather_scatter "
327 "extension",
328 DebugLoc(), DS_Error));
329 }
330 } else {
331 [[maybe_unused]] auto EleOpc = ElemType->getOpcode();
332 assert((EleOpc == SPIRV::OpTypeInt || EleOpc == SPIRV::OpTypeFloat ||
333 EleOpc == SPIRV::OpTypeBool) &&
334 "Invalid vector element type");
335 }
336
337 return createConstOrTypeAtFunctionEntry(
338 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
339 unsigned Op =
340 IsLongVectorEXT ? SPIRV::OpTypeVectorIdEXT : SPIRV::OpTypeVector;
341 Register VTy = createTypeVReg(MIRBuilder);
342 Register Ty = getSPIRVTypeID(SpirvType: ElemType);
343 auto MIB = MIRBuilder.buildInstr(Opcode: Op).addDef(RegNo: VTy).addUse(RegNo: Ty);
344 if (!IsLongVectorEXT)
345 return MIB.addImm(Val: NumElems);
346
347 const auto &ST = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
348 SPIRVTypeInst Int32Ty = getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
349 return MIB.addUse(RegNo: getOrCreateConstInt(Val: NumElems, I&: *MIB.getInstr(),
350 SpvType: Int32Ty, TII: *ST.getInstrInfo()));
351 });
352}
353
354SPIRVTypeInst
355SPIRVGlobalRegistry::getOpTypeVector(uint32_t NumElems, SPIRVTypeInst ElemType,
356 MachineIRBuilder &MIRBuilder) {
357 assert(NumElems >= 2 && "SPIR-V OpTypeVector requires at least 2 components");
358 return getOpTypeVectorImpl(NumElems, ElemType, MIRBuilder);
359}
360
361SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeVectorIdEXT(
362 uint32_t NumElems, SPIRVTypeInst ElemType, MachineIRBuilder &MIRBuilder) {
363 assert((NumElems < 2 || NumElems > 16 ||
364 (NumElems != 3 && NumElems != 4 && NumElems != 8)) &&
365 "SPIR-V OpTypeVectorIdExt should only be used for extended vectors");
366 return getOpTypeVectorImpl(NumElems, ElemType, MIRBuilder, IsLongVectorEXT: true);
367}
368
369Register SPIRVGlobalRegistry::getOrCreateConstFP(APFloat Val, MachineInstr &I,
370 SPIRVTypeInst SpvType,
371 const SPIRVInstrInfo &TII,
372 bool ZeroAsNull) {
373 LLVMContext &Ctx = CurMF->getFunction().getContext();
374 auto *const CF = ConstantFP::get(Context&: Ctx, V: Val);
375 const MachineInstr *MI = findMI(Obj: CF, MF: CurMF);
376 if (MI && (MI->getOpcode() == SPIRV::OpConstantNull ||
377 MI->getOpcode() == SPIRV::OpConstantF))
378 return MI->getOperand(i: 0).getReg();
379 return createConstFP(CF, I, SpvType, TII, ZeroAsNull);
380}
381
382Register SPIRVGlobalRegistry::createConstFP(const ConstantFP *CF,
383 MachineInstr &I,
384 SPIRVTypeInst SpvType,
385 const SPIRVInstrInfo &TII,
386 bool ZeroAsNull) {
387 unsigned BitWidth = getScalarOrVectorBitWidth(Type: SpvType);
388 LLT LLTy = LLT::scalar(SizeInBits: BitWidth);
389 Register Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
390 CurMF->getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::fIDRegClass);
391 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF: *CurMF);
392
393 MachineInstr *DepMI =
394 const_cast<MachineInstr *>(static_cast<const MachineInstr *>(SpvType));
395 MachineIRBuilder MIRBuilder(*DepMI->getParent(), DepMI->getIterator());
396 const MachineInstr *Const = createConstOrTypeAtFunctionEntry(
397 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
398 MachineInstrBuilder MIB;
399 // In OpenCL OpConstantNull - Scalar floating point: +0.0 (all bits 0)
400 if (CF->getValue().isPosZero() && ZeroAsNull) {
401 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
402 .addDef(RegNo: Res)
403 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
404 } else {
405 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantF)
406 .addDef(RegNo: Res)
407 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
408 addNumImm(Imm: APInt(BitWidth,
409 CF->getValueAPF().bitcastToAPInt().getZExtValue()),
410 MIB);
411 }
412 constrainSelectedInstRegOperands(MIB);
413 return MIB;
414 });
415 add(V: CF, MI: Const);
416 return Res;
417}
418
419Register SPIRVGlobalRegistry::getOrCreateConstInt(uint64_t Val, MachineInstr &I,
420 SPIRVTypeInst SpvType,
421 const SPIRVInstrInfo &TII,
422 bool ZeroAsNull) {
423 return getOrCreateConstInt(Val: APInt(getScalarOrVectorBitWidth(Type: SpvType), Val), I,
424 SpvType, TII, ZeroAsNull);
425}
426
427Register SPIRVGlobalRegistry::getOrCreateConstInt(const APInt &Val,
428 MachineInstr &I,
429 SPIRVTypeInst SpvType,
430 const SPIRVInstrInfo &TII,
431 bool ZeroAsNull) {
432 auto *const CI = ConstantInt::get(
433 Context&: cast<IntegerType>(Val: getTypeForSPIRVType(Ty: SpvType))->getContext(), V: Val);
434 const MachineInstr *MI = findMI(Obj: CI, MF: CurMF);
435 if (MI && (MI->getOpcode() == SPIRV::OpConstantNull ||
436 MI->getOpcode() == SPIRV::OpConstantI))
437 return MI->getOperand(i: 0).getReg();
438 return createConstInt(CI, I, SpvType, TII, ZeroAsNull);
439}
440
441Register SPIRVGlobalRegistry::createConstInt(const ConstantInt *CI,
442 MachineInstr &I,
443 SPIRVTypeInst SpvType,
444 const SPIRVInstrInfo &TII,
445 bool ZeroAsNull) {
446 unsigned BitWidth = getScalarOrVectorBitWidth(Type: SpvType);
447 LLT LLTy = LLT::scalar(SizeInBits: BitWidth);
448 Register Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
449 CurMF->getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::iIDRegClass);
450 assignIntTypeToVReg(BitWidth, VReg: Res, I, TII);
451
452 MachineInstr *DepMI =
453 const_cast<MachineInstr *>(static_cast<const MachineInstr *>(SpvType));
454 MachineIRBuilder MIRBuilder(*DepMI->getParent(), DepMI->getIterator());
455 const MachineInstr *Const = createConstOrTypeAtFunctionEntry(
456 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
457 MachineInstrBuilder MIB;
458 if (BitWidth == 1) {
459 MIB = MIRBuilder
460 .buildInstr(Opcode: CI->isZero() ? SPIRV::OpConstantFalse
461 : SPIRV::OpConstantTrue)
462 .addDef(RegNo: Res)
463 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
464 } else if (!CI->isZero() || !ZeroAsNull) {
465 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantI)
466 .addDef(RegNo: Res)
467 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
468 addNumImm(Imm: CI->getValue(), MIB);
469 } else {
470 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
471 .addDef(RegNo: Res)
472 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
473 }
474 constrainSelectedInstRegOperands(MIB);
475 return MIB;
476 });
477 add(V: CI, MI: Const);
478 return Res;
479}
480
481Register SPIRVGlobalRegistry::buildConstantInt(uint64_t Val,
482 MachineIRBuilder &MIRBuilder,
483 SPIRVTypeInst SpvType,
484 bool EmitIR, bool ZeroAsNull) {
485 assert(SpvType);
486 auto &MF = MIRBuilder.getMF();
487 const IntegerType *Ty = cast<IntegerType>(Val: getTypeForSPIRVType(Ty: SpvType));
488 // TODO: Avoid implicit trunc?
489 // See https://github.com/llvm/llvm-project/issues/112510.
490 auto *const CI = ConstantInt::get(Ty: const_cast<IntegerType *>(Ty), V: Val,
491 /*IsSigned=*/false, /*ImplicitTrunc=*/true);
492 Register Res = find(V: CI, MF: &MF);
493 if (Res.isValid())
494 return Res;
495
496 unsigned BitWidth = getScalarOrVectorBitWidth(Type: SpvType);
497 LLT LLTy = LLT::scalar(SizeInBits: BitWidth);
498 MachineRegisterInfo &MRI = MF.getRegInfo();
499 Res = MRI.createGenericVirtualRegister(Ty: LLTy);
500 MRI.setRegClass(Reg: Res, RC: &SPIRV::iIDRegClass);
501 assignTypeToVReg(Type: Ty, VReg: Res, MIRBuilder, AccessQual: SPIRV::AccessQualifier::ReadWrite,
502 EmitIR);
503
504 const MachineInstr *Const = createConstOrTypeAtFunctionEntry(
505 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
506 if (EmitIR)
507 return MIRBuilder.buildConstant(Res, Val: *CI);
508 Register SpvTypeReg = getSPIRVTypeID(SpirvType: SpvType);
509 MachineInstrBuilder MIB;
510 if (Val || !ZeroAsNull) {
511 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantI)
512 .addDef(RegNo: Res)
513 .addUse(RegNo: SpvTypeReg);
514 addNumImm(Imm: APInt(BitWidth, Val), MIB);
515 } else {
516 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
517 .addDef(RegNo: Res)
518 .addUse(RegNo: SpvTypeReg);
519 }
520 constrainSelectedInstRegOperands(MIB);
521 return MIB;
522 });
523 add(V: CI, MI: Const);
524 return Res;
525}
526
527Register SPIRVGlobalRegistry::buildConstantFP(APFloat Val,
528 MachineIRBuilder &MIRBuilder,
529 SPIRVTypeInst SpvType) {
530 auto &MF = MIRBuilder.getMF();
531 LLVMContext &Ctx = MF.getFunction().getContext();
532 if (!SpvType)
533 SpvType = getOrCreateSPIRVType(Type: Type::getFloatTy(C&: Ctx), MIRBuilder,
534 AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: true);
535 auto *const CF = ConstantFP::get(Context&: Ctx, V: Val);
536 Register Res = find(V: CF, MF: &MF);
537 if (Res.isValid())
538 return Res;
539
540 LLT LLTy = LLT::scalar(SizeInBits: getScalarOrVectorBitWidth(Type: SpvType));
541 Res = MF.getRegInfo().createGenericVirtualRegister(Ty: LLTy);
542 MF.getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::fIDRegClass);
543 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF);
544
545 const MachineInstr *Const = createConstOrTypeAtFunctionEntry(
546 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
547 MachineInstrBuilder MIB;
548 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantF)
549 .addDef(RegNo: Res)
550 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
551 addNumImm(Imm: CF->getValueAPF().bitcastToAPInt(), MIB);
552 return MIB;
553 });
554 add(V: CF, MI: Const);
555 return Res;
556}
557
558Register SPIRVGlobalRegistry::getOrCreateBaseRegister(
559 Constant *Val, MachineInstr &I, SPIRVTypeInst SpvType,
560 const SPIRVInstrInfo &TII, unsigned BitWidth, bool ZeroAsNull) {
561 SPIRVTypeInst Type = SpvType;
562 if (isVectorType(SPVTy: SpvType) || SpvType->getOpcode() == SPIRV::OpTypeArray) {
563 auto EleTypeReg = SpvType->getOperand(i: 1).getReg();
564 Type = getSPIRVTypeForVReg(VReg: EleTypeReg);
565 }
566 if (Type->getOpcode() == SPIRV::OpTypeFloat) {
567 SPIRVTypeInst SpvBaseType = getOrCreateSPIRVFloatType(BitWidth, I, TII);
568 return getOrCreateConstFP(Val: cast<ConstantFP>(Val)->getValue(), I, SpvType: SpvBaseType,
569 TII, ZeroAsNull);
570 }
571 assert(Type->getOpcode() == SPIRV::OpTypeInt);
572 SPIRVTypeInst SpvBaseType = getOrCreateSPIRVIntegerType(BitWidth, I, TII);
573 return getOrCreateConstInt(Val: Val->getUniqueInteger(), I, SpvType: SpvBaseType, TII,
574 ZeroAsNull);
575}
576
577Register SPIRVGlobalRegistry::getOrCreateCompositeOrNull(
578 Constant *Val, MachineInstr &I, SPIRVTypeInst SpvType,
579 const SPIRVInstrInfo &TII, Constant *CA, unsigned BitWidth,
580 unsigned ElemCnt, bool ZeroAsNull) {
581 if (Register R = find(V: CA, MF: CurMF); R.isValid())
582 return R;
583
584 bool IsNull = Val->isNullValue() && ZeroAsNull;
585 Register ElemReg;
586 if (!IsNull)
587 ElemReg =
588 getOrCreateBaseRegister(Val, I, SpvType, TII, BitWidth, ZeroAsNull);
589
590 LLT LLTy = LLT::scalar(SizeInBits: 64);
591 Register Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
592 CurMF->getRegInfo().setRegClass(Reg: Res, RC: getRegClass(SpvType));
593 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF: *CurMF);
594
595 MachineInstr *DepMI =
596 const_cast<MachineInstr *>(static_cast<const MachineInstr *>(SpvType));
597 MachineIRBuilder MIRBuilder(*DepMI->getParent(), DepMI->getIterator());
598 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
599 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
600 MachineInstrBuilder MIB;
601 if (!IsNull) {
602 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantComposite)
603 .addDef(RegNo: Res)
604 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
605 for (unsigned i = 0; i < ElemCnt; ++i)
606 MIB.addUse(RegNo: ElemReg);
607 } else {
608 MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
609 .addDef(RegNo: Res)
610 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
611 }
612 constrainSelectedInstRegOperands(MIB);
613 return MIB;
614 });
615 add(V: CA, MI: NewMI);
616 return Res;
617}
618
619Register SPIRVGlobalRegistry::getOrCreateConstVector(uint64_t Val,
620 MachineInstr &I,
621 SPIRVTypeInst SpvType,
622 const SPIRVInstrInfo &TII,
623 bool ZeroAsNull) {
624 return getOrCreateConstVector(Val: APInt(getScalarOrVectorBitWidth(Type: SpvType), Val),
625 I, SpvType, TII, ZeroAsNull);
626}
627
628Register SPIRVGlobalRegistry::getOrCreateConstVector(const APInt &Val,
629 MachineInstr &I,
630 SPIRVTypeInst SpvType,
631 const SPIRVInstrInfo &TII,
632 bool ZeroAsNull) {
633 const Type *LLVMTy = getTypeForSPIRVType(Ty: SpvType);
634 assert(LLVMTy->isVectorTy() &&
635 "Expected vector type for constant vector creation");
636 const FixedVectorType *LLVMVecTy = cast<FixedVectorType>(Val: LLVMTy);
637 Type *LLVMBaseTy = LLVMVecTy->getElementType();
638 [[maybe_unused]] const auto &ST = I.getMF()->getSubtarget<SPIRVSubtarget>();
639 assert((LLVMBaseTy->isIntegerTy() ||
640 (LLVMBaseTy->isPointerTy() &&
641 ST.canUseExtension(
642 SPIRV::Extension::SPV_INTEL_masked_gather_scatter))) &&
643 "Expected either integer element type for APInt constant vector or "
644 "pointer type if the SPV_INTEL_masked_gather_scatter extension is "
645 "enabled!");
646 Constant *ConstVal = nullptr;
647 if (LLVMBaseTy->isIntegerTy()) {
648 ConstVal = ConstantInt::get(Ty: LLVMBaseTy, V: Val);
649 } else {
650 if (Val.isZero())
651 ConstVal = ConstantPointerNull::get(T: LLVMBaseTy);
652 else
653 llvm_unreachable("Vectors of non-null constant pointers unimplemented!");
654 }
655 auto *ConstVec =
656 ConstantVector::getSplat(EC: LLVMVecTy->getElementCount(), Elt: ConstVal);
657 unsigned BW = getScalarOrVectorBitWidth(Type: SpvType);
658 return getOrCreateCompositeOrNull(Val: ConstVal, I, SpvType, TII, CA: ConstVec, BitWidth: BW,
659 ElemCnt: getScalarOrVectorComponentCount(Type: SpvType),
660 ZeroAsNull);
661}
662
663Register SPIRVGlobalRegistry::getOrCreateConstVector(APFloat Val,
664 MachineInstr &I,
665 SPIRVTypeInst SpvType,
666 const SPIRVInstrInfo &TII,
667 bool ZeroAsNull) {
668 const Type *LLVMTy = getTypeForSPIRVType(Ty: SpvType);
669 assert(LLVMTy->isVectorTy());
670 const FixedVectorType *LLVMVecTy = cast<FixedVectorType>(Val: LLVMTy);
671 Type *LLVMBaseTy = LLVMVecTy->getElementType();
672 assert(LLVMBaseTy->isFloatingPointTy());
673 auto *ConstVal = ConstantFP::get(Ty: LLVMBaseTy, V: Val);
674 auto *ConstVec =
675 ConstantVector::getSplat(EC: LLVMVecTy->getElementCount(), Elt: ConstVal);
676 unsigned BW = getScalarOrVectorBitWidth(Type: SpvType);
677 return getOrCreateCompositeOrNull(Val: ConstVal, I, SpvType, TII, CA: ConstVec, BitWidth: BW,
678 ElemCnt: getScalarOrVectorComponentCount(Type: SpvType),
679 ZeroAsNull);
680}
681
682Register SPIRVGlobalRegistry::getOrCreateConstIntArray(
683 uint64_t Val, size_t Num, MachineInstr &I, SPIRVTypeInst SpvType,
684 const SPIRVInstrInfo &TII) {
685 const Type *LLVMTy = getTypeForSPIRVType(Ty: SpvType);
686 assert(LLVMTy->isArrayTy());
687 const ArrayType *LLVMArrTy = cast<ArrayType>(Val: LLVMTy);
688 Type *LLVMBaseTy = LLVMArrTy->getElementType();
689 Constant *CI = ConstantInt::get(Ty: LLVMBaseTy, V: Val);
690 SPIRVTypeInst SpvBaseTy =
691 getSPIRVTypeForVReg(VReg: SpvType->getOperand(i: 1).getReg());
692 unsigned BW = getScalarOrVectorBitWidth(Type: SpvBaseTy);
693 // The following is reasonably unique key that is better that [Val]. The naive
694 // alternative would be something along the lines of:
695 // SmallVector<Constant *> NumCI(Num, CI);
696 // Constant *UniqueKey =
697 // ConstantArray::get(const_cast<ArrayType*>(LLVMArrTy), NumCI);
698 // that would be a truly unique but dangerous key, because it could lead to
699 // the creation of constants of arbitrary length (that is, the parameter of
700 // memset) which were missing in the original module.
701 Type *I64Ty = Type::getInt64Ty(C&: LLVMBaseTy->getContext());
702 Constant *UniqueKey = ConstantStruct::getAnon(
703 V: {PoisonValue::get(T: const_cast<ArrayType *>(LLVMArrTy)),
704 ConstantInt::get(Ty: LLVMBaseTy, V: Val), ConstantInt::get(Ty: I64Ty, V: Num)});
705 return getOrCreateCompositeOrNull(Val: CI, I, SpvType, TII, CA: UniqueKey, BitWidth: BW,
706 ElemCnt: LLVMArrTy->getNumElements());
707}
708
709Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull(
710 uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType,
711 bool EmitIR, Constant *CA, unsigned BitWidth, unsigned ElemCnt) {
712 if (Register R = find(V: CA, MF: CurMF); R.isValid())
713 return R;
714
715 Register ElemReg;
716 if (Val || EmitIR) {
717 SPIRVTypeInst SpvBaseType =
718 getOrCreateSPIRVIntegerType(BitWidth, MIRBuilder);
719 ElemReg = buildConstantInt(Val, MIRBuilder, SpvType: SpvBaseType, EmitIR);
720 }
721 LLT LLTy = EmitIR ? LLT::fixed_vector(NumElements: ElemCnt, ScalarSizeInBits: BitWidth) : LLT::scalar(SizeInBits: 64);
722 Register Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
723 CurMF->getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::iIDRegClass);
724 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF: *CurMF);
725
726 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
727 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
728 if (EmitIR)
729 return MIRBuilder.buildSplatBuildVector(Res, Src: ElemReg);
730
731 if (Val) {
732 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantComposite)
733 .addDef(RegNo: Res)
734 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
735 for (unsigned i = 0; i < ElemCnt; ++i)
736 MIB.addUse(RegNo: ElemReg);
737 return MIB;
738 }
739
740 return MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
741 .addDef(RegNo: Res)
742 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
743 });
744 add(V: CA, MI: NewMI);
745 return Res;
746}
747
748Register SPIRVGlobalRegistry::getOrCreateConsIntVector(
749 uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType,
750 bool EmitIR) {
751 const Type *LLVMTy = getTypeForSPIRVType(Ty: SpvType);
752 assert(LLVMTy->isVectorTy());
753 const FixedVectorType *LLVMVecTy = cast<FixedVectorType>(Val: LLVMTy);
754 Type *LLVMBaseTy = LLVMVecTy->getElementType();
755 const auto ConstInt = ConstantInt::get(Ty: LLVMBaseTy, V: Val);
756 auto ConstVec =
757 ConstantVector::getSplat(EC: LLVMVecTy->getElementCount(), Elt: ConstInt);
758 unsigned BW = getScalarOrVectorBitWidth(Type: SpvType);
759 return getOrCreateIntCompositeOrNull(
760 Val, MIRBuilder, SpvType, EmitIR, CA: ConstVec, BitWidth: BW,
761 ElemCnt: getScalarOrVectorComponentCount(Type: SpvType));
762}
763
764Register
765SPIRVGlobalRegistry::getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder,
766 SPIRVTypeInst SpvType) {
767 const Type *Ty = getTypeForSPIRVType(Ty: SpvType);
768 unsigned AddressSpace = typeToAddressSpace(Ty);
769 Type *ElemTy = ::getPointeeType(Ty);
770 assert(ElemTy);
771 const Constant *CP = ConstantTargetNone::get(
772 T: dyn_cast<TargetExtType>(Val: getTypedPointerWrapper(ElemTy, AS: AddressSpace)));
773 Register Res = find(V: CP, MF: CurMF);
774 if (Res.isValid())
775 return Res;
776
777 LLT LLTy = LLT::pointer(AddressSpace, SizeInBits: getPointerSize());
778 Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
779 CurMF->getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::pIDRegClass);
780 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF: *CurMF);
781
782 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
783 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
784 return MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantNull)
785 .addDef(RegNo: Res)
786 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
787 });
788 add(V: CP, MI: NewMI);
789 return Res;
790}
791
792Register
793SPIRVGlobalRegistry::buildConstantSampler(Register ResReg, unsigned AddrMode,
794 unsigned Param, unsigned FilerMode,
795 MachineIRBuilder &MIRBuilder) {
796 auto Sampler =
797 ResReg.isValid()
798 ? ResReg
799 : MIRBuilder.getMRI()->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
800 SPIRVTypeInst TypeSampler = getOrCreateOpTypeSampler(MIRBuilder);
801 Register TypeSamplerReg = getSPIRVTypeID(SpirvType: TypeSampler);
802 // We cannot use createOpType() logic here, because of the
803 // GlobalISel/IRTranslator.cpp check for a tail call that expects that
804 // MIRBuilder.getInsertPt() has a previous instruction. If this constant is
805 // inserted as a result of "__translate_sampler_initializer()" this would
806 // break this IRTranslator assumption.
807 MIRBuilder.buildInstr(Opcode: SPIRV::OpConstantSampler)
808 .addDef(RegNo: Sampler)
809 .addUse(RegNo: TypeSamplerReg)
810 .addImm(Val: AddrMode)
811 .addImm(Val: Param)
812 .addImm(Val: FilerMode);
813 return Sampler;
814}
815
816Register SPIRVGlobalRegistry::buildGlobalVariable(
817 Register ResVReg, SPIRVTypeInst BaseType, StringRef Name,
818 const GlobalValue *GV, SPIRV::StorageClass::StorageClass Storage,
819 const MachineInstr *Init, bool IsConst,
820 const std::optional<SPIRV::LinkageType::LinkageType> &LinkageType,
821 MachineIRBuilder &MIRBuilder, bool IsInstSelector) {
822 const GlobalVariable *GVar = nullptr;
823 if (GV) {
824 GVar = cast<const GlobalVariable>(Val: GV);
825 } else {
826 // If GV is not passed explicitly, use the name to find or construct
827 // the global variable.
828 Module *M = MIRBuilder.getMF().getFunction().getParent();
829 GVar = M->getGlobalVariable(Name);
830 if (GVar == nullptr) {
831 const Type *Ty = getTypeForSPIRVType(Ty: BaseType); // TODO: check type.
832 if (auto *TPTy = dyn_cast<TypedPointerType>(Val: Ty))
833 Ty = PointerType::get(C&: M->getContext(), AddressSpace: TPTy->getAddressSpace());
834 // Module takes ownership of the global var.
835 GVar = new GlobalVariable(*M, const_cast<Type *>(Ty), false,
836 GlobalValue::ExternalLinkage, nullptr,
837 Twine(Name));
838 }
839 GV = GVar;
840 }
841
842 const MachineFunction *MF = &MIRBuilder.getMF();
843 Register Reg = find(V: GVar, MF);
844 if (Reg.isValid()) {
845 if (Reg != ResVReg)
846 MIRBuilder.buildCopy(Res: ResVReg, Op: Reg);
847 return ResVReg;
848 }
849
850 // Emit the OpVariable into the entry block to ensure the def dominates
851 // all uses across all MBBs.
852 MachineBasicBlock &EntryBB = MIRBuilder.getMF().front();
853 MachineIRBuilder GVBuilder(MIRBuilder.getState());
854 if (&GVBuilder.getMBB() != &EntryBB)
855 GVBuilder.setInsertPt(MBB&: EntryBB, II: EntryBB.getFirstTerminator());
856
857 // Pointers to opaque types stay typed even with the extension on, so emit the
858 // untyped variant only when the result is actually an untyped pointer.
859 const bool UseUntypedPointers =
860 BaseType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
861 const unsigned VariableOpcode =
862 UseUntypedPointers ? SPIRV::OpUntypedVariableKHR : SPIRV::OpVariable;
863
864 auto MIB = GVBuilder.buildInstr(Opcode: VariableOpcode)
865 .addDef(RegNo: ResVReg)
866 .addUse(RegNo: getSPIRVTypeID(SpirvType: BaseType))
867 .addImm(Val: static_cast<uint32_t>(Storage));
868
869 // OpUntypedVariableKHR takes an extra Data Type operand right after the
870 // storage class, holding the global's value type.
871 if (UseUntypedPointers) {
872 SPIRVTypeInst DataType = getPointeeType(PtrType: BaseType);
873 if (!DataType)
874 DataType = getOrCreateSPIRVType(Type: GV->getValueType(), MIRBuilder&: GVBuilder,
875 AQ: SPIRV::AccessQualifier::ReadWrite,
876 /*EmitIR=*/false);
877 if (!DataType) {
878 const Function &F = MIRBuilder.getMF().getFunction();
879 F.getContext().diagnose(DI: DiagnosticInfoUnsupported(
880 F,
881 "Could not deduce the data type of untyped global variable '" +
882 GVar->getName() + "'",
883 DebugLoc(), DS_Error));
884 // Recover with i8 so that codegen can finish and report the error.
885 DataType =
886 getOrCreateSPIRVType(Type: Type::getInt8Ty(C&: F.getContext()), MIRBuilder&: GVBuilder,
887 AQ: SPIRV::AccessQualifier::ReadWrite,
888 /*EmitIR=*/false);
889 }
890 MIB.addUse(RegNo: getSPIRVTypeID(SpirvType: DataType));
891 }
892
893 if (Init)
894 MIB.addUse(RegNo: Init->getOperand(i: 0).getReg());
895 // ISel may introduce a new register on this step, so we need to add it to
896 // DT and correct its type avoiding fails on the next stage.
897 if (IsInstSelector) {
898 constrainSelectedInstRegOperands(MIB);
899 }
900 add(V: GVar, MI: MIB);
901
902 Reg = MIB->getOperand(i: 0).getReg();
903 addGlobalObject(V: GVar, MF, R: Reg);
904
905 // Set to Reg the same type as ResVReg has.
906 auto MRI = MIRBuilder.getMRI();
907 if (Reg != ResVReg) {
908 LLT RegLLTy =
909 LLT::pointer(AddressSpace: MRI->getType(Reg: ResVReg).getAddressSpace(), SizeInBits: getPointerSize());
910 MRI->setType(VReg: Reg, Ty: RegLLTy);
911 assignSPIRVTypeToVReg(SpirvType: BaseType, VReg: Reg, MF: MIRBuilder.getMF());
912 } else {
913 // Our knowledge about the type may be updated.
914 // If that's the case, we need to update a type
915 // associated with the register.
916 SPIRVTypeInst DefType = getSPIRVTypeForVReg(VReg: ResVReg);
917 if (!DefType || DefType != SPIRVTypeInst(BaseType))
918 assignSPIRVTypeToVReg(SpirvType: BaseType, VReg: Reg, MF: MIRBuilder.getMF());
919 }
920
921 // If it's a global variable with name, output OpName for it.
922 if (GVar && GVar->hasName())
923 buildOpName(Target: Reg, Name: GVar->getName(), MIRBuilder);
924
925 // Output decorations for the GV.
926 // TODO: maybe move to GenerateDecorations pass.
927 const SPIRVSubtarget &ST =
928 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
929 if (IsConst && !ST.isShader())
930 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::Constant, DecArgs: {});
931
932 if (GVar && GVar->getAlign().valueOrOne().value() != 1 && !ST.isShader()) {
933 unsigned Alignment = (unsigned)GVar->getAlign().valueOrOne().value();
934 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::Alignment, DecArgs: {Alignment});
935 }
936
937 if (LinkageType)
938 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::LinkageAttributes,
939 DecArgs: {static_cast<uint32_t>(*LinkageType)}, StrImm: Name);
940
941 SPIRV::BuiltIn::BuiltIn BuiltInId;
942 if (getSpirvBuiltInIdByName(Name, BI&: BuiltInId))
943 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::BuiltIn,
944 DecArgs: {static_cast<uint32_t>(BuiltInId)});
945
946 // If it's a global variable with "spirv.Decorations" metadata node
947 // recognize it as a SPIR-V friendly LLVM IR and parse "spirv.Decorations"
948 // arguments.
949 MDNode *GVarMD = nullptr;
950 if (GVar && (GVarMD = GVar->getMetadata(Kind: "spirv.Decorations")) != nullptr)
951 buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD, ST);
952
953 return Reg;
954}
955
956// Returns a name based on the Type. Notes that this does not look at
957// decorations, and will return the same string for two types that are the same
958// except for decorations.
959Register SPIRVGlobalRegistry::getOrCreateGlobalVariableWithBinding(
960 SPIRVTypeInst VarType, uint32_t Set, uint32_t Binding, StringRef Name,
961 MachineIRBuilder &MIRBuilder) {
962 Register VarReg =
963 MIRBuilder.getMRI()->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
964
965 buildGlobalVariable(ResVReg: VarReg, BaseType: VarType, Name, GV: nullptr,
966 Storage: getPointerStorageClass(Type: VarType), Init: nullptr, IsConst: false,
967 LinkageType: std::nullopt, MIRBuilder, IsInstSelector: false);
968
969 buildOpDecorate(Reg: VarReg, MIRBuilder, Dec: SPIRV::Decoration::DescriptorSet, DecArgs: {Set});
970 buildOpDecorate(Reg: VarReg, MIRBuilder, Dec: SPIRV::Decoration::Binding, DecArgs: {Binding});
971 return VarReg;
972}
973
974// TODO: Double check the calls to getOpTypeArray to make sure that `ElemType`
975// is explicitly laid out when required.
976SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeArray(uint32_t NumElems,
977 SPIRVTypeInst ElemType,
978 MachineIRBuilder &MIRBuilder,
979 bool ExplicitLayoutRequired,
980 bool EmitIR) {
981 assert((ElemType->getOpcode() != SPIRV::OpTypeVoid) &&
982 "Invalid array element type");
983 SPIRVTypeInst SpvTypeInt32 = getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
984 SPIRVTypeInst ArrayType = nullptr;
985 const SPIRVSubtarget &ST =
986 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
987 if (NumElems != 0) {
988 Register NumElementsVReg =
989 buildConstantInt(Val: NumElems, MIRBuilder, SpvType: SpvTypeInt32, EmitIR);
990 ArrayType = createConstOrTypeAtFunctionEntry(
991 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
992 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeArray)
993 .addDef(RegNo: createTypeVReg(MIRBuilder))
994 .addUse(RegNo: getSPIRVTypeID(SpirvType: ElemType))
995 .addUse(RegNo: NumElementsVReg);
996 });
997 } else if (ST.getTargetTriple().getVendor() == Triple::VendorType::AMD) {
998 // We set the array size to the token UINT64_MAX value, which is generally
999 // illegal (the maximum legal size is 61-bits) for the foreseeable future.
1000 SPIRVTypeInst SpvTypeInt64 = getOrCreateSPIRVIntegerType(BitWidth: 64, MIRBuilder);
1001 Register NumElementsVReg =
1002 buildConstantInt(UINT64_MAX, MIRBuilder, SpvType: SpvTypeInt64, EmitIR);
1003 ArrayType = createConstOrTypeAtFunctionEntry(
1004 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1005 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeArray)
1006 .addDef(RegNo: createTypeVReg(MIRBuilder))
1007 .addUse(RegNo: getSPIRVTypeID(SpirvType: ElemType))
1008 .addUse(RegNo: NumElementsVReg);
1009 });
1010 } else {
1011 if (!ST.isShader()) {
1012 llvm::reportFatalUsageError(
1013 reason: "Runtime arrays are not allowed in non-shader "
1014 "SPIR-V modules");
1015 return nullptr;
1016 }
1017 ArrayType = createConstOrTypeAtFunctionEntry(
1018 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1019 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeRuntimeArray)
1020 .addDef(RegNo: createTypeVReg(MIRBuilder))
1021 .addUse(RegNo: getSPIRVTypeID(SpirvType: ElemType));
1022 });
1023 }
1024
1025 if (ExplicitLayoutRequired && !isResourceType(Type: ElemType)) {
1026 Type *ET = const_cast<Type *>(getTypeForSPIRVType(Ty: ElemType));
1027 addArrayStrideDecorations(Reg: ArrayType->defs().begin()->getReg(), ElementType: ET,
1028 MIRBuilder);
1029 }
1030
1031 return ArrayType;
1032}
1033
1034SPIRVTypeInst
1035SPIRVGlobalRegistry::getOpTypeOpaque(const StructType *Ty,
1036 MachineIRBuilder &MIRBuilder) {
1037 assert(Ty->hasName());
1038 StringRef Name = Ty->hasName() ? Ty->getName() : "";
1039 Register ResVReg = createTypeVReg(MIRBuilder);
1040 return createConstOrTypeAtFunctionEntry(
1041 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1042 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeOpaque).addDef(RegNo: ResVReg);
1043 addStringImm(Str: Name, MIB);
1044 buildOpName(Target: ResVReg, Name, MIRBuilder);
1045 return MIB;
1046 });
1047}
1048
1049SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeStruct(
1050 const StructType *Ty, MachineIRBuilder &MIRBuilder,
1051 SPIRV::AccessQualifier::AccessQualifier AccQual,
1052 StructOffsetDecorator Decorator, bool EmitIR) {
1053 Type *OriginalElementType = nullptr;
1054 uint64_t TotalSize = 0;
1055 if (matchPeeledArrayPattern(Ty, OriginalElementType, TotalSize)) {
1056 SPIRVTypeInst ElementSPIRVType = findSPIRVType(
1057 Ty: OriginalElementType, MIRBuilder, accessQual: AccQual,
1058 /* ExplicitLayoutRequired= */ Decorator != nullptr, EmitIR);
1059 return getOpTypeArray(NumElems: TotalSize, ElemType: ElementSPIRVType, MIRBuilder,
1060 /*ExplicitLayoutRequired=*/Decorator != nullptr,
1061 EmitIR);
1062 }
1063
1064 const SPIRVSubtarget &ST =
1065 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
1066 SmallVector<Register, 4> FieldTypes;
1067 constexpr unsigned MaxWordCount = UINT16_MAX;
1068 const size_t NumElements = Ty->getNumElements();
1069
1070 size_t MaxNumElements = MaxWordCount - 2;
1071 size_t SPIRVStructNumElements = NumElements;
1072 if (NumElements > MaxNumElements) {
1073 // Do adjustments for continued instructions.
1074 SPIRVStructNumElements = MaxNumElements;
1075 MaxNumElements = MaxWordCount - 1;
1076 }
1077
1078 for (const auto &Elem : Ty->elements()) {
1079 SPIRVTypeInst ElemTy = findSPIRVType(
1080 Ty: toTypedPointer(Ty: Elem), MIRBuilder, accessQual: AccQual,
1081 /* ExplicitLayoutRequired= */ Decorator != nullptr, EmitIR);
1082 assert(ElemTy && ElemTy->getOpcode() != SPIRV::OpTypeVoid &&
1083 "Invalid struct element type");
1084 FieldTypes.push_back(Elt: getSPIRVTypeID(SpirvType: ElemTy));
1085 }
1086 Register ResVReg = createTypeVReg(MIRBuilder);
1087 if (Ty->hasName())
1088 buildOpName(Target: ResVReg, Name: Ty->getName(), MIRBuilder);
1089 if (Ty->isPacked() && !ST.isShader())
1090 buildOpDecorate(Reg: ResVReg, MIRBuilder, Dec: SPIRV::Decoration::CPacked, DecArgs: {});
1091
1092 SPIRVTypeInst SPVType = createConstOrTypeAtFunctionEntry(
1093 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1094 auto MIBStruct =
1095 MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeStruct).addDef(RegNo: ResVReg);
1096 for (size_t I = 0; I < SPIRVStructNumElements; ++I)
1097 MIBStruct.addUse(RegNo: FieldTypes[I]);
1098 for (size_t I = SPIRVStructNumElements; I < NumElements;
1099 I += MaxNumElements) {
1100 auto MIBCont =
1101 MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeStructContinuedINTEL);
1102 for (size_t J = I; J < std::min(a: I + MaxNumElements, b: NumElements); ++J)
1103 MIBCont.addUse(RegNo: FieldTypes[J]);
1104 }
1105 return MIBStruct;
1106 });
1107
1108 if (Decorator)
1109 Decorator(SPVType->defs().begin()->getReg());
1110
1111 return SPVType;
1112}
1113
1114SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSpecialType(
1115 const Type *Ty, MachineIRBuilder &MIRBuilder,
1116 SPIRV::AccessQualifier::AccessQualifier AccQual) {
1117 assert(isSpecialOpaqueType(Ty) && "Not a special opaque builtin type");
1118 return SPIRV::lowerBuiltinType(Type: Ty, AccessQual: AccQual, MIRBuilder, GR: this);
1119}
1120
1121SPIRVTypeInst SPIRVGlobalRegistry::getOpTypePointer(
1122 SPIRV::StorageClass::StorageClass SC, SPIRVTypeInst ElemType,
1123 MachineIRBuilder &MIRBuilder, Register Reg) {
1124 // Check if we should use untyped pointers.
1125 const SPIRVSubtarget &ST =
1126 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
1127 if (shouldUseUntypedPointer(ElemType, ST))
1128 return getOrCreateSPIRVUntypedPointerType(SC, MIRBuilder);
1129
1130 if (!Reg.isValid())
1131 Reg = createTypeVReg(MIRBuilder);
1132
1133 return createConstOrTypeAtFunctionEntry(MIRBuilder, Op: [&](MachineIRBuilder
1134 &MIRBuilder) {
1135 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypePointer)
1136 .addDef(RegNo: Reg)
1137 .addImm(Val: static_cast<uint32_t>(SC))
1138 .addUse(RegNo: getSPIRVTypeID(SpirvType: ElemType));
1139 });
1140}
1141
1142SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeFunction(
1143 const FunctionType *Ty, SPIRVTypeInst RetType,
1144 const SmallVectorImpl<SPIRVTypeInst> &ArgTypes,
1145 MachineIRBuilder &MIRBuilder) {
1146 const SPIRVSubtarget *ST =
1147 static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
1148 if (Ty->isVarArg() && ST->isShader()) {
1149 Function &Fn = MIRBuilder.getMF().getFunction();
1150 Ty->getContext().diagnose(DI: DiagnosticInfoUnsupported(
1151 Fn, "SPIR-V shaders do not support variadic functions",
1152 MIRBuilder.getDebugLoc()));
1153 }
1154 return createConstOrTypeAtFunctionEntry(MIRBuilder, Op: [&](MachineIRBuilder
1155 &MIRBuilder) {
1156 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeFunction)
1157 .addDef(RegNo: createTypeVReg(MIRBuilder))
1158 .addUse(RegNo: getSPIRVTypeID(SpirvType: RetType));
1159 for (auto &ArgType : ArgTypes)
1160 MIB.addUse(RegNo: getSPIRVTypeID(SpirvType: ArgType));
1161 return MIB;
1162 });
1163}
1164
1165SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeFunctionWithArgs(
1166 const Type *Ty, SPIRVTypeInst RetType,
1167 const SmallVectorImpl<SPIRVTypeInst> &ArgTypes,
1168 MachineIRBuilder &MIRBuilder) {
1169 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: &MIRBuilder.getMF()))
1170 return MI;
1171 const MachineInstr *NewMI =
1172 getOpTypeFunction(Ty: cast<FunctionType>(Val: Ty), RetType, ArgTypes, MIRBuilder);
1173 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
1174 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
1175}
1176
1177SPIRVTypeInst SPIRVGlobalRegistry::findSPIRVType(
1178 const Type *Ty, MachineIRBuilder &MIRBuilder,
1179 SPIRV::AccessQualifier::AccessQualifier AccQual,
1180 bool ExplicitLayoutRequired, bool EmitIR) {
1181 const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
1182 // Treat <1 x T> as T if the SPV_EXT_long_vector extension is not available.
1183 if (auto *FVT = dyn_cast<FixedVectorType>(Val: Ty);
1184 FVT && FVT->getNumElements() == 1 &&
1185 !STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))
1186 return findSPIRVType(Ty: FVT->getElementType(), MIRBuilder, AccQual,
1187 ExplicitLayoutRequired, EmitIR);
1188 Ty = adjustIntTypeByWidth(Ty);
1189 // TODO: findMI needs to know if a layout is required.
1190 if (const MachineInstr *MI =
1191 findMI(T: Ty, RequiresExplicitLayout: ExplicitLayoutRequired, MF: &MIRBuilder.getMF()))
1192 return MI;
1193 if (auto It = ForwardPointerTypes.find(Val: Ty); It != ForwardPointerTypes.end())
1194 return It->second;
1195 return restOfCreateSPIRVType(Type: Ty, MIRBuilder, AccessQual: AccQual, ExplicitLayoutRequired,
1196 EmitIR);
1197}
1198
1199Register SPIRVGlobalRegistry::getSPIRVTypeID(SPIRVTypeInst SpirvType) const {
1200 assert(SpirvType && "Attempting to get type id for nullptr type.");
1201 if (SpirvType->getOpcode() == SPIRV::OpTypeForwardPointer ||
1202 SpirvType->getOpcode() == SPIRV::OpTypeStructContinuedINTEL)
1203 return SpirvType->uses().begin()->getReg();
1204 return SpirvType->defs().begin()->getReg();
1205}
1206
1207// We need to use a new LLVM integer type if there is a mismatch between
1208// number of bits in LLVM and SPIRV integer types to let DuplicateTracker
1209// ensure uniqueness of a SPIRV type by the corresponding LLVM type. Without
1210// such an adjustment SPIRVGlobalRegistry::getOpTypeInt() could create the
1211// same "OpTypeInt 8" type for a series of LLVM integer types with number of
1212// bits less than 8. This would lead to duplicate type definitions
1213// eventually due to the method that DuplicateTracker utilizes to reason
1214// about uniqueness of type records.
1215const Type *SPIRVGlobalRegistry::adjustIntTypeByWidth(const Type *Ty) const {
1216 if (auto IType = dyn_cast<IntegerType>(Val: Ty)) {
1217 unsigned SrcBitWidth = IType->getBitWidth();
1218 if (SrcBitWidth > 1) {
1219 unsigned BitWidth = adjustOpTypeIntWidth(Width: SrcBitWidth);
1220 // Maybe change source LLVM type to keep DuplicateTracker consistent.
1221 if (SrcBitWidth != BitWidth)
1222 Ty = IntegerType::get(C&: Ty->getContext(), NumBits: BitWidth);
1223 }
1224 }
1225 return Ty;
1226}
1227
1228SPIRVTypeInst SPIRVGlobalRegistry::createSPIRVType(
1229 const Type *Ty, MachineIRBuilder &MIRBuilder,
1230 SPIRV::AccessQualifier::AccessQualifier AccQual,
1231 bool ExplicitLayoutRequired, bool EmitIR) {
1232 if (isSpecialOpaqueType(Ty))
1233 return getOrCreateSpecialType(Ty, MIRBuilder, AccQual);
1234
1235 if (const MachineInstr *MI =
1236 findMI(T: Ty, RequiresExplicitLayout: ExplicitLayoutRequired, MF: &MIRBuilder.getMF()))
1237 return MI;
1238
1239 if (auto IType = dyn_cast<IntegerType>(Val: Ty)) {
1240 const unsigned Width = IType->getBitWidth();
1241 return Width == 1 ? getOpTypeBool(MIRBuilder)
1242 : getOpTypeInt(Width, MIRBuilder, IsSigned: false);
1243 }
1244 if (Ty->isFloatingPointTy()) {
1245 if (Ty->isFP128Ty() || Ty->isPPC_FP128Ty())
1246 llvm::reportFatalUsageError(reason: "fp128 is not supported in SPIR-V");
1247 if (Ty->isBFloatTy()) {
1248 return getOpTypeFloat(Width: Ty->getPrimitiveSizeInBits(), MIRBuilder,
1249 FPEncode: SPIRV::FPEncoding::BFloat16KHR);
1250 } else {
1251 return getOpTypeFloat(Width: Ty->getPrimitiveSizeInBits(), MIRBuilder);
1252 }
1253 }
1254 if (Ty->isVoidTy())
1255 return getOpTypeVoid(MIRBuilder);
1256 if (Ty->isVectorTy()) {
1257 SPIRVTypeInst El =
1258 findSPIRVType(Ty: cast<FixedVectorType>(Val: Ty)->getElementType(), MIRBuilder,
1259 AccQual, ExplicitLayoutRequired, EmitIR);
1260 unsigned NumElts = cast<FixedVectorType>(Val: Ty)->getNumElements();
1261 const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
1262 if (isLongVectorEXT(Ty) &&
1263 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))
1264 return getOpTypeVectorIdEXT(NumElems: NumElts, ElemType: El, MIRBuilder);
1265 return getOpTypeVector(NumElems: NumElts, ElemType: El, MIRBuilder);
1266 }
1267 if (Ty->isArrayTy()) {
1268 SPIRVTypeInst El = findSPIRVType(Ty: Ty->getArrayElementType(), MIRBuilder,
1269 AccQual, ExplicitLayoutRequired, EmitIR);
1270 return getOpTypeArray(NumElems: Ty->getArrayNumElements(), ElemType: El, MIRBuilder,
1271 ExplicitLayoutRequired, EmitIR);
1272 }
1273 if (auto SType = dyn_cast<StructType>(Val: Ty)) {
1274 if (SType->isOpaque())
1275 return getOpTypeOpaque(Ty: SType, MIRBuilder);
1276
1277 StructOffsetDecorator Decorator = nullptr;
1278 if (ExplicitLayoutRequired) {
1279 Decorator = [&MIRBuilder, SType, this](Register Reg) {
1280 addStructOffsetDecorations(Reg, Ty: const_cast<StructType *>(SType),
1281 MIRBuilder);
1282 };
1283 }
1284 return getOpTypeStruct(Ty: SType, MIRBuilder, AccQual, Decorator: std::move(Decorator),
1285 EmitIR);
1286 }
1287 if (auto FType = dyn_cast<FunctionType>(Val: Ty)) {
1288 SPIRVTypeInst RetTy =
1289 findSPIRVType(Ty: FType->getReturnType(), MIRBuilder, AccQual,
1290 ExplicitLayoutRequired, EmitIR);
1291 SmallVector<SPIRVTypeInst, 4> ParamTypes;
1292 for (const auto &ParamTy : FType->params())
1293 ParamTypes.push_back(Elt: findSPIRVType(Ty: ParamTy, MIRBuilder, AccQual,
1294 ExplicitLayoutRequired, EmitIR));
1295 return getOpTypeFunction(Ty: FType, RetType: RetTy, ArgTypes: ParamTypes, MIRBuilder);
1296 }
1297
1298 unsigned AddrSpace = typeToAddressSpace(Ty);
1299
1300 // Get access to information about available extensions
1301 const SPIRVSubtarget *ST =
1302 static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
1303 auto SC = addressSpaceToStorageClass(AddrSpace, STI: *ST);
1304
1305 SPIRVTypeInst SpvElementType = nullptr;
1306 Type *ElemTy = ::getPointeeType(Ty);
1307 if (ElemTy && isa<FunctionType>(Val: ElemTy) &&
1308 !ST->canUseExtension(E: SPIRV::Extension::SPV_INTEL_function_pointers))
1309 ElemTy = nullptr;
1310 if (ElemTy)
1311 SpvElementType = getOrCreateSPIRVType(Type: ElemTy, MIRBuilder, AQ: AccQual, EmitIR);
1312 else
1313 SpvElementType = getOrCreateSPIRVIntegerType(BitWidth: 8, MIRBuilder);
1314
1315 if (!ElemTy) {
1316 ElemTy = Type::getInt8Ty(C&: MIRBuilder.getContext());
1317 }
1318
1319 // If we have forward pointer associated with this type, use its register
1320 // operand to create OpTypePointer.
1321 if (auto It = ForwardPointerTypes.find(Val: Ty); It != ForwardPointerTypes.end()) {
1322 Register Reg = getSPIRVTypeID(SpirvType: It->second);
1323 // TODO: what does getOpTypePointer do?
1324 return getOpTypePointer(SC, ElemType: SpvElementType, MIRBuilder, Reg);
1325 }
1326
1327 return getOrCreateSPIRVPointerType(BaseType: ElemTy, MIRBuilder, SC);
1328}
1329
1330SPIRVTypeInst SPIRVGlobalRegistry::restOfCreateSPIRVType(
1331 const Type *Ty, MachineIRBuilder &MIRBuilder,
1332 SPIRV::AccessQualifier::AccessQualifier AccessQual,
1333 bool ExplicitLayoutRequired, bool EmitIR) {
1334 // TODO: Could this create a problem if one requires an explicit layout, and
1335 // the next time it does not?
1336 if (TypesInProcessing.count(Ptr: Ty) && !isPointerTyOrWrapper(Ty))
1337 return nullptr;
1338 TypesInProcessing.insert(Ptr: Ty);
1339 SPIRVTypeInst SpirvType = createSPIRVType(Ty, MIRBuilder, AccQual: AccessQual,
1340 ExplicitLayoutRequired, EmitIR);
1341 TypesInProcessing.erase(Ptr: Ty);
1342 VRegToTypeMap[&MIRBuilder.getMF()][getSPIRVTypeID(SpirvType)] = SpirvType;
1343
1344 // TODO: We could end up with two SPIR-V types pointing to the same llvm type.
1345 // Is that a problem?
1346 SPIRVToLLVMType[SpirvType] = unifyPtrType(Ty);
1347
1348 if (SpirvType->getOpcode() == SPIRV::OpTypeForwardPointer ||
1349 SpirvType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR ||
1350 findMI(T: Ty, RequiresExplicitLayout: false, MF: &MIRBuilder.getMF()) || isSpecialOpaqueType(Ty))
1351 return SpirvType;
1352
1353 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty);
1354 ExtTy && isTypedPointerWrapper(ExtTy))
1355 add(PointeeTy: ExtTy->getTypeParameter(i: 0), AddressSpace: ExtTy->getIntParameter(i: 0), MI: SpirvType);
1356 else if (!isPointerTy(T: Ty))
1357 add(T: Ty, RequiresExplicitLayout: ExplicitLayoutRequired, MI: SpirvType);
1358 else if (isTypedPointerTy(T: Ty))
1359 add(PointeeTy: cast<TypedPointerType>(Val: Ty)->getElementType(),
1360 AddressSpace: getPointerAddressSpace(T: Ty), MI: SpirvType);
1361 else
1362 add(PointeeTy: Type::getInt8Ty(C&: MIRBuilder.getMF().getFunction().getContext()),
1363 AddressSpace: getPointerAddressSpace(T: Ty), MI: SpirvType);
1364 return SpirvType;
1365}
1366
1367SPIRVTypeInst
1368SPIRVGlobalRegistry::getSPIRVTypeForVReg(Register VReg,
1369 const MachineFunction *MF) const {
1370 auto t = VRegToTypeMap.find(Val: MF ? MF : CurMF);
1371 if (t != VRegToTypeMap.end()) {
1372 auto tt = t->second.find(Val: VReg);
1373 if (tt != t->second.end())
1374 return tt->second;
1375 }
1376 return nullptr;
1377}
1378
1379SPIRVTypeInst SPIRVGlobalRegistry::getResultType(Register VReg,
1380 MachineFunction *MF) {
1381 if (!MF)
1382 MF = CurMF;
1383 MachineInstr *Instr = getVRegDef(MRI&: MF->getRegInfo(), Reg: VReg);
1384 return getSPIRVTypeForVReg(VReg: Instr->getOperand(i: 1).getReg(), MF);
1385}
1386
1387SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVType(
1388 const Type *Ty, MachineIRBuilder &MIRBuilder,
1389 SPIRV::AccessQualifier::AccessQualifier AccessQual,
1390 bool ExplicitLayoutRequired, bool EmitIR) {
1391 // SPIR-V doesn't support single-element vectors. Treat <1 x T> as T if the
1392 // SPV_EXT_long_vector extension is not available.
1393 const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
1394 if (auto *FVT = dyn_cast<FixedVectorType>(Val: Ty);
1395 FVT && FVT->getNumElements() == 1 &&
1396 !STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))
1397 return getOrCreateSPIRVType(Ty: FVT->getElementType(), MIRBuilder, AccessQual,
1398 ExplicitLayoutRequired, EmitIR);
1399 const MachineFunction *MF = &MIRBuilder.getMF();
1400 Register Reg;
1401 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty);
1402 ExtTy && isTypedPointerWrapper(ExtTy))
1403 Reg = find(PointeeTy: ExtTy->getTypeParameter(i: 0), AddressSpace: ExtTy->getIntParameter(i: 0), MF);
1404 else if (!isPointerTy(T: Ty))
1405 Reg = find(T: Ty = adjustIntTypeByWidth(Ty), RequiresExplicitLayout: ExplicitLayoutRequired, MF);
1406 else if (isTypedPointerTy(T: Ty))
1407 Reg = find(PointeeTy: cast<TypedPointerType>(Val: Ty)->getElementType(),
1408 AddressSpace: getPointerAddressSpace(T: Ty), MF);
1409 else
1410 Reg = find(PointeeTy: Type::getInt8Ty(C&: MIRBuilder.getMF().getFunction().getContext()),
1411 AddressSpace: getPointerAddressSpace(T: Ty), MF);
1412 if (Reg.isValid() && !isSpecialOpaqueType(Ty))
1413 return getSPIRVTypeForVReg(VReg: Reg);
1414
1415 TypesInProcessing.clear();
1416 SPIRVTypeInst STy = restOfCreateSPIRVType(Ty, MIRBuilder, AccessQual,
1417 ExplicitLayoutRequired, EmitIR);
1418 // Create normal pointer types for the corresponding OpTypeForwardPointers.
1419 for (auto &CU : ForwardPointerTypes) {
1420 // Pointer type themselves do not require an explicit layout. The types
1421 // they pointer to might, but that is taken care of when creating the type.
1422 bool PtrNeedsLayout = false;
1423 const Type *Ty2 = CU.first;
1424 SPIRVTypeInst STy2 = CU.second;
1425 if ((Reg = find(T: Ty2, RequiresExplicitLayout: PtrNeedsLayout, MF)).isValid())
1426 STy2 = getSPIRVTypeForVReg(VReg: Reg);
1427 else
1428 STy2 = restOfCreateSPIRVType(Ty: Ty2, MIRBuilder, AccessQual, ExplicitLayoutRequired: PtrNeedsLayout,
1429 EmitIR);
1430 if (Ty == Ty2)
1431 STy = STy2;
1432 }
1433 ForwardPointerTypes.clear();
1434 return STy;
1435}
1436
1437bool SPIRVGlobalRegistry::isScalarOfType(Register VReg,
1438 unsigned TypeOpcode) const {
1439 SPIRVTypeInst Type = getSPIRVTypeForVReg(VReg);
1440 assert(Type && "isScalarOfType VReg has no type assigned");
1441 return Type->getOpcode() == TypeOpcode;
1442}
1443
1444bool SPIRVGlobalRegistry::isScalarOrVectorOfType(Register VReg,
1445 unsigned TypeOpcode) const {
1446 SPIRVTypeInst Type = getSPIRVTypeForVReg(VReg);
1447 assert(Type && "isScalarOrVectorOfType VReg has no type assigned");
1448 if (Type->getOpcode() == TypeOpcode)
1449 return true;
1450 if (!isVectorType(SPVTy: Type))
1451 return false;
1452 Register ScalarTypeVReg = Type->getOperand(i: 1).getReg();
1453 SPIRVTypeInst ScalarType = getSPIRVTypeForVReg(VReg: ScalarTypeVReg);
1454 return ScalarType->getOpcode() == TypeOpcode;
1455}
1456
1457bool SPIRVGlobalRegistry::isResourceType(SPIRVTypeInst Type) const {
1458 switch (Type->getOpcode()) {
1459 case SPIRV::OpTypeImage:
1460 case SPIRV::OpTypeSampler:
1461 case SPIRV::OpTypeSampledImage:
1462 return true;
1463 case SPIRV::OpTypeStruct:
1464 return BlockDecoratedTypes.contains(V: Type);
1465 default:
1466 return false;
1467 }
1468 return false;
1469}
1470unsigned
1471SPIRVGlobalRegistry::getScalarOrVectorComponentCount(Register VReg) const {
1472 return getScalarOrVectorComponentCount(Type: getSPIRVTypeForVReg(VReg));
1473}
1474
1475unsigned
1476SPIRVGlobalRegistry::getScalarOrVectorComponentCount(SPIRVTypeInst Type) const {
1477 if (!Type)
1478 return 0;
1479 if (isVectorType(SPVTy: Type))
1480 return (Type->getOpcode() == SPIRV::OpTypeVector)
1481 ? static_cast<unsigned>(Type->getOperand(i: 2).getImm())
1482 : foldImm(MO: Type->getOperand(i: 2), MRI: &CurMF->getRegInfo());
1483 return 1;
1484}
1485
1486SPIRVTypeInst
1487SPIRVGlobalRegistry::getScalarOrVectorComponentType(SPIRVTypeInst Type) const {
1488 if (!Type)
1489 return nullptr;
1490 Register ScalarReg = (isVectorType(SPVTy: Type)) ? Type->getOperand(i: 1).getReg()
1491 : Type->getOperand(i: 0).getReg();
1492 SPIRVTypeInst ScalarType = getSPIRVTypeForVReg(VReg: ScalarReg);
1493 assert(isScalarOrVectorOfType(Type->getOperand(0).getReg(),
1494 ScalarType->getOpcode()));
1495 return ScalarType;
1496}
1497
1498unsigned
1499SPIRVGlobalRegistry::getScalarOrVectorBitWidth(SPIRVTypeInst Type) const {
1500 assert(Type && "Invalid Type pointer");
1501 SPIRVTypeInst ScalarType = getScalarOrVectorComponentType(Type);
1502 if (ScalarType->getOpcode() == SPIRV::OpTypeInt ||
1503 ScalarType->getOpcode() == SPIRV::OpTypeFloat)
1504 return ScalarType->getOperand(i: 1).getImm();
1505 if (ScalarType->getOpcode() == SPIRV::OpTypeBool)
1506 return 1;
1507 if (ScalarType->getOpcode() == SPIRV::OpTypePointer)
1508 return getPointerSize(); // TODO: does not work for different per AS sizes.
1509 llvm_unreachable(
1510 "Attempting to get bit width of non-integer/float/pointer type.");
1511}
1512
1513unsigned SPIRVGlobalRegistry::getNumScalarOrVectorTotalBitWidth(
1514 SPIRVTypeInst Type) const {
1515 assert(Type && "Invalid Type pointer");
1516 unsigned NumElements = getScalarOrVectorComponentCount(Type);
1517 SPIRVTypeInst ScalarType = getScalarOrVectorComponentType(Type);
1518 return ScalarType->getOpcode() == SPIRV::OpTypeInt ||
1519 ScalarType->getOpcode() == SPIRV::OpTypeFloat
1520 ? NumElements * ScalarType->getOperand(i: 1).getImm()
1521 : 0;
1522}
1523
1524bool SPIRVGlobalRegistry::shouldKeepTypedPtrType(SPIRVTypeInst ElemType) const {
1525 // A function pointer has to keep its function type, which an untyped pointer
1526 // cannot express.
1527 if (ElemType && ElemType->getOpcode() == SPIRV::OpTypeFunction)
1528 return true;
1529 auto It = SPIRVToLLVMType.find(Val: ElemType);
1530 return It != SPIRVToLLVMType.end() && It->second &&
1531 isSpecialOpaqueType(Ty: It->second);
1532}
1533
1534bool SPIRVGlobalRegistry::shouldUseUntypedPointer(
1535 SPIRVTypeInst ElemType, const SPIRVSubtarget &ST) const {
1536 // Shaders keep typed pointers, as this implementation targets compute.
1537 return ST.canUseExtension(E: SPIRV::Extension::SPV_KHR_untyped_pointers) &&
1538 !ST.isShader() && !shouldKeepTypedPtrType(ElemType);
1539}
1540
1541SPIRVTypeInst
1542SPIRVGlobalRegistry::retrieveScalarOrVectorIntType(SPIRVTypeInst Type) const {
1543 SPIRVTypeInst ScalarType = getScalarOrVectorComponentType(Type);
1544 return ScalarType && ScalarType->getOpcode() == SPIRV::OpTypeInt ? ScalarType
1545 : nullptr;
1546}
1547
1548bool SPIRVGlobalRegistry::isScalarOrVectorSigned(SPIRVTypeInst Type) const {
1549 SPIRVTypeInst IntType = retrieveScalarOrVectorIntType(Type);
1550 return IntType && IntType->getOperand(i: 2).getImm() != 0;
1551}
1552
1553SPIRVTypeInst SPIRVGlobalRegistry::getPointeeType(SPIRVTypeInst PtrType) {
1554 return PtrType && PtrType->getOpcode() == SPIRV::OpTypePointer
1555 ? getSPIRVTypeForVReg(VReg: PtrType->getOperand(i: 2).getReg())
1556 : nullptr;
1557}
1558
1559bool SPIRVGlobalRegistry::isBitcastCompatible(SPIRVTypeInst Type1,
1560 SPIRVTypeInst Type2) const {
1561 if (!Type1 || !Type2)
1562 return false;
1563 // Ignore difference between <1.5 and >=1.5 protocol versions:
1564 // it's valid if either Result Type or Operand is a pointer, and the other
1565 // is a pointer, an integer scalar, or an integer vector.
1566 if (Type1.isPointer() &&
1567 (Type2.isPointer() || retrieveScalarOrVectorIntType(Type: Type2)))
1568 return true;
1569 if (Type2.isPointer() &&
1570 (Type1.isPointer() || retrieveScalarOrVectorIntType(Type: Type1)))
1571 return true;
1572 unsigned Bits1 = getNumScalarOrVectorTotalBitWidth(Type: Type1),
1573 Bits2 = getNumScalarOrVectorTotalBitWidth(Type: Type2);
1574 return Bits1 > 0 && Bits1 == Bits2;
1575}
1576
1577SPIRV::StorageClass::StorageClass
1578SPIRVGlobalRegistry::getPointerStorageClass(Register VReg) const {
1579 SPIRVTypeInst Type = getSPIRVTypeForVReg(VReg);
1580 assert(Type && Type.isPointer() && Type->getOperand(1).isImm() &&
1581 "Pointer type is expected");
1582 return getPointerStorageClass(Type);
1583}
1584
1585SPIRV::StorageClass::StorageClass
1586SPIRVGlobalRegistry::getPointerStorageClass(SPIRVTypeInst Type) const {
1587 return static_cast<SPIRV::StorageClass::StorageClass>(
1588 Type->getOperand(i: 1).getImm());
1589}
1590
1591SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateVulkanBufferType(
1592 MachineIRBuilder &MIRBuilder, Type *ElemType,
1593 SPIRV::StorageClass::StorageClass SC, bool IsWritable, bool EmitIr) {
1594 auto Key = SPIRV::irhandle_vkbuffer(ElementType: ElemType, SC, IsWriteable: IsWritable);
1595 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1596 return MI;
1597
1598 bool ExplicitLayoutRequired = storageClassRequiresExplictLayout(SC);
1599 // We need to get the SPIR-V type for the element here, so we can add the
1600 // decoration to it.
1601 auto *T = StructType::create(Elements: ElemType);
1602 SPIRVTypeInst BlockType =
1603 getOrCreateSPIRVType(Ty: T, MIRBuilder, AccessQual: SPIRV::AccessQualifier::None,
1604 ExplicitLayoutRequired, EmitIR: EmitIr);
1605
1606 buildOpDecorate(Reg: BlockType->defs().begin()->getReg(), MIRBuilder,
1607 Dec: SPIRV::Decoration::Block, DecArgs: {});
1608 BlockDecoratedTypes.insert(V: BlockType);
1609
1610 if (!IsWritable) {
1611 buildOpMemberDecorate(Reg: BlockType->defs().begin()->getReg(), MIRBuilder,
1612 Dec: SPIRV::Decoration::NonWritable, Member: 0, DecArgs: {});
1613 }
1614
1615 SPIRVTypeInst R =
1616 getOrCreateSPIRVPointerTypeInternal(BaseType: BlockType, MIRBuilder, SC);
1617 add(Handle: Key, MI: R);
1618 return R;
1619}
1620
1621SPIRVTypeInst
1622SPIRVGlobalRegistry::getOrCreatePaddingType(MachineIRBuilder &MIRBuilder) {
1623 auto Key = SPIRV::irhandle_padding();
1624 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1625 return MI;
1626 auto *T = Type::getInt8Ty(C&: MIRBuilder.getContext());
1627 SPIRVTypeInst R = getOrCreateSPIRVIntegerType(BitWidth: 8, MIRBuilder);
1628 finishCreatingSPIRVType(LLVMTy: T, SpirvType: R);
1629 add(Handle: Key, MI: R);
1630 return R;
1631}
1632
1633SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateVulkanPushConstantType(
1634 MachineIRBuilder &MIRBuilder, Type *T) {
1635 const auto SC = SPIRV::StorageClass::PushConstant;
1636
1637 auto Key = SPIRV::irhandle_vkbuffer(ElementType: T, SC, /* IsWritable= */ IsWriteable: false);
1638 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1639 return MI;
1640
1641 // We need to get the SPIR-V type for the element here, so we can add the
1642 // decoration to it.
1643 SPIRVTypeInst BlockType = getOrCreateSPIRVType(
1644 Ty: T, MIRBuilder, AccessQual: SPIRV::AccessQualifier::None,
1645 /* ExplicitLayoutRequired= */ true, /* EmitIr= */ EmitIR: false);
1646
1647 buildOpDecorate(Reg: BlockType->defs().begin()->getReg(), MIRBuilder,
1648 Dec: SPIRV::Decoration::Block, DecArgs: {});
1649 BlockDecoratedTypes.insert(V: BlockType);
1650 SPIRVTypeInst R = BlockType;
1651 add(Handle: Key, MI: R);
1652 return R;
1653}
1654
1655SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateLayoutType(
1656 MachineIRBuilder &MIRBuilder, const TargetExtType *T, bool EmitIr) {
1657 auto Key = SPIRV::handle(Ty: T);
1658 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1659 return MI;
1660
1661 StructType *ST = cast<StructType>(Val: T->getTypeParameter(i: 0));
1662 ArrayRef<uint32_t> Offsets = T->int_params().slice(N: 1);
1663 assert(ST->getNumElements() == Offsets.size());
1664
1665 StructOffsetDecorator Decorator = [&MIRBuilder, &Offsets](Register Reg) {
1666 for (uint32_t I = 0; I < Offsets.size(); ++I) {
1667 buildOpMemberDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::Offset, Member: I,
1668 DecArgs: {Offsets[I]});
1669 }
1670 };
1671
1672 // We need a new OpTypeStruct instruction because decorations will be
1673 // different from a struct with an explicit layout created from a different
1674 // entry point.
1675 SPIRVTypeInst SPIRVStructType =
1676 getOpTypeStruct(Ty: ST, MIRBuilder, AccQual: SPIRV::AccessQualifier::None,
1677 Decorator: std::move(Decorator), EmitIR: EmitIr);
1678 add(Handle: Key, MI: SPIRVStructType);
1679 return SPIRVStructType;
1680}
1681
1682SPIRVTypeInst SPIRVGlobalRegistry::getImageType(
1683 const TargetExtType *ExtensionType,
1684 const SPIRV::AccessQualifier::AccessQualifier Qualifier,
1685 MachineIRBuilder &MIRBuilder) {
1686 assert(ExtensionType->getNumTypeParameters() == 1 &&
1687 "SPIR-V image builtin type must have sampled type parameter!");
1688 const SPIRVTypeInst SampledType =
1689 getOrCreateSPIRVType(Type: ExtensionType->getTypeParameter(i: 0), MIRBuilder,
1690 AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: true);
1691 assert((ExtensionType->getNumIntParameters() == 7 ||
1692 ExtensionType->getNumIntParameters() == 6) &&
1693 "Invalid number of parameters for SPIR-V image builtin!");
1694
1695 SPIRV::AccessQualifier::AccessQualifier accessQualifier =
1696 SPIRV::AccessQualifier::None;
1697 if (ExtensionType->getNumIntParameters() == 7) {
1698 accessQualifier = Qualifier == SPIRV::AccessQualifier::WriteOnly
1699 ? SPIRV::AccessQualifier::WriteOnly
1700 : SPIRV::AccessQualifier::AccessQualifier(
1701 ExtensionType->getIntParameter(i: 6));
1702 }
1703
1704 // Create or get an existing type from GlobalRegistry.
1705 SPIRVTypeInst R = getOrCreateOpTypeImage(
1706 MIRBuilder, SampledType,
1707 Dim: SPIRV::Dim::Dim(ExtensionType->getIntParameter(i: 0)),
1708 Depth: ExtensionType->getIntParameter(i: 1), Arrayed: ExtensionType->getIntParameter(i: 2),
1709 Multisampled: ExtensionType->getIntParameter(i: 3), Sampled: ExtensionType->getIntParameter(i: 4),
1710 ImageFormat: SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(i: 5)),
1711 AccQual: accessQualifier);
1712 SPIRVToLLVMType[R] = ExtensionType;
1713 return R;
1714}
1715
1716SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeImage(
1717 MachineIRBuilder &MIRBuilder, SPIRVTypeInst SampledType,
1718 SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed,
1719 uint32_t Multisampled, uint32_t Sampled,
1720 SPIRV::ImageFormat::ImageFormat ImageFormat,
1721 SPIRV::AccessQualifier::AccessQualifier AccessQual) {
1722 auto Key = SPIRV::irhandle_image(SampledTy: SPIRVToLLVMType.lookup(Val: SampledType), Dim,
1723 Depth, Arrayed, MS: Multisampled, Sampled,
1724 ImageFormat, AQ: AccessQual);
1725 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1726 return MI;
1727 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1728 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1729 auto MIB =
1730 MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeImage)
1731 .addDef(RegNo: createTypeVReg(MIRBuilder))
1732 .addUse(RegNo: getSPIRVTypeID(SpirvType: SampledType))
1733 .addImm(Val: Dim)
1734 .addImm(Val: Depth) // Depth (whether or not it is a Depth image).
1735 .addImm(Val: Arrayed) // Arrayed.
1736 .addImm(Val: Multisampled) // Multisampled (0 = only single-sample).
1737 .addImm(Val: Sampled) // Sampled (0 = usage known at runtime).
1738 .addImm(Val: ImageFormat);
1739 if (AccessQual != SPIRV::AccessQualifier::None)
1740 MIB.addImm(Val: AccessQual);
1741 return MIB;
1742 });
1743 add(Handle: Key, MI: NewMI);
1744 return NewMI;
1745}
1746
1747SPIRVTypeInst
1748SPIRVGlobalRegistry::getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder) {
1749 auto Key = SPIRV::irhandle_sampler();
1750 const MachineFunction *MF = &MIRBuilder.getMF();
1751 if (const MachineInstr *MI = findMI(Handle: Key, MF))
1752 return MI;
1753 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1754 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1755 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeSampler)
1756 .addDef(RegNo: createTypeVReg(MIRBuilder));
1757 });
1758 add(Handle: Key, MI: NewMI);
1759 return NewMI;
1760}
1761
1762SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypePipe(
1763 MachineIRBuilder &MIRBuilder,
1764 SPIRV::AccessQualifier::AccessQualifier AccessQual) {
1765 auto Key = SPIRV::irhandle_pipe(AQ: AccessQual);
1766 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1767 return MI;
1768 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1769 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1770 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypePipe)
1771 .addDef(RegNo: createTypeVReg(MIRBuilder))
1772 .addImm(Val: AccessQual);
1773 });
1774 add(Handle: Key, MI: NewMI);
1775 return NewMI;
1776}
1777
1778SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeDeviceEvent(
1779 MachineIRBuilder &MIRBuilder) {
1780 auto Key = SPIRV::irhandle_event();
1781 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1782 return MI;
1783 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1784 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1785 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeDeviceEvent)
1786 .addDef(RegNo: createTypeVReg(MIRBuilder));
1787 });
1788 add(Handle: Key, MI: NewMI);
1789 return NewMI;
1790}
1791
1792SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeSampledImage(
1793 SPIRVTypeInst ImageType, MachineIRBuilder &MIRBuilder) {
1794 auto Key = SPIRV::irhandle_sampled_image(
1795 SampledTy: SPIRVToLLVMType.lookup(Val: MIRBuilder.getMF().getRegInfo().getVRegDef(
1796 Reg: ImageType->getOperand(i: 1).getReg())),
1797 ImageTy: ImageType);
1798 if (const MachineInstr *MI = findMI(Handle: Key, MF: &MIRBuilder.getMF()))
1799 return MI;
1800 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1801 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1802 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeSampledImage)
1803 .addDef(RegNo: createTypeVReg(MIRBuilder))
1804 .addUse(RegNo: getSPIRVTypeID(SpirvType: ImageType));
1805 });
1806 add(Handle: Key, MI: NewMI);
1807 return NewMI;
1808}
1809
1810SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeCoopMatr(
1811 MachineIRBuilder &MIRBuilder, const TargetExtType *ExtensionType,
1812 SPIRVTypeInst ElemType, uint32_t Scope, uint32_t Rows, uint32_t Columns,
1813 uint32_t Use, bool EmitIR) {
1814 if (const MachineInstr *MI =
1815 findMI(T: ExtensionType, RequiresExplicitLayout: false, MF: &MIRBuilder.getMF()))
1816 return MI;
1817 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1818 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1819 SPIRVTypeInst SpvTypeInt32 =
1820 getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
1821 const Type *ET = getTypeForSPIRVType(Ty: ElemType);
1822 if (ET->isIntegerTy() && ET->getIntegerBitWidth() == 4 &&
1823 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget())
1824 .canUseExtension(E: SPIRV::Extension::SPV_INTEL_int4)) {
1825 MIRBuilder.buildInstr(Opcode: SPIRV::OpCapability)
1826 .addImm(Val: SPIRV::Capability::Int4CooperativeMatrixINTEL);
1827 }
1828 return MIRBuilder.buildInstr(Opcode: SPIRV::OpTypeCooperativeMatrixKHR)
1829 .addDef(RegNo: createTypeVReg(MIRBuilder))
1830 .addUse(RegNo: getSPIRVTypeID(SpirvType: ElemType))
1831 .addUse(RegNo: buildConstantInt(Val: Scope, MIRBuilder, SpvType: SpvTypeInt32, EmitIR))
1832 .addUse(RegNo: buildConstantInt(Val: Rows, MIRBuilder, SpvType: SpvTypeInt32, EmitIR))
1833 .addUse(RegNo: buildConstantInt(Val: Columns, MIRBuilder, SpvType: SpvTypeInt32, EmitIR))
1834 .addUse(RegNo: buildConstantInt(Val: Use, MIRBuilder, SpvType: SpvTypeInt32, EmitIR));
1835 });
1836 add(T: ExtensionType, RequiresExplicitLayout: false, MI: NewMI);
1837 return NewMI;
1838}
1839
1840SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeByOpcode(
1841 const Type *Ty, MachineIRBuilder &MIRBuilder, unsigned Opcode) {
1842 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: &MIRBuilder.getMF()))
1843 return MI;
1844 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1845 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1846 return MIRBuilder.buildInstr(Opcode).addDef(RegNo: createTypeVReg(MIRBuilder));
1847 });
1848 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
1849 return NewMI;
1850}
1851
1852SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateUnknownType(
1853 const Type *Ty, MachineIRBuilder &MIRBuilder, unsigned Opcode,
1854 const ArrayRef<MCOperand> Operands) {
1855 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: &MIRBuilder.getMF()))
1856 return MI;
1857 Register ResVReg = createTypeVReg(MIRBuilder);
1858 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1859 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1860 MachineInstrBuilder MIB = MIRBuilder.buildInstr(Opcode: SPIRV::UNKNOWN_type)
1861 .addDef(RegNo: ResVReg)
1862 .addImm(Val: Opcode);
1863 for (MCOperand Operand : Operands) {
1864 if (Operand.isReg()) {
1865 MIB.addUse(RegNo: Operand.getReg());
1866 } else if (Operand.isImm()) {
1867 MIB.addImm(Val: Operand.getImm());
1868 }
1869 }
1870 return MIB;
1871 });
1872 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
1873 return NewMI;
1874}
1875
1876// Returns nullptr if unable to recognize SPIRV type name
1877SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
1878 StringRef TypeStr, MachineIRBuilder &MIRBuilder, bool EmitIR,
1879 SPIRV::StorageClass::StorageClass SC,
1880 SPIRV::AccessQualifier::AccessQualifier AQ) {
1881 unsigned VecElts = 0;
1882 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1883
1884 // Parse strings representing either a SPIR-V or OpenCL builtin type.
1885 if (hasBuiltinTypePrefix(Name: TypeStr))
1886 return getOrCreateSPIRVType(Ty: SPIRV::parseBuiltinTypeNameToTargetExtType(
1887 TypeName: TypeStr.str(), Context&: MIRBuilder.getContext()),
1888 MIRBuilder, AccessQual: AQ, ExplicitLayoutRequired: false, EmitIR: true);
1889
1890 // Parse type name in either "typeN" or "type vector[N]" format, where
1891 // N is the number of elements of the vector.
1892 Type *Ty;
1893
1894 Ty = parseBasicTypeName(TypeName&: TypeStr, Ctx);
1895 if (!Ty)
1896 // Unable to recognize SPIRV type name
1897 return nullptr;
1898
1899 SPIRVTypeInst SpirvTy = getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual: AQ, ExplicitLayoutRequired: false, EmitIR: true);
1900
1901 // Handle "type*" or "type* vector[N]".
1902 if (TypeStr.consume_front(Prefix: "*"))
1903 SpirvTy = getOrCreateSPIRVPointerType(BaseType: Ty, MIRBuilder, SC);
1904
1905 // Handle "typeN*" or "type vector[N]*".
1906 bool IsPtrToVec = TypeStr.consume_back(Suffix: "*");
1907
1908 if (TypeStr.consume_front(Prefix: " vector[")) {
1909 TypeStr = TypeStr.substr(Start: 0, N: TypeStr.find(C: ']'));
1910 }
1911 TypeStr.getAsInteger(Radix: 10, Result&: VecElts);
1912 if (VecElts > 0)
1913 SpirvTy = getOrCreateSPIRVVectorType(BaseType: SpirvTy, NumElements: VecElts, MIRBuilder, EmitIR);
1914
1915 if (IsPtrToVec)
1916 SpirvTy = getOrCreateSPIRVPointerType(BaseType: SpirvTy, MIRBuilder, SC);
1917
1918 return SpirvTy;
1919}
1920
1921SPIRVTypeInst
1922SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(unsigned BitWidth,
1923 MachineIRBuilder &MIRBuilder) {
1924 return getOrCreateSPIRVType(
1925 Ty: IntegerType::get(C&: MIRBuilder.getMF().getFunction().getContext(), NumBits: BitWidth),
1926 MIRBuilder, AccessQual: SPIRV::AccessQualifier::ReadWrite, ExplicitLayoutRequired: false, EmitIR: true);
1927}
1928
1929SPIRVTypeInst
1930SPIRVGlobalRegistry::finishCreatingSPIRVType(const Type *LLVMTy,
1931 SPIRVTypeInst SpirvType) {
1932 assert(CurMF == SpirvType->getMF());
1933 VRegToTypeMap[CurMF][getSPIRVTypeID(SpirvType)] = SpirvType;
1934 SPIRVToLLVMType[SpirvType] = unifyPtrType(Ty: LLVMTy);
1935 return SpirvType;
1936}
1937
1938SPIRVTypeInst
1939SPIRVGlobalRegistry::getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I,
1940 const SPIRVInstrInfo &TII,
1941 unsigned SPIRVOPcode, Type *Ty) {
1942 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: CurMF))
1943 return MI;
1944 MachineBasicBlock &DepMBB = I.getMF()->front();
1945 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
1946 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
1947 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
1948 auto NewTypeMI = BuildMI(BB&: MIRBuilder.getMBB(), I&: *MIRBuilder.getInsertPt(),
1949 MIMD: MIRBuilder.getDL(), MCID: TII.get(Opcode: SPIRVOPcode))
1950 .addDef(RegNo: createTypeVReg(MRI&: CurMF->getRegInfo()))
1951 .addImm(Val: BitWidth);
1952 // Don't add Encoding to FP type
1953 if (!Ty->isFloatTy()) {
1954 return NewTypeMI.addImm(Val: 0);
1955 } else {
1956 return NewTypeMI;
1957 }
1958 });
1959 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
1960 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
1961}
1962
1963SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(
1964 unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) {
1965 // Maybe adjust bit width to keep DuplicateTracker consistent. Without
1966 // such an adjustment SPIRVGlobalRegistry::getOpTypeInt() could create, for
1967 // example, the same "OpTypeInt 8" type for a series of LLVM integer types
1968 // with number of bits less than 8, causing duplicate type definitions.
1969 if (BitWidth > 1)
1970 BitWidth = adjustOpTypeIntWidth(Width: BitWidth);
1971 Type *LLVMTy = IntegerType::get(C&: CurMF->getFunction().getContext(), NumBits: BitWidth);
1972 return getOrCreateSPIRVType(BitWidth, I, TII, SPIRVOPcode: SPIRV::OpTypeInt, Ty: LLVMTy);
1973}
1974
1975SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVFloatType(
1976 unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) {
1977 LLVMContext &Ctx = CurMF->getFunction().getContext();
1978 Type *LLVMTy;
1979 switch (BitWidth) {
1980 case 16:
1981 LLVMTy = Type::getHalfTy(C&: Ctx);
1982 break;
1983 case 32:
1984 LLVMTy = Type::getFloatTy(C&: Ctx);
1985 break;
1986 case 64:
1987 LLVMTy = Type::getDoubleTy(C&: Ctx);
1988 break;
1989 default:
1990 llvm_unreachable("Bit width is of unexpected size.");
1991 }
1992 return getOrCreateSPIRVType(BitWidth, I, TII, SPIRVOPcode: SPIRV::OpTypeFloat, Ty: LLVMTy);
1993}
1994
1995SPIRVTypeInst
1996SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder,
1997 bool EmitIR) {
1998 return getOrCreateSPIRVType(
1999 Ty: IntegerType::get(C&: MIRBuilder.getMF().getFunction().getContext(), NumBits: 1),
2000 MIRBuilder, AccessQual: SPIRV::AccessQualifier::ReadWrite, ExplicitLayoutRequired: false, EmitIR);
2001}
2002
2003SPIRVTypeInst
2004SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineInstr &I,
2005 const SPIRVInstrInfo &TII) {
2006 Type *Ty = IntegerType::get(C&: CurMF->getFunction().getContext(), NumBits: 1);
2007 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: CurMF))
2008 return MI;
2009 MachineBasicBlock &DepMBB = I.getMF()->front();
2010 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
2011 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
2012 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
2013 return BuildMI(BB&: MIRBuilder.getMBB(), I&: *MIRBuilder.getInsertPt(),
2014 MIMD: MIRBuilder.getDL(), MCID: TII.get(Opcode: SPIRV::OpTypeBool))
2015 .addDef(RegNo: createTypeVReg(MRI&: CurMF->getRegInfo()));
2016 });
2017 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
2018 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
2019}
2020
2021SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
2022 SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder,
2023 bool EmitIR) {
2024 return getOrCreateSPIRVType(
2025 Ty: FixedVectorType::get(ElementType: const_cast<Type *>(getTypeForSPIRVType(Ty: BaseType)),
2026 NumElts: NumElements),
2027 MIRBuilder, AccessQual: SPIRV::AccessQualifier::ReadWrite, ExplicitLayoutRequired: false, EmitIR);
2028}
2029
2030SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
2031 SPIRVTypeInst BaseType, unsigned NumElements, MachineInstr &I,
2032 const SPIRVInstrInfo &TII) {
2033 const auto &STI = I.getMF()->getSubtarget<SPIRVSubtarget>();
2034 if (!STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))
2035 // At this point of time all 1-element vectors are resolved. Add assertion
2036 // to fire if anything changes.
2037 assert(NumElements >= 2 &&
2038 "SPIR-V vectors must have at least 2 components");
2039 Type *Ty = FixedVectorType::get(
2040 ElementType: const_cast<Type *>(getTypeForSPIRVType(Ty: BaseType)), NumElts: NumElements);
2041 if (const MachineInstr *MI = findMI(T: Ty, RequiresExplicitLayout: false, MF: CurMF))
2042 return MI;
2043 MachineInstr *DepMI =
2044 const_cast<MachineInstr *>(static_cast<const MachineInstr *>(BaseType));
2045 MachineIRBuilder MIRBuilder(*DepMI->getParent(), DepMI->getIterator());
2046 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
2047 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
2048 // TODO: consider adding non-const accessors to SPIRVTypeInst, which
2049 // would remove the need for the gash casting here.
2050 return const_cast<MachineInstr *>(
2051 static_cast<const MachineInstr *>(getOpTypeVectorImpl(
2052 NumElems: NumElements, ElemType: BaseType, MIRBuilder, IsLongVectorEXT: isLongVectorEXT(Ty))));
2053 });
2054 add(T: Ty, RequiresExplicitLayout: false, MI: NewMI);
2055 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
2056}
2057
2058SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
2059 const Type *BaseType, MachineInstr &I, SPIRV::StorageClass::StorageClass SC,
2060 bool ForceTyped) {
2061 MachineIRBuilder MIRBuilder(I);
2062 return getOrCreateSPIRVPointerType(BaseType, MIRBuilder, SC, ForceTyped);
2063}
2064
2065SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
2066 const Type *BaseType, MachineIRBuilder &MIRBuilder,
2067 SPIRV::StorageClass::StorageClass SC, bool ForceTyped) {
2068 if (BaseType->isFunctionTy() &&
2069 !cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget())
2070 .canUseExtension(E: SPIRV::Extension::SPV_INTEL_function_pointers)) {
2071 const Function &F = MIRBuilder.getMF().getFunction();
2072 F.getContext().diagnose(
2073 DI: DiagnosticInfoUnsupported(F,
2074 "Function used as a data pointer requires "
2075 "SPV_INTEL_function_pointers extension",
2076 DebugLoc(), DS_Error));
2077 }
2078 // TODO: Need to check if EmitIr should always be true.
2079 SPIRVTypeInst SpirvBaseType = getOrCreateSPIRVType(
2080 Ty: BaseType, MIRBuilder, AccessQual: SPIRV::AccessQualifier::ReadWrite,
2081 ExplicitLayoutRequired: storageClassRequiresExplictLayout(SC), EmitIR: true);
2082 assert(SpirvBaseType);
2083 return getOrCreateSPIRVPointerTypeInternal(BaseType: SpirvBaseType, MIRBuilder, SC,
2084 ForceTyped);
2085}
2086
2087SPIRVTypeInst SPIRVGlobalRegistry::changePointerStorageClass(
2088 SPIRVTypeInst PtrType, SPIRV::StorageClass::StorageClass SC,
2089 MachineInstr &I) {
2090 [[maybe_unused]] SPIRV::StorageClass::StorageClass OldSC =
2091 getPointerStorageClass(Type: PtrType);
2092 assert(storageClassRequiresExplictLayout(OldSC) ==
2093 storageClassRequiresExplictLayout(SC));
2094
2095 SPIRVTypeInst PointeeType = getPointeeType(PtrType);
2096 MachineIRBuilder MIRBuilder(I);
2097 return getOrCreateSPIRVPointerTypeInternal(BaseType: PointeeType, MIRBuilder, SC);
2098}
2099
2100SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
2101 SPIRVTypeInst BaseType, MachineIRBuilder &MIRBuilder,
2102 SPIRV::StorageClass::StorageClass SC) {
2103 const Type *LLVMType = getTypeForSPIRVType(Ty: BaseType);
2104 assert(!storageClassRequiresExplictLayout(SC));
2105 SPIRVTypeInst R = getOrCreateSPIRVPointerType(BaseType: LLVMType, MIRBuilder, SC);
2106 assert(
2107 (R->getOpcode() == SPIRV::OpTypeUntypedPointerKHR ||
2108 getPointeeType(R) == BaseType) &&
2109 "The base type was not correctly laid out for the given storage class.");
2110 return R;
2111}
2112
2113SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerTypeInternal(
2114 SPIRVTypeInst BaseType, MachineIRBuilder &MIRBuilder,
2115 SPIRV::StorageClass::StorageClass SC, bool ForceTyped) {
2116 // Check if we should use untyped pointers.
2117 const SPIRVSubtarget &ST =
2118 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
2119 if (!ForceTyped && shouldUseUntypedPointer(ElemType: BaseType, ST))
2120 return getOrCreateSPIRVUntypedPointerType(SC, MIRBuilder);
2121
2122 const Type *PointerElementType = getTypeForSPIRVType(Ty: BaseType);
2123 unsigned AddressSpace = storageClassToAddressSpace(SC);
2124 if (const MachineInstr *MI = findMI(PointeeTy: PointerElementType, AddressSpace, MF: CurMF))
2125 return MI;
2126 Type *Ty = TypedPointerType::get(ElementType: const_cast<Type *>(PointerElementType),
2127 AddressSpace);
2128 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
2129 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
2130 return BuildMI(BB&: MIRBuilder.getMBB(), I: MIRBuilder.getInsertPt(),
2131 MIMD: MIRBuilder.getDebugLoc(),
2132 MCID: MIRBuilder.getTII().get(Opcode: SPIRV::OpTypePointer))
2133 .addDef(RegNo: createTypeVReg(MRI&: CurMF->getRegInfo()))
2134 .addImm(Val: static_cast<uint32_t>(SC))
2135 .addUse(RegNo: getSPIRVTypeID(SpirvType: BaseType));
2136 });
2137 add(PointeeTy: PointerElementType, AddressSpace, MI: NewMI);
2138 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
2139}
2140
2141SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVUntypedPointerType(
2142 SPIRV::StorageClass::StorageClass SC, MachineIRBuilder &MIRBuilder) {
2143 [[maybe_unused]] const SPIRVSubtarget &ST =
2144 cast<SPIRVSubtarget>(Val: MIRBuilder.getMF().getSubtarget());
2145 assert(ST.canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers) &&
2146 !ST.isShader() && "Untyped pointers are not available");
2147 unsigned AddressSpace = storageClassToAddressSpace(SC);
2148 // Use STK_UntypedPointer handle keyed by address space only.
2149 auto Handle = SPIRV::irhandle_untyped_pointer(AddressSpace);
2150 if (const MachineInstr *MI = findMI(Handle, MF: CurMF))
2151 return MI;
2152
2153 Type *Ty = PointerType::get(C&: MIRBuilder.getMF().getFunction().getContext(),
2154 AddressSpace);
2155 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
2156 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
2157 return BuildMI(BB&: MIRBuilder.getMBB(), I: MIRBuilder.getInsertPt(),
2158 MIMD: MIRBuilder.getDebugLoc(),
2159 MCID: MIRBuilder.getTII().get(Opcode: SPIRV::OpTypeUntypedPointerKHR))
2160 .addDef(RegNo: createTypeVReg(MRI&: CurMF->getRegInfo()))
2161 .addImm(Val: static_cast<uint32_t>(SC));
2162 });
2163 add(Handle, MI: NewMI);
2164 return finishCreatingSPIRVType(LLVMTy: Ty, SpirvType: NewMI);
2165}
2166
2167Register SPIRVGlobalRegistry::getOrCreateUndef(MachineInstr &I,
2168 SPIRVTypeInst SpvType,
2169 const SPIRVInstrInfo &TII) {
2170 UndefValue *UV =
2171 UndefValue::get(T: const_cast<Type *>(getTypeForSPIRVType(Ty: SpvType)));
2172 Register Res = find(V: UV, MF: CurMF);
2173 if (Res.isValid())
2174 return Res;
2175
2176 LLT LLTy = LLT::scalar(SizeInBits: 64);
2177 Res = CurMF->getRegInfo().createGenericVirtualRegister(Ty: LLTy);
2178 CurMF->getRegInfo().setRegClass(Reg: Res, RC: &SPIRV::iIDRegClass);
2179 assignSPIRVTypeToVReg(SpirvType: SpvType, VReg: Res, MF: *CurMF);
2180
2181 MachineInstr *DepMI =
2182 const_cast<MachineInstr *>(static_cast<const MachineInstr *>(SpvType));
2183 MachineIRBuilder MIRBuilder(*DepMI->getParent(), DepMI->getIterator());
2184 const MachineInstr *NewMI = createConstOrTypeAtFunctionEntry(
2185 MIRBuilder, Op: [&](MachineIRBuilder &MIRBuilder) {
2186 auto MIB = BuildMI(BB&: MIRBuilder.getMBB(), I&: *MIRBuilder.getInsertPt(),
2187 MIMD: MIRBuilder.getDL(), MCID: TII.get(Opcode: SPIRV::OpUndef))
2188 .addDef(RegNo: Res)
2189 .addUse(RegNo: getSPIRVTypeID(SpirvType: SpvType));
2190 constrainSelectedInstRegOperands(MIB);
2191 return MIB;
2192 });
2193 add(V: UV, MI: NewMI);
2194 return Res;
2195}
2196
2197const TargetRegisterClass *
2198SPIRVGlobalRegistry::getRegClass(SPIRVTypeInst SpvType) const {
2199 unsigned Opcode = SpvType->getOpcode();
2200 switch (Opcode) {
2201 case SPIRV::OpTypeFloat:
2202 return &SPIRV::fIDRegClass;
2203 case SPIRV::OpTypePointer:
2204 return &SPIRV::pIDRegClass;
2205 case SPIRV::OpTypeVector:
2206 case SPIRV::OpTypeVectorIdEXT: {
2207 SPIRVTypeInst ElemType = getScalarOrVectorComponentType(Type: SpvType);
2208 unsigned ElemOpcode = ElemType ? ElemType->getOpcode() : 0;
2209 if (ElemOpcode == SPIRV::OpTypeFloat)
2210 return &SPIRV::vfIDRegClass;
2211 if (ElemOpcode == SPIRV::OpTypePointer)
2212 return &SPIRV::vpIDRegClass;
2213 return &SPIRV::viIDRegClass;
2214 }
2215 }
2216 return &SPIRV::iIDRegClass;
2217}
2218
2219inline unsigned getAS(SPIRVTypeInst SpvType) {
2220 return storageClassToAddressSpace(
2221 SC: static_cast<SPIRV::StorageClass::StorageClass>(
2222 SpvType->getOperand(i: 1).getImm()));
2223}
2224
2225LLT SPIRVGlobalRegistry::getRegType(SPIRVTypeInst SpvType) const {
2226 unsigned Opcode = SpvType ? SpvType->getOpcode() : 0;
2227 switch (Opcode) {
2228 case SPIRV::OpTypeInt:
2229 case SPIRV::OpTypeFloat:
2230 case SPIRV::OpTypeBool:
2231 return LLT::scalar(SizeInBits: getScalarOrVectorBitWidth(Type: SpvType));
2232 case SPIRV::OpTypePointer:
2233 case SPIRV::OpTypeUntypedPointerKHR:
2234 return LLT::pointer(AddressSpace: getAS(SpvType), SizeInBits: getPointerSize());
2235 case SPIRV::OpTypeVector:
2236 case SPIRV::OpTypeVectorIdEXT: {
2237 SPIRVTypeInst ElemType = getScalarOrVectorComponentType(Type: SpvType);
2238 LLT ET;
2239 switch (ElemType ? ElemType->getOpcode() : 0) {
2240 case SPIRV::OpTypePointer:
2241 case SPIRV::OpTypeUntypedPointerKHR:
2242 ET = LLT::pointer(AddressSpace: getAS(SpvType: ElemType), SizeInBits: getPointerSize());
2243 break;
2244 case SPIRV::OpTypeInt:
2245 case SPIRV::OpTypeFloat:
2246 case SPIRV::OpTypeBool:
2247 ET = LLT::scalar(SizeInBits: getScalarOrVectorBitWidth(Type: ElemType));
2248 break;
2249 default:
2250 ET = LLT::scalar(SizeInBits: 64);
2251 }
2252 auto EC = ElementCount::getFixed(MinVal: getScalarOrVectorComponentCount(Type: SpvType));
2253 return LLT::scalarOrVector(EC, ScalarTy: ET);
2254 }
2255 }
2256 return LLT::scalar(SizeInBits: 64);
2257}
2258
2259// Aliasing list MD contains several scope MD nodes whithin it. Each scope MD
2260// has a selfreference and an extra MD node for aliasing domain and also it
2261// can contain an optional string operand. Domain MD contains a self-reference
2262// with an optional string operand. Here we unfold the list, creating SPIR-V
2263// aliasing instructions.
2264// TODO: add support for an optional string operand.
2265MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
2266 MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD) {
2267 if (AliasingListMD->getNumOperands() == 0)
2268 return nullptr;
2269 const MachineFunction *MF = &MIRBuilder.getMF();
2270 if (auto L = AliasInstMDMap.find(Val: {MF, AliasingListMD});
2271 L != AliasInstMDMap.end())
2272 return L->second;
2273
2274 SmallVector<MachineInstr *> ScopeList;
2275 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
2276 for (const MDOperand &MDListOp : AliasingListMD->operands()) {
2277 if (MDNode *ScopeMD = dyn_cast<MDNode>(Val: MDListOp)) {
2278 if (ScopeMD->getNumOperands() < 2)
2279 return nullptr;
2280 MDNode *DomainMD = dyn_cast<MDNode>(Val: ScopeMD->getOperand(I: 1));
2281 if (!DomainMD)
2282 return nullptr;
2283 auto *Domain = [&] {
2284 auto D = AliasInstMDMap.find(Val: {MF, DomainMD});
2285 if (D != AliasInstMDMap.end())
2286 return D->second;
2287 const Register Ret = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
2288 auto MIB =
2289 MIRBuilder.buildInstr(Opcode: SPIRV::OpAliasDomainDeclINTEL).addDef(RegNo: Ret);
2290 return MIB.getInstr();
2291 }();
2292 AliasInstMDMap.insert(
2293 KV: std::make_pair(x: std::make_pair(x&: MF, y&: DomainMD), y&: Domain));
2294 auto *Scope = [&] {
2295 auto S = AliasInstMDMap.find(Val: {MF, ScopeMD});
2296 if (S != AliasInstMDMap.end())
2297 return S->second;
2298 const Register Ret = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
2299 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpAliasScopeDeclINTEL)
2300 .addDef(RegNo: Ret)
2301 .addUse(RegNo: Domain->getOperand(i: 0).getReg());
2302 return MIB.getInstr();
2303 }();
2304 AliasInstMDMap.insert(KV: std::make_pair(x: std::make_pair(x&: MF, y&: ScopeMD), y&: Scope));
2305 ScopeList.push_back(Elt: Scope);
2306 }
2307 }
2308
2309 const Register Ret = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
2310 auto MIB =
2311 MIRBuilder.buildInstr(Opcode: SPIRV::OpAliasScopeListDeclINTEL).addDef(RegNo: Ret);
2312 for (auto *Scope : ScopeList)
2313 MIB.addUse(RegNo: Scope->getOperand(i: 0).getReg());
2314 auto List = MIB.getInstr();
2315 AliasInstMDMap.insert(
2316 KV: std::make_pair(x: std::make_pair(x&: MF, y&: AliasingListMD), y&: List));
2317 return List;
2318}
2319
2320void SPIRVGlobalRegistry::buildMemAliasingOpDecorate(
2321 Register Reg, MachineIRBuilder &MIRBuilder, uint32_t Dec,
2322 const MDNode *AliasingListMD) {
2323 MachineInstr *AliasList =
2324 getOrAddMemAliasingINTELInst(MIRBuilder, AliasingListMD);
2325 if (!AliasList)
2326 return;
2327 MIRBuilder.buildInstr(Opcode: SPIRV::OpDecorateId)
2328 .addUse(RegNo: Reg)
2329 .addImm(Val: Dec)
2330 .addUse(RegNo: AliasList->getOperand(i: 0).getReg());
2331}
2332void SPIRVGlobalRegistry::replaceAllUsesWith(Value *Old, Value *New,
2333 bool DeleteOld) {
2334 Old->replaceAllUsesWith(V: New);
2335 updateIfExistDeducedElementType(OldVal: Old, NewVal: New, DeleteOld);
2336 updateIfExistAssignPtrTypeInstr(OldVal: Old, NewVal: New, DeleteOld);
2337}
2338
2339void SPIRVGlobalRegistry::buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg,
2340 bool CanUseAnyVectorRank) {
2341 Value *OfType = getNormalizedPoisonValue(Ty, CanUseAnyVectorRank);
2342 CallInst *AssignCI = nullptr;
2343 if (Arg->getType()->isAggregateType() && Ty->isAggregateType() &&
2344 allowEmitFakeUse(Arg)) {
2345 LLVMContext &Ctx = Arg->getContext();
2346 SmallVector<Metadata *, 2> ArgMDs{
2347 MDNode::get(Context&: Ctx, MDs: ValueAsMetadata::getConstant(C: OfType)),
2348 MDString::get(Context&: Ctx, Str: Arg->getName())};
2349 B.CreateIntrinsic(ID: Intrinsic::spv_value_md,
2350 Args: {MetadataAsValue::get(Context&: Ctx, MD: MDTuple::get(Context&: Ctx, MDs: ArgMDs))});
2351 AssignCI = B.CreateIntrinsicWithoutFolding(ID: Intrinsic::fake_use, Args: {Arg});
2352 } else {
2353 AssignCI = buildIntrWithMD(IntrID: Intrinsic::spv_assign_type, Types: {Arg->getType()},
2354 Arg: OfType, Arg2: Arg, Imms: {}, B);
2355 }
2356 addAssignPtrTypeInstr(Val: Arg, AssignPtrTyCI: AssignCI);
2357}
2358
2359void SPIRVGlobalRegistry::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
2360 Value *Arg) {
2361 Value *OfType = PoisonValue::get(T: ElemTy);
2362 CallInst *AssignPtrTyCI = findAssignPtrTypeInstr(Val: Arg);
2363 Function *CurrF =
2364 B.GetInsertBlock() ? B.GetInsertBlock()->getParent() : nullptr;
2365 if (AssignPtrTyCI == nullptr ||
2366 AssignPtrTyCI->getParent()->getParent() != CurrF) {
2367 AssignPtrTyCI = buildIntrWithMD(
2368 IntrID: Intrinsic::spv_assign_ptr_type, Types: {Arg->getType()}, Arg: OfType, Arg2: Arg,
2369 Imms: {B.getInt32(C: getPointerAddressSpace(T: Arg->getType()))}, B);
2370 addDeducedElementType(Val: AssignPtrTyCI, Ty: ElemTy);
2371 addDeducedElementType(Val: Arg, Ty: ElemTy);
2372 addAssignPtrTypeInstr(Val: Arg, AssignPtrTyCI);
2373 } else {
2374 updateAssignType(AssignCI: AssignPtrTyCI, Arg, OfType);
2375 }
2376}
2377
2378void SPIRVGlobalRegistry::updateAssignType(CallInst *AssignCI, Value *Arg,
2379 Value *OfType) {
2380 AssignCI->setArgOperand(i: 1, v: buildMD(Arg: OfType));
2381 if (cast<IntrinsicInst>(Val: AssignCI)->getIntrinsicID() !=
2382 Intrinsic::spv_assign_ptr_type)
2383 return;
2384
2385 // update association with the pointee type
2386 Type *ElemTy = OfType->getType();
2387 addDeducedElementType(Val: AssignCI, Ty: ElemTy);
2388 addDeducedElementType(Val: Arg, Ty: ElemTy);
2389}
2390
2391void SPIRVGlobalRegistry::addStructOffsetDecorations(
2392 Register Reg, StructType *Ty, MachineIRBuilder &MIRBuilder) {
2393 ArrayRef<TypeSize> Offsets = DL.getStructLayout(Ty)->getMemberOffsets();
2394 for (uint32_t I = 0; I < Ty->getNumElements(); ++I) {
2395 buildOpMemberDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::Offset, Member: I,
2396 DecArgs: {static_cast<uint32_t>(Offsets[I])});
2397 }
2398}
2399
2400void SPIRVGlobalRegistry::addArrayStrideDecorations(
2401 Register Reg, Type *ElementType, MachineIRBuilder &MIRBuilder) {
2402 uint32_t SizeInBytes = DL.getTypeAllocSize(Ty: ElementType);
2403 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::ArrayStride,
2404 DecArgs: {SizeInBytes});
2405}
2406