[llvm] [DirectX] Make DXILOpLowering split vector coordinates, offsets, and gradient operands (PR #223091)

Deric C. via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 09:49:16 PDT 2026


https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/223091

>From 17eb826dc9bcad494b413a22db9ccd077f78b0f0 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Fri, 11 Sep 2026 11:27:29 -0700
Subject: [PATCH 1/2] Make DXILOpLowering split vector coordinates, offsets,
 and gradient operands

---
 llvm/lib/Target/DirectX/DXILOpLowering.cpp    | 115 +++++++++-----
 llvm/test/CodeGen/DirectX/Sample.ll           |  73 ++++++---
 llvm/test/CodeGen/DirectX/SampleBias.ll       |  74 ++++++---
 llvm/test/CodeGen/DirectX/SampleGrad.ll       | 149 +++++++++++-------
 llvm/test/CodeGen/DirectX/SampleLevel.ll      |  65 ++++++--
 .../DirectX/Texture2DArray-SampleBias.ll      |  50 +++++-
 .../DirectX/Texture2DArray-SampleGrad.ll      |  59 ++++++-
 llvm/test/CodeGen/DirectX/TextureLoad.ll      |  86 ++++++----
 llvm/test/CodeGen/DirectX/TextureStore.ll     |  99 +++++++++---
 9 files changed, 561 insertions(+), 209 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index a98c115bcd62e..aa73629eee232 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -26,6 +26,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/IR/Use.h"
+#include "llvm/IR/ValueHandle.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -639,22 +640,56 @@ class OpLowerer {
     });
   }
 
+  /// Recover the scalar components of `Vec` from the `insertelement` chain that
+  /// built it. Since we run after the scalarizer, such a chain is usually just
+  /// a temporary gathered to pass the vector to a call.
+  static void collectInsertedElements(Value *Vec,
+                                      MutableArrayRef<Value *> Elements) {
+    unsigned NumElts = cast<FixedVectorType>(Vec->getType())->getNumElements();
+    assert(NumElts <= Elements.size() && "Not enough room for the components");
+
+    SmallVector<InsertElementInst *, 4> Chain;
+    for (auto *IEI = dyn_cast<InsertElementInst>(Vec); IEI;
+         IEI = dyn_cast<InsertElementInst>(IEI->getOperand(0))) {
+      if (!isa<ConstantInt>(IEI->getOperand(2)))
+        break; // This break should never happen below SM6.9.
+      Chain.push_back(IEI);
+    }
+
+    // Replay element insertion from the innermost first, so that a repeated
+    // index ends up holding the live value.
+    while (!Chain.empty()) {
+      InsertElementInst *IEI = Chain.pop_back_val();
+      uint64_t IndexVal = cast<ConstantInt>(IEI->getOperand(2))->getZExtValue();
+      if (IndexVal < NumElts)
+        Elements[IndexVal] = IEI->getOperand(1);
+    }
+  }
+
   // Copies `Src` into `Args` starting at `ArgIdx`. If `Src` is a vector, its
-  // elements are extracted and stored in consecutive slots; otherwise `Src`
-  // is stored directly. At most `MaxElements` elements are expected.
+  // elements are placed in consecutive slots; otherwise `Src` is stored
+  // directly. At most `MaxElements` elements are expected.
   static void extractElementsIntoArgs(IRBuilder<> &IRB,
                                       MutableArrayRef<Value *> Args,
                                       unsigned ArgIdx, Value *Src,
                                       unsigned MaxElements) {
-    Type *Ty = Src->getType();
-    if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
-      unsigned Count = VecTy->getNumElements();
-      assert(Count <= MaxElements && "Expected at most 3 elements in vector");
-      for (unsigned I = 0; I < Count; ++I)
-        Args[ArgIdx + I] = IRB.CreateExtractElement(Src, uint64_t(I));
-    } else {
+    auto *VecTy = dyn_cast<FixedVectorType>(Src->getType());
+    if (!VecTy) {
       Args[ArgIdx] = Src;
+      return;
     }
+
+    unsigned Count = VecTy->getNumElements();
+    assert(Count <= MaxElements && "Too many elements for the arg list");
+
+    SmallVector<Value *, 4> Elements(Count, nullptr);
+    collectInsertedElements(Src, Elements);
+
+    for (unsigned I = 0; I < Count; ++I)
+      Args[ArgIdx + I] = Elements[I]
+                             ? Elements[I]
+                             : IRB.CreateExtractElement(
+                                   Src, ConstantInt::get(IRB.getInt32Ty(), I));
   }
 
   /// Copy offsets into the argument list at the given index, unless
@@ -676,6 +711,7 @@ class OpLowerer {
     return replaceFunction(F, [&](CallInst *CI) -> Error {
       IRB.SetInsertPoint(CI);
 
+      SmallVector<WeakTrackingVH, 4> VectorArgs = collectVectorArgs(CI);
       Value *Handle =
           createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
       Value *Coords = CI->getArgOperand(1);
@@ -710,6 +746,8 @@ class OpLowerer {
       if (Error E = replaceResRetUses(CI, *OpCall, /*HasCheckBit=*/false))
         return E;
 
+      eraseDeadInsertElementChains(VectorArgs);
+
       return Error::success();
     });
   }
@@ -725,6 +763,7 @@ class OpLowerer {
     return replaceFunction(F, [&](CallInst *CI) -> Error {
       IRB.SetInsertPoint(CI);
 
+      SmallVector<WeakTrackingVH, 4> VectorArgs = collectVectorArgs(CI);
       Value *Handle =
           createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
       Value *Sampler =
@@ -755,6 +794,8 @@ class OpLowerer {
       if (Error E = replaceResRetUses(CI, *OpCall, /*HasCheckBit=*/false))
         return E;
 
+      eraseDeadInsertElementChains(VectorArgs);
+
       return Error::success();
     });
   }
@@ -946,35 +987,8 @@ class OpLowerer {
   static std::array<Value *, 4> splitStoreData(IRBuilder<> &IRB, Value *Data,
                                                uint64_t NumElements,
                                                bool FillWithUndef) {
-    Type *DataTy = Data->getType();
-    Type *ScalarTy = DataTy->getScalarType();
-
     std::array<Value *, 4> DataElements{nullptr, nullptr, nullptr, nullptr};
-    if (DataTy == ScalarTy)
-      DataElements[0] = Data;
-    else {
-      // Since we're post-scalarizer, if we see a vector here it's likely
-      // constructed solely for the argument of the store. Just use the scalar
-      // values from before they're inserted into the temporary.
-      auto *IEI = dyn_cast<InsertElementInst>(Data);
-      while (IEI) {
-        auto *IndexOp = dyn_cast<ConstantInt>(IEI->getOperand(2));
-        if (!IndexOp)
-          break;
-        size_t IndexVal = IndexOp->getZExtValue();
-        assert(IndexVal < 4 && "Too many elements for resource store");
-        DataElements[IndexVal] = IEI->getOperand(1);
-        IEI = dyn_cast<InsertElementInst>(IEI->getOperand(0));
-      }
-    }
-
-    // If for some reason we weren't able to forward the arguments from the
-    // scalarizer artifact, then we may need to actually extract elements from
-    // the vector.
-    for (uint64_t I = 0, E = NumElements; I < E; ++I)
-      if (DataElements[I] == nullptr)
-        DataElements[I] = IRB.CreateExtractElement(
-            Data, ConstantInt::get(IRB.getInt32Ty(), I));
+    extractElementsIntoArgs(IRB, DataElements, 0, Data, 4);
 
     // For any elements beyond the length of the vector, we should fill it up
     // with undef - however, for typed UAVs we repeat the first element to
@@ -982,13 +996,14 @@ class OpLowerer {
     for (uint64_t I = NumElements, E = 4; I < E; ++I)
       if (DataElements[I] == nullptr)
         DataElements[I] =
-            FillWithUndef ? UndefValue::get(ScalarTy) : DataElements[0];
+            FillWithUndef ? UndefValue::get(Data->getType()->getScalarType())
+                          : DataElements[0];
 
     return DataElements;
   }
 
-  /// Erase the chain of `insertelement`s that only existed to build up the
-  /// value operand of a store we've just replaced.
+  /// Erase the chain of `insertelement`s that only existed to build up a vector
+  /// operand of an intrinsic we've just replaced.
   static void eraseDeadInsertElementChain(Value *Data) {
     auto *IEI = dyn_cast<InsertElementInst>(Data);
     while (IEI && IEI->use_empty()) {
@@ -1059,6 +1074,23 @@ class OpLowerer {
     });
   }
 
+  /// Snapshot the vector-typed arguments of `CI` so their `insertelement`
+  /// chains can be cleaned up once `CI` has been replaced. The handles are weak
+  /// because two arguments can share an `insertelement` chain.
+  static SmallVector<WeakTrackingVH, 4> collectVectorArgs(CallInst *CI) {
+    SmallVector<WeakTrackingVH, 4> Vectors;
+    for (Value *Arg : CI->args())
+      if (isa<FixedVectorType>(Arg->getType()))
+        Vectors.emplace_back(Arg);
+    return Vectors;
+  }
+
+  static void eraseDeadInsertElementChains(ArrayRef<WeakTrackingVH> Vectors) {
+    for (const WeakTrackingVH &VH : Vectors)
+      if (Value *V = VH)
+        eraseDeadInsertElementChain(V);
+  }
+
   [[nodiscard]] bool lowerTextureStore(Function &F) {
     const DataLayout &DL = F.getDataLayout();
     IRBuilder<> &IRB = OpBuilder.getIRB();
@@ -1068,6 +1100,7 @@ class OpLowerer {
     return replaceFunction(F, [&](CallInst *CI) -> Error {
       IRB.SetInsertPoint(CI);
 
+      SmallVector<WeakTrackingVH, 4> VectorArgs = collectVectorArgs(CI);
       Value *Handle =
           createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
       Value *Coords = CI->getArgOperand(1);
@@ -1101,7 +1134,7 @@ class OpLowerer {
         return E;
 
       CI->eraseFromParent();
-      eraseDeadInsertElementChain(Data);
+      eraseDeadInsertElementChains(VectorArgs);
 
       return Error::success();
     });
diff --git a/llvm/test/CodeGen/DirectX/Sample.ll b/llvm/test/CodeGen/DirectX/Sample.ll
index 779df2beb347d..f9a6fcc868b14 100644
--- a/llvm/test/CodeGen/DirectX/Sample.ll
+++ b/llvm/test/CodeGen/DirectX/Sample.ll
@@ -16,8 +16,8 @@ define void @sample_texture2d_float4(<2 x float> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -46,8 +46,8 @@ define void @sample_texture2d_with_clamp(<2 x float> %coords, float %clamp) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -76,8 +76,8 @@ define void @sample_texture2d_with_offset(<2 x float> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -106,10 +106,10 @@ define void @sample_texture2d_with_dynamic_offset(<2 x float> %coords, <2 x i32>
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i64 0
-  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i32 0
+  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -138,8 +138,8 @@ define void @sample_texture2d_with_offset_and_clamp(<2 x float> %coords, float %
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -196,9 +196,9 @@ define void @sample_texture3d_float4(<3 x float> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -227,8 +227,8 @@ define void @sample_texture2d_scalar(<2 x float> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sample.f32(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -257,8 +257,8 @@ define void @sample_texture2d_half4(<2 x float> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f16
   ; CHECK-SAME: @dx.op.sample.f16(i32 60,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -276,3 +276,38 @@ define void @sample_texture2d_half4(<2 x float> %coords) {
   call void @use_half4(<4 x half> %data)
   ret void
 }
+
+; The scalarizer re-gathers the coordinates just to pass them to the intrinsic.
+; DXIL has no vector instructions, so the scalars the vector was built from are
+; forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @sample_texture2d_scalarized(
+define void @sample_texture2d_scalarized(float %u, float %v) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 2)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <2 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <2 x float> %coords.0, float %v, i32 1
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sample.f32(i32 60,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float undef, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float undef)
+  %data = call <4 x float>
+      @llvm.dx.resource.sample.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <2 x float> %coords.1, <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/SampleBias.ll b/llvm/test/CodeGen/DirectX/SampleBias.ll
index 47cded9a65275..dfca61b61ab85 100644
--- a/llvm/test/CodeGen/DirectX/SampleBias.ll
+++ b/llvm/test/CodeGen/DirectX/SampleBias.ll
@@ -16,8 +16,8 @@ define void @samplebias_texture2d_float4(<2 x float> %coords, float %bias) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -47,8 +47,8 @@ define void @samplebias_texture2d_with_clamp(<2 x float> %coords, float %bias, f
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -78,8 +78,8 @@ define void @samplebias_texture2d_with_offset(<2 x float> %coords, float %bias)
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -109,10 +109,10 @@ define void @samplebias_texture2d_with_dynamic_offset(<2 x float> %coords, float
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i64 0
-  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i32 0
+  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -142,8 +142,8 @@ define void @samplebias_texture2d_with_offset_and_clamp(<2 x float> %coords, flo
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -202,9 +202,9 @@ define void @samplebias_texture3d_float4(<3 x float> %coords, float %bias) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -234,8 +234,8 @@ define void @samplebias_texture2d_scalar(<2 x float> %coords, float %bias) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -265,8 +265,8 @@ define void @samplebias_texture2d_half4(<2 x float> %coords, float %bias) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f16
   ; CHECK-SAME: @dx.op.sampleBias.f16(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -285,3 +285,39 @@ define void @samplebias_texture2d_half4(<2 x float> %coords, float %bias) {
   call void @use_half4(<4 x half> %data)
   ret void
 }
+
+; The scalarizer re-gathers the coordinates just to pass them to the intrinsic.
+; DXIL has no vector instructions, so the scalars the vector was built from are
+; forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @samplebias_texture2d_scalarized(
+define void @samplebias_texture2d_scalarized(float %u, float %v, float %bias) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 2)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <2 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <2 x float> %coords.0, float %v, i32 1
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float undef, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float %bias,
+  ; CHECK-SAME: float undef)
+  %data = call <4 x float>
+      @llvm.dx.resource.samplebias.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <2 x float> %coords.1, float %bias, <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/SampleGrad.ll b/llvm/test/CodeGen/DirectX/SampleGrad.ll
index 0371079c9f29d..37ec29d03a570 100644
--- a/llvm/test/CodeGen/DirectX/SampleGrad.ll
+++ b/llvm/test/CodeGen/DirectX/SampleGrad.ll
@@ -16,12 +16,12 @@ define void @samplegrad_texture2d_float4(<2 x float> %coords, <2 x float> %ddx,
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -53,12 +53,12 @@ define void @samplegrad_texture2d_with_clamp(<2 x float> %coords, <2 x float> %d
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -90,12 +90,12 @@ define void @samplegrad_texture2d_with_offset(<2 x float> %coords, <2 x float> %
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -127,14 +127,14 @@ define void @samplegrad_texture2d_with_dynamic_offset(<2 x float> %coords, <2 x
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i64 0
-  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i32 0
+  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -166,12 +166,12 @@ define void @samplegrad_texture2d_with_offset_and_clamp(<2 x float> %coords, <2
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -233,15 +233,15 @@ define void @samplegrad_texture3d_float4(<3 x float> %coords, <3 x float> %ddx,
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
-  ; CHECK: %[[DDX0:.*]] = extractelement <3 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <3 x float> %ddx, i64 1
-  ; CHECK: %[[DDX2:.*]] = extractelement <3 x float> %ddx, i64 2
-  ; CHECK: %[[DDY0:.*]] = extractelement <3 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <3 x float> %ddy, i64 1
-  ; CHECK: %[[DDY2:.*]] = extractelement <3 x float> %ddy, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
+  ; CHECK: %[[DDX0:.*]] = extractelement <3 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <3 x float> %ddx, i32 1
+  ; CHECK: %[[DDX2:.*]] = extractelement <3 x float> %ddx, i32 2
+  ; CHECK: %[[DDY0:.*]] = extractelement <3 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <3 x float> %ddy, i32 1
+  ; CHECK: %[[DDY2:.*]] = extractelement <3 x float> %ddy, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -273,12 +273,12 @@ define void @samplegrad_texture2d_scalar(<2 x float> %coords, <2 x float> %ddx,
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -310,12 +310,12 @@ define void @samplegrad_texture2d_half4(<2 x float> %coords, <2 x float> %ddx, <
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f16
   ; CHECK-SAME: @dx.op.sampleGrad.f16(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -336,3 +336,46 @@ define void @samplegrad_texture2d_half4(<2 x float> %coords, <2 x float> %ddx, <
   call void @use_half4(<4 x half> %data)
   ret void
 }
+
+; DXIL has no vector instructions, so the scalars the vector operands were
+; built from are forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @sample_grad_texture2d_scalarized(
+define void @sample_grad_texture2d_scalarized(float %u, float %v, float %ddxu,
+                                              float %ddxv, float %ddyu,
+                                              float %ddyv) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 2)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <2 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <2 x float> %coords.0, float %v, i32 1
+  %ddx.0 = insertelement <2 x float> poison, float %ddxu, i32 0
+  %ddx.1 = insertelement <2 x float> %ddx.0, float %ddxv, i32 1
+  %ddy.0 = insertelement <2 x float> poison, float %ddyu, i32 0
+  %ddy.1 = insertelement <2 x float> %ddy.0, float %ddyv, i32 1
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement <2 x float>
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float undef, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float %ddxu, float %ddxv, float undef,
+  ; CHECK-SAME: float %ddyu, float %ddyv, float undef,
+  ; CHECK-SAME: float undef)
+  %data = call <4 x float>
+      @llvm.dx.resource.samplegrad.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2f32.v2f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <2 x float> %coords.1, <2 x float> %ddx.1, <2 x float> %ddy.1,
+          <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/SampleLevel.ll b/llvm/test/CodeGen/DirectX/SampleLevel.ll
index 3cfbc544418d9..f902e646c90c1 100644
--- a/llvm/test/CodeGen/DirectX/SampleLevel.ll
+++ b/llvm/test/CodeGen/DirectX/SampleLevel.ll
@@ -16,8 +16,8 @@ define void @samplelevel_texture2d_float4(<2 x float> %coords, float %lod) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -46,8 +46,8 @@ define void @samplelevel_texture2d_with_offset(<2 x float> %coords, float %lod)
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -76,10 +76,10 @@ define void @samplelevel_texture2d_with_dynamic_offset(<2 x float> %coords, floa
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
-  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i64 0
-  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
+  ; CHECK: %[[OFF0:.*]] = extractelement <2 x i32> %offsets, i32 0
+  ; CHECK: %[[OFF1:.*]] = extractelement <2 x i32> %offsets, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -136,9 +136,9 @@ define void @samplelevel_texture3d_float4(<3 x float> %coords, float %lod) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -167,8 +167,8 @@ define void @samplelevel_texture2d_scalar(<2 x float> %coords, float %lod) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -197,8 +197,8 @@ define void @samplelevel_texture2d_half4(<2 x float> %coords, float %lod) {
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x float> %coords, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f16
   ; CHECK-SAME: @dx.op.sampleLevel.f16(i32 62,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -216,3 +216,38 @@ define void @samplelevel_texture2d_half4(<2 x float> %coords, float %lod) {
   call void @use_half4(<4 x half> %data)
   ret void
 }
+
+; The scalarizer re-gathers the coordinates just to pass them to the intrinsic.
+; DXIL has no vector instructions, so the scalars the vector was built from are
+; forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @samplelevel_texture2d_scalarized(
+define void @samplelevel_texture2d_scalarized(float %u, float %v, float %lod) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 2)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <2 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <2 x float> %coords.0, float %v, i32 1
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sampleLevel.f32(i32 62,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float undef, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float %lod)
+  %data = call <4 x float>
+      @llvm.dx.resource.samplelevel.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <2 x float> %coords.1, float %lod, <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/Texture2DArray-SampleBias.ll b/llvm/test/CodeGen/DirectX/Texture2DArray-SampleBias.ll
index 84a77920bcbed..76ceecb9ec6c2 100644
--- a/llvm/test/CodeGen/DirectX/Texture2DArray-SampleBias.ll
+++ b/llvm/test/CodeGen/DirectX/Texture2DArray-SampleBias.ll
@@ -14,9 +14,9 @@ define void @samplebias_texture2darray_float4(<3 x float> %coords, float %bias)
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -46,9 +46,9 @@ define void @samplebias_texture2darray_with_offset(<3 x float> %coords, float %b
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -94,3 +94,41 @@ define void @samplebias_texture2darray_with_clamp(<3 x float> %coords, float %bi
   call void @use_float4(<4 x float> %data)
   ret void
 }
+
+; The scalarizer re-gathers the coordinates just to pass them to the intrinsic.
+; DXIL has no vector instructions, so the scalars the vector was built from are
+; forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @samplebias_texture2darray_scalarized(
+define void @samplebias_texture2darray_scalarized(float %u, float %v, float %w,
+                                                  float %bias) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 7)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_7t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <3 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <3 x float> %coords.0, float %v, i32 1
+  %coords.2 = insertelement <3 x float> %coords.1, float %w, i32 2
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sampleBias.f32(i32 61,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float %w, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float %bias,
+  ; CHECK-SAME: float undef)
+  %data = call <4 x float>
+      @llvm.dx.resource.samplebias.v4f32.tdx.Texture_v4f32_0_0_0_7t.tdx.Sampler_0t.v3f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 7) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <3 x float> %coords.2, float %bias, <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/Texture2DArray-SampleGrad.ll b/llvm/test/CodeGen/DirectX/Texture2DArray-SampleGrad.ll
index 214906036542a..fa06b4cbe5f03 100644
--- a/llvm/test/CodeGen/DirectX/Texture2DArray-SampleGrad.ll
+++ b/llvm/test/CodeGen/DirectX/Texture2DArray-SampleGrad.ll
@@ -14,13 +14,13 @@ define void @samplegrad_texture2darray_float4(<3 x float> %coords, <2 x float> %
       @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i64 2
-  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i64 0
-  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i64 1
-  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i64 0
-  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x float> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x float> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x float> %coords, i32 2
+  ; CHECK: %[[DDX0:.*]] = extractelement <2 x float> %ddx, i32 0
+  ; CHECK: %[[DDX1:.*]] = extractelement <2 x float> %ddx, i32 1
+  ; CHECK: %[[DDY0:.*]] = extractelement <2 x float> %ddy, i32 0
+  ; CHECK: %[[DDY1:.*]] = extractelement <2 x float> %ddy, i32 1
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
@@ -70,3 +70,48 @@ define void @samplegrad_texture2darray_with_offset(<3 x float> %coords, <2 x flo
   call void @use_float4(<4 x float> %data)
   ret void
 }
+
+; The scalarizer re-gathers the vector operands just to pass them to the
+; intrinsic. DXIL has no vector instructions, so the scalars they were built
+; from are forwarded into the sample rather than extracted again.
+; CHECK-LABEL: define void @samplegrad_texture2darray_scalarized(
+define void @samplegrad_texture2darray_scalarized(float %u, float %v, float %w,
+                                                  float %ddxu, float %ddxv,
+                                                  float %ddyu, float %ddyv) {
+  %texture = call target("dx.Texture", <4 x float>, 0, 0, 0, 7)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_7t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+  %sampler = call target("dx.Sampler", 0)
+      @llvm.dx.resource.handlefrombinding.tdx.Sampler_0t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <3 x float> poison, float %u, i32 0
+  %coords.1 = insertelement <3 x float> %coords.0, float %v, i32 1
+  %coords.2 = insertelement <3 x float> %coords.1, float %w, i32 2
+  %ddx.0 = insertelement <2 x float> poison, float %ddxu, i32 0
+  %ddx.1 = insertelement <2 x float> %ddx.0, float %ddxv, i32 1
+  %ddy.0 = insertelement <2 x float> poison, float %ddyu, i32 0
+  %ddy.1 = insertelement <2 x float> %ddy.0, float %ddyv, i32 1
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
+  ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
+  ; CHECK-SAME: float %u, float %v, float %w, float undef,
+  ; CHECK-SAME: i32 undef, i32 undef, i32 undef,
+  ; CHECK-SAME: float %ddxu, float %ddxv, float undef,
+  ; CHECK-SAME: float %ddyu, float %ddyv, float undef,
+  ; CHECK-SAME: float undef)
+  %data = call <4 x float>
+      @llvm.dx.resource.samplegrad.v4f32.tdx.Texture_v4f32_0_0_0_7t.tdx.Sampler_0t.v3f32.v2f32.v2f32.v2i32(
+          target("dx.Texture", <4 x float>, 0, 0, 0, 7) %texture,
+          target("dx.Sampler", 0) %sampler,
+          <3 x float> %coords.2, <2 x float> %ddx.1, <2 x float> %ddy.1,
+          <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[SAMPLE]], 0
+  call void @use_float4(<4 x float> %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/TextureLoad.ll b/llvm/test/CodeGen/DirectX/TextureLoad.ll
index cf6c460ac2105..29329f4bf9896 100644
--- a/llvm/test/CodeGen/DirectX/TextureLoad.ll
+++ b/llvm/test/CodeGen/DirectX/TextureLoad.ll
@@ -13,8 +13,8 @@ define void @load_texture2d_float4(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
@@ -31,8 +31,8 @@ define void @load_texture2d_float(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_f32_0_0_0_2t(
           i32 0, i32 1, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call float @llvm.dx.resource.load.level.f32.tdx.Texture_f32_0_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", float, 0, 0, 0, 2) %texture,
@@ -49,8 +49,8 @@ define void @load_texture2d_int3(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v3i32_0_0_1_2t(
           i32 0, i32 2, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.i32 @dx.op.textureLoad.i32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call <3 x i32> @llvm.dx.resource.load.level.v3i32.tdx.Texture_v3i32_0_0_1_2t.v2i32.i32.v2i32(
       target("dx.Texture", <3 x i32>, 0, 0, 1, 2) %texture,
@@ -66,8 +66,8 @@ define void @load_texture2d_float4_with_level(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 2, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
@@ -84,8 +84,8 @@ define void @load_texture2d_float4_with_offset(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 1, i32 -2, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
@@ -102,8 +102,8 @@ define void @load_texture2d_float4_with_level_and_offset(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 3, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 -1, i32 2, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 2) %texture,
@@ -152,9 +152,9 @@ define void @load_texture3d_float3(<3 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v3f32_0_0_0_4t(
           i32 0, i32 4, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], i32 undef, i32 undef, i32 undef)
   %data = call <3 x float> @llvm.dx.resource.load.level.v3f32.tdx.Texture_v3f32_0_0_0_4t.v3i32.i32.v3i32(
       target("dx.Texture", <3 x float>, 0, 0, 0, 4) %texture,
@@ -171,9 +171,9 @@ define void @load_texture3d_float3_with_level_and_offset(<3 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v3f32_0_0_0_4t(
           i32 0, i32 4, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 2, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], i32 1, i32 -2, i32 3)
   %data = call <3 x float> @llvm.dx.resource.load.level.v3f32.tdx.Texture_v3f32_0_0_0_4t.v3i32.i32.v3i32(
       target("dx.Texture", <3 x float>, 0, 0, 0, 4) %texture,
@@ -190,9 +190,9 @@ define void @load_texture2darray_float4(<3 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_7t(
           i32 0, i32 5, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 0, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_7t.v3i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 7) %texture,
@@ -209,9 +209,9 @@ define void @load_texture2darray_float4_with_level_and_offset(<3 x i32> %coords)
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_0_0_0_7t(
           i32 0, i32 5, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 1, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], i32 -1, i32 2, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_7t.v3i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 0, 0, 0, 7) %texture,
@@ -232,8 +232,8 @@ define void @load_rwtexture2d_float4_implicit_mip(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_1_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 undef, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_1_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 1, 0, 0, 2) %texture,
@@ -250,8 +250,8 @@ define void @load_rwtexture2d_float4_explicit_lod(<2 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_1_0_0_2t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 undef, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_1_0_0_2t.v2i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 1, 0, 0, 2) %texture,
@@ -268,9 +268,9 @@ define void @load_rwtexture2darray_float4(<3 x i32> %coords) {
       @llvm.dx.resource.handlefrombinding.tdx.Texture_v4f32_1_0_0_7t(
           i32 0, i32 0, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 undef, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], i32 undef, i32 undef, i32 undef)
   %data = call <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_1_0_0_7t.v3i32.i32.v2i32(
       target("dx.Texture", <4 x float>, 1, 0, 0, 7) %texture,
@@ -280,3 +280,27 @@ define void @load_rwtexture2darray_float4(<3 x i32> %coords) {
   call void @use_float4(<4 x float> %data)
   ret void
 }
+
+; DXIL has no vector instructions, so the scalars the coordinate vector was
+; built from are forwarded into the load rather than extracted again.
+; CHECK-LABEL: define void @load_rwtexture2darray_scalarized_coords(
+define void @load_rwtexture2darray_scalarized_coords(i32 %x, i32 %y, i32 %z) {
+  %texture = call target("dx.Texture", float, 1, 0, 0, 7)
+      @llvm.dx.resource.handlefrombinding.tdx.Texture_f32_1_0_0_7t(
+          i32 0, i32 0, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <3 x i32> poison, i32 %x, i32 0
+  %coords.1 = insertelement <3 x i32> %coords.0, i32 %y, i32 1
+  %coords.2 = insertelement <3 x i32> %coords.1, i32 %z, i32 2
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: %[[LOAD:.*]] = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %{{.*}}, i32 undef, i32 %x, i32 %y, i32 %z, i32 undef, i32 undef, i32 undef)
+  %data = call float @llvm.dx.resource.load.level.f32.tdx.Texture_f32_1_0_0_7t.v3i32.i32.v2i32(
+      target("dx.Texture", float, 1, 0, 0, 7) %texture,
+      <3 x i32> %coords.2, i32 0, <2 x i32> zeroinitializer)
+
+  ; CHECK: extractvalue %dx.types.ResRet.f32 %[[LOAD]], 0
+  call void @use_float(float %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/TextureStore.ll b/llvm/test/CodeGen/DirectX/TextureStore.ll
index c37b3f2baccd9..efaeb11620746 100644
--- a/llvm/test/CodeGen/DirectX/TextureStore.ll
+++ b/llvm/test/CodeGen/DirectX/TextureStore.ll
@@ -28,8 +28,8 @@ define void @store_texture2d_float4(<4 x float> %data, <2 x i32> %coords) {
   ; CHECK: %[[DATA1:.*]] = extractelement <4 x float> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <4 x float> %data, i32 2
   ; CHECK: %[[DATA3:.*]] = extractelement <4 x float> %data, i32 3
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, float %[[DATA0]], float %[[DATA1]], float %[[DATA2]], float %[[DATA3]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x float>, 1, 0, 0, 2) %texture,
@@ -47,9 +47,9 @@ define void @store_texture3d_float4(<4 x float> %data, <3 x i32> %coords) {
   ; CHECK: %[[DATA1:.*]] = extractelement <4 x float> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <4 x float> %data, i32 2
   ; CHECK: %[[DATA3:.*]] = extractelement <4 x float> %data, i32 3
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], float %[[DATA0]], float %[[DATA1]], float %[[DATA2]], float %[[DATA3]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x float>, 1, 0, 0, 4) %texture,
@@ -67,8 +67,8 @@ define void @store_texture1darray_float4(<4 x float> %data, <2 x i32> %coords) {
   ; CHECK: %[[DATA1:.*]] = extractelement <4 x float> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <4 x float> %data, i32 2
   ; CHECK: %[[DATA3:.*]] = extractelement <4 x float> %data, i32 3
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, float %[[DATA0]], float %[[DATA1]], float %[[DATA2]], float %[[DATA3]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x float>, 1, 0, 0, 6) %texture,
@@ -86,9 +86,9 @@ define void @store_texture2darray_float4(<4 x float> %data, <3 x i32> %coords) {
   ; CHECK: %[[DATA1:.*]] = extractelement <4 x float> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <4 x float> %data, i32 2
   ; CHECK: %[[DATA3:.*]] = extractelement <4 x float> %data, i32 3
-  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i64 1
-  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i64 2
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords, i32 1
+  ; CHECK: %[[COORD2:.*]] = extractelement <3 x i32> %coords, i32 2
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 %[[COORD2]], float %[[DATA0]], float %[[DATA1]], float %[[DATA2]], float %[[DATA3]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x float>, 1, 0, 0, 7) %texture,
@@ -104,8 +104,8 @@ define void @store_texture2d_float(float %data, <2 x i32> %coords) {
   %texture = call target("dx.Texture", float, 1, 0, 0, 2)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, ptr null)
 
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, float %data, float %data, float %data, float %data, i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", float, 1, 0, 0, 2) %texture,
@@ -123,8 +123,8 @@ define void @store_texture2d_int3(<3 x i32> %data, <2 x i32> %coords) {
   ; CHECK: %[[DATA0:.*]] = extractelement <3 x i32> %data, i32 0
   ; CHECK: %[[DATA1:.*]] = extractelement <3 x i32> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <3 x i32> %data, i32 2
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.i32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, i32 %[[DATA0]], i32 %[[DATA1]], i32 %[[DATA2]], i32 %[[DATA0]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <3 x i32>, 1, 0, 1, 2) %texture,
@@ -142,8 +142,8 @@ define void @store_texture2d_half4(<4 x half> %data, <2 x i32> %coords) {
   ; CHECK: %[[DATA1:.*]] = extractelement <4 x half> %data, i32 1
   ; CHECK: %[[DATA2:.*]] = extractelement <4 x half> %data, i32 2
   ; CHECK: %[[DATA3:.*]] = extractelement <4 x half> %data, i32 3
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.f16(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, half %[[DATA0]], half %[[DATA1]], half %[[DATA2]], half %[[DATA3]], i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x half>, 1, 0, 0, 2) %texture,
@@ -165,8 +165,8 @@ define void @store_texture2d_scalarized(float %x, float %y, float %z, float %w,
   %vec.3 = insertelement <4 x float> %vec.2, float %w, i32 3
 
   ; CHECK-NOT: insertelement
-  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i64 0
-  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i64 1
+  ; CHECK: %[[COORD0:.*]] = extractelement <2 x i32> %coords, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <2 x i32> %coords, i32 1
   ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 undef, float %x, float %y, float %z, float %w, i8 15)
   call void @llvm.dx.resource.store.texture(
       target("dx.Texture", <4 x float>, 1, 0, 0, 2) %texture,
@@ -174,3 +174,66 @@ define void @store_texture2d_scalarized(float %x, float %y, float %z, float %w,
 
   ret void
 }
+
+; DXIL has no vector instructions, so the scalars the coordinate vector was
+; built from are forwarded into the store rather than extracted again.
+; CHECK-LABEL: define void @store_texture2darray_scalarized_coords(
+define void @store_texture2darray_scalarized_coords(float %data, i32 %x, i32 %y, i32 %z) {
+  %texture = call target("dx.Texture", float, 1, 0, 0, 7)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 9, i32 1, i32 0, ptr null)
+
+  %coords.0 = insertelement <3 x i32> poison, i32 %x, i32 0
+  %coords.1 = insertelement <3 x i32> %coords.0, i32 %y, i32 1
+  %coords.2 = insertelement <3 x i32> %coords.1, i32 %z, i32 2
+
+  ; CHECK-NOT: insertelement
+  ; CHECK-NOT: extractelement
+  ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %x, i32 %y, i32 %z, float %data, float %data, float %data, float %data, i8 15)
+  call void @llvm.dx.resource.store.texture(
+      target("dx.Texture", float, 1, 0, 0, 7) %texture,
+      <3 x i32> %coords.2, float %data)
+
+  ; CHECK-NOT: insertelement
+  ; CHECK: ret void
+  ret void
+}
+
+; Coordinates that don't come from an insertelement still have to be extracted.
+; CHECK-LABEL: define void @store_texture2darray_partial_coords(
+define void @store_texture2darray_partial_coords(float %data, <3 x i32> %coords, i32 %z) {
+  %texture = call target("dx.Texture", float, 1, 0, 0, 7)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 10, i32 1, i32 0, ptr null)
+
+  %coords.z = insertelement <3 x i32> %coords, i32 %z, i32 2
+
+  ; CHECK: %[[COORD0:.*]] = extractelement <3 x i32> %coords.z, i32 0
+  ; CHECK: %[[COORD1:.*]] = extractelement <3 x i32> %coords.z, i32 1
+  ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %[[COORD0]], i32 %[[COORD1]], i32 %z, float %data, float %data, float %data, float %data, i8 15)
+  call void @llvm.dx.resource.store.texture(
+      target("dx.Texture", float, 1, 0, 0, 7) %texture,
+      <3 x i32> %coords.z, float %data)
+
+  ret void
+}
+
+; An index can be inserted more than once; the outermost insert is the live
+; value for that component.
+; CHECK-LABEL: define void @store_texture2d_repeated_index(
+define void @store_texture2d_repeated_index(float %x, float %y, float %z, float %w,
+                                            float %live, <2 x i32> %coords) {
+  %texture = call target("dx.Texture", <4 x float>, 1, 0, 0, 2)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 11, i32 1, i32 0, ptr null)
+
+  %vec.0 = insertelement <4 x float> poison, float %x, i32 0
+  %vec.1 = insertelement <4 x float> %vec.0, float %y, i32 1
+  %vec.2 = insertelement <4 x float> %vec.1, float %z, i32 2
+  %vec.3 = insertelement <4 x float> %vec.2, float %w, i32 3
+  %vec.4 = insertelement <4 x float> %vec.3, float %live, i32 0
+
+  ; CHECK: call void @dx.op.textureStore.f32(i32 67, %dx.types.Handle %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 undef, float %live, float %y, float %z, float %w, i8 15)
+  call void @llvm.dx.resource.store.texture(
+      target("dx.Texture", <4 x float>, 1, 0, 0, 2) %texture,
+      <2 x i32> %coords, <4 x float> %vec.4)
+
+  ret void
+}

>From 33ec9468566429d18b69f3cf202d5b0dafac0263 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Fri, 11 Sep 2026 15:57:10 -0700
Subject: [PATCH 2/2] touch-up tests

---
 llvm/test/CodeGen/DirectX/SampleGrad.ll   | 2 +-
 llvm/test/CodeGen/DirectX/TextureStore.ll | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/DirectX/SampleGrad.ll b/llvm/test/CodeGen/DirectX/SampleGrad.ll
index 37ec29d03a570..f1fd44cbbd0b7 100644
--- a/llvm/test/CodeGen/DirectX/SampleGrad.ll
+++ b/llvm/test/CodeGen/DirectX/SampleGrad.ll
@@ -358,7 +358,7 @@ define void @sample_grad_texture2d_scalarized(float %u, float %v, float %ddxu,
   %ddy.1 = insertelement <2 x float> %ddy.0, float %ddyv, i32 1
 
   ; CHECK-NOT: insertelement
-  ; CHECK-NOT: extractelement <2 x float>
+  ; CHECK-NOT: extractelement
   ; CHECK: %[[SAMPLE:.*]] = call %dx.types.ResRet.f32
   ; CHECK-SAME: @dx.op.sampleGrad.f32(i32 63,
   ; CHECK-SAME: %dx.types.Handle %{{[^,]*}},
diff --git a/llvm/test/CodeGen/DirectX/TextureStore.ll b/llvm/test/CodeGen/DirectX/TextureStore.ll
index efaeb11620746..7e52ea3f61c47 100644
--- a/llvm/test/CodeGen/DirectX/TextureStore.ll
+++ b/llvm/test/CodeGen/DirectX/TextureStore.ll
@@ -193,7 +193,6 @@ define void @store_texture2darray_scalarized_coords(float %data, i32 %x, i32 %y,
       target("dx.Texture", float, 1, 0, 0, 7) %texture,
       <3 x i32> %coords.2, float %data)
 
-  ; CHECK-NOT: insertelement
   ; CHECK: ret void
   ret void
 }



More information about the llvm-commits mailing list