[llvm] [SPIR-V] Implement OpSpecConstantOp with ptr-cast operation (PR #109979)
Vyacheslav Levytskyy via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 26 03:45:00 PDT 2024
https://github.com/VyacheslavLevytskyy updated https://github.com/llvm/llvm-project/pull/109979
>From 69274cc428f7ea73d5bfb5bc1c1a7171243aea30 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 01:07:28 -0700
Subject: [PATCH 1/7] fix compilation error 'use of parameter from containing
function' when building with gcc
---
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 3640188670d15c..35031b918ebd35 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -256,12 +256,9 @@ SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id) {
// We don't need aliases for Invocation and CrossDevice, as we already have
// them covered by "singlethread" and "" strings respectively (see
// implementation of LLVMContext::LLVMContext()).
- static const llvm::SyncScope::ID SubGroup =
- Ctx.getOrInsertSyncScopeID("subgroup");
- static const llvm::SyncScope::ID WorkGroup =
- Ctx.getOrInsertSyncScopeID("workgroup");
- static const llvm::SyncScope::ID Device =
- Ctx.getOrInsertSyncScopeID("device");
+ llvm::SyncScope::ID SubGroup = Ctx.getOrInsertSyncScopeID("subgroup");
+ llvm::SyncScope::ID WorkGroup = Ctx.getOrInsertSyncScopeID("workgroup");
+ llvm::SyncScope::ID Device = Ctx.getOrInsertSyncScopeID("device");
if (Id == llvm::SyncScope::SingleThread)
return SPIRV::Scope::Invocation;
>From eb9a433c3300d6dd7dfb946adaf7f587f0dfa67f Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 01:12:48 -0700
Subject: [PATCH 2/7] static const
---
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 35031b918ebd35..3640188670d15c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -256,9 +256,12 @@ SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id) {
// We don't need aliases for Invocation and CrossDevice, as we already have
// them covered by "singlethread" and "" strings respectively (see
// implementation of LLVMContext::LLVMContext()).
- llvm::SyncScope::ID SubGroup = Ctx.getOrInsertSyncScopeID("subgroup");
- llvm::SyncScope::ID WorkGroup = Ctx.getOrInsertSyncScopeID("workgroup");
- llvm::SyncScope::ID Device = Ctx.getOrInsertSyncScopeID("device");
+ static const llvm::SyncScope::ID SubGroup =
+ Ctx.getOrInsertSyncScopeID("subgroup");
+ static const llvm::SyncScope::ID WorkGroup =
+ Ctx.getOrInsertSyncScopeID("workgroup");
+ static const llvm::SyncScope::ID Device =
+ Ctx.getOrInsertSyncScopeID("device");
if (Id == llvm::SyncScope::SingleThread)
return SPIRV::Scope::Invocation;
>From eb76c4788d0114c39366017b392ca945755ffcbc Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 06:27:43 -0700
Subject: [PATCH 3/7] fix AddrSpaceCast
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 5 +
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h | 2 +
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 103 +++++++++++++-----
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 15 ++-
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 1 +
.../pointers/PtrCast-in-OpSpecConstantOp.ll | 63 +++++++++++
6 files changed, 161 insertions(+), 28 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/PtrCast-in-OpSpecConstantOp.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 3e1873e899680c..ceca0a180c95b4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -1128,6 +1128,11 @@ SPIRVGlobalRegistry::getPointerStorageClass(Register VReg) const {
SPIRVType *Type = getSPIRVTypeForVReg(VReg);
assert(Type && Type->getOpcode() == SPIRV::OpTypePointer &&
Type->getOperand(1).isImm() && "Pointer type is expected");
+ return getPointerStorageClass(Type);
+}
+
+SPIRV::StorageClass::StorageClass
+SPIRVGlobalRegistry::getPointerStorageClass(const SPIRVType *Type) const {
return static_cast<SPIRV::StorageClass::StorageClass>(
Type->getOperand(1).getImm());
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index 92f95418624fe9..ace5cfe91ebe48 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -405,6 +405,8 @@ class SPIRVGlobalRegistry {
// Gets the storage class of the pointer type assigned to this vreg.
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const;
+ SPIRV::StorageClass::StorageClass
+ getPointerStorageClass(const SPIRVType *Type) const;
// Return the number of bits SPIR-V pointers and size_t variables require.
unsigned getPointerSize() const { return PointerSize; }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 43c92f24a0ad1d..4a054397f7afd2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1250,36 +1250,87 @@ static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
const SPIRVType *ResType,
MachineInstr &I) const {
- // If the AddrSpaceCast user is single and in OpConstantComposite or
- // OpVariable, we should select OpSpecConstantOp.
- auto UIs = MRI->use_instructions(ResVReg);
- if (!UIs.empty() && ++UIs.begin() == UIs.end() &&
- (UIs.begin()->getOpcode() == SPIRV::OpConstantComposite ||
- UIs.begin()->getOpcode() == SPIRV::OpVariable ||
- isSpvIntrinsic(*UIs.begin(), Intrinsic::spv_init_global))) {
- Register NewReg = I.getOperand(1).getReg();
- MachineBasicBlock &BB = *I.getParent();
- SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
- ResType = GR.getOrCreateSPIRVPointerType(SpvBaseTy, I, TII,
- SPIRV::StorageClass::Generic);
- bool Result =
- BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
- .addUse(NewReg)
- .constrainAllUses(TII, TRI, RBI);
- return Result;
- }
+ MachineBasicBlock &BB = *I.getParent();
+ const DebugLoc &DL = I.getDebugLoc();
+
Register SrcPtr = I.getOperand(1).getReg();
SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
- SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr);
- SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResVReg);
+ // don't generate a cast for a null that is represented by OpTypeInt
+ if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer ||
+ ResType->getOpcode() != SPIRV::OpTypePointer)
+ return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY))
+ .addDef(ResVReg)
+ .addUse(SrcPtr)
+ .constrainAllUses(TII, TRI, RBI);
+
+ SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
+ SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
+
+ // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
+ // are expressed by OpSpecConstantOp with an Opcode.
+ bool IsGRef = false;
+ bool IsAllowedRefs =
+ std::all_of(MRI->use_instr_begin(ResVReg), MRI->use_instr_end(),
+ [&IsGRef](auto const &It) {
+ unsigned Opcode = It.getOpcode();
+ if (Opcode == SPIRV::OpConstantComposite ||
+ Opcode == SPIRV::OpVariable ||
+ isSpvIntrinsic(It, Intrinsic::spv_init_global))
+ return IsGRef = true;
+ return Opcode == SPIRV::OpName;
+ });
+ if (IsAllowedRefs && IsGRef) {
+ // TODO: insert a check whether the Kernel capability was declared.
+ unsigned SpecOpcode =
+ DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)
+ ? static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
+ : (SrcSC == SPIRV::StorageClass::Generic &&
+ isGenericCastablePtr(DstSC)
+ ? static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
+ : 0);
+ if (SpecOpcode) {
+ // TODO: OpConstantComposite expects i8*, so we are forced to forget a
+ // correct value of ResType and use general i8* instead. Maybe this should
+ // be addressed in the emit-intrinsic step to infer a correct
+ // OpConstantComposite type.
+ SPIRVType *NewResType = GR.getOrCreateSPIRVPointerType(
+ GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, DstSC);
+ bool Result = BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(NewResType))
+ .addImm(SpecOpcode)
+ .addUse(SrcPtr)
+ .constrainAllUses(TII, TRI, RBI);
+ return Result;
+ } else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
+ SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
+ GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
+ Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
+ MRI->setType(Tmp, LLT::pointer(0, 64));
+ GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *BB.getParent());
+ MachineInstrBuilder MIB =
+ BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
+ .addDef(Tmp)
+ .addUse(GR.getSPIRVTypeID(GenericPtrTy))
+ .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
+ .addUse(SrcPtr);
+ GR.add(MIB.getInstr(), BB.getParent(), Tmp);
+ bool Result = MIB.constrainAllUses(TII, TRI, RBI);
+ SPIRVType *NewResType = GR.getOrCreateSPIRVPointerType(
+ GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, DstSC);
+ return Result &&
+ BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(NewResType))
+ .addImm(static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
+ .addUse(Tmp)
+ .constrainAllUses(TII, TRI, RBI);
+ }
+ }
// don't generate a cast between identical storage classes
if (SrcSC == DstSC)
- return BuildMI(*I.getParent(), I, I.getDebugLoc(),
- TII.get(TargetOpcode::COPY))
+ return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY))
.addDef(ResVReg)
.addUse(SrcPtr)
.constrainAllUses(TII, TRI, RBI);
@@ -1295,8 +1346,6 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
Register Tmp = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
- MachineBasicBlock &BB = *I.getParent();
- const DebugLoc &DL = I.getDebugLoc();
bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
.addDef(Tmp)
.addUse(GR.getSPIRVTypeID(GenericPtrTy))
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 42f3ded336f951..79f69500557949 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -294,8 +294,21 @@ static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR,
default:
break;
}
- if (SpvType)
+ if (SpvType) {
+ // check if the address space needs correction
+ LLT RegType = MRI.getType(Reg);
+ if (SpvType->getOpcode() == SPIRV::OpTypePointer &&
+ RegType.isPointer() &&
+ storageClassToAddressSpace(GR->getPointerStorageClass(SpvType)) !=
+ RegType.getAddressSpace()) {
+ const SPIRVSubtarget &ST =
+ MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
+ SpvType = GR->getOrCreateSPIRVPointerType(
+ GR->getPointeeType(SpvType), *MI, *ST.getInstrInfo(),
+ addressSpaceToStorageClass(RegType.getAddressSpace(), ST));
+ }
GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
+ }
if (!MRI.getRegClassOrNull(Reg))
MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
: &SPIRV::iIDRegClass);
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 23cd32eff45d5b..a74b2cc8615eff 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -1631,6 +1631,7 @@ multiclass OpcodeOperand<bits<32> value> {
defm InBoundsAccessChain : OpcodeOperand<66>;
defm InBoundsPtrAccessChain : OpcodeOperand<70>;
defm PtrCastToGeneric : OpcodeOperand<121>;
+defm GenericCastToPtr : OpcodeOperand<122>;
defm Bitcast : OpcodeOperand<124>;
defm ConvertPtrToU : OpcodeOperand<117>;
defm ConvertUToPtr : OpcodeOperand<120>;
diff --git a/llvm/test/CodeGen/SPIRV/pointers/PtrCast-in-OpSpecConstantOp.ll b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-in-OpSpecConstantOp.ll
new file mode 100644
index 00000000000000..cd1a1b0080c621
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-in-OpSpecConstantOp.ll
@@ -0,0 +1,63 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: OpName %[[F:.*]] "F"
+; CHECK-DAG: OpName %[[B:.*]] "B"
+; CHECK-DAG: OpName %[[G1:.*]] "G1"
+; CHECK-DAG: OpName %[[G2:.*]] "G2"
+; CHECK-DAG: OpName %[[X:.*]] "X"
+; CHECK-DAG: OpName %[[Y:.*]] "Y"
+; CHECK-DAG: OpName %[[G3:.*]] "G3"
+; CHECK-DAG: OpName %[[G4:.*]] "G4"
+
+; CHECK-DAG: %[[Int:.*]] = OpTypeInt 32 0
+; CHECK-DAG: %[[Char:.*]] = OpTypeInt 8 0
+; CHECK-DAG: %[[GenPtrChar:.*]] = OpTypePointer Generic %[[Char]]
+; CHECK-DAG: %[[CWPtrChar:.*]] = OpTypePointer CrossWorkgroup %[[Char]]
+; CHECK-DAG: %[[Arr1:.*]] = OpTypeArray %[[CWPtrChar]] %[[#]]
+; CHECK-DAG: %[[Struct1:.*]] = OpTypeStruct %8
+; CHECK-DAG: %[[Arr2:.*]] = OpTypeArray %[[GenPtrChar]] %[[#]]
+; CHECK-DAG: %[[Struct2:.*]] = OpTypeStruct %[[Arr2]]
+; CHECK-DAG: %[[GenPtr:.*]] = OpTypePointer Generic %[[Int]]
+; CHECK-DAG: %[[CWPtr:.*]] = OpTypePointer CrossWorkgroup %[[Int]]
+; CHECK-DAG: %[[WPtr:.*]] = OpTypePointer Workgroup %[[Int]]
+
+; CHECK-DAG: %[[F]] = OpVariable %[[CWPtr]] CrossWorkgroup %[[#]]
+; CHECK-DAG: %[[GenF:.*]] = OpSpecConstantOp %[[GenPtrChar]] 121 %[[F]]
+; CHECK-DAG: %[[B]] = OpVariable %[[CWPtr]] CrossWorkgroup %[[#]]
+; CHECK-DAG: %[[GenB:.*]] = OpSpecConstantOp %[[GenPtrChar]] 121 %[[B]]
+; CHECK-DAG: %[[GenFB:.*]] = OpConstantComposite %[[Arr2]] %[[GenF]] %[[GenB]]
+; CHECK-DAG: %[[GenBF:.*]] = OpConstantComposite %[[Arr2]] %[[GenB]] %[[GenF]]
+; CHECK-DAG: %[[CG1:.*]] = OpConstantComposite %[[Struct2]] %[[GenFB]]
+; CHECK-DAG: %[[CG2:.*]] = OpConstantComposite %[[Struct2]] %[[GenBF]]
+
+; CHECK-DAG: %[[X]] = OpVariable %[[WPtr]] Workgroup %[[#]]
+; CHECK-DAG: %[[GenX:.*]] = OpSpecConstantOp %[[GenPtr]] 121 %[[X]]
+; CHECK-DAG: %[[CWX:.*]] = OpSpecConstantOp %[[CWPtrChar]] 122 %[[GenX]]
+; CHECK-DAG: %[[Y]] = OpVariable %[[WPtr]] Workgroup %[[#]]
+; CHECK-DAG: %[[GenY:.*]] = OpSpecConstantOp %[[GenPtr]] 121 %[[Y]]
+; CHECK-DAG: %[[CWY:.*]] = OpSpecConstantOp %[[CWPtrChar]] 122 %[[GenY]]
+; CHECK-DAG: %[[CWXY:.*]] = OpConstantComposite %[[Arr1]] %[[CWX]] %[[CWY]]
+; CHECK-DAG: %[[CWYX:.*]] = OpConstantComposite %[[Arr1]] %[[CWY]] %[[CWX]]
+; CHECK-DAG: %[[CG3:.*]] = OpConstantComposite %[[Struct1]] %[[CWXY]]
+; CHECK-DAG: %[[CG4:.*]] = OpConstantComposite %[[Struct1]] %[[CWYX]]
+
+; CHECK-DAG: %[[G4]] = OpVariable %[[#]] CrossWorkgroup %[[CG4]]
+; CHECK-DAG: %[[G3]] = OpVariable %[[#]] CrossWorkgroup %[[CG3]]
+; CHECK-DAG: %[[G2]] = OpVariable %[[#]] CrossWorkgroup %[[CG2]]
+; CHECK-DAG: %[[G1]] = OpVariable %[[#]] CrossWorkgroup %[[CG1]]
+
+ at F = addrspace(1) constant i32 0
+ at B = addrspace(1) constant i32 1
+ at G1 = addrspace(1) constant { [2 x ptr addrspace(4)] } { [2 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr addrspace(1) @F to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr addrspace(1) @B to ptr addrspace(4))] }
+ at G2 = addrspace(1) constant { [2 x ptr addrspace(4)] } { [2 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr addrspace(1) @B to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr addrspace(1) @F to ptr addrspace(4))] }
+
+ at X = addrspace(3) constant i32 0
+ at Y = addrspace(3) constant i32 1
+ at G3 = addrspace(1) constant { [2 x ptr addrspace(1)] } { [2 x ptr addrspace(1)] [ptr addrspace(1) addrspacecast (ptr addrspace(3) @X to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr addrspace(3) @Y to ptr addrspace(1))] }
+ at G4 = addrspace(1) constant { [2 x ptr addrspace(1)] } { [2 x ptr addrspace(1)] [ptr addrspace(1) addrspacecast (ptr addrspace(3) @Y to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr addrspace(3) @X to ptr addrspace(1))] }
+
+define void @foo() {
+entry:
+ ret void
+}
>From 81a468d23a0cf191afc00cfc4f5d251af6e256c8 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 07:23:09 -0700
Subject: [PATCH 4/7] add tests
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 +-
.../fun-ptr-addrcast.ll | 25 +++++++++++++++++++
.../PtrCast-null-in-OpSpecConstantOp.ll | 19 ++++++++++++++
3 files changed, 45 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 4a054397f7afd2..db194d49f44c91 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1255,7 +1255,7 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
Register SrcPtr = I.getOperand(1).getReg();
SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
- // don't generate a cast for a null that is represented by OpTypeInt
+ // don't generate a cast for a null that may be represented by OpTypeInt
if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer ||
ResType->getOpcode() != SPIRV::OpTypePointer)
return BuildMI(BB, I, DL, TII.get(TargetOpcode::COPY))
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
new file mode 100644
index 00000000000000..60353c6d125534
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
@@ -0,0 +1,25 @@
+; The goal of this test case is to check that cases covered by pointers/PtrCast-in-OpSpecConstantOp.ll and
+; pointers/PtrCast-null-in-OpSpecConstantOp.ll (that is OpSpecConstantOp with ptr-cast operation) correctly
+; work also for function pointers.
+
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - --spirv-ext=+SPV_INTEL_function_pointers | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-COUNT-3: %[[#]] = OpSpecConstantOp %[[#]] 121 %[[#]]
+; CHECK-COUNT-3: OpPtrCastToGeneric
+
+ at G1 = addrspace(1) constant { [3 x ptr addrspace(4)] } { [3 x ptr addrspace(4)] [ptr addrspace(4) null, ptr addrspace(4) addrspacecast (ptr @foo to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr @bar to ptr addrspace(4))] }
+ at G2 = addrspace(1) constant { [3 x ptr addrspace(4)] } { [3 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr null to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr @bar to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr @foo to ptr addrspace(4))] }
+
+define void @foo(ptr addrspace(4) %p) {
+entry:
+ %r1 = addrspacecast ptr @foo to ptr addrspace(4)
+ %r2 = addrspacecast ptr null to ptr addrspace(4)
+ ret void
+}
+
+define void @bar(ptr addrspace(4) %p) {
+entry:
+ %r1 = addrspacecast ptr @bar to ptr addrspace(4)
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
new file mode 100644
index 00000000000000..5565111e788704
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
@@ -0,0 +1,19 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[Array:.*]] = OpTypeArray %[[#]] %[[#]]
+; CHECK-DAG: %[[Struct:.*]] = OpTypeStruct %[[Array]]
+; CHECK-DAG: %[[Zero:.*]] = OpTypeInt 64 0
+; CHECK-DAG: %[[Null:.*]] = OpConstantNull %[[Zero]]
+; CHECK-DAG: %[[R1:.*]] = OpConstantComposite %[[Array]] %[[Null]]
+; CHECK-DAG: %[[#]] = OpConstantComposite %[[Struct]] %[[R1]]
+; CHECK-DAG: %[[R2:.*]] = OpConstantComposite %[[Array]] %[[Null]]
+; CHECK-DAG: %[[#]] = OpConstantComposite %[[Struct]] %[[R2]]
+
+ at G1 = addrspace(1) constant { [1 x ptr addrspace(4)] } { [1 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr null to ptr addrspace(4))] }
+ at G2 = addrspace(1) constant { [1 x ptr addrspace(4)] } { [1 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr addrspace(1) null to ptr addrspace(4))] }
+
+define void @foo() {
+entry:
+ ret void
+}
>From 4160813c718719482988ac74922c19a1743d34a0 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 08:29:34 -0700
Subject: [PATCH 5/7] fix the test case
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 8 ++++++++
.../SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 79f69500557949..536a21b621824c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -523,6 +523,14 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
? MI.getOperand(1).getCImm()->getType()
: TargetExtIt->second;
const ConstantInt *OpCI = MI.getOperand(1).getCImm();
+ // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
+ // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
+ // at this point not i64/i32 constant but null pointer in the
+ // corresponding address space of RegType.getAddressSpace(). This may
+ // help to successfully validate the case when a OpConstantComposite's
+ // constituent has type that does not match Result Type of
+ // OpConstantComposite (see, for example,
+ // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
Register PrimaryReg = GR->find(OpCI, &MF);
if (!PrimaryReg.isValid()) {
GR->add(OpCI, &MF, Reg);
diff --git a/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
index 5565111e788704..99e2c3e6d39630 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/PtrCast-null-in-OpSpecConstantOp.ll
@@ -1,5 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[Array:.*]] = OpTypeArray %[[#]] %[[#]]
; CHECK-DAG: %[[Struct:.*]] = OpTypeStruct %[[Array]]
>From 49ab6cfa3117c1abda476273b1a59139e739b73e Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Wed, 25 Sep 2024 08:41:21 -0700
Subject: [PATCH 6/7] add a comment
---
.../extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
index 60353c6d125534..b238b07bbc04ec 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fun-ptr-addrcast.ll
@@ -5,6 +5,9 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - --spirv-ext=+SPV_INTEL_function_pointers | FileCheck %s
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; Running with -verify-machineinstrs would lead to "Reading virtual register without a def"
+; error, because OpConstantFunctionPointerINTEL forward-refers to a function definition.
+
; CHECK-COUNT-3: %[[#]] = OpSpecConstantOp %[[#]] 121 %[[#]]
; CHECK-COUNT-3: OpPtrCastToGeneric
>From d3325a25b70a4cebff18bb2a918db9a8a2f104b2 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Thu, 26 Sep 2024 03:44:31 -0700
Subject: [PATCH 7/7] improve code readability
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 129 +++++++++++-------
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 29 +---
llvm/lib/Target/SPIRV/SPIRVUtils.h | 26 +++-
3 files changed, 108 insertions(+), 76 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index db194d49f44c91..c6592ad8b8db94 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -249,6 +249,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool selectUnmergeValues(MachineInstr &I) const;
+ // Utilities
Register buildI32Constant(uint32_t Val, MachineInstr &I,
const SPIRVType *ResType = nullptr) const;
@@ -260,6 +261,14 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool wrapIntoSpecConstantOp(MachineInstr &I,
SmallVector<Register> &CompositeArgs) const;
+
+ Register getUcharPtrTypeReg(MachineInstr &I,
+ SPIRV::StorageClass::StorageClass SC) const;
+ MachineInstrBuilder buildSpecConstantOp(MachineInstr &I, Register Dest,
+ Register Src, Register DestType,
+ uint32_t Opcode) const;
+ MachineInstrBuilder buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
+ SPIRVType *SrcPtrTy) const;
};
} // end anonymous namespace
@@ -1242,6 +1251,58 @@ static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
}
}
+// Returns true ResVReg is referred only from global vars and OpName's.
+static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg) {
+ bool IsGRef = false;
+ bool IsAllowedRefs =
+ std::all_of(MRI->use_instr_begin(ResVReg), MRI->use_instr_end(),
+ [&IsGRef](auto const &It) {
+ unsigned Opcode = It.getOpcode();
+ if (Opcode == SPIRV::OpConstantComposite ||
+ Opcode == SPIRV::OpVariable ||
+ isSpvIntrinsic(It, Intrinsic::spv_init_global))
+ return IsGRef = true;
+ return Opcode == SPIRV::OpName;
+ });
+ return IsAllowedRefs && IsGRef;
+}
+
+Register SPIRVInstructionSelector::getUcharPtrTypeReg(
+ MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
+ return GR.getSPIRVTypeID(GR.getOrCreateSPIRVPointerType(
+ GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, SC));
+}
+
+MachineInstrBuilder
+SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest,
+ Register Src, Register DestType,
+ uint32_t Opcode) const {
+ return BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(SPIRV::OpSpecConstantOp))
+ .addDef(Dest)
+ .addUse(DestType)
+ .addImm(Opcode)
+ .addUse(Src);
+}
+
+MachineInstrBuilder
+SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
+ SPIRVType *SrcPtrTy) const {
+ SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
+ GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
+ Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
+ MRI->setType(Tmp, LLT::pointer(storageClassToAddressSpace(
+ SPIRV::StorageClass::Generic),
+ GR.getPointerSize()));
+ MachineFunction *MF = I.getParent()->getParent();
+ GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
+ MachineInstrBuilder MIB = buildSpecConstantOp(
+ I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
+ static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
+ GR.add(MIB.getInstr(), MF, Tmp);
+ return MIB;
+}
+
// In SPIR-V address space casting can only happen to and from the Generic
// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
// pointers to and from Generic pointers. As such, we can convert e.g. from
@@ -1255,6 +1316,7 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
Register SrcPtr = I.getOperand(1).getReg();
SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
+
// don't generate a cast for a null that may be represented by OpTypeInt
if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer ||
ResType->getOpcode() != SPIRV::OpTypePointer)
@@ -1266,21 +1328,11 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
- // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
- // are expressed by OpSpecConstantOp with an Opcode.
- bool IsGRef = false;
- bool IsAllowedRefs =
- std::all_of(MRI->use_instr_begin(ResVReg), MRI->use_instr_end(),
- [&IsGRef](auto const &It) {
- unsigned Opcode = It.getOpcode();
- if (Opcode == SPIRV::OpConstantComposite ||
- Opcode == SPIRV::OpVariable ||
- isSpvIntrinsic(It, Intrinsic::spv_init_global))
- return IsGRef = true;
- return Opcode == SPIRV::OpName;
- });
- if (IsAllowedRefs && IsGRef) {
- // TODO: insert a check whether the Kernel capability was declared.
+ if (isASCastInGVar(MRI, ResVReg)) {
+ // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
+ // are expressed by OpSpecConstantOp with an Opcode.
+ // TODO: maybe insert a check whether the Kernel capability was declared and
+ // so PtrCastToGeneric/GenericCastToPtr are available.
unsigned SpecOpcode =
DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)
? static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
@@ -1288,42 +1340,21 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
isGenericCastablePtr(DstSC)
? static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
: 0);
+ // TODO: OpConstantComposite expects i8*, so we are forced to forget a
+ // correct value of ResType and use general i8* instead. Maybe this should
+ // be addressed in the emit-intrinsic step to infer a correct
+ // OpConstantComposite type.
if (SpecOpcode) {
- // TODO: OpConstantComposite expects i8*, so we are forced to forget a
- // correct value of ResType and use general i8* instead. Maybe this should
- // be addressed in the emit-intrinsic step to infer a correct
- // OpConstantComposite type.
- SPIRVType *NewResType = GR.getOrCreateSPIRVPointerType(
- GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, DstSC);
- bool Result = BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(NewResType))
- .addImm(SpecOpcode)
- .addUse(SrcPtr)
- .constrainAllUses(TII, TRI, RBI);
- return Result;
+ return buildSpecConstantOp(I, ResVReg, SrcPtr,
+ getUcharPtrTypeReg(I, DstSC), SpecOpcode)
+ .constrainAllUses(TII, TRI, RBI);
} else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
- SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
- GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
- Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
- MRI->setType(Tmp, LLT::pointer(0, 64));
- GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *BB.getParent());
- MachineInstrBuilder MIB =
- BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
- .addDef(Tmp)
- .addUse(GR.getSPIRVTypeID(GenericPtrTy))
- .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
- .addUse(SrcPtr);
- GR.add(MIB.getInstr(), BB.getParent(), Tmp);
- bool Result = MIB.constrainAllUses(TII, TRI, RBI);
- SPIRVType *NewResType = GR.getOrCreateSPIRVPointerType(
- GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, DstSC);
- return Result &&
- BuildMI(BB, I, DL, TII.get(SPIRV::OpSpecConstantOp))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(NewResType))
- .addImm(static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
- .addUse(Tmp)
+ MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy);
+ return MIB.constrainAllUses(TII, TRI, RBI) &&
+ buildSpecConstantOp(
+ I, ResVReg, MIB->getOperand(0).getReg(),
+ getUcharPtrTypeReg(I, DstSC),
+ static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
.constrainAllUses(TII, TRI, RBI);
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 3640188670d15c..d204a8ac7975d8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -45,7 +45,9 @@ static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) {
}
// Get length including padding and null terminator.
-static size_t getPaddedLen(const StringRef &Str) { return Str.size() + 4 & ~3; }
+static size_t getPaddedLen(const StringRef &Str) {
+ return (Str.size() + 4) & ~3;
+}
void addStringImm(const StringRef &Str, MCInst &Inst) {
const size_t PaddedLen = getPaddedLen(Str);
@@ -160,31 +162,6 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
}
}
-// TODO: maybe the following two functions should be handled in the subtarget
-// to allow for different OpenCL vs Vulkan handling.
-unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
- switch (SC) {
- case SPIRV::StorageClass::Function:
- return 0;
- case SPIRV::StorageClass::CrossWorkgroup:
- return 1;
- case SPIRV::StorageClass::UniformConstant:
- return 2;
- case SPIRV::StorageClass::Workgroup:
- return 3;
- case SPIRV::StorageClass::Generic:
- return 4;
- case SPIRV::StorageClass::DeviceOnlyINTEL:
- return 5;
- case SPIRV::StorageClass::HostOnlyINTEL:
- return 6;
- case SPIRV::StorageClass::Input:
- return 7;
- default:
- report_fatal_error("Unable to get address space id");
- }
-}
-
SPIRV::StorageClass::StorageClass
addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
switch (AddrSpace) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 0d9b238db1403d..f7e8a827c2767f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -134,7 +134,31 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
const MDNode *GVarMD);
// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
-unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
+// TODO: maybe the following two functions should be handled in the subtarget
+// to allow for different OpenCL vs Vulkan handling.
+constexpr unsigned
+storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
+ switch (SC) {
+ case SPIRV::StorageClass::Function:
+ return 0;
+ case SPIRV::StorageClass::CrossWorkgroup:
+ return 1;
+ case SPIRV::StorageClass::UniformConstant:
+ return 2;
+ case SPIRV::StorageClass::Workgroup:
+ return 3;
+ case SPIRV::StorageClass::Generic:
+ return 4;
+ case SPIRV::StorageClass::DeviceOnlyINTEL:
+ return 5;
+ case SPIRV::StorageClass::HostOnlyINTEL:
+ return 6;
+ case SPIRV::StorageClass::Input:
+ return 7;
+ default:
+ report_fatal_error("Unable to get address space id");
+ }
+}
// Convert an LLVM IR address space to a SPIR-V storage class.
SPIRV::StorageClass::StorageClass
More information about the llvm-commits
mailing list