Author: Dan Brown
Date: 2026-08-07T11:54:10-07:00
New Revision: c4eda0c444131b8f0cba2f33a126fb1632a25b3e

URL: 
https://github.com/llvm/llvm-project/commit/c4eda0c444131b8f0cba2f33a126fb1632a25b3e
DIFF: 
https://github.com/llvm/llvm-project/commit/c4eda0c444131b8f0cba2f33a126fb1632a25b3e.diff

LOG: [HLSL][DirectX] Lower llvm.dx.load.input and llvm.dx.store.output to DXIL 
(#208871)

Addresses #189766.

Co-authored-by: Finn Plummer <[email protected]>
Assisted-by: Claude Sonnet 4

---------

Co-authored-by: Finn Plummer <[email protected]>

Added: 
    llvm/test/CodeGen/DirectX/LoadInput.ll
    llvm/test/CodeGen/DirectX/StoreOutput.ll

Modified: 
    clang/lib/CodeGen/CGHLSLRuntime.cpp
    clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
    clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
    clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
    clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
    
clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
    clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl
    clang/test/CodeGenHLSL/semantics/semantic.struct.output.hlsl
    clang/test/CodeGenHLSL/sret_output.hlsl
    llvm/include/llvm/IR/IntrinsicsDirectX.td
    llvm/lib/Target/DirectX/DXIL.td
    llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f86cb00c204f8..a24e63f0b2b93 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1220,12 +1220,8 @@ void 
CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
                                               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),
-                            B.getInt32(0),
-                            B.getInt8(0),
-                            llvm::PoisonValue::get(B.getInt32Ty()),
-                            Source};
+  SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
+                            B.getInt8(0), 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..0dbf307074e89 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -11,7 +11,7 @@ float4 main(float4 p : SV_Position) : A {
 
   // 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:    %[[#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 4, 
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..aee4ee183bf9d 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
@@ -12,7 +12,7 @@ float4 main(float4 p : SV_Position) : SV_Position {
 
   // 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:    %[[#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 4, 
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..2c7929a9e821d 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 4, 
i32 0, i32 0, i8 0, <4 x float> %[[#TMP]])
   return p;
 }
 

diff  --git a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl 
b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
index 18942699aaa2c..4e70ea037952c 100644
--- a/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.output.hlsl
@@ -19,10 +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 4, 
i32 0, i32 0, i8 0, i32 poison, [2 x <4 x float>] %[[#TMP]])
+  // CHECK-DXIL:               call void @llvm.dx.store.output.a2v4f32(i32 4, 
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 4, 
i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
+  // CHECK-DXIL:               call void @llvm.dx.store.output.v4f32(i32 4, 
i32 0, 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..57b5b777f4736 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 4, 
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..96506c5bdeaa0 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 4, 
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..b1b1d2159ebac 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 4, 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 4, i32 0, 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..e2f806a2646f6 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 4, 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 090656ffb36c8..62489b58a0300 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -323,14 +323,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 /*sigpointId*/, 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 /*sigpointId*/, llvm_i32_ty /*sigElementId*/,
+           llvm_i32_ty /*rowIndex*/, llvm_i8_ty /*colIndex*/,
+           llvm_any_ty /*value*/],
+          [IntrConvergent]>;
 }

diff  --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 3d978c207f104..842c1b48efecf 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -412,6 +412,31 @@ class DXILOp<int opcode, DXILOpClass opclass> {
 //
 // This are sorted by ascending value of the DXIL Opcodes
 
+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>]>];
+  // inputSigId, rowIndex, colIndex, gsVertexOrPrimIndex
+  let arguments = [Int32Ty, Int32Ty, Int8Ty, Int32Ty];
+  let result = OverloadTy;
+  let overloads = [Overloads<DXIL1_0, [HalfTy, FloatTy, Int16Ty, Int32Ty]>];
+  let stages = [Stages<DXIL1_0, [all_stages]>];
+  let attributes = [Attributes<DXIL1_0, [ReadOnly]>];
+}
+
+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>]>];
+  // outputSigId, rowIndex, colIndex, value
+  let arguments = [Int32Ty, Int32Ty, Int8Ty, OverloadTy];
+  let result = VoidTy;
+  let overloads = [Overloads<DXIL1_0, [HalfTy, FloatTy, Int16Ty, Int32Ty]>];
+  let stages = [Stages<DXIL1_0, [all_stages]>];
+}
+
 def Abs : DXILOp<6, unary> {
   let Doc = "Returns the absolute value of the input.";
   let intrinsics = [IntrinSelect<int_fabs>];

diff  --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp 
b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index a251288a6ae42..c5b8b4efee956 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -234,6 +234,8 @@ static bool isIntrinsicExpansion(Function &F) {
   case Intrinsic::matrix_transpose:
   case Intrinsic::umul_with_overflow:
   case Intrinsic::smul_with_overflow:
+  case Intrinsic::dx_load_input:
+  case Intrinsic::dx_store_output:
     return true;
   case Intrinsic::dx_resource_load_rawbuffer:
     return resourceAccessNeeds64BitExpansion(
@@ -1212,6 +1214,84 @@ static Value *expandMatrixTranspose(CallInst *Orig) {
   return Builder.CreateShuffleVector(Mat, Mask);
 }
 
+// Scalarize a vector int_dx_store_output call into per-component scalar calls.
+// 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());
+  if (!VT)
+    return false; // already scalar, nothing to expand
+
+  IRBuilder<> Builder(Orig);
+  Module *M = Orig->getModule();
+  Type *Int8Ty = Builder.getInt8Ty();
+  Type *Int32Ty = Builder.getInt32Ty();
+  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 *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
+
+  Function *ScalarFn = Intrinsic::getOrInsertDeclaration(
+      M, Intrinsic::dx_store_output, {ScalarTy});
+
+  for (unsigned I = 0; I < NumElems; ++I) {
+    Value *Scalar =
+        Builder.CreateExtractElement(Data, ConstantInt::get(Int32Ty, I));
+    Value *ColIdx =
+        Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty, I));
+    Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
+    Builder.CreateCall(ScalarFn,
+                       {SigpointId, SigElementId, RowIndex, ColI8, Scalar});
+  }
+
+  Orig->eraseFromParent();
+  return true;
+}
+
+// Scalarize a vector int_dx_load_input call into per-component scalar calls
+// and reassemble the vector. The DXIL LoadInput op is per-component.
+static Value *expandLoadInput(CallInst *Orig) {
+  auto *VT = dyn_cast<FixedVectorType>(Orig->getType());
+  if (!VT)
+    return nullptr; // already scalar, nothing to expand
+
+  IRBuilder<> Builder(Orig);
+  Module *M = Orig->getModule();
+  Type *Int8Ty = Builder.getInt8Ty();
+  Type *Int32Ty = Builder.getInt32Ty();
+  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 *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
+
+  Function *ScalarFn = Intrinsic::getOrInsertDeclaration(
+      M, Intrinsic::dx_load_input, {ScalarTy});
+
+  Value *Vec = PoisonValue::get(VT);
+  for (unsigned I = 0; I < NumElems; ++I) {
+    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});
+    Vec =
+        Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty, I));
+  }
+
+  return Vec;
+}
+
 static bool expandIntrinsic(Function &F, CallInst *Orig) {
   Value *Result = nullptr;
   Intrinsic::ID IntrinsicId = F.getIntrinsicID();
@@ -1287,6 +1367,13 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) 
{
   case Intrinsic::dx_radians:
     Result = expandRadiansIntrinsic(Orig);
     break;
+  case Intrinsic::dx_load_input:
+    Result = expandLoadInput(Orig);
+    break;
+  case Intrinsic::dx_store_output:
+    if (expandStoreOutput(Orig))
+      return true;
+    break;
   case Intrinsic::dx_resource_load_rawbuffer:
     if (expandBufferLoadIntrinsic(Orig, /*IsRaw*/ true))
       return true;

diff  --git a/llvm/test/CodeGen/DirectX/LoadInput.ll 
b/llvm/test/CodeGen/DirectX/LoadInput.ll
new file mode 100644
index 0000000000000..b29167d2dfb27
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/LoadInput.ll
@@ -0,0 +1,51 @@
+; RUN: opt -S -dxil-intrinsic-expansion -dxil-op-lower %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.0-pixel"
+
+; Scalar float load: one LoadInput call, result forwarded directly.
+; CHECK-LABEL: define float @load_scalar_f32
+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)
+  ret float %v
+}
+
+; Vector float4 load: four per-component LoadInput calls reassembled into a 
vector.
+; CHECK-LABEL: define <4 x float> @load_v4f32
+define <4 x float> @load_v4f32() {
+  ; CHECK: [[S0:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, 
i8 0, i32 0)
+  ; CHECK-NEXT: insertelement <4 x float> {{.*}}, float [[S0]], i32 0
+  ; CHECK: [[S1:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, 
i8 1, i32 0)
+  ; CHECK-NEXT: insertelement {{.*}}, float [[S1]], i32 1
+  ; CHECK: [[S2:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, 
i8 2, i32 0)
+  ; CHECK-NEXT: insertelement {{.*}}, float [[S2]], i32 2
+  ; 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)
+  ret <4 x float> %v
+}
+
+; Vector float2 load with non-zero start column: col indices must be 2 and 3.
+; CHECK-LABEL: define <2 x float> @load_v2f32_col2
+define <2 x float> @load_v2f32_col2() {
+  ; CHECK: [[S0:%.*]] = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, 
i8 2, i32 0)
+  ; CHECK-NEXT: insertelement <2 x float> {{.*}}, float [[S0]], i32 0
+  ; 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)
+  ret <2 x float> %v
+}
+
+; Scalar int load: one LoadInput call, result forwarded directly.
+; CHECK-LABEL: define i32 @load_scalar_i32
+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)
+  ret i32 %v
+}

diff  --git a/llvm/test/CodeGen/DirectX/StoreOutput.ll 
b/llvm/test/CodeGen/DirectX/StoreOutput.ll
new file mode 100644
index 0000000000000..04970a1488710
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/StoreOutput.ll
@@ -0,0 +1,49 @@
+; RUN: opt -S -dxil-intrinsic-expansion -dxil-op-lower %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.0-pixel"
+
+; Scalar float store: one StoreOutput call, no residual intrinsic.
+; CHECK-LABEL: define void @store_scalar_f32
+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)
+  ret void
+}
+
+; Vector float4 store: four per-component StoreOutput calls, col indices 0..3.
+; CHECK-LABEL: define void @store_v4f32
+define void @store_v4f32(<4 x float> %val) {
+  ; CHECK: [[E0:%.*]] = extractelement <4 x float> %val, i32 0
+  ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 0, 
float [[E0]])
+  ; CHECK-NEXT: [[E1:%.*]] = extractelement <4 x float> %val, i32 1
+  ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 1, 
float [[E1]])
+  ; CHECK-NEXT: [[E2:%.*]] = extractelement <4 x float> %val, i32 2
+  ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 2, 
float [[E2]])
+  ; 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)
+  ret void
+}
+
+; Vector float2 store with non-zero start column: col indices must be 2 and 3.
+; CHECK-LABEL: define void @store_v2f32_col2
+define void @store_v2f32_col2(<2 x float> %val) {
+  ; CHECK: [[E0:%.*]] = extractelement <2 x float> %val, i32 0
+  ; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 0, i8 2, 
float [[E0]])
+  ; 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)
+  ret void
+}
+
+; Scalar int store: one StoreOutput call, no residual intrinsic.
+; CHECK-LABEL: define void @store_scalar_i32
+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)
+  ret void
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to