[clang] [llvm] [SPIR-V] Implement SPV_KHR_untyped_pointers extension (PR #201233)

Dmitry Sidorov via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 29 10:45:54 PDT 2026


================
@@ -4553,32 +4567,88 @@ bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
                                          SPIRVTypeInst ResType,
                                          MachineInstr &I) const {
   const bool IsGEPInBounds = I.getOperand(2).getImm();
+  // Pointers to opaque types stay typed even with the extension on, so emit the
+  // untyped variant only when the result is actually an untyped pointer.
+  const bool UseUntypedPointers =
+      ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
 
-  // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
-  // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
-  // we have to use Op[InBounds]AccessChain.
-  const unsigned Opcode = STI.isLogicalSPIRV()
-                              ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
-                                               : SPIRV::OpAccessChain)
-                              : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
-                                               : SPIRV::OpPtrAccessChain);
+  // Determine the opcode based on pointer type and bounds checking.
+  // When using untyped pointers, use OpUntyped*AccessChainKHR variants.
+  unsigned Opcode;
+  if (UseUntypedPointers) {
+    if (STI.isLogicalSPIRV()) {
+      Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsAccessChainKHR
+                             : SPIRV::OpUntypedAccessChainKHR;
+    } else {
+      Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsPtrAccessChainKHR
+                             : SPIRV::OpUntypedPtrAccessChainKHR;
+    }
+  } else {
+    // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator
+    // only relies on PtrAccessChain, so we'll try not to deviate. For Vulkan
+    // however, we have to use Op[InBounds]AccessChain.
+    // FIXME: fix llvm-spirv.
+    if (STI.isLogicalSPIRV()) {
+      Opcode =
+          IsGEPInBounds ? SPIRV::OpInBoundsAccessChain : SPIRV::OpAccessChain;
+    } else {
+      Opcode = IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
+                             : SPIRV::OpPtrAccessChain;
+    }
+  }
 
   auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
                  .addDef(ResVReg)
-                 .addUse(GR.getSPIRVTypeID(ResType))
-                 // Object to get a pointer to.
-                 .addUse(I.getOperand(3).getReg());
-  assert(
-      (Opcode == SPIRV::OpPtrAccessChain ||
-       Opcode == SPIRV::OpInBoundsPtrAccessChain ||
-       (getImm(I.getOperand(4), MRI) && foldImm(I.getOperand(4), MRI) == 0)) &&
-      "Cannot translate GEP to OpAccessChain. First index must be 0.");
+                 .addUse(GR.getSPIRVTypeID(ResType));
+
+  // For untyped access chains, we need to add the base type operand.
+  if (UseUntypedPointers) {
+    // Get the element type from the base pointer register.
+    // For untyped pointers, this was stored when processing
+    // spv_assign_ptr_type.
+    Register BaseReg = I.getOperand(3).getReg();
+    SPIRVTypeInst BaseType = GR.getUntypedPtrElementType(BaseReg);
+    if (!BaseType) {
+      // Otherwise try the pointee type for mixed typed-pointer usage.
+      SPIRVTypeInst BasePtrType = GR.getSPIRVTypeForVReg(BaseReg);
+      BaseType = BasePtrType ? GR.getPointeeType(BasePtrType) : nullptr;
+    }
+    if (!BaseType) {
+      // The base may be a not-yet-selected global. Read its value type from
+      // the defining G_GLOBAL_VALUE, following copies.
+      Register DefReg = BaseReg;
+      MachineInstr *Def = MRI->getVRegDef(DefReg);
+      while (Def && Def->getOpcode() == TargetOpcode::COPY &&
+             Def->getOperand(1).isReg())
+        Def = MRI->getVRegDef(Def->getOperand(1).getReg());
+      if (Def && Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
+        if (const auto *GVar =
+                dyn_cast<GlobalVariable>(Def->getOperand(1).getGlobal()))
+          BaseType = GR.getOrCreateSPIRVType(GVar->getValueType(), I,
+                                             SPIRV::AccessQualifier::ReadWrite,
+                                             /*EmitIR=*/false);
+    }
+    if (!BaseType) {
+      BaseType = GR.getOrCreateSPIRVIntegerType(8, I, TII);
+    }
----------------
MrSidims wrote:

replaced with an error

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


More information about the cfe-commits mailing list