[llvm] [SPIR-V] Add the Flat Decorator for Double and Int Storage Element Types (PR #194302)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 27 00:05:15 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Farzon Lotfi (farzonl)

<details>
<summary>Changes</summary>

fixes #<!-- -->194293

Adds a helper in SPIRVModuleAnalysis to iterate over `GlobalVarList` and apply the `Flat` decoration to integer and 64-bit float variables.

- Unwraps MIR types (Pointers, Arrays, Vectors) to check the base type.
- Guards emission with `ST.isShader()` to prevent capability validation crashes on OpenCL/Kernel targets.
- Make sure we are only operating on StorageClass::Input.
- Inserts decorations via `buildOpDecorate` before `processOtherInstrs` so they are correctly swept into the annotations section.
- Add test to check for Flat Decoration


Assisted by Gemini 3.1 Pro

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


2 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (+59) 
- (added) llvm/test/CodeGen/SPIRV/spv-flat-decoration.ll (+61) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index f32f3006c5e0e..5927e615095a0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2765,6 +2765,62 @@ static void handleMIFlagDecoration(
   }
 }
 
+static void applyFlatDecorations(SPIRV::ModuleAnalysisInfo &MAI,
+                                 const SPIRVInstrInfo &TII,
+                                 const SPIRVSubtarget &ST) {
+  // 1. Safety Guard: Flat is a Shader concept. Abort if OpenCL.
+  if (!ST.isShader())
+    return;
+
+  for (const MachineInstr *VarMI : MAI.GlobalVarList) {
+    if (!VarMI || VarMI->getOpcode() != SPIRV::OpVariable)
+      continue;
+
+    if (VarMI->getNumOperands() < 3 || !VarMI->getOperand(2).isImm() ||
+        VarMI->getOperand(2).getImm() != SPIRV::StorageClass::Input)
+      continue;
+
+    const MachineRegisterInfo &MRI = VarMI->getMF()->getRegInfo();
+    if (!VarMI->getOperand(1).isReg())
+      continue;
+
+    MachineInstr *TypeInst = MRI.getVRegDef(VarMI->getOperand(1).getReg());
+
+    // 2. Unwrap Pointer
+    if (TypeInst && TypeInst->getOpcode() == SPIRV::OpTypePointer &&
+        TypeInst->getNumOperands() >= 3) {
+      if (TypeInst->getOperand(2).isReg())
+        TypeInst = MRI.getVRegDef(TypeInst->getOperand(2).getReg());
+    }
+
+    // 3. Unwrap Arrays, RuntimeArrays, and Vectors
+    while (TypeInst && (TypeInst->getOpcode() == SPIRV::OpTypeArray ||
+                        TypeInst->getOpcode() == SPIRV::OpTypeRuntimeArray ||
+                        TypeInst->getOpcode() == SPIRV::OpTypeVector)) {
+      if (TypeInst->getNumOperands() < 2 || !TypeInst->getOperand(1).isReg())
+        break;
+      TypeInst = MRI.getVRegDef(TypeInst->getOperand(1).getReg());
+    }
+
+    if (!TypeInst)
+      continue;
+
+    // 4. Check base types
+    bool IsInt = (TypeInst->getOpcode() == SPIRV::OpTypeInt);
+    bool IsDouble =
+        (TypeInst->getOpcode() == SPIRV::OpTypeFloat &&
+         TypeInst->getNumOperands() >= 2 && TypeInst->getOperand(1).isImm() &&
+         TypeInst->getOperand(1).getImm() == 64);
+
+    // 5. Apply decoration right before the variable definition
+    if (IsInt || IsDouble) {
+      MachineInstr *NonConstMI = const_cast<MachineInstr *>(VarMI);
+      buildOpDecorate(VarMI->getOperand(0).getReg(), *NonConstMI, TII,
+                      SPIRV::Decoration::Flat, {});
+    }
+  }
+}
+
 // Walk all functions and add decorations related to MI flags.
 static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
                            MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
@@ -2965,6 +3021,9 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
   // Number rest of registers from N+1 onwards.
   numberRegistersGlobally(M);
 
+  // Apply our custom Flat decorations to global variables
+  applyFlatDecorations(MAI, *TII, *ST);
+
   // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
   processOtherInstrs(M);
 
diff --git a/llvm/test/CodeGen/SPIRV/spv-flat-decoration.ll b/llvm/test/CodeGen/SPIRV/spv-flat-decoration.ll
new file mode 100644
index 0000000000000..a9ee61c297fa5
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/spv-flat-decoration.ll
@@ -0,0 +1,61 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o - | FileCheck %s
+; We can't add the validator until we support VUID-StandaloneSpirv-Location-04916
+; TODO %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpName %[[#INT_VAR:]] "int_var"
+; CHECK-DAG: OpName %[[#DOUBLE_VAR:]] "double_var"
+; CHECK-DAG: OpName %[[#VEC_INT_VAR:]] "vec_int_var"
+; CHECK-DAG: OpName %[[#ARR_DOUBLE_VAR:]] "arr_double_var"
+; CHECK-DAG: OpName %[[#ARR_VEC_INT_VAR:]] "arr_vec_int_var"
+; CHECK-DAG: OpName %[[#FLOAT_VAR:]] "float_var"
+; CHECK-DAG: OpName %[[#PRIVATE_INT_VAR:]] "private_int_var"
+
+; -----------------------------------------------------------------------------
+; 1. Verify int and doubles scalar and element types receive the Flat decoration.
+; -----------------------------------------------------------------------------
+; CHECK-DAG: OpDecorate %[[#INT_VAR]] Flat
+; CHECK-DAG: OpDecorate %[[#DOUBLE_VAR]] Flat
+; CHECK-DAG: OpDecorate %[[#VEC_INT_VAR]] Flat
+; CHECK-DAG: OpDecorate %[[#ARR_DOUBLE_VAR]] Flat
+; CHECK-DAG: OpDecorate %[[#ARR_VEC_INT_VAR]] Flat
+
+; -----------------------------------------------------------------------------
+; 2. Verify that the negative test cases DO NOT receive the Flat decoration.
+; -----------------------------------------------------------------------------
+; CHECK-NOT: OpDecorate %[[#FLOAT_VAR]] Flat
+; CHECK-NOT: OpDecorate %[[#PRIVATE_INT_VAR]] Flat
+
+; scalar flat cases
+ at int_var = internal addrspace(7) global i32 undef
+ at double_var = internal addrspace(7) global double undef
+
+; vector flat case
+ at vec_int_var = internal addrspace(7) global <4 x i32> undef
+
+; array flat case
+ at arr_double_var = internal addrspace(7) global [4 x double] undef
+
+; array of vector flat case
+ at arr_vec_int_var = internal addrspace(7) global [2 x <4 x i32>] undef
+
+; float case so no Flat decoration
+ at float_var = internal addrspace(7) global float undef
+
+; wrong addresspace so no Flat decoration
+ at private_int_var = internal addrspace(0) global i32 undef
+
+define void @main() #1 {
+entry:
+  %0 = load volatile i32, ptr addrspace(7) @int_var
+  %1 = load volatile double, ptr addrspace(7) @double_var
+  %2 = load volatile <4 x i32>, ptr addrspace(7) @vec_int_var
+  %3 = load volatile [4 x double], ptr addrspace(7) @arr_double_var
+  %4 = load volatile [2 x <4 x i32>], ptr addrspace(7) @arr_vec_int_var
+  
+  %5 = load volatile float, ptr addrspace(7) @float_var
+  %6 = load volatile i32, ptr addrspace(0) @private_int_var
+  ret void
+}
+
+attributes #1 = { "hlsl.shader"="pixel" }
+

``````````

</details>


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


More information about the llvm-commits mailing list