[llvm] [SPIRV] Make access qualifier optional for spirv.Image type (PR #110852)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 2 07:45:14 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Steven Perron (s-perron)

<details>
<summary>Changes</summary>

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`.


---
Full diff: https://github.com/llvm/llvm-project/pull/110852.diff


8 Files Affected:

- (modified) llvm/docs/SPIRVUsage.rst (+5-5) 
- (modified) llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp (+13-5) 
- (modified) llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h (+4-2) 
- (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+13-10) 
- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (+10-7) 
- (modified) llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td (+1) 
- (added) llvm/test/CodeGen/SPIRV/ShaderBufferImage.ll (+20) 
- (added) llvm/test/CodeGen/SPIRV/ShaderImage.ll (+21) 


``````````diff
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 38c41b0fad12e6..5485bb6195c3d4 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -223,19 +223,19 @@ using target extension types and are represented as follows:
 
   .. table:: SPIR-V Opaque Types
 
-     ================== ====================== =========================================================================================
+     ================== ====================== ===========================================================================================
      SPIR-V Type        LLVM type name         LLVM type arguments
-     ================== ====================== =========================================================================================
-     OpTypeImage        ``spirv.Image``        sampled type, dimensionality, depth, arrayed, MS, sampled, image format, access qualifier
+     ================== ====================== ===========================================================================================
+     OpTypeImage        ``spirv.Image``        sampled type, dimensionality, depth, arrayed, MS, sampled, image format, [access qualifier]
      OpTypeSampler      ``spirv.Sampler``      (none)
-     OpTypeSampledImage ``spirv.SampledImage`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, access qualifier
+     OpTypeSampledImage ``spirv.SampledImage`` sampled type, dimensionality, depth, arrayed, MS, sampled, image format, [access qualifier]
      OpTypeEvent        ``spirv.Event``        (none)
      OpTypeDeviceEvent  ``spirv.DeviceEvent``  (none)
      OpTypeReserveId    ``spirv.ReserveId``    (none)
      OpTypeQueue        ``spirv.Queue``        (none)
      OpTypePipe         ``spirv.Pipe``         access qualifier
      OpTypePipeStorage  ``spirv.PipeStorage``  (none)
-     ================== ====================== =========================================================================================
+     ================== ====================== ===========================================================================================
 
 All integer arguments take the same value as they do in their `corresponding
 SPIR-V instruction <https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_type_declaration_instructions>`_.
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 66cf163a1a0ac2..ed95f40edd8631 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -2678,8 +2678,19 @@ getImageType(const TargetExtType *ExtensionType,
          "SPIR-V image builtin type must have sampled type parameter!");
   const SPIRVType *SampledType =
       GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder);
-  assert(ExtensionType->getNumIntParameters() == 7 &&
+  assert((ExtensionType->getNumIntParameters() == 7 ||
+          ExtensionType->getNumIntParameters() == 6) &&
          "Invalid number of parameters for SPIR-V image builtin!");
+
+  SPIRV::AccessQualifier::AccessQualifier accessQualifier =
+      SPIRV::AccessQualifier::None;
+  if (ExtensionType->getNumIntParameters() == 7) {
+    accessQualifier = Qualifier == SPIRV::AccessQualifier::WriteOnly
+                          ? SPIRV::AccessQualifier::WriteOnly
+                          : SPIRV::AccessQualifier::AccessQualifier(
+                                ExtensionType->getIntParameter(6));
+  }
+
   // Create or get an existing type from GlobalRegistry.
   return GR->getOrCreateOpTypeImage(
       MIRBuilder, SampledType,
@@ -2687,10 +2698,7 @@ getImageType(const TargetExtType *ExtensionType,
       ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2),
       ExtensionType->getIntParameter(3), ExtensionType->getIntParameter(4),
       SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(5)),
-      Qualifier == SPIRV::AccessQualifier::WriteOnly
-          ? SPIRV::AccessQualifier::WriteOnly
-          : SPIRV::AccessQualifier::AccessQualifier(
-                ExtensionType->getIntParameter(6)));
+      accessQualifier);
 }
 
 static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,
diff --git a/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h b/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h
index a37e65a47eda04..609dcf397ba4f7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h
+++ b/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h
@@ -103,13 +103,15 @@ make_descr_image(const Type *SampledTy, unsigned Dim, unsigned Depth,
 inline SpecialTypeDescriptor
 make_descr_sampled_image(const Type *SampledTy, const MachineInstr *ImageTy) {
   assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);
+  unsigned AC = AccessQualifier::AccessQualifier::None;
+  if (ImageTy->getNumOperands() > 8)
+    AC = ImageTy->getOperand(8).getImm();
   return std::make_tuple(
       SampledTy,
       ImageAttrs(
           ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),
           ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),
-          ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(),
-          ImageTy->getOperand(8).getImm())
+          ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(), AC)
           .Val,
       SpecialTypeKind::STK_SampledImage);
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index ceca0a180c95b4..f35c2435e60a4d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -1149,16 +1149,19 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateOpTypeImage(
     return Res;
   Register ResVReg = createTypeVReg(MIRBuilder);
   DT.add(TD, &MIRBuilder.getMF(), ResVReg);
-  return MIRBuilder.buildInstr(SPIRV::OpTypeImage)
-      .addDef(ResVReg)
-      .addUse(getSPIRVTypeID(SampledType))
-      .addImm(Dim)
-      .addImm(Depth)        // Depth (whether or not it is a Depth image).
-      .addImm(Arrayed)      // Arrayed.
-      .addImm(Multisampled) // Multisampled (0 = only single-sample).
-      .addImm(Sampled)      // Sampled (0 = usage known at runtime).
-      .addImm(ImageFormat)
-      .addImm(AccessQual);
+  auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeImage)
+                 .addDef(ResVReg)
+                 .addUse(getSPIRVTypeID(SampledType))
+                 .addImm(Dim)
+                 .addImm(Depth)   // Depth (whether or not it is a Depth image).
+                 .addImm(Arrayed) // Arrayed.
+                 .addImm(Multisampled) // Multisampled (0 = only single-sample).
+                 .addImm(Sampled)      // Sampled (0 = usage known at runtime).
+                 .addImm(ImageFormat);
+
+  if (AccessQual != SPIRV::AccessQualifier::None)
+    MIB.addImm(AccessQual);
+  return MIB;
 }
 
 SPIRVType *
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 8908d8965b67c5..fbad10361308d2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -691,7 +691,9 @@ void RequirementHandler::initAvailableCapabilitiesForVulkan(
 
   // Provided by all supported Vulkan versions.
   addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float16,
-                    Capability::Float64, Capability::GroupNonUniform});
+                    Capability::Float64, Capability::GroupNonUniform,
+                    Capability::Image1D, Capability::SampledBuffer,
+                    Capability::ImageBuffer});
 }
 
 } // namespace SPIRV
@@ -776,12 +778,13 @@ static void addOpTypeImageReqs(const MachineInstr &MI,
   }
 
   // Has optional access qualifier.
-  // TODO: check if it's OpenCL's kernel.
-  if (MI.getNumOperands() > 8 &&
-      MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
-    Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
-  else
-    Reqs.addRequirements(SPIRV::Capability::ImageBasic);
+  if (ST.isOpenCLEnv()) {
+    if (MI.getNumOperands() > 8 &&
+        MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
+      Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
+    else
+      Reqs.addRequirements(SPIRV::Capability::ImageBasic);
+  }
 }
 
 // Add requirements for handling atomic float instructions
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 6bc27c7a0d193a..8c1e7b922b61c3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -1096,6 +1096,7 @@ multiclass AccessQualifierOperand<bits<32> value, list<Capability> reqCapabiliti
 defm ReadOnly : AccessQualifierOperand<0, [Kernel]>;
 defm WriteOnly : AccessQualifierOperand<1, [Kernel]>;
 defm ReadWrite : AccessQualifierOperand<2, [Kernel]>;
+defm None : AccessQualifierOperand<3, []>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define FunctionParameterAttribute enum values and at the
diff --git a/llvm/test/CodeGen/SPIRV/ShaderBufferImage.ll b/llvm/test/CodeGen/SPIRV/ShaderBufferImage.ll
new file mode 100644
index 00000000000000..ee9120cac7ae22
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/ShaderBufferImage.ll
@@ -0,0 +1,20 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-NOT: OpCapability ImageBasic
+; CHECK-NOT: OpCapability ImageReadWrite
+; CHECK: OpCapability ImageBuffer
+; CHECK-NOT: OpCapability ImageBasic
+; CHECK-NOT: OpCapability ImageReadWrite
+
+; CHECK: [[Float:%[0-9]+]] = OpTypeFloat 32
+; CHECK: [[Void:%[0-9]+]] = OpTypeVoid
+; CHECK: [[ImageType:%[0-9]+]] = OpTypeImage [[Float]] Buffer 2 0 0 2 R32i {{$}}
+; CHECK: [[ImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[ImageType]]
+
+; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[ImageFuncType]]    ; -- Begin function ImageWithNoAccessQualifier
+define void @ImageWithNoAccessQualifier(target("spirv.Image", float, 5, 2, 0, 0, 2, 24) %img) #0 {
+  ret void
+}
+
+attributes #0 = { convergent noinline norecurse "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
diff --git a/llvm/test/CodeGen/SPIRV/ShaderImage.ll b/llvm/test/CodeGen/SPIRV/ShaderImage.ll
new file mode 100644
index 00000000000000..9eea3e8cb74cce
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/ShaderImage.ll
@@ -0,0 +1,21 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: [[Float:%[0-9]+]] = OpTypeFloat 32
+; CHECK: [[Void:%[0-9]+]] = OpTypeVoid
+; CHECK: [[ImageType:%[0-9]+]] = OpTypeImage [[Float]] Buffer 2 0 0 1 R32i {{$}}
+; CHECK: [[ImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[ImageType]]
+; CHECK: [[SampledImageType:%[0-9]+]] = OpTypeSampledImage [[ImageType]]
+; CHECK: [[SampledImageFuncType:%[0-9]+]] = OpTypeFunction [[Void]] [[SampledImageType]]
+
+; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[ImageFuncType]]    ; -- Begin function ImageWithNoAccessQualifier
+define void @ImageWithNoAccessQualifier(target("spirv.Image", float, 5, 2, 0, 0, 1, 24) %img) #0 {
+  ret void
+}
+
+; CHECK: {{%[0-9]+}} = OpFunction [[Void]] DontInline [[SampledImageFuncType]]    ; -- Begin function SampledImageWithNoAccessQualifier
+define void @SampledImageWithNoAccessQualifier(target("spirv.SampledImage", float, 5, 2, 0, 0, 1, 24) %img) #0 {
+  ret void
+}
+
+attributes #0 = { convergent noinline norecurse "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }

``````````

</details>


https://github.com/llvm/llvm-project/pull/110852


More information about the llvm-commits mailing list