[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