Skip to content

Commit 5114758

Browse files
authored
[SPIRV] Make access qualifier optional for spirv.Image type (#110852)
The SPIRV backend has a special type named `spirv.Image`. This type is meant to correspond to the OpTypeImage instruction in SPIR-V, but there is one difference. The access qualifier operand in OpTypeImage is optional. On top of that, the access qualifiers are only valid for kernels, and not for shaders. We want to reuse this type when generating shader from HLSL, but we can't use the access qualifier. This commit make the access qualifer optional in the target extension type. The same is done for `spirv.SampledImage`. Contributes to #81036
1 parent a646436 commit 5114758

8 files changed

+87
-29
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,19 +223,19 @@ using target extension types and are represented as follows:
223223

224224
.. table:: SPIR-V Opaque Types
225225

226-
================== ====================== =========================================================================================
226+
================== ====================== ===========================================================================================
227227
SPIR-V Type LLVM type name LLVM type arguments
228-
================== ====================== =========================================================================================
229-
OpTypeImage ``spirv.Image`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, access qualifier
228+
================== ====================== ===========================================================================================
229+
OpTypeImage ``spirv.Image`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, [access qualifier]
230230
OpTypeSampler ``spirv.Sampler`` (none)
231-
OpTypeSampledImage ``spirv.SampledImage`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, access qualifier
231+
OpTypeSampledImage ``spirv.SampledImage`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, [access qualifier]
232232
OpTypeEvent ``spirv.Event`` (none)
233233
OpTypeDeviceEvent ``spirv.DeviceEvent`` (none)
234234
OpTypeReserveId ``spirv.ReserveId`` (none)
235235
OpTypeQueue ``spirv.Queue`` (none)
236236
OpTypePipe ``spirv.Pipe`` access qualifier
237237
OpTypePipeStorage ``spirv.PipeStorage`` (none)
238-
================== ====================== =========================================================================================
238+
================== ====================== ===========================================================================================
239239

240240
All integer arguments take the same value as they do in their `corresponding
241241
SPIR-V instruction <https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_type_declaration_instructions>`_.

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,19 +2678,27 @@ getImageType(const TargetExtType *ExtensionType,
26782678
"SPIR-V image builtin type must have sampled type parameter!");
26792679
const SPIRVType *SampledType =
26802680
GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder);
2681-
assert(ExtensionType->getNumIntParameters() == 7 &&
2681+
assert((ExtensionType->getNumIntParameters() == 7 ||
2682+
ExtensionType->getNumIntParameters() == 6) &&
26822683
"Invalid number of parameters for SPIR-V image builtin!");
2684+
2685+
SPIRV::AccessQualifier::AccessQualifier accessQualifier =
2686+
SPIRV::AccessQualifier::None;
2687+
if (ExtensionType->getNumIntParameters() == 7) {
2688+
accessQualifier = Qualifier == SPIRV::AccessQualifier::WriteOnly
2689+
? SPIRV::AccessQualifier::WriteOnly
2690+
: SPIRV::AccessQualifier::AccessQualifier(
2691+
ExtensionType->getIntParameter(6));
2692+
}
2693+
26832694
// Create or get an existing type from GlobalRegistry.
26842695
return GR->getOrCreateOpTypeImage(
26852696
MIRBuilder, SampledType,
26862697
SPIRV::Dim::Dim(ExtensionType->getIntParameter(0)),
26872698
ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2),
26882699
ExtensionType->getIntParameter(3), ExtensionType->getIntParameter(4),
26892700
SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(5)),
2690-
Qualifier == SPIRV::AccessQualifier::WriteOnly
2691-
? SPIRV::AccessQualifier::WriteOnly
2692-
: SPIRV::AccessQualifier::AccessQualifier(
2693-
ExtensionType->getIntParameter(6)));
2701+
accessQualifier);
26942702
}
26952703

26962704
static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,

llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,15 @@ make_descr_image(const Type *SampledTy, unsigned Dim, unsigned Depth,
103103
inline SpecialTypeDescriptor
104104
make_descr_sampled_image(const Type *SampledTy, const MachineInstr *ImageTy) {
105105
assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);
106+
unsigned AC = AccessQualifier::AccessQualifier::None;
107+
if (ImageTy->getNumOperands() > 8)
108+
AC = ImageTy->getOperand(8).getImm();
106109
return std::make_tuple(
107110
SampledTy,
108111
ImageAttrs(
109112
ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),
110113
ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),
111-
ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(),
112-
ImageTy->getOperand(8).getImm())
114+
ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(), AC)
113115
.Val,
114116
SpecialTypeKind::STK_SampledImage);
115117
}

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,16 +1149,19 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateOpTypeImage(
11491149
return Res;
11501150
Register ResVReg = createTypeVReg(MIRBuilder);
11511151
DT.add(TD, &MIRBuilder.getMF(), ResVReg);
1152-
return MIRBuilder.buildInstr(SPIRV::OpTypeImage)
1153-
.addDef(ResVReg)
1154-
.addUse(getSPIRVTypeID(SampledType))
1155-
.addImm(Dim)
1156-
.addImm(Depth) // Depth (whether or not it is a Depth image).
1157-
.addImm(Arrayed) // Arrayed.
1158-
.addImm(Multisampled) // Multisampled (0 = only single-sample).
1159-
.addImm(Sampled) // Sampled (0 = usage known at runtime).
1160-
.addImm(ImageFormat)
1161-
.addImm(AccessQual);
1152+
auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeImage)
1153+
.addDef(ResVReg)
1154+
.addUse(getSPIRVTypeID(SampledType))
1155+
.addImm(Dim)
1156+
.addImm(Depth) // Depth (whether or not it is a Depth image).
1157+
.addImm(Arrayed) // Arrayed.
1158+
.addImm(Multisampled) // Multisampled (0 = only single-sample).
1159+
.addImm(Sampled) // Sampled (0 = usage known at runtime).
1160+
.addImm(ImageFormat);
1161+
1162+
if (AccessQual != SPIRV::AccessQualifier::None)
1163+
MIB.addImm(AccessQual);
1164+
return MIB;
11621165
}
11631166

11641167
SPIRVType *

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,9 @@ void RequirementHandler::initAvailableCapabilitiesForVulkan(
691691

692692
// Provided by all supported Vulkan versions.
693693
addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float16,
694-
Capability::Float64, Capability::GroupNonUniform});
694+
Capability::Float64, Capability::GroupNonUniform,
695+
Capability::Image1D, Capability::SampledBuffer,
696+
Capability::ImageBuffer});
695697
}
696698

697699
} // namespace SPIRV
@@ -776,12 +778,13 @@ static void addOpTypeImageReqs(const MachineInstr &MI,
776778
}
777779

778780
// Has optional access qualifier.
779-
// TODO: check if it's OpenCL's kernel.
780-
if (MI.getNumOperands() > 8 &&
781-
MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
782-
Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
783-
else
784-
Reqs.addRequirements(SPIRV::Capability::ImageBasic);
781+
if (ST.isOpenCLEnv()) {
782+
if (MI.getNumOperands() > 8 &&
783+
MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
784+
Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
785+
else
786+
Reqs.addRequirements(SPIRV::Capability::ImageBasic);
787+
}
785788
}
786789

787790
// Add requirements for handling atomic float instructions

llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ multiclass AccessQualifierOperand<bits<32> value, list<Capability> reqCapabiliti
10961096
defm ReadOnly : AccessQualifierOperand<0, [Kernel]>;
10971097
defm WriteOnly : AccessQualifierOperand<1, [Kernel]>;
10981098
defm ReadWrite : AccessQualifierOperand<2, [Kernel]>;
1099+
defm None : AccessQualifierOperand<3, []>;
10991100

11001101
//===----------------------------------------------------------------------===//
11011102
// Multiclass used to define FunctionParameterAttribute enum values and at the
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-NOT: OpCapability ImageBasic
5+
; CHECK-NOT: OpCapability ImageReadWrite
6+
; CHECK: OpCapability ImageBuffer
7+
; CHECK-NOT: OpCapability ImageBasic
8+
; CHECK-NOT: OpCapability ImageReadWrite
9+
10+
; CHECK-DAG: [[Float:%[0-9]+]] = OpTypeFloat 32
11+
; CHECK-DAG: [[Void:%[0-9]+]] = OpTypeVoid
12+
; CHECK-DAG: [[ImageType:%[0-9]+]] = OpTypeImage [[Float]] Buffer 2 0 0 2 R32i {{$}}
13+
; CHECK-DAG: [[ImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[ImageType]]
14+
15+
; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[ImageFuncType]]
16+
define void @ImageWithNoAccessQualifier(target("spirv.Image", float, 5, 2, 0, 0, 2, 24) %img) #0 {
17+
ret void
18+
}
19+
20+
attributes #0 = { convergent noinline norecurse "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-DAG: [[Float:%[0-9]+]] = OpTypeFloat 32
5+
; CHECK-DAG: [[Void:%[0-9]+]] = OpTypeVoid
6+
; CHECK-DAG: [[ImageType:%[0-9]+]] = OpTypeImage [[Float]] Buffer 2 0 0 1 R32i {{$}}
7+
; CHECK-DAG: [[ImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[ImageType]]
8+
; CHECK-DAG: [[SampledImageType:%[0-9]+]] = OpTypeSampledImage [[ImageType]]
9+
; CHECK-DAG: [[SampledImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[SampledImageType]]
10+
11+
; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[ImageFuncType]]
12+
define void @ImageWithNoAccessQualifier(target("spirv.Image", float, 5, 2, 0, 0, 1, 24) %img) #0 {
13+
ret void
14+
}
15+
16+
; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[SampledImageFuncType]]
17+
define void @SampledImageWithNoAccessQualifier(target("spirv.SampledImage", float, 5, 2, 0, 0, 1, 24) %img) #0 {
18+
ret void
19+
}
20+
21+
attributes #0 = { convergent noinline norecurse "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }

0 commit comments

Comments
 (0)