[clang] [llvm] [HLSL][DirectX] Correct codegen of `dx.load.input`/`dx.store.output` intrinsic calls (PR #212656)

Finn Plummer via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 13:05:21 PDT 2026


https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/212656

>From 633294bcfebc861240abbe66dc4987bebeb830ca Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 24 Jul 2026 23:34:32 +0000
Subject: [PATCH 01/15] remove operands

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 11 ++++------
 .../CodeGenHLSL/semantics/SV_Position.ps.hlsl |  4 ++--
 .../CodeGenHLSL/semantics/SV_Position.vs.hlsl |  4 ++--
 .../CodeGenHLSL/semantics/SV_Target.ps.hlsl   |  2 +-
 .../CodeGenHLSL/semantics/SV_VertexID.vs.hlsl |  2 +-
 .../semantics/semantic.arbitrary.hlsl         |  6 +++---
 .../CodeGenHLSL/semantics/semantic.array.hlsl |  9 ++++++---
 .../semantics/semantic.array.output.hlsl      |  9 ++++++---
 ...antic.explicit-location-output-struct.hlsl |  2 +-
 .../semantics/semantic.explicit-location.hlsl |  2 +-
 .../semantics/semantic.struct.output.hlsl     |  4 ++--
 clang/test/CodeGenHLSL/sret_output.hlsl       |  2 +-
 llvm/include/llvm/IR/IntrinsicsDirectX.td     | 20 +++++++++++--------
 13 files changed, 42 insertions(+), 35 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f86cb00c204f8..bdb99fad984a9 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1194,10 +1194,9 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
   Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
 
   // DXIL packing rules etc shall be handled here.
-  // FIXME: generate proper sigpoint, index, col, row values.
+  // FIXME: generate proper index, col, row values.
   // FIXME: also DXIL loads vectors element by element.
-  SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
-                            B.getInt8(0),
+  SmallVector<Value *> Args{B.getInt32(0), B.getInt32(0), B.getInt8(0),
                             llvm::PoisonValue::get(B.getInt32Ty())};
 
   llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
@@ -1219,12 +1218,10 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
                                               HLSLAppliedSemanticAttr *Semantic,
                                               std::optional<unsigned> Index) {
   // DXIL packing rules etc shall be handled here.
-  // FIXME: generate proper sigpoint, index, col, row values.
-  SmallVector<Value *> Args{B.getInt32(4),
-                            B.getInt32(0),
+  // FIXME: generate proper sigid, index, col, row values.
+  SmallVector<Value *> Args{B.getInt32(0),
                             B.getInt32(0),
                             B.getInt8(0),
-                            llvm::PoisonValue::get(B.getInt32Ty()),
                             Source};
 
   llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index b118ee395f7de..ac695b1f7d5eb 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -9,9 +9,9 @@ float4 main(float4 p : SV_Position) : A {
   // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
   // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 4
 
-  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
   // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
index caab744c1fa98..350b5e3612e32 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
@@ -10,9 +10,9 @@ float4 main(float4 p : SV_Position) : SV_Position {
   // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
   // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Position, align 4
 
-  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
   // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
index 1ab4df4f61bd7..73255e3a9b939 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
@@ -9,7 +9,7 @@ float4 main(float4 p : SV_Position) : SV_Target {
   // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 4
 
   // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
index e2c184ac7948c..491f10b530c38 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
@@ -8,7 +8,7 @@ uint main(uint id : SV_VertexID) : A {
   // CHECK-SPIRV: %[[#P:]] = load i32, ptr addrspace(7) @SV_VertexID, align 4
   // CHECK-SPIRV:   %[[#]] = call spir_func i32 @_Z4mainj(i32 %[[#P]])
 
-  // CHECK-DXIL: %SV_VertexID0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %SV_VertexID0 = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison)
   // CHECK-DXIL:        %[[#]] = call i32 @_Z4mainj(i32 %SV_VertexID0)
   return id;
 }
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
index 1ea2827660307..720dafcd4f1b6 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
@@ -14,9 +14,9 @@ void main(float a : AAA, int b : B, float2 c : CC) {
 
 // CHECK: define void @main()
 
-// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:   %B0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL   %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:   %B0 = call i32 @llvm.dx.load.input.i32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK-DXIL   %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
 // CHECK-DXIL:         call void @_Z4mainfiDv2_f(float %AAA0, i32 %B0, <2 x float> %CC0)
 
 // CHECK-SPIRV: %[[#AAA0:]] = load float, ptr addrspace(7) @AAA0, align 4
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
index c62c4d4a517f2..b50d2da9a0114 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
@@ -12,9 +12,12 @@ struct S0 {
 // CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
 
 // CHECK:       define void @main0()
-// CHECK-DXIL:          %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:  %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0
-// CHECK-DXIL:          %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:          %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[#POS0:]] = insertvalue [2 x <4 x float>] poison, <4 x float> %A0, 0
+// CHECK-DXIL:          %A1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 1, i8 0, i32 poison)
+// CHECK-DXIL: %[[#POS1:]] = insertvalue [2 x <4 x float>] %[[#POS0]], <4 x float> %A1, 1
+// CHECK-DXIL:  %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#POS1]], 0
+// CHECK-DXIL:          %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
 // CHECK-DXIL:  %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1
 
 // CHECK-SPIRV:   %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 4
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 18942699aaa2c..9d3afc5e8fba6 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -12,17 +12,20 @@ struct S0 {
 S0 main1(float4 input : A) : B {
 // CHECK:         %[[#ARG:]] = alloca %struct.S0
 // CHECK-SPIRV: %[[#INPUT:]] = load <4 x float>, ptr addrspace(7) @A0, align 4
-// CHECK-DXIL:           %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:           %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
 // CHECK-DXIL:                 call void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %A0)
 // CHECK-SPIRV:                call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %[[#INPUT]])
 
   // CHECK:        %[[#ST:]] = load %struct.S0, ptr %[[#ARG]]
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0
   // CHECK-SPIRV:              store [2 x <4 x float>] %[[#TMP]], ptr addrspace(8) @B0, align 4
-  // CHECK-DXIL:               call void @llvm.dx.store.output.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, [2 x <4 x float>] %[[#TMP]])
+  // CHECK-DXIL:  %[[#POS0:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 0
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#POS0]])
+  // CHECK-DXIL:  %[[#POS1:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 1
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 1, i8 0, <4 x float> %[[#POS1]])
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1
   // CHECK-SPIRV:              store <4 x float> %[[#TMP]], ptr addrspace(8) @B2, align 4
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#TMP]])
 
   S0 output;
   output.position[0] = input;
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
index 8bd8998cdceb5..b24cee7baf8ae 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
@@ -21,7 +21,7 @@ Output main(float4 p : SV_Position) {
   // CHECK: %[[#FIELD:]] = extractvalue %struct.Output %[[#TMP]], 0
 
   // CHECK-SPIRV:                store <4 x float> %[[#FIELD]], ptr addrspace(8) @SV_Target0, align 4
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#FIELD]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#FIELD]])
   Output o;
   o.field = p;
   return o;
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
index 625d5dcb02ec4..2ca0f3fe65a57 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
@@ -9,7 +9,7 @@
   // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 4
 
   // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
index 0f2444d21724a..426738adfe7ef 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
@@ -43,10 +43,10 @@ Output main(Input input) {
 // CHECK: %[[#TMP:]] = load %struct.Output, ptr %[[#OUTPUT]], align 4
 // CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 0
 // CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A4, align 4
-// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#VAL]])
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#VAL]])
 // CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 1
 // CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A2, align 4
-// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#VAL]])
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 1, i32 0, i8 0, float %[[#VAL]])
 
 // CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
 // CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]}
diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl b/clang/test/CodeGenHLSL/sret_output.hlsl
index e1aa0973fe5db..325c31541f473 100644
--- a/clang/test/CodeGenHLSL/sret_output.hlsl
+++ b/clang/test/CodeGenHLSL/sret_output.hlsl
@@ -25,7 +25,7 @@ S vs_main() {
 // CHECK-VK:              call spir_func void @_Z7vs_mainv(ptr %[[#alloca]])
 // CHECK: %[[#a:]] = load %struct.S, ptr %[[#alloca]], align 4
 // CHECK: %[[#b:]] = extractvalue %struct.S %[[#a]], 0
-// CHECK-DX:         call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#b]])
+// CHECK-DX:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#b]])
 // CHECK-VK:         store float %3, ptr addrspace(8) @A4, align 4
 // CHECK:            ret void
 
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 72835175fded8..fd1b522c5e012 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -324,14 +324,18 @@ def int_dx_group_memory_barrier_with_group_sync
     : DefaultAttrsIntrinsic<[], [], [IntrConvergent]>;
 
 def int_dx_load_input
-    : DefaultAttrsIntrinsic<[llvm_any_ty],
-                            [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
-                             llvm_i32_ty],
-                            [IntrConvergent]>;
+    : DefaultAttrsIntrinsic<
+          [llvm_any_ty],
+          [llvm_i32_ty /*SigElementId*/,
+           llvm_i32_ty /*RowIndex*/, llvm_i8_ty /*ColIndex*/,
+           llvm_i32_ty /*GsVertexOrPrimIndex*/],
+          [IntrConvergent]>;
 
 def int_dx_store_output
-    : DefaultAttrsIntrinsic<[],
-                            [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
-                             llvm_i32_ty, llvm_any_ty],
-                            [IntrConvergent]>;
+    : DefaultAttrsIntrinsic<
+          [],
+          [llvm_i32_ty /*SigElementId*/,
+           llvm_i32_ty /*RowIndex*/, llvm_i8_ty /*ColIndex*/,
+           llvm_any_ty /*Value*/],
+          [IntrConvergent]>;
 }

>From 6654b0b320b14fd692ceaea725923fbe90adcc19 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 28 Jul 2026 20:41:35 +0000
Subject: [PATCH 02/15] assign semantic ids in parse order

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp                 | 13 ++++++-------
 clang/lib/CodeGen/CGHLSLRuntime.h                   |  5 +++++
 .../test/CodeGenHLSL/semantics/semantic.array.hlsl  |  9 +++------
 .../semantics/semantic.array.output.hlsl            |  5 +----
 4 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index bdb99fad984a9..08a13a7e22068 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1194,9 +1194,10 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
   Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
 
   // DXIL packing rules etc shall be handled here.
-  // FIXME: generate proper index, col, row values.
-  // FIXME: also DXIL loads vectors element by element.
-  SmallVector<Value *> Args{B.getInt32(0), B.getInt32(0), B.getInt8(0),
+  // FIXME: generate proper col, row values, also DXIL loads vectors element by
+  // element.
+  SmallVector<Value *> Args{B.getInt32(DXILInputSemanticIndex++), B.getInt32(0),
+                            B.getInt8(0),
                             llvm::PoisonValue::get(B.getInt32Ty())};
 
   llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
@@ -1219,10 +1220,8 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
                                               std::optional<unsigned> Index) {
   // DXIL packing rules etc shall be handled here.
   // FIXME: generate proper sigid, index, col, row values.
-  SmallVector<Value *> Args{B.getInt32(0),
-                            B.getInt32(0),
-                            B.getInt8(0),
-                            Source};
+  SmallVector<Value *> Args{B.getInt32(DXILOutputSemanticIndex++),
+                            B.getInt32(0), B.getInt8(0), Source};
 
   llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
 
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 23b47980f2ef0..aeb33a09c86aa 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -369,6 +369,11 @@ class CGHLSLRuntime {
   llvm::DenseMap<const clang::RecordType *, llvm::StructType *> LayoutTypes;
   unsigned SPIRVLastAssignedInputSemanticLocation = 0;
   unsigned SPIRVLastAssignedOutputSemanticLocation = 0;
+  // DXIL assigns each leaf semantic an index in parse order. Inputs and outputs
+  // are counted independently. Reset in emitEntryFunction before lowering the
+  // semantics of an entry point.
+  unsigned DXILInputSemanticIndex = 0;
+  unsigned DXILOutputSemanticIndex = 0;
 };
 
 } // namespace CodeGen
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
index b50d2da9a0114..d395baaa6b335 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
@@ -12,13 +12,10 @@ struct S0 {
 // CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
 
 // CHECK:       define void @main0()
-// CHECK-DXIL:          %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL: %[[#POS0:]] = insertvalue [2 x <4 x float>] poison, <4 x float> %A0, 0
-// CHECK-DXIL:          %A1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 1, i8 0, i32 poison)
-// CHECK-DXIL: %[[#POS1:]] = insertvalue [2 x <4 x float>] %[[#POS0]], <4 x float> %A1, 1
-// CHECK-DXIL:  %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#POS1]], 0
+// CHECK-DXIL:          %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0
 // CHECK-DXIL:          %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:  %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1
+// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1
 
 // CHECK-SPIRV:   %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 4
 // CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 9d3afc5e8fba6..32b7019b0c630 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -19,10 +19,7 @@ S0 main1(float4 input : A) : B {
   // CHECK:        %[[#ST:]] = load %struct.S0, ptr %[[#ARG]]
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0
   // CHECK-SPIRV:              store [2 x <4 x float>] %[[#TMP]], ptr addrspace(8) @B0, align 4
-  // CHECK-DXIL:  %[[#POS0:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 0
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#POS0]])
-  // CHECK-DXIL:  %[[#POS1:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 1
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 1, i8 0, <4 x float> %[[#POS1]])
+  // CHECK-DXIL:               call void @llvm.dx.store.output.a2v4f32(i32 0, i32 0, i8 0, [2 x <4 x float>] %[[#TMP]])
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1
   // CHECK-SPIRV:              store <4 x float> %[[#TMP]], ptr addrspace(8) @B2, align 4
   // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#TMP]])

>From a26420354afc5cf945e6dfdf0e5cf02afa913320 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 28 Jul 2026 20:53:15 +0000
Subject: [PATCH 03/15] add test cases

---
 .../CodeGenHLSL/semantics/semantic.input.hlsl | 55 ++++++++++++++++++
 .../semantics/semantic.output.hlsl            | 58 +++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
 create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.output.hlsl

diff --git a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
new file mode 100644
index 0000000000000..e1ea53bf16de9
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
@@ -0,0 +1,55 @@
+// Per-row load.input emission for the range of semantic leaf types:
+//   float          - scalar        -> 1 row
+//   float4         - vector        -> 1 row (4 columns)
+//   float[5]       - scalar array  -> 5 rows
+//   float4[2][3]   - vector array  -> 6 rows (multidimensional, 4 columns each)
+//
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S {
+  float a       : A;
+  float4 b      : B;
+  float d[5]    : D;
+  float4 e[2][3] : E;
+};
+
+[shader("vertex")]
+void main(S s) {}
+
+// float a : A -> 1 row, 1 column.
+// CHECK: %A0 = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK: %[[#S:]] = insertvalue %struct.S poison, float %A0, 0
+
+// float4 b : B -> 1 row, 4 columns.
+// CHECK: %B0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], <4 x float> %B0, 1
+
+// float d[5] : D -> 5 rows, 1 column each.
+// CHECK: %D0 = call float @llvm.dx.load.input.f32(i32 2, i32 0, i8 0, i32 poison)
+// CHECK: %[[#D:]] = insertvalue [5 x float] poison, float %D0, 0
+// CHECK: %D1 = call float @llvm.dx.load.input.f32(i32 2, i32 1, i8 0, i32 poison)
+// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D1, 1
+// CHECK: %D2 = call float @llvm.dx.load.input.f32(i32 2, i32 2, i8 0, i32 poison)
+// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D2, 2
+// CHECK: %D3 = call float @llvm.dx.load.input.f32(i32 2, i32 3, i8 0, i32 poison)
+// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D3, 3
+// CHECK: %D4 = call float @llvm.dx.load.input.f32(i32 2, i32 4, i8 0, i32 poison)
+// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D4, 4
+// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], [5 x float] %[[#D]], 2
+
+// float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
+// CHECK: %E0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 0, i8 0, i32 poison)
+// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] poison, <4 x float> %E0, 0
+// CHECK: %E1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 1, i8 0, i32 poison)
+// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] %[[#E0]], <4 x float> %E1, 1
+// CHECK: %E2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 2, i8 0, i32 poison)
+// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] %[[#E0]], <4 x float> %E2, 2
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] poison, [3 x <4 x float>] %[[#E0]], 0
+// CHECK: %E3 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 3, i8 0, i32 poison)
+// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] poison, <4 x float> %E3, 0
+// CHECK: %E4 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 4, i8 0, i32 poison)
+// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] %[[#E1]], <4 x float> %E4, 1
+// CHECK: %E5 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 5, i8 0, i32 poison)
+// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] %[[#E1]], <4 x float> %E5, 2
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], [3 x <4 x float>] %[[#E1]], 1
+// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], [2 x [3 x <4 x float>]] %[[#E]], 3
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
new file mode 100644
index 0000000000000..2b1d36b140838
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
@@ -0,0 +1,58 @@
+// Per-row store.output emission for the range of semantic leaf types:
+//   float          - scalar        -> 1 row
+//   float4         - vector        -> 1 row (4 columns)
+//   float[5]       - scalar array  -> 5 rows
+//   float4[2][3]   - vector array  -> 6 rows (multidimensional, 4 columns each)
+//
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S {
+  float a       : A;
+  float4 b      : B;
+  float d[5]    : D;
+  float4 e[2][3] : E;
+};
+
+[shader("vertex")]
+S main() {
+  S s;
+  return s;
+}
+
+// float a : A -> 1 row, 1 column.
+// CHECK: %[[#A:]] = extractvalue %struct.S %[[#S:]], 0
+// CHECK: call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#A]])
+
+// float4 b : B -> 1 row, 4 columns; the whole vector is stored.
+// CHECK: %[[#B:]] = extractvalue %struct.S %[[#S]], 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#B]])
+
+// float d[5] : D -> 5 rows, 1 column each.
+// CHECK: %[[#D:]] = extractvalue %struct.S %[[#S]], 2
+// CHECK: %[[#D0:]] = extractvalue [5 x float] %[[#D]], 0
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 0, i8 0, float %[[#D0]])
+// CHECK: %[[#D1:]] = extractvalue [5 x float] %[[#D]], 1
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 1, i8 0, float %[[#D1]])
+// CHECK: %[[#D2:]] = extractvalue [5 x float] %[[#D]], 2
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 2, i8 0, float %[[#D2]])
+// CHECK: %[[#D3:]] = extractvalue [5 x float] %[[#D]], 3
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 3, i8 0, float %[[#D3]])
+// CHECK: %[[#D4:]] = extractvalue [5 x float] %[[#D]], 4
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 4, i8 0, float %[[#D4]])
+
+// float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
+// CHECK: %[[#E:]] = extractvalue %struct.S %[[#S]], 3
+// CHECK: %[[#E0:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0
+// CHECK: %[[#E00:]] = extractvalue [3 x <4 x float>] %[[#E0]], 0
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 0, i8 0, <4 x float> %[[#E00]])
+// CHECK: %[[#E01:]] = extractvalue [3 x <4 x float>] %[[#E0]], 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 1, i8 0, <4 x float> %[[#E01]])
+// CHECK: %[[#E02:]] = extractvalue [3 x <4 x float>] %[[#E0]], 2
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 2, i8 0, <4 x float> %[[#E02]])
+// CHECK: %[[#E1:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1
+// CHECK: %[[#E10:]] = extractvalue [3 x <4 x float>] %[[#E1]], 0
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 3, i8 0, <4 x float> %[[#E10]])
+// CHECK: %[[#E11:]] = extractvalue [3 x <4 x float>] %[[#E1]], 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 4, i8 0, <4 x float> %[[#E11]])
+// CHECK: %[[#E12:]] = extractvalue [3 x <4 x float>] %[[#E1]], 2
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 5, i8 0, <4 x float> %[[#E12]])

>From be246a4dd457f2720c78c42efe1630494ce2bb4b Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 28 Jul 2026 23:16:48 +0000
Subject: [PATCH 04/15] correct intrin calls

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 175 +++++++++++++++---
 clang/lib/CodeGen/CGHLSLRuntime.h             |   3 +
 .../CodeGenHLSL/semantics/semantic.array.hlsl |  11 +-
 .../semantics/semantic.array.output.hlsl      |   5 +-
 4 files changed, 163 insertions(+), 31 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 08a13a7e22068..cb2be9bbdd0b5 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1186,21 +1186,59 @@ void CGHLSLRuntime::emitSPIRVUserSemanticStore(
                            VariableName.str());
 }
 
+namespace {
+// Describes how a semantic leaf lowers to signature rows
+struct SemanticShape {
+  unsigned Rows;
+  unsigned Cols;
+  QualType RowType;
+};
+} // namespace
+
+// Returns the QualType of a semantic leaf declarator. For a function the
+// declared return type is used, otherwise the declared type.
+static QualType getSemanticLeafType(const clang::DeclaratorDecl *Decl) {
+  if (const auto *FD = dyn_cast<clang::FunctionDecl>(Decl))
+    return FD->getDeclaredReturnType();
+  return Decl->getType();
+}
+
+// Walks through the surrounding constant array types of \p Ty, accumulating the
+// number of rows, until reaching a scalar, vector, or matrix leaf. The leaf is
+// returned as the row type together with the number of rows.
+static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
+  unsigned Rows = 1;
+  while (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(Ty)) {
+    Rows *= CAT->getSize().getZExtValue();
+    Ty = CAT->getElementType();
+  }
+
+  unsigned Cols = 1;
+  if (const auto *VT = Ty->getAs<clang::VectorType>()) {
+    Cols = VT->getNumElements();
+  } else if (const auto *MT = Ty->getAs<clang::ConstantMatrixType>()) {
+    // FIXME: a matrix leaf lowers to one row per matrix row but if column_major
+    // is specified we transpose the num rows and num cols, this depends on
+    // #211977 to resolve
+    Cols = MT->getNumColumns();
+  }
+
+  return {Rows, Cols, Ty};
+}
+
 llvm::Value *
 CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+                                        const clang::DeclaratorDecl *Decl,
                                         HLSLAppliedSemanticAttr *Semantic,
                                         std::optional<unsigned> Index) {
-  Twine BaseName = Twine(Semantic->getAttrName()->getName());
-  Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
+  StringRef Name = Semantic->getAttrName()->getName();
+  SemanticShape Shape =
+      getSemanticShape(CGM.getContext(), getSemanticLeafType(Decl));
 
-  // DXIL packing rules etc shall be handled here.
-  // FIXME: generate proper col, row values, also DXIL loads vectors element by
-  // element.
-  SmallVector<Value *> Args{B.getInt32(DXILInputSemanticIndex++), B.getInt32(0),
-                            B.getInt8(0),
-                            llvm::PoisonValue::get(B.getInt32Ty())};
+  llvm::Type *RowTy = CGM.getTypes().ConvertTypeForMem(Shape.RowType);
 
-  llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
+  llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
+      B.GetInsertBlock()->getModule(), llvm::Intrinsic::dx_load_input, {RowTy});
 
   SmallVector<OperandBundleDef, 1> OB;
   if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
@@ -1208,22 +1246,82 @@ CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
     OB.emplace_back("convergencectrl", bundleArgs);
   }
 
-  llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
-      B.GetInsertBlock()->getModule(), IntrinsicID, {Type});
-  llvm::Value *Value = B.CreateCall(IntrFn, Args, OB, VariableName);
-  return Value;
+  unsigned SigId = DXILInputSemanticIndex++;
+  unsigned Row = 0;
+
+  // Scalar and vector leaves need no aggregate reconstruction.
+  if (!isa<llvm::ArrayType>(Type)) {
+    SmallVector<Value *> Args{
+        /*SigElementId=*/B.getInt32(SigId),
+        /*RowIndex=*/B.getInt32(Row),
+        /*ColIndex=*/B.getInt8(0),
+        /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
+    llvm::Value *Result =
+        B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row++)));
+    assert(Row == Shape.Rows && "unexpected number of semantic rows");
+    return Result;
+  }
+
+  struct LoadItem {
+    llvm::ArrayType *Type;
+    llvm::Value *Aggregate;
+    unsigned NextIndex;
+  };
+
+  SmallVector<LoadItem> Worklist;
+  auto *RootTy = cast<llvm::ArrayType>(Type);
+  Worklist.push_back({RootTy, llvm::PoisonValue::get(RootTy), 0});
+
+  llvm::Value *Result = nullptr;
+  while (!Worklist.empty()) {
+    LoadItem &Frame = Worklist.back();
+
+    if (Frame.NextIndex == Frame.Type->getNumElements()) {
+      llvm::Value *Aggregate = Frame.Aggregate;
+      Worklist.pop_back();
+      if (Worklist.empty()) {
+        Result = Aggregate;
+        break;
+      }
+
+      LoadItem &Parent = Worklist.back();
+      Parent.Aggregate =
+          B.CreateInsertValue(Parent.Aggregate, Aggregate, Parent.NextIndex++);
+      continue;
+    }
+
+    llvm::Type *ElementTy = Frame.Type->getElementType();
+    if (auto *AT = dyn_cast<llvm::ArrayType>(ElementTy)) {
+      Worklist.push_back({AT, llvm::PoisonValue::get(AT), 0});
+      continue;
+    }
+
+    SmallVector<Value *> Args{
+        /*SigElementId=*/B.getInt32(SigId),
+        /*RowIndex=*/B.getInt32(Row),
+        /*ColIndex=*/B.getInt8(0),
+        /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
+    llvm::Value *Elt =
+        B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row++)));
+    Frame.Aggregate =
+        B.CreateInsertValue(Frame.Aggregate, Elt, Frame.NextIndex++);
+  }
+  assert(Row == Shape.Rows && "unexpected number of semantic rows");
+  return Result;
 }
 
 void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
                                               llvm::Value *Source,
+                                              const clang::DeclaratorDecl *Decl,
                                               HLSLAppliedSemanticAttr *Semantic,
                                               std::optional<unsigned> Index) {
-  // DXIL packing rules etc shall be handled here.
-  // FIXME: generate proper sigid, index, col, row values.
-  SmallVector<Value *> Args{B.getInt32(DXILOutputSemanticIndex++),
-                            B.getInt32(0), B.getInt8(0), Source};
+  SemanticShape Shape =
+      getSemanticShape(CGM.getContext(), getSemanticLeafType(Decl));
+  llvm::Type *RowTy = CGM.getTypes().ConvertTypeForMem(Shape.RowType);
 
-  llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
+  llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
+      B.GetInsertBlock()->getModule(), llvm::Intrinsic::dx_store_output,
+      {RowTy});
 
   SmallVector<OperandBundleDef, 1> OB;
   if (auto *Token = getConvergenceToken(*B.GetInsertBlock())) {
@@ -1231,9 +1329,34 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
     OB.emplace_back("convergencectrl", bundleArgs);
   }
 
-  llvm::Function *IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
-      B.GetInsertBlock()->getModule(), IntrinsicID, {Source->getType()});
-  B.CreateCall(IntrFn, Args, OB);
+  unsigned SigId = DXILOutputSemanticIndex++;
+  unsigned Row = 0;
+
+  struct StoreItem {
+    llvm::Value *Aggregate;
+    std::optional<unsigned> Index;
+  };
+
+  SmallVector<StoreItem> Worklist{{Source, std::nullopt}};
+  while (!Worklist.empty()) {
+    StoreItem Item = Worklist.pop_back_val();
+    llvm::Value *Val = Item.Index
+                           ? B.CreateExtractValue(Item.Aggregate, *Item.Index)
+                           : Item.Aggregate;
+
+    if (auto *AT = dyn_cast<llvm::ArrayType>(Val->getType())) {
+      // Push elements in reverse so index 0 is visited first
+      for (unsigned I = AT->getNumElements(); I-- > 0;)
+        Worklist.push_back({Val, I});
+      continue;
+    }
+
+    SmallVector<Value *> Args{/*SigElementId=*/B.getInt32(SigId),
+                              /*RowIndex=*/B.getInt32(Row++),
+                              /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
+    B.CreateCall(IntrFn, Args, OB);
+  }
+  assert(Row == Shape.Rows && "unexpected number of semantic rows");
 }
 
 llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
@@ -1244,7 +1367,7 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
     return emitSPIRVUserSemanticLoad(B, FD, Type, Decl, Semantic, Index);
 
   if (CGM.getTarget().getTriple().isDXIL())
-    return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
+    return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index);
 
   llvm_unreachable("Unsupported target for user-semantic load.");
 }
@@ -1257,7 +1380,7 @@ void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
     return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index);
 
   if (CGM.getTarget().getTriple().isDXIL())
-    return emitDXILUserSemanticStore(B, Source, Semantic, Index);
+    return emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index);
 
   llvm_unreachable("Unsupported target for user-semantic load.");
 }
@@ -1312,7 +1435,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
                                       Semantic->getAttrName()->getName(),
                                       /* BuiltIn::FragCoord */ 15);
       if (CGM.getTarget().getTriple().isDXIL())
-        return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
+        return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index);
     }
 
     if (ST == Triple::EnvironmentType::Vertex) {
@@ -1327,7 +1450,7 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
                                       Semantic->getAttrName()->getName(),
                                       /* BuiltIn::VertexIndex */ 42);
       else
-        return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
+        return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index);
     }
   }
 
@@ -1357,7 +1480,7 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
   std::string SemanticName = Semantic->getAttrName()->getName().upper();
   if (SemanticName == "SV_POSITION") {
     if (CGM.getTarget().getTriple().isDXIL()) {
-      emitDXILUserSemanticStore(B, Source, Semantic, Index);
+      emitDXILUserSemanticStore(B, Source, Decl, Semantic, Index);
       return;
     }
 
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index aeb33a09c86aa..badb6fb867b55 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -340,6 +340,7 @@ class CGHLSLRuntime {
                                          HLSLAppliedSemanticAttr *Semantic,
                                          std::optional<unsigned> Index);
   llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+                                        const clang::DeclaratorDecl *Decl,
                                         HLSLAppliedSemanticAttr *Semantic,
                                         std::optional<unsigned> Index);
   llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B,
@@ -353,6 +354,7 @@ class CGHLSLRuntime {
                                   HLSLAppliedSemanticAttr *Semantic,
                                   std::optional<unsigned> Index);
   void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+                                 const clang::DeclaratorDecl *Decl,
                                  HLSLAppliedSemanticAttr *Semantic,
                                  std::optional<unsigned> Index);
   void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
@@ -369,6 +371,7 @@ class CGHLSLRuntime {
   llvm::DenseMap<const clang::RecordType *, llvm::StructType *> LayoutTypes;
   unsigned SPIRVLastAssignedInputSemanticLocation = 0;
   unsigned SPIRVLastAssignedOutputSemanticLocation = 0;
+
   // DXIL assigns each leaf semantic an index in parse order. Inputs and outputs
   // are counted independently. Reset in emitEntryFunction before lowering the
   // semantics of an entry point.
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
index d395baaa6b335..5466948bd32bc 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
@@ -12,10 +12,13 @@ struct S0 {
 // CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
 
 // CHECK:       define void @main0()
-// CHECK-DXIL:          %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0
-// CHECK-DXIL:          %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1
+// CHECK-DXIL:          %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[#POS0:]] = insertvalue [2 x <4 x float>] poison, <4 x float> %A0, 0
+// CHECK-DXIL:          %A1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 1, i8 0, i32 poison)
+// CHECK-DXIL: %[[#POS1:]] = insertvalue [2 x <4 x float>] %[[#POS0]], <4 x float> %A1, 1
+// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#POS1]], 0
+// CHECK-DXIL:        %A01 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A01, 1
 
 // CHECK-SPIRV:   %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 4
 // CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 32b7019b0c630..9d3afc5e8fba6 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -19,7 +19,10 @@ S0 main1(float4 input : A) : B {
   // CHECK:        %[[#ST:]] = load %struct.S0, ptr %[[#ARG]]
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0
   // CHECK-SPIRV:              store [2 x <4 x float>] %[[#TMP]], ptr addrspace(8) @B0, align 4
-  // CHECK-DXIL:               call void @llvm.dx.store.output.a2v4f32(i32 0, i32 0, i8 0, [2 x <4 x float>] %[[#TMP]])
+  // CHECK-DXIL:  %[[#POS0:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 0
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#POS0]])
+  // CHECK-DXIL:  %[[#POS1:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 1
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 1, i8 0, <4 x float> %[[#POS1]])
   // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1
   // CHECK-SPIRV:              store <4 x float> %[[#TMP]], ptr addrspace(8) @B2, align 4
   // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#TMP]])

>From 4262438a40b2c112b87035e60217e4651cacabcf Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 29 Jul 2026 15:52:34 +0000
Subject: [PATCH 05/15] clang format

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index cb2be9bbdd0b5..9a378b78144e1 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1226,11 +1226,9 @@ static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
   return {Rows, Cols, Ty};
 }
 
-llvm::Value *
-CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
-                                        const clang::DeclaratorDecl *Decl,
-                                        HLSLAppliedSemanticAttr *Semantic,
-                                        std::optional<unsigned> Index) {
+llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
+    llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
+    HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
   StringRef Name = Semantic->getAttrName()->getName();
   SemanticShape Shape =
       getSemanticShape(CGM.getContext(), getSemanticLeafType(Decl));

>From a78b13c909166d70c964e2c5697c5da7e88bdd2e Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 29 Jul 2026 22:19:34 +0000
Subject: [PATCH 06/15] small note

---
 clang/lib/CodeGen/CGHLSLRuntime.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index badb6fb867b55..5ea4afe65100b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -372,9 +372,8 @@ class CGHLSLRuntime {
   unsigned SPIRVLastAssignedInputSemanticLocation = 0;
   unsigned SPIRVLastAssignedOutputSemanticLocation = 0;
 
-  // DXIL assigns each leaf semantic an index in parse order. Inputs and outputs
-  // are counted independently. Reset in emitEntryFunction before lowering the
-  // semantics of an entry point.
+  // FIXME: #57928, storing these here and reseting them in the entry is not
+  // very nice and is a temporary until we accumulate the signatures as part of
   unsigned DXILInputSemanticIndex = 0;
   unsigned DXILOutputSemanticIndex = 0;
 };

>From 29dd572106e7622611e7ab0ab59c8368ee1d1ee8 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 4 Aug 2026 21:23:56 +0000
Subject: [PATCH 07/15] review: fix bool representation

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp              | 16 ++++++++++++++++
 .../CodeGenHLSL/semantics/semantic.bool.hlsl     | 15 +++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 9a378b78144e1..34a7d34ed7cee 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1256,6 +1256,14 @@ llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
         /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
     llvm::Value *Result =
         B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row++)));
+    // Booleans use their memory representation in DXIL signatures, but direct
+    // function parameters use their value representation.
+    if (Result->getType() != Type) {
+      assert(Shape.RowType->hasBooleanRepresentation() &&
+             "unexpected semantic load type mismatch");
+      Result = B.CreateICmpNE(
+          Result, llvm::Constant::getNullValue(Result->getType()), "loadedv");
+    }
     assert(Row == Shape.Rows && "unexpected number of semantic rows");
     return Result;
   }
@@ -1349,6 +1357,14 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
       continue;
     }
 
+    // Booleans use their memory representation in DXIL signatures, but direct
+    // function results use their value representation.
+    if (Val->getType() != RowTy) {
+      assert(Shape.RowType->hasBooleanRepresentation() &&
+             "unexpected semantic store type mismatch");
+      Val = B.CreateZExt(Val, RowTy, "storedv");
+    }
+
     SmallVector<Value *> Args{/*SigElementId=*/B.getInt32(SigId),
                               /*RowIndex=*/B.getInt32(Row++),
                               /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl
new file mode 100644
index 0000000000000..2f9269a553114
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+[shader("vertex")]
+bool main(bool b : B) : A {
+  return b;
+}
+
+// DXIL signatures represent bool as i32, while the entry implementation uses
+// the i1 value representation.
+// CHECK-LABEL: define void @main()
+// CHECK: %[[INPUT:.*]] = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK: %[[BOOL:.*]] = icmp ne i32 %[[INPUT]], 0
+// CHECK: %[[RESULT:.*]] = call i1 @_Z4mainb(i1 %[[BOOL]])
+// CHECK: %[[OUTPUT:.*]] = zext i1 %[[RESULT]] to i32
+// CHECK: call void @llvm.dx.store.output.i32(i32 0, i32 0, i8 0, i32 %[[OUTPUT]])

>From 9075f78062ffee5ece6c753277d38215913b0f23 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Tue, 4 Aug 2026 21:32:34 +0000
Subject: [PATCH 08/15] review: reset the semantic index between counters

had this here to start but must have deleted it by accident before
pushing. These will be replaced in the pr following this anyway
---
 clang/lib/CodeGen/CGHLSLRuntime.cpp                 |  3 +++
 clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl | 10 ++++++++++
 2 files changed, 13 insertions(+)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 34a7d34ed7cee..e131e10a38aea 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1622,6 +1622,9 @@ CGHLSLRuntime::handleSemanticStore(
 
 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
                                       llvm::Function *Fn) {
+  DXILInputSemanticIndex = 0;
+  DXILOutputSemanticIndex = 0;
+
   llvm::Module &M = CGM.getModule();
   llvm::LLVMContext &Ctx = M.getContext();
   auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl
index 2f9269a553114..3d46d796b3338 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.bool.hlsl
@@ -13,3 +13,13 @@ bool main(bool b : B) : A {
 // CHECK: %[[RESULT:.*]] = call i1 @_Z4mainb(i1 %[[BOOL]])
 // CHECK: %[[OUTPUT:.*]] = zext i1 %[[RESULT]] to i32
 // CHECK: call void @llvm.dx.store.output.i32(i32 0, i32 0, i8 0, i32 %[[OUTPUT]])
+
+[shader("vertex")]
+bool other(bool b : D) : C {
+  return b;
+}
+
+// Signature element IDs are local to each entry point.
+// CHECK-LABEL: define void @other()
+// CHECK: call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK: call void @llvm.dx.store.output.i32(i32 0, i32 0, i8 0, i32 %{{.*}})

>From 0d972c10d2ba8eb530411756ae9871109b068ae8 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 5 Aug 2026 17:45:40 +0000
Subject: [PATCH 09/15] review: fix and clean up typos

---
 clang/lib/CodeGen/CGHLSLRuntime.h              |  1 +
 .../semantics/semantic.arbitrary.hlsl          | 18 ++++++++----------
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 5ea4afe65100b..20a8730ab928b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -374,6 +374,7 @@ class CGHLSLRuntime {
 
   // FIXME: #57928, storing these here and reseting them in the entry is not
   // very nice and is a temporary until we accumulate the signatures as part of
+  // the mentioned issue.
   unsigned DXILInputSemanticIndex = 0;
   unsigned DXILOutputSemanticIndex = 0;
 };
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
index 720dafcd4f1b6..f0bf3fff0ab66 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
@@ -5,8 +5,6 @@
 // CHECK-SPIRV-DAG:    @B0 = external hidden thread_local addrspace(7) externally_initialized constant i32, !spirv.Decorations ![[#METADATA_2:]]
 // CHECK-SPIRV-DAG:   @CC0 = external hidden thread_local addrspace(7) externally_initialized constant <2 x float>, !spirv.Decorations ![[#METADATA_4:]]
 
-
-// FIXME: replace `float2 c` with a  matrix when available.
 void main(float a : AAA, int b : B, float2 c : CC) {
   float tmp = a + b + c.x + c.y;
 }
@@ -14,15 +12,15 @@ void main(float a : AAA, int b : B, float2 c : CC) {
 
 // CHECK: define void @main()
 
-// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:   %B0 = call i32 @llvm.dx.load.input.i32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK-DXIL   %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:         call void @_Z4mainfiDv2_f(float %AAA0, i32 %B0, <2 x float> %CC0)
+// CHECK-DXIL: %[[#AAA:]]  = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:   %[[#B:]]  = call i32 @llvm.dx.load.input.i32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:  %[[#CC:]]  = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:               call void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]])
 
-// CHECK-SPIRV: %[[#AAA0:]] = load float, ptr addrspace(7) @AAA0, align 4
-// CHECK-SPIRV:   %[[#B0:]] = load i32, ptr addrspace(7) @B0, align 4
-// CHECK-SPIRV:  %[[#CC0:]] = load <2 x float>, ptr addrspace(7) @CC0, align 4
-// CHECK-SPIRV:               call spir_func void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ]
+// CHECK-SPIRV: %[[#AAA:]] = load float, ptr addrspace(7) @AAA0, align 4
+// CHECK-SPIRV:   %[[#B:]] = load i32, ptr addrspace(7) @B0, align 4
+// CHECK-SPIRV:  %[[#CC:]] = load <2 x float>, ptr addrspace(7) @CC0, align 4
+// CHECK-SPIRV:              call spir_func void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ]
 
 
 // CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}

>From 6307373f9dddc3e5a156fa359af8b8af1dc43c0f Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 5 Aug 2026 18:05:16 +0000
Subject: [PATCH 10/15] self-review: change from a worklist to row iteration

don't know why I didn't realize this the first time but a fresh look
over it made me realize that imo this is cleaner
---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 124 ++++++------------
 .../CodeGenHLSL/semantics/semantic.input.hlsl |  14 +-
 .../semantics/semantic.output.hlsl            |  14 +-
 3 files changed, 55 insertions(+), 97 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index e131e10a38aea..a17244ac9a83f 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1189,9 +1189,16 @@ void CGHLSLRuntime::emitSPIRVUserSemanticStore(
 namespace {
 // Describes how a semantic leaf lowers to signature rows
 struct SemanticShape {
-  unsigned Rows;
+  SmallVector<unsigned> Dimensions; // Empty dims denotes a scalar
   unsigned Cols;
   QualType RowType;
+
+  unsigned getNumRows() const {
+    unsigned Rows = 1;
+    for (unsigned Dimension : Dimensions)
+      Rows *= Dimension;
+    return Rows;
+  }
 };
 } // namespace
 
@@ -1203,13 +1210,12 @@ static QualType getSemanticLeafType(const clang::DeclaratorDecl *Decl) {
   return Decl->getType();
 }
 
-// Walks through the surrounding constant array types of \p Ty, accumulating the
-// number of rows, until reaching a scalar, vector, or matrix leaf. The leaf is
-// returned as the row type together with the number of rows.
+// Walks through the surrounding constant array types of \p Ty, collecting their
+// dimensions until reaching a scalar, vector, or matrix leaf.
 static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
-  unsigned Rows = 1;
+  SmallVector<unsigned> Dimensions;
   while (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(Ty)) {
-    Rows *= CAT->getSize().getZExtValue();
+    Dimensions.push_back(CAT->getSize().getZExtValue());
     Ty = CAT->getElementType();
   }
 
@@ -1223,7 +1229,7 @@ static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
     Cols = MT->getNumColumns();
   }
 
-  return {Rows, Cols, Ty};
+  return {std::move(Dimensions), Cols, Ty};
 }
 
 llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
@@ -1245,74 +1251,39 @@ llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
   }
 
   unsigned SigId = DXILInputSemanticIndex++;
-  unsigned Row = 0;
 
-  // Scalar and vector leaves need no aggregate reconstruction.
-  if (!isa<llvm::ArrayType>(Type)) {
+  llvm::Type *LeafTy = CGM.getTypes().ConvertType(Shape.RowType);
+  llvm::Value *Result = llvm::PoisonValue::get(Type);
+
+  SmallVector<unsigned> Indices(Shape.Dimensions.size());
+
+  for (unsigned Row = 0; Row < Shape.getNumRows(); ++Row) {
     SmallVector<Value *> Args{
         /*SigElementId=*/B.getInt32(SigId),
         /*RowIndex=*/B.getInt32(Row),
         /*ColIndex=*/B.getInt8(0),
         /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
-    llvm::Value *Result =
-        B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row++)));
-    // Booleans use their memory representation in DXIL signatures, but direct
+    llvm::Value *Value =
+        B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row)));
+    // Booleans use their memory representation in DXIL signatures, but
     // function parameters use their value representation.
-    if (Result->getType() != Type) {
+    if (Value->getType() != LeafTy) {
       assert(Shape.RowType->hasBooleanRepresentation() &&
              "unexpected semantic load type mismatch");
-      Result = B.CreateICmpNE(
-          Result, llvm::Constant::getNullValue(Result->getType()), "loadedv");
+      Value = B.CreateICmpNE(
+          Value, llvm::Constant::getNullValue(Value->getType()), "loadedv");
     }
-    assert(Row == Shape.Rows && "unexpected number of semantic rows");
-    return Result;
-  }
 
-  struct LoadItem {
-    llvm::ArrayType *Type;
-    llvm::Value *Aggregate;
-    unsigned NextIndex;
-  };
+    Result =
+        Indices.empty() ? Value : B.CreateInsertValue(Result, Value, Indices);
 
-  SmallVector<LoadItem> Worklist;
-  auto *RootTy = cast<llvm::ArrayType>(Type);
-  Worklist.push_back({RootTy, llvm::PoisonValue::get(RootTy), 0});
-
-  llvm::Value *Result = nullptr;
-  while (!Worklist.empty()) {
-    LoadItem &Frame = Worklist.back();
-
-    if (Frame.NextIndex == Frame.Type->getNumElements()) {
-      llvm::Value *Aggregate = Frame.Aggregate;
-      Worklist.pop_back();
-      if (Worklist.empty()) {
-        Result = Aggregate;
+    // Advance the multidimensional index
+    for (unsigned I = Indices.size(); I-- > 0;) {
+      if (++Indices[I] < Shape.Dimensions[I])
         break;
-      }
-
-      LoadItem &Parent = Worklist.back();
-      Parent.Aggregate =
-          B.CreateInsertValue(Parent.Aggregate, Aggregate, Parent.NextIndex++);
-      continue;
+      Indices[I] = 0;
     }
-
-    llvm::Type *ElementTy = Frame.Type->getElementType();
-    if (auto *AT = dyn_cast<llvm::ArrayType>(ElementTy)) {
-      Worklist.push_back({AT, llvm::PoisonValue::get(AT), 0});
-      continue;
-    }
-
-    SmallVector<Value *> Args{
-        /*SigElementId=*/B.getInt32(SigId),
-        /*RowIndex=*/B.getInt32(Row),
-        /*ColIndex=*/B.getInt8(0),
-        /*GsVertexOrPrimIndex=*/llvm::PoisonValue::get(B.getInt32Ty())};
-    llvm::Value *Elt =
-        B.CreateCall(IntrFn, Args, OB, Twine(Name).concat(Twine(Row++)));
-    Frame.Aggregate =
-        B.CreateInsertValue(Frame.Aggregate, Elt, Frame.NextIndex++);
   }
-  assert(Row == Shape.Rows && "unexpected number of semantic rows");
   return Result;
 }
 
@@ -1336,26 +1307,11 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
   }
 
   unsigned SigId = DXILOutputSemanticIndex++;
-  unsigned Row = 0;
 
-  struct StoreItem {
-    llvm::Value *Aggregate;
-    std::optional<unsigned> Index;
-  };
-
-  SmallVector<StoreItem> Worklist{{Source, std::nullopt}};
-  while (!Worklist.empty()) {
-    StoreItem Item = Worklist.pop_back_val();
-    llvm::Value *Val = Item.Index
-                           ? B.CreateExtractValue(Item.Aggregate, *Item.Index)
-                           : Item.Aggregate;
-
-    if (auto *AT = dyn_cast<llvm::ArrayType>(Val->getType())) {
-      // Push elements in reverse so index 0 is visited first
-      for (unsigned I = AT->getNumElements(); I-- > 0;)
-        Worklist.push_back({Val, I});
-      continue;
-    }
+  SmallVector<unsigned> Indices(Shape.Dimensions.size());
+  for (unsigned Row = 0; Row < Shape.getNumRows(); ++Row) {
+    llvm::Value *Val =
+        Indices.empty() ? Source : B.CreateExtractValue(Source, Indices);
 
     // Booleans use their memory representation in DXIL signatures, but direct
     // function results use their value representation.
@@ -1366,11 +1322,17 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
     }
 
     SmallVector<Value *> Args{/*SigElementId=*/B.getInt32(SigId),
-                              /*RowIndex=*/B.getInt32(Row++),
+                              /*RowIndex=*/B.getInt32(Row),
                               /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
     B.CreateCall(IntrFn, Args, OB);
+
+    // Advance the multidimensional index
+    for (unsigned I = Indices.size(); I-- > 0;) {
+      if (++Indices[I] < Shape.Dimensions[I])
+        break;
+      Indices[I] = 0;
+    }
   }
-  assert(Row == Shape.Rows && "unexpected number of semantic rows");
 }
 
 llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
index e1ea53bf16de9..bdda150e7d667 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
@@ -39,17 +39,15 @@ void main(S s) {}
 
 // float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
 // CHECK: %E0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 0, i8 0, i32 poison)
-// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] poison, <4 x float> %E0, 0
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] poison, <4 x float> %E0, 0, 0
 // CHECK: %E1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 1, i8 0, i32 poison)
-// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] %[[#E0]], <4 x float> %E1, 1
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E1, 0, 1
 // CHECK: %E2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 2, i8 0, i32 poison)
-// CHECK: %[[#E0:]] = insertvalue [3 x <4 x float>] %[[#E0]], <4 x float> %E2, 2
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] poison, [3 x <4 x float>] %[[#E0]], 0
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E2, 0, 2
 // CHECK: %E3 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 3, i8 0, i32 poison)
-// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] poison, <4 x float> %E3, 0
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E3, 1, 0
 // CHECK: %E4 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 4, i8 0, i32 poison)
-// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] %[[#E1]], <4 x float> %E4, 1
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E4, 1, 1
 // CHECK: %E5 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 5, i8 0, i32 poison)
-// CHECK: %[[#E1:]] = insertvalue [3 x <4 x float>] %[[#E1]], <4 x float> %E5, 2
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], [3 x <4 x float>] %[[#E1]], 1
+// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E5, 1, 2
 // CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], [2 x [3 x <4 x float>]] %[[#E]], 3
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
index 2b1d36b140838..726ca82c7d475 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
@@ -42,17 +42,15 @@ S main() {
 
 // float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
 // CHECK: %[[#E:]] = extractvalue %struct.S %[[#S]], 3
-// CHECK: %[[#E0:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0
-// CHECK: %[[#E00:]] = extractvalue [3 x <4 x float>] %[[#E0]], 0
+// CHECK: %[[#E00:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 0
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 0, i8 0, <4 x float> %[[#E00]])
-// CHECK: %[[#E01:]] = extractvalue [3 x <4 x float>] %[[#E0]], 1
+// CHECK: %[[#E01:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 1
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 1, i8 0, <4 x float> %[[#E01]])
-// CHECK: %[[#E02:]] = extractvalue [3 x <4 x float>] %[[#E0]], 2
+// CHECK: %[[#E02:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 2
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 2, i8 0, <4 x float> %[[#E02]])
-// CHECK: %[[#E1:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1
-// CHECK: %[[#E10:]] = extractvalue [3 x <4 x float>] %[[#E1]], 0
+// CHECK: %[[#E10:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 0
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 3, i8 0, <4 x float> %[[#E10]])
-// CHECK: %[[#E11:]] = extractvalue [3 x <4 x float>] %[[#E1]], 1
+// CHECK: %[[#E11:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 1
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 4, i8 0, <4 x float> %[[#E11]])
-// CHECK: %[[#E12:]] = extractvalue [3 x <4 x float>] %[[#E1]], 2
+// CHECK: %[[#E12:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 2
 // CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 5, i8 0, <4 x float> %[[#E12]])

>From 3c7bbe3151e5e4b006a2ee625be44b4579a614a9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Wed, 5 Aug 2026 19:09:43 +0000
Subject: [PATCH 11/15] typos whoops

---
 .../test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
index f0bf3fff0ab66..295d902011da2 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
@@ -12,15 +12,15 @@ void main(float a : AAA, int b : B, float2 c : CC) {
 
 // CHECK: define void @main()
 
-// CHECK-DXIL: %[[#AAA:]]  = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:   %[[#B:]]  = call i32 @llvm.dx.load.input.i32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:  %[[#CC:]]  = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:               call void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]])
+// CHECK-DXIL: %[[AAA:.*]] = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[B:.*]] = call i32 @llvm.dx.load.input.i32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[CC:.*]] = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: call void @_Z4mainfiDv2_f(float %[[AAA]], i32 %[[B]], <2 x float> %[[CC]])
 
 // CHECK-SPIRV: %[[#AAA:]] = load float, ptr addrspace(7) @AAA0, align 4
 // CHECK-SPIRV:   %[[#B:]] = load i32, ptr addrspace(7) @B0, align 4
 // CHECK-SPIRV:  %[[#CC:]] = load <2 x float>, ptr addrspace(7) @CC0, align 4
-// CHECK-SPIRV:              call spir_func void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ]
+// CHECK-SPIRV:              call spir_func void @_Z4mainfiDv2_f(float %[[#AAA]], i32 %[[#B]], <2 x float> %[[#CC]]) [ "convergencectrl"(token %0) ]
 
 
 // CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}

>From 814713934de3a71a074acafc993ae2c4e872b27e Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 7 Aug 2026 19:26:23 +0000
Subject: [PATCH 12/15] review: clean ups

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 36 ++++++++++++++++-------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a17244ac9a83f..c47e179a2ebb6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -50,6 +50,7 @@
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
+#include <array>
 #include <cstdint>
 #include <optional>
 
@@ -1213,23 +1214,24 @@ static QualType getSemanticLeafType(const clang::DeclaratorDecl *Decl) {
 // Walks through the surrounding constant array types of \p Ty, collecting their
 // dimensions until reaching a scalar, vector, or matrix leaf.
 static SemanticShape getSemanticShape(ASTContext &Ctx, QualType Ty) {
-  SmallVector<unsigned> Dimensions;
-  while (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(Ty)) {
-    Dimensions.push_back(CAT->getSize().getZExtValue());
-    Ty = CAT->getElementType();
+  SemanticShape Shape{{}, 1, Ty};
+  while (const ConstantArrayType *CAT =
+             Ctx.getAsConstantArrayType(Shape.RowType)) {
+    Shape.Dimensions.push_back(CAT->getSize().getZExtValue());
+    Shape.RowType = CAT->getElementType();
   }
 
-  unsigned Cols = 1;
-  if (const auto *VT = Ty->getAs<clang::VectorType>()) {
-    Cols = VT->getNumElements();
-  } else if (const auto *MT = Ty->getAs<clang::ConstantMatrixType>()) {
+  if (const auto *VT = Shape.RowType->getAs<clang::VectorType>()) {
+    Shape.Cols = VT->getNumElements();
+  } else if (const auto *MT =
+                 Shape.RowType->getAs<clang::ConstantMatrixType>()) {
     // FIXME: a matrix leaf lowers to one row per matrix row but if column_major
     // is specified we transpose the num rows and num cols, this depends on
     // #211977 to resolve
-    Cols = MT->getNumColumns();
+    Shape.Cols = MT->getNumColumns();
   }
 
-  return {std::move(Dimensions), Cols, Ty};
+  return Shape;
 }
 
 llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
@@ -1256,9 +1258,10 @@ llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
   llvm::Value *Result = llvm::PoisonValue::get(Type);
 
   SmallVector<unsigned> Indices(Shape.Dimensions.size());
+  const unsigned NumRows = Shape.getNumRows();
 
-  for (unsigned Row = 0; Row < Shape.getNumRows(); ++Row) {
-    SmallVector<Value *> Args{
+  for (unsigned Row = 0; Row < NumRows; ++Row) {
+    std::array<Value *, 4> Args{
         /*SigElementId=*/B.getInt32(SigId),
         /*RowIndex=*/B.getInt32(Row),
         /*ColIndex=*/B.getInt8(0),
@@ -1309,7 +1312,8 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
   unsigned SigId = DXILOutputSemanticIndex++;
 
   SmallVector<unsigned> Indices(Shape.Dimensions.size());
-  for (unsigned Row = 0; Row < Shape.getNumRows(); ++Row) {
+  const unsigned NumRows = Shape.getNumRows();
+  for (unsigned Row = 0; Row < NumRows; ++Row) {
     llvm::Value *Val =
         Indices.empty() ? Source : B.CreateExtractValue(Source, Indices);
 
@@ -1321,9 +1325,9 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
       Val = B.CreateZExt(Val, RowTy, "storedv");
     }
 
-    SmallVector<Value *> Args{/*SigElementId=*/B.getInt32(SigId),
-                              /*RowIndex=*/B.getInt32(Row),
-                              /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
+    std::array<Value *, 4> Args{/*SigElementId=*/B.getInt32(SigId),
+                                /*RowIndex=*/B.getInt32(Row),
+                                /*ColIndex=*/B.getInt8(0), /*Value=*/Val};
     B.CreateCall(IntrFn, Args, OB);
 
     // Advance the multidimensional index

>From 207640beeae820c4a5b72136ec9cd0817295234d Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 7 Aug 2026 19:32:17 +0000
Subject: [PATCH 13/15] review: update filechecks to always match

---
 .../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 12 ++--
 .../CodeGenHLSL/semantics/SV_Position.vs.hlsl | 12 ++--
 .../CodeGenHLSL/semantics/SV_Target.ps.hlsl   |  9 +--
 .../CodeGenHLSL/semantics/SV_VertexID.vs.hlsl |  8 +--
 .../semantics/semantic.arbitrary.hlsl         |  8 +--
 .../CodeGenHLSL/semantics/semantic.array.hlsl | 30 +++++-----
 .../semantics/semantic.array.output.hlsl      | 30 +++++-----
 ...antic.explicit-location-output-struct.hlsl | 17 +++---
 .../semantics/semantic.explicit-location.hlsl |  9 +--
 .../CodeGenHLSL/semantics/semantic.input.hlsl | 56 +++++++++----------
 .../semantics/semantic.output.hlsl            | 56 +++++++++----------
 .../semantics/semantic.struct.output.hlsl     | 36 ++++++------
 clang/test/CodeGenHLSL/sret_output.hlsl       | 14 ++---
 13 files changed, 150 insertions(+), 147 deletions(-)

diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index ac695b1f7d5eb..095532863ac5a 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -5,13 +5,13 @@
 
 // CHECK: define void @main() {{.*}} {
 float4 main(float4 p : SV_Position) : A {
-  // CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 4
-  // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
-  // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 4
+  // CHECK-SPIRV: %[[P:.*]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 4
+  // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[P]])
+  // CHECK-SPIRV:            store <4 x float> %[[R]], ptr addrspace(8) @A0, align 4
 
-  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
-  // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
+  // CHECK-DXIL: %[[INPUT:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %[[RESULT:.*]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %[[INPUT]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[RESULT]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
index 350b5e3612e32..c227e8198c964 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
@@ -6,13 +6,13 @@
 
 // CHECK: define void @main() {{.*}} {
 float4 main(float4 p : SV_Position) : SV_Position {
-  // CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position0, align 4
-  // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
-  // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Position, align 4
+  // CHECK-SPIRV: %[[P:.*]] = load <4 x float>, ptr addrspace(7) @SV_Position0, align 4
+  // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[P]])
+  // CHECK-SPIRV:            store <4 x float> %[[R]], ptr addrspace(8) @SV_Position, align 4
 
-  // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
-  // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
+  // CHECK-DXIL: %[[INPUT:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %[[RESULT:.*]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %[[INPUT]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[RESULT]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
index 73255e3a9b939..ae216d821750c 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
@@ -5,11 +5,12 @@
 
 // CHECK: define void @main() {{.*}} {
 float4 main(float4 p : SV_Position) : SV_Target {
-  // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#]])
-  // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 4
+  // CHECK-SPIRV: %[[RESULT:.*]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %{{.*}})
+  // CHECK-SPIRV:                 store <4 x float> %[[RESULT]], ptr addrspace(8) @SV_Target0, align 4
 
-  // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
+  // CHECK-DXIL: %[[INPUT:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %[[RESULT:.*]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %[[INPUT]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[RESULT]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
index 491f10b530c38..c965432b923db 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
@@ -5,11 +5,11 @@
 
 // CHECK: define void @main() {{.*}} {
 uint main(uint id : SV_VertexID) : A {
-  // CHECK-SPIRV: %[[#P:]] = load i32, ptr addrspace(7) @SV_VertexID, align 4
-  // CHECK-SPIRV:   %[[#]] = call spir_func i32 @_Z4mainj(i32 %[[#P]])
+  // CHECK-SPIRV: %[[INPUT:.*]] = load i32, ptr addrspace(7) @SV_VertexID, align 4
+  // CHECK-SPIRV: %[[RESULT:.*]] = call spir_func i32 @_Z4mainj(i32 %[[INPUT]])
 
-  // CHECK-DXIL: %SV_VertexID0 = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison)
-  // CHECK-DXIL:        %[[#]] = call i32 @_Z4mainj(i32 %SV_VertexID0)
+  // CHECK-DXIL: %[[INPUT:.*]] = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %[[RESULT:.*]] = call i32 @_Z4mainj(i32 %[[INPUT]])
   return id;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
index 295d902011da2..f1d13cb70c214 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
@@ -17,10 +17,10 @@ void main(float a : AAA, int b : B, float2 c : CC) {
 // CHECK-DXIL: %[[CC:.*]] = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 0, i32 poison)
 // CHECK-DXIL: call void @_Z4mainfiDv2_f(float %[[AAA]], i32 %[[B]], <2 x float> %[[CC]])
 
-// CHECK-SPIRV: %[[#AAA:]] = load float, ptr addrspace(7) @AAA0, align 4
-// CHECK-SPIRV:   %[[#B:]] = load i32, ptr addrspace(7) @B0, align 4
-// CHECK-SPIRV:  %[[#CC:]] = load <2 x float>, ptr addrspace(7) @CC0, align 4
-// CHECK-SPIRV:              call spir_func void @_Z4mainfiDv2_f(float %[[#AAA]], i32 %[[#B]], <2 x float> %[[#CC]]) [ "convergencectrl"(token %0) ]
+// CHECK-SPIRV: %[[AAA:.*]] = load float, ptr addrspace(7) @AAA0, align 4
+// CHECK-SPIRV:   %[[B:.*]] = load i32, ptr addrspace(7) @B0, align 4
+// CHECK-SPIRV:  %[[CC:.*]] = load <2 x float>, ptr addrspace(7) @CC0, align 4
+// CHECK-SPIRV:              call spir_func void @_Z4mainfiDv2_f(float %[[AAA]], i32 %[[B]], <2 x float> %[[CC]]) [ "convergencectrl"(token %{{.*}}) ]
 
 
 // CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
index 5466948bd32bc..524c521913a2a 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
@@ -12,23 +12,23 @@ struct S0 {
 // CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
 
 // CHECK:       define void @main0()
-// CHECK-DXIL:          %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL: %[[#POS0:]] = insertvalue [2 x <4 x float>] poison, <4 x float> %A0, 0
-// CHECK-DXIL:          %A1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 1, i8 0, i32 poison)
-// CHECK-DXIL: %[[#POS1:]] = insertvalue [2 x <4 x float>] %[[#POS0]], <4 x float> %A1, 1
-// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#POS1]], 0
-// CHECK-DXIL:        %A01 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A01, 1
+// CHECK-DXIL:  %[[A0:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[POS0:.*]] = insertvalue [2 x <4 x float>] poison, <4 x float> %[[A0]], 0
+// CHECK-DXIL:  %[[A1:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 1, i8 0, i32 poison)
+// CHECK-DXIL: %[[POS1:.*]] = insertvalue [2 x <4 x float>] %[[POS0]], <4 x float> %[[A1]], 1
+// CHECK-DXIL: %[[TMP0:.*]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[POS1]], 0
+// CHECK-DXIL: %[[A01:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[TMP1:.*]] = insertvalue %struct.S0 %[[TMP0]], <4 x float> %[[A01]], 1
 
-// CHECK-SPIRV:   %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 4
-// CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0
-// CHECK-SPIRV:  %[[#A01:]] = load <4 x float>, ptr addrspace(7) @A2, align 4
-// CHECK-SPIRV: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A01]], 1
+// CHECK-SPIRV:   %[[A0:.*]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 4
+// CHECK-SPIRV: %[[TMP0:.*]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[A0]], 0
+// CHECK-SPIRV:  %[[A01:.*]] = load <4 x float>, ptr addrspace(7) @A2, align 4
+// CHECK-SPIRV: %[[TMP1:.*]] = insertvalue %struct.S0 %[[TMP0]], <4 x float> %[[A01]], 1
 
-// CHECK:        %[[#ARG:]] = alloca %struct.S0
-// CHECK:                     store %struct.S0 %[[#TMP1]], ptr %[[#ARG]]
-// CHECK-DXIL:                call void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
-// CHECK-SPIRV:               call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
+// CHECK:        %[[ARG:.*]] = alloca %struct.S0
+// CHECK:                     store %struct.S0 %[[TMP1]], ptr %[[ARG]]
+// CHECK-DXIL:                call void @{{.*}}main0{{.*}}(ptr %[[ARG]])
+// CHECK-SPIRV:               call spir_func void @{{.*}}main0{{.*}}(ptr %[[ARG]])
 [shader("pixel")]
 void main0(S0 p : A) {
   float tmp = p.position[0] + p.position[1] + p.color;
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 9d3afc5e8fba6..8c8fe6443183e 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -10,22 +10,22 @@ struct S0 {
 
 [shader("pixel")]
 S0 main1(float4 input : A) : B {
-// CHECK:         %[[#ARG:]] = alloca %struct.S0
-// CHECK-SPIRV: %[[#INPUT:]] = load <4 x float>, ptr addrspace(7) @A0, align 4
-// CHECK-DXIL:           %A0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK-DXIL:                 call void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %A0)
-// CHECK-SPIRV:                call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]], <4 x float> %[[#INPUT]])
+// CHECK:         %[[ARG:.*]] = alloca %struct.S0
+// CHECK-SPIRV: %[[INPUT:.*]] = load <4 x float>, ptr addrspace(7) @A0, align 4
+// CHECK-DXIL:  %[[INPUT:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL:                 call void @{{.*}}main1{{.*}}(ptr %[[ARG]], <4 x float> %[[INPUT]])
+// CHECK-SPIRV:                call spir_func void @{{.*}}main1{{.*}}(ptr %[[ARG]], <4 x float> %[[INPUT]])
 
-  // CHECK:        %[[#ST:]] = load %struct.S0, ptr %[[#ARG]]
-  // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 0
-  // CHECK-SPIRV:              store [2 x <4 x float>] %[[#TMP]], ptr addrspace(8) @B0, align 4
-  // CHECK-DXIL:  %[[#POS0:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 0
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#POS0]])
-  // CHECK-DXIL:  %[[#POS1:]] = extractvalue [2 x <4 x float>] %[[#TMP]], 1
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 1, i8 0, <4 x float> %[[#POS1]])
-  // CHECK:       %[[#TMP:]] = extractvalue %struct.S0 %[[#ST]], 1
-  // CHECK-SPIRV:              store <4 x float> %[[#TMP]], ptr addrspace(8) @B2, align 4
-  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#TMP]])
+  // CHECK:       %[[ST:.*]] = load %struct.S0, ptr %[[ARG]]
+  // CHECK: %[[POSITIONS:.*]] = extractvalue %struct.S0 %[[ST]], 0
+  // CHECK-SPIRV:              store [2 x <4 x float>] %[[POSITIONS]], ptr addrspace(8) @B0, align 4
+  // CHECK-DXIL:  %[[POS0:.*]] = extractvalue [2 x <4 x float>] %[[POSITIONS]], 0
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[POS0]])
+  // CHECK-DXIL:  %[[POS1:.*]] = extractvalue [2 x <4 x float>] %[[POSITIONS]], 1
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 0, i32 1, i8 0, <4 x float> %[[POS1]])
+  // CHECK:    %[[COLOR:.*]] = extractvalue %struct.S0 %[[ST]], 1
+  // CHECK-SPIRV:              store <4 x float> %[[COLOR]], ptr addrspace(8) @B2, align 4
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[COLOR]])
 
   S0 output;
   output.position[0] = input;
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
index b24cee7baf8ae..60468b179498b 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
@@ -10,18 +10,19 @@ struct Output {
 
 // CHECK: define void @main() {{.*}} {
 Output main(float4 p : SV_Position) {
-  // CHECK:   %[[#OUT:]] = alloca %struct.Output
+  // CHECK:   %[[OUT:.*]] = alloca %struct.Output
 
-  // CHECK-SPIRV:    %[[#IN:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 4
-  // CHECK-SPIRV:                call spir_func void @_Z4mainDv4_f(ptr %[[#OUT]], <4 x float> %[[#IN]])
+  // CHECK-SPIRV: %[[IN:.*]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 4
+  // CHECK-SPIRV:             call spir_func void @_Z4mainDv4_f(ptr %[[OUT]], <4 x float> %[[IN]])
 
-  // CHECK-DXIL:                 call void @_Z4mainDv4_f(ptr %[[#OUT]], <4 x float> %SV_Position0)
+  // CHECK-DXIL: %[[IN:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL:             call void @_Z4mainDv4_f(ptr %[[OUT]], <4 x float> %[[IN]])
 
-  // CHECK:   %[[#TMP:]] = load %struct.Output, ptr %[[#OUT]]
-  // CHECK: %[[#FIELD:]] = extractvalue %struct.Output %[[#TMP]], 0
+  // CHECK:   %[[TMP:.*]] = load %struct.Output, ptr %[[OUT]]
+  // CHECK: %[[FIELD:.*]] = extractvalue %struct.Output %[[TMP]], 0
 
-  // CHECK-SPIRV:                store <4 x float> %[[#FIELD]], ptr addrspace(8) @SV_Target0, align 4
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#FIELD]])
+  // CHECK-SPIRV:                store <4 x float> %[[FIELD]], ptr addrspace(8) @SV_Target0, align 4
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[FIELD]])
   Output o;
   o.field = p;
   return o;
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
index 2ca0f3fe65a57..a6e90b29349b9 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
@@ -5,11 +5,12 @@
 
 // CHECK: define void @main() {{.*}} {
 [[vk::location(2)]] float4 main(float4 p : SV_Position) : SV_Target {
-  // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#]])
-  // CHECK-SPIRV:            store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 4
+  // CHECK-SPIRV: %[[RESULT:.*]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %{{.*}})
+  // CHECK-SPIRV:                 store <4 x float> %[[RESULT]], ptr addrspace(8) @SV_Target0, align 4
 
-  // CHECK-DXIL:    %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
-  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
+  // CHECK-DXIL: %[[INPUT:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL: %[[RESULT:.*]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %[[INPUT]])
+  // CHECK-DXIL:                 call void @llvm.dx.store.output.v4f32(i32 0, i32 0, i8 0, <4 x float> %[[RESULT]])
   return p;
 }
 
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
index bdda150e7d667..3c46eace082ee 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.input.hlsl
@@ -17,37 +17,37 @@ struct S {
 void main(S s) {}
 
 // float a : A -> 1 row, 1 column.
-// CHECK: %A0 = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
-// CHECK: %[[#S:]] = insertvalue %struct.S poison, float %A0, 0
+// CHECK: %[[A:.*]] = call float @llvm.dx.load.input.f32(i32 0, i32 0, i8 0, i32 poison)
+// CHECK: %[[S0:.*]] = insertvalue %struct.S poison, float %[[A]], 0
 
 // float4 b : B -> 1 row, 4 columns.
-// CHECK: %B0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
-// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], <4 x float> %B0, 1
+// CHECK: %[[B:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 poison)
+// CHECK: %[[S1:.*]] = insertvalue %struct.S %[[S0]], <4 x float> %[[B]], 1
 
 // float d[5] : D -> 5 rows, 1 column each.
-// CHECK: %D0 = call float @llvm.dx.load.input.f32(i32 2, i32 0, i8 0, i32 poison)
-// CHECK: %[[#D:]] = insertvalue [5 x float] poison, float %D0, 0
-// CHECK: %D1 = call float @llvm.dx.load.input.f32(i32 2, i32 1, i8 0, i32 poison)
-// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D1, 1
-// CHECK: %D2 = call float @llvm.dx.load.input.f32(i32 2, i32 2, i8 0, i32 poison)
-// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D2, 2
-// CHECK: %D3 = call float @llvm.dx.load.input.f32(i32 2, i32 3, i8 0, i32 poison)
-// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D3, 3
-// CHECK: %D4 = call float @llvm.dx.load.input.f32(i32 2, i32 4, i8 0, i32 poison)
-// CHECK: %[[#D:]] = insertvalue [5 x float] %[[#D]], float %D4, 4
-// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], [5 x float] %[[#D]], 2
+// CHECK: %[[D0:.*]] = call float @llvm.dx.load.input.f32(i32 2, i32 0, i8 0, i32 poison)
+// CHECK: %[[D_ARRAY0:.*]] = insertvalue [5 x float] poison, float %[[D0]], 0
+// CHECK: %[[D1:.*]] = call float @llvm.dx.load.input.f32(i32 2, i32 1, i8 0, i32 poison)
+// CHECK: %[[D_ARRAY1:.*]] = insertvalue [5 x float] %[[D_ARRAY0]], float %[[D1]], 1
+// CHECK: %[[D2:.*]] = call float @llvm.dx.load.input.f32(i32 2, i32 2, i8 0, i32 poison)
+// CHECK: %[[D_ARRAY2:.*]] = insertvalue [5 x float] %[[D_ARRAY1]], float %[[D2]], 2
+// CHECK: %[[D3:.*]] = call float @llvm.dx.load.input.f32(i32 2, i32 3, i8 0, i32 poison)
+// CHECK: %[[D_ARRAY3:.*]] = insertvalue [5 x float] %[[D_ARRAY2]], float %[[D3]], 3
+// CHECK: %[[D4:.*]] = call float @llvm.dx.load.input.f32(i32 2, i32 4, i8 0, i32 poison)
+// CHECK: %[[D_ARRAY4:.*]] = insertvalue [5 x float] %[[D_ARRAY3]], float %[[D4]], 4
+// CHECK: %[[S2:.*]] = insertvalue %struct.S %[[S1]], [5 x float] %[[D_ARRAY4]], 2
 
 // float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
-// CHECK: %E0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 0, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] poison, <4 x float> %E0, 0, 0
-// CHECK: %E1 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 1, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E1, 0, 1
-// CHECK: %E2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 2, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E2, 0, 2
-// CHECK: %E3 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 3, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E3, 1, 0
-// CHECK: %E4 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 4, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E4, 1, 1
-// CHECK: %E5 = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 5, i8 0, i32 poison)
-// CHECK: %[[#E:]] = insertvalue [2 x [3 x <4 x float>]] %[[#E]], <4 x float> %E5, 1, 2
-// CHECK: %[[#S:]] = insertvalue %struct.S %[[#S]], [2 x [3 x <4 x float>]] %[[#E]], 3
+// CHECK: %[[E0:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 0, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY0:.*]] = insertvalue [2 x [3 x <4 x float>]] poison, <4 x float> %[[E0]], 0, 0
+// CHECK: %[[E1:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 1, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY1:.*]] = insertvalue [2 x [3 x <4 x float>]] %[[E_ARRAY0]], <4 x float> %[[E1]], 0, 1
+// CHECK: %[[E2:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 2, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY2:.*]] = insertvalue [2 x [3 x <4 x float>]] %[[E_ARRAY1]], <4 x float> %[[E2]], 0, 2
+// CHECK: %[[E3:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 3, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY3:.*]] = insertvalue [2 x [3 x <4 x float>]] %[[E_ARRAY2]], <4 x float> %[[E3]], 1, 0
+// CHECK: %[[E4:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 4, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY4:.*]] = insertvalue [2 x [3 x <4 x float>]] %[[E_ARRAY3]], <4 x float> %[[E4]], 1, 1
+// CHECK: %[[E5:.*]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 3, i32 5, i8 0, i32 poison)
+// CHECK: %[[E_ARRAY5:.*]] = insertvalue [2 x [3 x <4 x float>]] %[[E_ARRAY4]], <4 x float> %[[E5]], 1, 2
+// CHECK: %[[S3:.*]] = insertvalue %struct.S %[[S2]], [2 x [3 x <4 x float>]] %[[E_ARRAY5]], 3
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
index 726ca82c7d475..fdb195899ca97 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.output.hlsl
@@ -20,37 +20,37 @@ S main() {
 }
 
 // float a : A -> 1 row, 1 column.
-// CHECK: %[[#A:]] = extractvalue %struct.S %[[#S:]], 0
-// CHECK: call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#A]])
+// CHECK: %[[A:.*]] = extractvalue %struct.S %[[S:.*]], 0
+// CHECK: call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[A]])
 
 // float4 b : B -> 1 row, 4 columns; the whole vector is stored.
-// CHECK: %[[#B:]] = extractvalue %struct.S %[[#S]], 1
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[#B]])
+// CHECK: %[[B:.*]] = extractvalue %struct.S %[[S]], 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %[[B]])
 
 // float d[5] : D -> 5 rows, 1 column each.
-// CHECK: %[[#D:]] = extractvalue %struct.S %[[#S]], 2
-// CHECK: %[[#D0:]] = extractvalue [5 x float] %[[#D]], 0
-// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 0, i8 0, float %[[#D0]])
-// CHECK: %[[#D1:]] = extractvalue [5 x float] %[[#D]], 1
-// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 1, i8 0, float %[[#D1]])
-// CHECK: %[[#D2:]] = extractvalue [5 x float] %[[#D]], 2
-// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 2, i8 0, float %[[#D2]])
-// CHECK: %[[#D3:]] = extractvalue [5 x float] %[[#D]], 3
-// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 3, i8 0, float %[[#D3]])
-// CHECK: %[[#D4:]] = extractvalue [5 x float] %[[#D]], 4
-// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 4, i8 0, float %[[#D4]])
+// CHECK: %[[D:.*]] = extractvalue %struct.S %[[S]], 2
+// CHECK: %[[D0:.*]] = extractvalue [5 x float] %[[D]], 0
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 0, i8 0, float %[[D0]])
+// CHECK: %[[D1:.*]] = extractvalue [5 x float] %[[D]], 1
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 1, i8 0, float %[[D1]])
+// CHECK: %[[D2:.*]] = extractvalue [5 x float] %[[D]], 2
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 2, i8 0, float %[[D2]])
+// CHECK: %[[D3:.*]] = extractvalue [5 x float] %[[D]], 3
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 3, i8 0, float %[[D3]])
+// CHECK: %[[D4:.*]] = extractvalue [5 x float] %[[D]], 4
+// CHECK: call void @llvm.dx.store.output.f32(i32 2, i32 4, i8 0, float %[[D4]])
 
 // float4 e[2][3] : E -> 6 rows (2 x 3), 4 columns each; row-major flattening.
-// CHECK: %[[#E:]] = extractvalue %struct.S %[[#S]], 3
-// CHECK: %[[#E00:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 0
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 0, i8 0, <4 x float> %[[#E00]])
-// CHECK: %[[#E01:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 1
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 1, i8 0, <4 x float> %[[#E01]])
-// CHECK: %[[#E02:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 0, 2
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 2, i8 0, <4 x float> %[[#E02]])
-// CHECK: %[[#E10:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 0
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 3, i8 0, <4 x float> %[[#E10]])
-// CHECK: %[[#E11:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 1
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 4, i8 0, <4 x float> %[[#E11]])
-// CHECK: %[[#E12:]] = extractvalue [2 x [3 x <4 x float>]] %[[#E]], 1, 2
-// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 5, i8 0, <4 x float> %[[#E12]])
+// CHECK: %[[E:.*]] = extractvalue %struct.S %[[S]], 3
+// CHECK: %[[E00:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 0, 0
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 0, i8 0, <4 x float> %[[E00]])
+// CHECK: %[[E01:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 0, 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 1, i8 0, <4 x float> %[[E01]])
+// CHECK: %[[E02:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 0, 2
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 2, i8 0, <4 x float> %[[E02]])
+// CHECK: %[[E10:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 1, 0
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 3, i8 0, <4 x float> %[[E10]])
+// CHECK: %[[E11:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 1, 1
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 4, i8 0, <4 x float> %[[E11]])
+// CHECK: %[[E12:.*]] = extractvalue [2 x [3 x <4 x float>]] %[[E]], 1, 2
+// CHECK: call void @llvm.dx.store.output.v4f32(i32 3, i32 5, i8 0, <4 x float> %[[E12]])
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
index 426738adfe7ef..7bf54c4984eac 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
@@ -16,15 +16,15 @@ struct Output {
 // CHECK-SPIRV-DAG:    @A4 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#METADATA_0:]]
 // CHECK-SPIRV-DAG:    @A2 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#METADATA_2:]]
 
-// CHECK: %Idx = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 0
-// CHECK: %[[#tmp:]] = load float, ptr %Idx, align 1
-// CHECK: %a = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 0
-// CHECK: store float %[[#tmp]], ptr %a, align 1
+// CHECK: %[[IDX0:.*]] = getelementptr inbounds nuw %struct.Input, ptr %{{.*}}, i32 0, i32 0
+// CHECK: %[[LOAD0:.*]] = load float, ptr %[[IDX0]], align 1
+// CHECK: %[[A:.*]] = getelementptr inbounds nuw %struct.Output, ptr %{{.*}}, i32 0, i32 0
+// CHECK: store float %[[LOAD0]], ptr %[[A]], align 1
 
-// CHECK: %Idx1 = getelementptr inbounds nuw %struct.Input, ptr %input, i32 0, i32 0
-// CHECK: %[[#tmp:]] = load float, ptr %Idx1, align 1
-// CHECK: %b = getelementptr inbounds nuw %struct.Output, ptr %agg.result, i32 0, i32 1
-// CHECK: store float %[[#tmp]], ptr %b, align 1
+// CHECK: %[[IDX1:.*]] = getelementptr inbounds nuw %struct.Input, ptr %{{.*}}, i32 0, i32 0
+// CHECK: %[[LOAD1:.*]] = load float, ptr %[[IDX1]], align 1
+// CHECK: %[[B:.*]] = getelementptr inbounds nuw %struct.Output, ptr %{{.*}}, i32 0, i32 1
+// CHECK: store float %[[LOAD1]], ptr %[[B]], align 1
 
 Output main(Input input) {
   Output o;
@@ -35,18 +35,18 @@ Output main(Input input) {
 
 // Code generated in the entrypoint wrapper:
 
-// CHECK: %[[#OUTPUT:]] = alloca %struct.Output, align 8
+// CHECK: %[[OUTPUT:.*]] = alloca %struct.Output, align 8
 
-// CHECK-SPIRV: call spir_func void @_Z4main5Input(ptr %[[#OUTPUT]], ptr %[[#]])
-// CHECK-DXIL:  call void @_Z4main5Input(ptr %[[#OUTPUT]], ptr %[[#]])
+// CHECK-SPIRV: call spir_func void @_Z4main5Input(ptr %[[OUTPUT]], ptr %{{.*}})
+// CHECK-DXIL:  call void @_Z4main5Input(ptr %[[OUTPUT]], ptr %{{.*}})
 
-// CHECK: %[[#TMP:]] = load %struct.Output, ptr %[[#OUTPUT]], align 4
-// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 0
-// CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A4, align 4
-// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#VAL]])
-// CHECK: %[[#VAL:]] = extractvalue %struct.Output %[[#TMP]], 1
-// CHECK-SPIRV:        store float %[[#VAL]], ptr addrspace(8) @A2, align 4
-// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 1, i32 0, i8 0, float %[[#VAL]])
+// CHECK: %[[TMP:.*]] = load %struct.Output, ptr %[[OUTPUT]], align 4
+// CHECK: %[[VAL0:.*]] = extractvalue %struct.Output %[[TMP]], 0
+// CHECK-SPIRV:        store float %[[VAL0]], ptr addrspace(8) @A4, align 4
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[VAL0]])
+// CHECK: %[[VAL1:.*]] = extractvalue %struct.Output %[[TMP]], 1
+// CHECK-SPIRV:        store float %[[VAL1]], ptr addrspace(8) @A2, align 4
+// CHECK-DXIL:         call void @llvm.dx.store.output.f32(i32 1, i32 0, i8 0, float %[[VAL1]])
 
 // CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
 // CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]}
diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl b/clang/test/CodeGenHLSL/sret_output.hlsl
index 325c31541f473..2f8b17d337424 100644
--- a/clang/test/CodeGenHLSL/sret_output.hlsl
+++ b/clang/test/CodeGenHLSL/sret_output.hlsl
@@ -20,13 +20,13 @@ S vs_main() {
   return s;
 };
 
-// CHECK: %[[#alloca:]] = alloca %struct.S, align 8
-// CHECK-DX:              call void @_Z7vs_mainv(ptr %[[#alloca]])
-// CHECK-VK:              call spir_func void @_Z7vs_mainv(ptr %[[#alloca]])
-// CHECK: %[[#a:]] = load %struct.S, ptr %[[#alloca]], align 4
-// CHECK: %[[#b:]] = extractvalue %struct.S %[[#a]], 0
-// CHECK-DX:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[#b]])
-// CHECK-VK:         store float %3, ptr addrspace(8) @A4, align 4
+// CHECK: %[[ALLOCA:.*]] = alloca %struct.S, align 8
+// CHECK-DX:              call void @_Z7vs_mainv(ptr %[[ALLOCA]])
+// CHECK-VK:              call spir_func void @_Z7vs_mainv(ptr %[[ALLOCA]])
+// CHECK: %[[S:.*]] = load %struct.S, ptr %[[ALLOCA]], align 4
+// CHECK: %[[A:.*]] = extractvalue %struct.S %[[S]], 0
+// CHECK-DX:         call void @llvm.dx.store.output.f32(i32 0, i32 0, i8 0, float %[[A]])
+// CHECK-VK:         store float %[[A]], ptr addrspace(8) @A4, align 4
 // CHECK:            ret void
 
 // CHECK-VK: ![[#ATTR0]] = !{![[#ATTR1:]]}

>From b3a5e05a6246d9860f53260a4d9617d1dcd0c380 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 7 Aug 2026 19:58:33 +0000
Subject: [PATCH 14/15] conflict review: update lowering to account for removed
 sigpoint operand

---
 llvm/lib/Target/DirectX/DXIL.td               |  8 ++----
 .../Target/DirectX/DXILIntrinsicExpansion.cpp | 28 ++++++++-----------
 llvm/test/CodeGen/DirectX/LoadInput.ll        |  8 +++---
 llvm/test/CodeGen/DirectX/StoreOutput.ll      |  8 +++---
 4 files changed, 22 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 842c1b48efecf..c2d1b0ad4300c 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -414,9 +414,7 @@ class DXILOp<int opcode, DXILOpClass opclass> {
 
 def LoadInput : DXILOp<4, loadInput> {
   let Doc = "Loads a scalar value from a shader input register component.";
-  let intrinsics = [IntrinSelect<int_dx_load_input,
-      [IntrinArgIndex<1>, IntrinArgIndex<2>, IntrinArgIndex<3>,
-       IntrinArgIndex<4>]>];
+  let intrinsics = [IntrinSelect<int_dx_load_input>];
   // inputSigId, rowIndex, colIndex, gsVertexOrPrimIndex
   let arguments = [Int32Ty, Int32Ty, Int8Ty, Int32Ty];
   let result = OverloadTy;
@@ -427,9 +425,7 @@ def LoadInput : DXILOp<4, loadInput> {
 
 def StoreOutput : DXILOp<5, storeOutput> {
   let Doc = "Stores a scalar value to a shader output register component.";
-  let intrinsics = [IntrinSelect<int_dx_store_output,
-      [IntrinArgIndex<1>, IntrinArgIndex<2>, IntrinArgIndex<3>,
-       IntrinArgIndex<4>]>];
+  let intrinsics = [IntrinSelect<int_dx_store_output>];
   // outputSigId, rowIndex, colIndex, value
   let arguments = [Int32Ty, Int32Ty, Int8Ty, OverloadTy];
   let result = VoidTy;
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index c5b8b4efee956..73867d6e344a2 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -1218,7 +1218,7 @@ static Value *expandMatrixTranspose(CallInst *Orig) {
 // The DXIL StoreOutput op is per-component; vector intrinsics are split here
 // so that DXILOpLowering sees only scalar variants.
 static bool expandStoreOutput(CallInst *Orig) {
-  auto *VT = dyn_cast<FixedVectorType>(Orig->getArgOperand(4)->getType());
+  auto *VT = dyn_cast<FixedVectorType>(Orig->getArgOperand(3)->getType());
   if (!VT)
     return false; // already scalar, nothing to expand
 
@@ -1229,11 +1229,10 @@ static bool expandStoreOutput(CallInst *Orig) {
   Type *ScalarTy = VT->getElementType();
   unsigned NumElems = VT->getNumElements();
 
-  Value *SigpointId = Orig->getArgOperand(0);
-  Value *SigElementId = Orig->getArgOperand(1);
-  Value *RowIndex = Orig->getArgOperand(2);
-  Value *StartCol = Orig->getArgOperand(3); // i8
-  Value *Data = Orig->getArgOperand(4);
+  Value *SigElementId = Orig->getArgOperand(0);
+  Value *RowIndex = Orig->getArgOperand(1);
+  Value *StartCol = Orig->getArgOperand(2); // i8
+  Value *Data = Orig->getArgOperand(3);
   Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
 
   Function *ScalarFn = Intrinsic::getOrInsertDeclaration(
@@ -1245,8 +1244,7 @@ static bool expandStoreOutput(CallInst *Orig) {
     Value *ColIdx =
         Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty, I));
     Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
-    Builder.CreateCall(ScalarFn,
-                       {SigpointId, SigElementId, RowIndex, ColI8, Scalar});
+    Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
   }
 
   Orig->eraseFromParent();
@@ -1267,11 +1265,10 @@ static Value *expandLoadInput(CallInst *Orig) {
   Type *ScalarTy = VT->getElementType();
   unsigned NumElems = VT->getNumElements();
 
-  Value *SigpointId = Orig->getArgOperand(0);
-  Value *SigElementId = Orig->getArgOperand(1);
-  Value *RowIndex = Orig->getArgOperand(2);
-  Value *StartCol = Orig->getArgOperand(3); // i8
-  Value *GsVertexOrPrimIndex = Orig->getArgOperand(4);
+  Value *SigElementId = Orig->getArgOperand(0);
+  Value *RowIndex = Orig->getArgOperand(1);
+  Value *StartCol = Orig->getArgOperand(2); // i8
+  Value *GsVertexOrPrimIndex = Orig->getArgOperand(3);
   Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
 
   Function *ScalarFn = Intrinsic::getOrInsertDeclaration(
@@ -1282,9 +1279,8 @@ static Value *expandLoadInput(CallInst *Orig) {
     Value *ColIdx =
         Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty, I));
     Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
-    Value *Scalar =
-        Builder.CreateCall(ScalarFn, {SigpointId, SigElementId, RowIndex, ColI8,
-                                      GsVertexOrPrimIndex});
+    Value *Scalar = Builder.CreateCall(
+        ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
     Vec =
         Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty, I));
   }
diff --git a/llvm/test/CodeGen/DirectX/LoadInput.ll b/llvm/test/CodeGen/DirectX/LoadInput.ll
index b29167d2dfb27..7eaed85b2df2c 100644
--- a/llvm/test/CodeGen/DirectX/LoadInput.ll
+++ b/llvm/test/CodeGen/DirectX/LoadInput.ll
@@ -8,7 +8,7 @@ define float @load_scalar_f32() {
   ; CHECK: [[V:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 1, i8 2, i32 0)
   ; CHECK-NEXT: ret float [[V]]
   ; CHECK-NOT: llvm.dx.load.input
-  %v = call float @llvm.dx.load.input.f32(i32 99, i32 0, i32 1, i8 2, i32 0)
+  %v = call float @llvm.dx.load.input.f32(i32 0, i32 1, i8 2, i32 0)
   ret float %v
 }
 
@@ -24,7 +24,7 @@ define <4 x float> @load_v4f32() {
   ; CHECK: [[S3:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 3, i32 0)
   ; CHECK-NEXT: insertelement {{.*}}, float [[S3]], i32 3
   ; CHECK-NOT: llvm.dx.load.input
-  %v = call <4 x float> @llvm.dx.load.input.v4f32(i32 99, i32 1, i32 0, i8 0, i32 0)
+  %v = call <4 x float> @llvm.dx.load.input.v4f32(i32 1, i32 0, i8 0, i32 0)
   ret <4 x float> %v
 }
 
@@ -36,7 +36,7 @@ define <2 x float> @load_v2f32_col2() {
   ; CHECK: [[S1:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 3, i32 0)
   ; CHECK-NEXT: insertelement {{.*}}, float [[S1]], i32 1
   ; CHECK-NOT: llvm.dx.load.input
-  %v = call <2 x float> @llvm.dx.load.input.v2f32(i32 99, i32 2, i32 0, i8 2, i32 0)
+  %v = call <2 x float> @llvm.dx.load.input.v2f32(i32 2, i32 0, i8 2, i32 0)
   ret <2 x float> %v
 }
 
@@ -46,6 +46,6 @@ define i32 @load_scalar_i32() {
   ; CHECK: [[V:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 2, i32 0, i8 0, i32 0)
   ; CHECK-NEXT: ret i32 [[V]]
   ; CHECK-NOT: llvm.dx.load.input
-  %v = call i32 @llvm.dx.load.input.i32(i32 99, i32 2, i32 0, i8 0, i32 0)
+  %v = call i32 @llvm.dx.load.input.i32(i32 2, i32 0, i8 0, i32 0)
   ret i32 %v
 }
diff --git a/llvm/test/CodeGen/DirectX/StoreOutput.ll b/llvm/test/CodeGen/DirectX/StoreOutput.ll
index 04970a1488710..e67c972941ba4 100644
--- a/llvm/test/CodeGen/DirectX/StoreOutput.ll
+++ b/llvm/test/CodeGen/DirectX/StoreOutput.ll
@@ -7,7 +7,7 @@ target triple = "dxil-pc-shadermodel6.0-pixel"
 define void @store_scalar_f32(float %val) {
   ; CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 1, i8 2, float %val)
   ; CHECK-NOT: llvm.dx.store.output
-  call void @llvm.dx.store.output.f32(i32 99, i32 0, i32 1, i8 2, float %val)
+  call void @llvm.dx.store.output.f32(i32 0, i32 1, i8 2, float %val)
   ret void
 }
 
@@ -23,7 +23,7 @@ define void @store_v4f32(<4 x float> %val) {
   ; CHECK-NEXT: [[E3:%.*]] = extractelement <4 x float> %val, i32 3
   ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 3, float [[E3]])
   ; CHECK-NOT: llvm.dx.store.output
-  call void @llvm.dx.store.output.v4f32(i32 99, i32 1, i32 0, i8 0, <4 x float> %val)
+  call void @llvm.dx.store.output.v4f32(i32 1, i32 0, i8 0, <4 x float> %val)
   ret void
 }
 
@@ -35,7 +35,7 @@ define void @store_v2f32_col2(<2 x float> %val) {
   ; CHECK-NEXT: [[E1:%.*]] = extractelement <2 x float> %val, i32 1
   ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 0, i8 3, float [[E1]])
   ; CHECK-NOT: llvm.dx.store.output
-  call void @llvm.dx.store.output.v2f32(i32 99, i32 2, i32 0, i8 2, <2 x float> %val)
+  call void @llvm.dx.store.output.v2f32(i32 2, i32 0, i8 2, <2 x float> %val)
   ret void
 }
 
@@ -44,6 +44,6 @@ define void @store_v2f32_col2(<2 x float> %val) {
 define void @store_scalar_i32(i32 %val) {
   ; CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 2, i32 0, i8 0, i32 %val)
   ; CHECK-NOT: llvm.dx.store.output
-  call void @llvm.dx.store.output.i32(i32 99, i32 2, i32 0, i8 0, i32 %val)
+  call void @llvm.dx.store.output.i32(i32 2, i32 0, i8 0, i32 %val)
   ret void
 }

>From 722c8cdaec506d5c4bb3f5fadbe6928a831ac905 Mon Sep 17 00:00:00 2001
From: Finn Plummer <mail at inbelic.dev>
Date: Fri, 7 Aug 2026 20:04:32 +0000
Subject: [PATCH 15/15] self-review: nit

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index c47e179a2ebb6..3d0930ac4644b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1281,8 +1281,9 @@ llvm::Value *CGHLSLRuntime::emitDXILUserSemanticLoad(
         Indices.empty() ? Value : B.CreateInsertValue(Result, Value, Indices);
 
     // Advance the multidimensional index
-    for (unsigned I = Indices.size(); I-- > 0;) {
-      if (++Indices[I] < Shape.Dimensions[I])
+    for (unsigned I = Indices.size(); I > 0; I--) {
+      Indices[I] += 1;
+      if (Indices[I] < Shape.Dimensions[I])
         break;
       Indices[I] = 0;
     }
@@ -1331,8 +1332,9 @@ void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
     B.CreateCall(IntrFn, Args, OB);
 
     // Advance the multidimensional index
-    for (unsigned I = Indices.size(); I-- > 0;) {
-      if (++Indices[I] < Shape.Dimensions[I])
+    for (unsigned I = Indices.size(); I > 0; I--) {
+      Indices[I] += 1;
+      if (Indices[I] < Shape.Dimensions[I])
         break;
       Indices[I] = 0;
     }



More information about the llvm-commits mailing list