https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/212656
>From 5a5d75d02f02eac883a7deedfec18bfc0277d603 Mon Sep 17 00:00:00 2001 From: Finn Plummer <[email protected]> Date: Fri, 24 Jul 2026 23:34:32 +0000 Subject: [PATCH 1/5] 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 8794579166b6a..03cc39de49638 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1150,10 +1150,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; @@ -1175,12 +1174,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 4dd86270f0d01..f16686186aac2 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -321,14 +321,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 94e89e9bc8afadfa51b67c76c6479d192d561dc9 Mon Sep 17 00:00:00 2001 From: Finn Plummer <[email protected]> Date: Tue, 28 Jul 2026 20:41:35 +0000 Subject: [PATCH 2/5] 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 03cc39de49638..12852f05e4fea 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1150,9 +1150,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; @@ -1175,10 +1176,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 cf47b1633fd3c..8f8bad69cae37 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -368,6 +368,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 f71cd5396c3efbdd2b354d3e1db5faf6c3fe6ed0 Mon Sep 17 00:00:00 2001 From: Finn Plummer <[email protected]> Date: Tue, 28 Jul 2026 20:53:15 +0000 Subject: [PATCH 3/5] 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 e84d362d8e30541cef8acde230fa0a4aa7255c47 Mon Sep 17 00:00:00 2001 From: Finn Plummer <[email protected]> Date: Tue, 28 Jul 2026 23:16:48 +0000 Subject: [PATCH 4/5] 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 12852f05e4fea..0ef1456fec49e 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1142,21 +1142,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())) { @@ -1164,22 +1202,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())) { @@ -1187,9 +1285,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( @@ -1199,7 +1322,7 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( return emitSPIRVUserSemanticLoad(B, 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."); } @@ -1212,7 +1335,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."); } @@ -1267,7 +1390,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) { @@ -1282,7 +1405,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); } } @@ -1312,7 +1435,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 8f8bad69cae37..bbd9d59a4de4c 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, llvm::Type *Type, @@ -352,6 +353,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, @@ -368,6 +370,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 12f99419a3a1fe9c94d76cf2f7bfcb569ff6a51b Mon Sep 17 00:00:00 2001 From: Finn Plummer <[email protected]> Date: Wed, 29 Jul 2026 15:52:34 +0000 Subject: [PATCH 5/5] 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 0ef1456fec49e..df6cb42540a75 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1182,11 +1182,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)); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
