Browse Source

Fix intrinsic arguments for WriteSamplerFeedback operations (#2387)

- Align coord dimensions with Sample for future flexibility and alignment
- Fix ddx and ddy arguments to support the correct number of dimensions
- Rewrite lowering, using SamplerHelper
- Clean up SampleHelper a bit, adding additional asserts/checks
- Set components to zero for default offset, not undef
Tex Riddell 6 years ago
parent
commit
c012b4d0f5

+ 49 - 25
include/dxc/DXIL/DxilInstructions.h

@@ -5749,7 +5749,7 @@ struct DxilInst_WriteSamplerFeedback {
   // Validation support
   bool isAllowed() const { return true; }
   bool isArgumentListValid() const {
-    if (8 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    if (9 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
     return true;
   }
   // Metadata
@@ -5762,7 +5762,8 @@ struct DxilInst_WriteSamplerFeedback {
     arg_c0 = 4,
     arg_c1 = 5,
     arg_c2 = 6,
-    arg_clamp = 7,
+    arg_c3 = 7,
+    arg_clamp = 8,
   };
   // Accessors
   llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
@@ -5777,8 +5778,10 @@ struct DxilInst_WriteSamplerFeedback {
   void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
   llvm::Value *get_c2() const { return Instr->getOperand(6); }
   void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
-  llvm::Value *get_clamp() const { return Instr->getOperand(7); }
-  void set_clamp(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_c3() const { return Instr->getOperand(7); }
+  void set_c3(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(8); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(8, val); }
 };
 
 /// This instruction updates a feedback texture for a sampling operation with a bias on the mipmap level
@@ -5792,7 +5795,7 @@ struct DxilInst_WriteSamplerFeedbackBias {
   // Validation support
   bool isAllowed() const { return true; }
   bool isArgumentListValid() const {
-    if (9 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    if (10 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
     return true;
   }
   // Metadata
@@ -5805,8 +5808,9 @@ struct DxilInst_WriteSamplerFeedbackBias {
     arg_c0 = 4,
     arg_c1 = 5,
     arg_c2 = 6,
-    arg_bias = 7,
-    arg_clamp = 8,
+    arg_c3 = 7,
+    arg_bias = 8,
+    arg_clamp = 9,
   };
   // Accessors
   llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
@@ -5821,10 +5825,12 @@ struct DxilInst_WriteSamplerFeedbackBias {
   void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
   llvm::Value *get_c2() const { return Instr->getOperand(6); }
   void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
-  llvm::Value *get_bias() const { return Instr->getOperand(7); }
-  void set_bias(llvm::Value *val) { Instr->setOperand(7, val); }
-  llvm::Value *get_clamp() const { return Instr->getOperand(8); }
-  void set_clamp(llvm::Value *val) { Instr->setOperand(8, val); }
+  llvm::Value *get_c3() const { return Instr->getOperand(7); }
+  void set_c3(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_bias() const { return Instr->getOperand(8); }
+  void set_bias(llvm::Value *val) { Instr->setOperand(8, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(9); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(9, val); }
 };
 
 /// This instruction updates a feedback texture for a sampling operation with a mipmap-level offset
@@ -5838,7 +5844,7 @@ struct DxilInst_WriteSamplerFeedbackLevel {
   // Validation support
   bool isAllowed() const { return true; }
   bool isArgumentListValid() const {
-    if (8 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    if (9 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
     return true;
   }
   // Metadata
@@ -5851,7 +5857,8 @@ struct DxilInst_WriteSamplerFeedbackLevel {
     arg_c0 = 4,
     arg_c1 = 5,
     arg_c2 = 6,
-    arg_lod = 7,
+    arg_c3 = 7,
+    arg_lod = 8,
   };
   // Accessors
   llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
@@ -5866,8 +5873,10 @@ struct DxilInst_WriteSamplerFeedbackLevel {
   void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
   llvm::Value *get_c2() const { return Instr->getOperand(6); }
   void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
-  llvm::Value *get_lod() const { return Instr->getOperand(7); }
-  void set_lod(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_c3() const { return Instr->getOperand(7); }
+  void set_c3(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_lod() const { return Instr->getOperand(8); }
+  void set_lod(llvm::Value *val) { Instr->setOperand(8, val); }
 };
 
 /// This instruction updates a feedback texture for a sampling operation with explicit gradients
@@ -5881,7 +5890,7 @@ struct DxilInst_WriteSamplerFeedbackGrad {
   // Validation support
   bool isAllowed() const { return true; }
   bool isArgumentListValid() const {
-    if (10 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    if (15 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
     return true;
   }
   // Metadata
@@ -5894,9 +5903,14 @@ struct DxilInst_WriteSamplerFeedbackGrad {
     arg_c0 = 4,
     arg_c1 = 5,
     arg_c2 = 6,
-    arg_ddx = 7,
-    arg_ddy = 8,
-    arg_clamp = 9,
+    arg_c3 = 7,
+    arg_ddx0 = 8,
+    arg_ddx1 = 9,
+    arg_ddx2 = 10,
+    arg_ddy0 = 11,
+    arg_ddy1 = 12,
+    arg_ddy2 = 13,
+    arg_clamp = 14,
   };
   // Accessors
   llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
@@ -5911,12 +5925,22 @@ struct DxilInst_WriteSamplerFeedbackGrad {
   void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
   llvm::Value *get_c2() const { return Instr->getOperand(6); }
   void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
-  llvm::Value *get_ddx() const { return Instr->getOperand(7); }
-  void set_ddx(llvm::Value *val) { Instr->setOperand(7, val); }
-  llvm::Value *get_ddy() const { return Instr->getOperand(8); }
-  void set_ddy(llvm::Value *val) { Instr->setOperand(8, val); }
-  llvm::Value *get_clamp() const { return Instr->getOperand(9); }
-  void set_clamp(llvm::Value *val) { Instr->setOperand(9, val); }
+  llvm::Value *get_c3() const { return Instr->getOperand(7); }
+  void set_c3(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_ddx0() const { return Instr->getOperand(8); }
+  void set_ddx0(llvm::Value *val) { Instr->setOperand(8, val); }
+  llvm::Value *get_ddx1() const { return Instr->getOperand(9); }
+  void set_ddx1(llvm::Value *val) { Instr->setOperand(9, val); }
+  llvm::Value *get_ddx2() const { return Instr->getOperand(10); }
+  void set_ddx2(llvm::Value *val) { Instr->setOperand(10, val); }
+  llvm::Value *get_ddy0() const { return Instr->getOperand(11); }
+  void set_ddy0(llvm::Value *val) { Instr->setOperand(11, val); }
+  llvm::Value *get_ddy1() const { return Instr->getOperand(12); }
+  void set_ddy1(llvm::Value *val) { Instr->setOperand(12, val); }
+  llvm::Value *get_ddy2() const { return Instr->getOperand(13); }
+  void set_ddy2(llvm::Value *val) { Instr->setOperand(13, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(14); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(14, val); }
 };
 
 /// This instruction allocates space for RayQuery and return handle

+ 1 - 0
include/dxc/DXIL/DxilOperations.h

@@ -99,6 +99,7 @@ public:
   static bool IsDxilOpFuncCallInst(const llvm::Instruction *I, OpCode opcode);
   static bool IsDxilOpWave(OpCode C);
   static bool IsDxilOpGradient(OpCode C);
+  static bool IsDxilOpFeedback(OpCode C);
   static bool IsDxilOpTypeName(llvm::StringRef name);
   static bool IsDxilOpType(llvm::StructType *ST);
   static bool IsDupDxilOpType(llvm::StructType *ST);

+ 7 - 3
include/dxc/HLSL/HLOperations.h

@@ -300,9 +300,13 @@ const unsigned kGatherCmpStatusWithSampleOffsetArgIndex = 9;
 const unsigned kWriteSamplerFeedbackSampledArgIndex = 2;
 const unsigned kWriteSamplerFeedbackSamplerArgIndex = 3;
 const unsigned kWriteSamplerFeedbackCoordArgIndex = 4;
-const unsigned kWriteSamplerFeedbackBiasOrLodArgIndex = 5;
-const unsigned kWriteSamplerFeedbackDdxArgIndex = 5;
-const unsigned kWriteSamplerFeedbackDdyArgIndex = 6;
+const unsigned kWriteSamplerFeedbackBias_BiasArgIndex = 5;
+const unsigned kWriteSamplerFeedbackLevel_LodArgIndex = 5;
+const unsigned kWriteSamplerFeedbackGrad_DdxArgIndex = 5;
+const unsigned kWriteSamplerFeedbackGrad_DdyArgIndex = 6;
+const unsigned kWriteSamplerFeedback_ClampArgIndex = 5;
+const unsigned kWriteSamplerFeedbackBias_ClampArgIndex = 6;
+const unsigned kWriteSamplerFeedbackGrad_ClampArgIndex = 7;
 
 // StreamAppend.
 const unsigned kStreamAppendStreamOpIndex = 1;

+ 14 - 4
lib/DXIL/DxilOperations.cpp

@@ -584,6 +584,16 @@ bool OP::IsDxilOpGradient(OpCode C) {
   // OPCODE-GRADIENT:END
 }
 
+bool OP::IsDxilOpFeedback(OpCode C) {
+  unsigned op = (unsigned)C;
+  /* <py::lines('OPCODE-FEEDBACK')>hctdb_instrhelp.get_instrs_pred("op", "is_feedback")</py>*/
+  // OPCODE-FEEDBACK:BEGIN
+  // Instructions: WriteSamplerFeedback=174, WriteSamplerFeedbackBias=175,
+  // WriteSamplerFeedbackLevel=176, WriteSamplerFeedbackGrad=177
+  return (174 <= op && op <= 177);
+  // OPCODE-FEEDBACK:END
+}
+
 #define SFLAG(stage) ((unsigned)1 << (unsigned)DXIL::ShaderKind::stage)
 void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
                                   unsigned &major, unsigned &minor,
@@ -1228,10 +1238,10 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
   case OpCode::DispatchMesh:           A(pV);       A(pI32); A(pI32); A(pI32); A(pI32); A(pETy); break;
 
     // Sampler Feedback
-  case OpCode::WriteSamplerFeedback:   A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); break;
-  case OpCode::WriteSamplerFeedbackBias:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
-  case OpCode::WriteSamplerFeedbackLevel:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); break;
-  case OpCode::WriteSamplerFeedbackGrad:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedback:   A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackBias:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackLevel:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackGrad:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
 
     // Inline Ray Query
   case OpCode::AllocateRayQuery:       A(pI32);     A(pI32); A(pI32); break;

+ 185 - 131
lib/HLSL/HLOperationLower.cpp

@@ -2670,24 +2670,40 @@ Value *TranslateMul(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
 struct SampleHelper {
   SampleHelper(CallInst *CI, OP::OpCode op, HLObjectOperationLowerHelper *pObjHelper);
 
-  OP::OpCode opcode;
-  Value *texHandle;
-  Value *samplerHandle;
+  OP::OpCode opcode = OP::OpCode::NumOpCodes;
+  DXIL::ResourceKind resourceKind = DXIL::ResourceKind::Invalid;
+  Value *sampledTexHandle = nullptr;
+  Value *texHandle = nullptr;
+  Value *samplerHandle = nullptr;
   static const unsigned kMaxCoordDimensions = 4;
+  unsigned coordDimensions = 0;
   Value *coord[kMaxCoordDimensions];
-  Value *special; // For CompareValue, Bias, LOD.
+  Value *compareValue = nullptr;
+  Value *bias = nullptr;
+  Value *lod = nullptr;
   // SampleGrad only.
   static const unsigned kMaxDDXYDimensions = 3;
   Value *ddx[kMaxDDXYDimensions];
   Value *ddy[kMaxDDXYDimensions];
   // Optional.
   static const unsigned kMaxOffsetDimensions = 3;
+  unsigned offsetDimensions = 0;
   Value *offset[kMaxOffsetDimensions];
-  Value *clamp;
-  Value *status;
-  void TranslateCoord(CallInst *CI, unsigned coordIdx,
-                      unsigned coordDimensions) {
-    Value *coordArg = CI->getArgOperand(coordIdx);
+  Value *clamp = nullptr;
+  Value *status = nullptr;
+  unsigned maxHLOperandRead = 0;
+  Value *ReadHLOperand(CallInst *CI, unsigned opIdx) {
+    if (CI->getNumArgOperands() > opIdx) {
+      maxHLOperandRead = std::max(maxHLOperandRead, opIdx);
+      return CI->getArgOperand(opIdx);
+    }
+    return nullptr;
+  }
+  void TranslateCoord(CallInst *CI, unsigned coordIdx) {
+    Value *coordArg = ReadHLOperand(CI, coordIdx);
+    DXASSERT_NOMSG(coordArg);
+    DXASSERT(coordArg->getType()->getVectorNumElements() == coordDimensions,
+             "otherwise, HL coordinate dimensions mismatch");
     IRBuilder<> Builder(CI);
     for (unsigned i = 0; i < coordDimensions; i++)
       coord[i] = Builder.CreateExtractElement(coordArg, i);
@@ -2695,24 +2711,47 @@ struct SampleHelper {
     for (unsigned i = coordDimensions; i < kMaxCoordDimensions; i++)
       coord[i] = undefF;
   }
-  void TranslateOffset(CallInst *CI, unsigned offsetIdx,
-                       unsigned offsetDimensions) {
-    Value *undefI = UndefValue::get(Type::getInt32Ty(CI->getContext()));
-    if (CI->getNumArgOperands() > offsetIdx) {
-      Value *offsetArg = CI->getArgOperand(offsetIdx);
+  void TranslateOffset(CallInst *CI, unsigned offsetIdx) {
+    IntegerType *i32Ty = Type::getInt32Ty(CI->getContext());
+    if (Value *offsetArg = ReadHLOperand(CI, offsetIdx)) {
+      DXASSERT(offsetArg->getType()->getVectorNumElements() == offsetDimensions,
+               "otherwise, HL coordinate dimensions mismatch");
       IRBuilder<> Builder(CI);
       for (unsigned i = 0; i < offsetDimensions; i++)
         offset[i] = Builder.CreateExtractElement(offsetArg, i);
-      for (unsigned i = offsetDimensions; i < kMaxOffsetDimensions; i++)
-        offset[i] = undefI;
     } else {
-      for (unsigned i = 0; i < kMaxOffsetDimensions; i++)
-        offset[i] = undefI;
+      // Use zeros for offsets when not specified, not undef.
+      Value *zero = ConstantInt::get(i32Ty, (uint64_t)0);
+      for (unsigned i = 0; i < offsetDimensions; i++)
+        offset[i] = zero;
+    }
+    // Use undef for components that should not be used for this resource dim.
+    Value *undefI = UndefValue::get(i32Ty);
+    for (unsigned i = offsetDimensions; i < kMaxOffsetDimensions; i++)
+      offset[i] = undefI;
+  }
+  void SetBias(CallInst *CI, unsigned biasIdx) {
+    // Clamp bias for immediate.
+    bias = ReadHLOperand(CI, biasIdx);
+    DXASSERT_NOMSG(bias);
+    if (ConstantFP *FP = dyn_cast<ConstantFP>(bias)) {
+      float v = FP->getValueAPF().convertToFloat();
+      if (v > DXIL::kMaxMipLodBias)
+        bias = ConstantFP::get(FP->getType(), DXIL::kMaxMipLodBias);
+      if (v < DXIL::kMinMipLodBias)
+        bias = ConstantFP::get(FP->getType(), DXIL::kMinMipLodBias);
     }
   }
+  void SetLOD(CallInst *CI, unsigned lodIdx) {
+    lod = ReadHLOperand(CI, lodIdx);
+    DXASSERT_NOMSG(lod);
+  }
+  void SetCompareValue(CallInst *CI, unsigned cmpIdx) {
+    compareValue = ReadHLOperand(CI, cmpIdx);
+    DXASSERT_NOMSG(compareValue);
+  }
   void SetClamp(CallInst *CI, unsigned clampIdx) {
-    if (CI->getNumArgOperands() > clampIdx) {
-      clamp = CI->getArgOperand(clampIdx);
+    if (clamp = ReadHLOperand(CI, clampIdx)) {
       if (clamp->getType()->isVectorTy()) {
         IRBuilder<> Builder(CI);
         clamp = Builder.CreateExtractElement(clamp, (uint64_t)0);
@@ -2721,14 +2760,18 @@ struct SampleHelper {
       clamp = UndefValue::get(Type::getFloatTy(CI->getContext()));
   }
   void SetStatus(CallInst *CI, unsigned statusIdx) {
-    if (CI->getNumArgOperands() == (statusIdx + 1))
-      status = CI->getArgOperand(statusIdx);
-    else
-      status = nullptr;
+    status = ReadHLOperand(CI, statusIdx);
+  }
+  void SetDDX(CallInst *CI, unsigned ddxIdx) {
+    SetDDXY(CI, ddx, ReadHLOperand(CI, ddxIdx));
   }
-  void SetDDXY(CallInst *CI, MutableArrayRef<Value *> ddxy, Value *ddxyArg,
-               unsigned ddxySize) {
+  void SetDDY(CallInst *CI, unsigned ddyIdx) {
+    SetDDXY(CI, ddy, ReadHLOperand(CI, ddyIdx));
+  }
+  void SetDDXY(CallInst *CI, MutableArrayRef<Value *> ddxy, Value *ddxyArg) {
+    DXASSERT_NOMSG(ddxyArg);
     IRBuilder<> Builder(CI);
+    unsigned ddxySize = ddxyArg->getType()->getVectorNumElements();
     for (unsigned i = 0; i < ddxySize; i++)
       ddxy[i] = Builder.CreateExtractElement(ddxyArg, i);
     Value *undefF = UndefValue::get(Type::getFloatTy(CI->getContext()));
@@ -2740,77 +2783,88 @@ struct SampleHelper {
 SampleHelper::SampleHelper(
     CallInst *CI, OP::OpCode op, HLObjectOperationLowerHelper *pObjHelper)
     : opcode(op) {
-  const unsigned thisIdx =
-      HLOperandIndex::kHandleOpIdx; // opcode takes arg0, this pointer is arg1.
-  const unsigned kSamplerArgIndex = HLOperandIndex::kSampleSamplerArgIndex;
 
-  IRBuilder<> Builder(CI);
-  texHandle = CI->getArgOperand(thisIdx);
-  samplerHandle = CI->getArgOperand(kSamplerArgIndex);
-
-  DXIL::ResourceKind RK = pObjHelper->GetRK(texHandle);
-  if (RK == DXIL::ResourceKind::Invalid) {
+  texHandle = CI->getArgOperand(HLOperandIndex::kHandleOpIdx);
+  resourceKind = pObjHelper->GetRK(texHandle);
+  if (resourceKind == DXIL::ResourceKind::Invalid) {
     opcode = DXIL::OpCode::NumOpCodes;
     return;
   }
-  unsigned coordDimensions = DxilResource::GetNumCoords(RK);
-  unsigned offsetDimensions = DxilResource::GetNumOffsets(RK);
 
-  const unsigned kCoordArgIdx = HLOperandIndex::kSampleCoordArgIndex;
-  TranslateCoord(CI, kCoordArgIdx, coordDimensions);
+  coordDimensions = opcode == DXIL::OpCode::CalculateLOD ? DxilResource::GetNumDimensionsForCalcLOD(resourceKind)
+                                                         : DxilResource::GetNumCoords(resourceKind);
+  offsetDimensions = DxilResource::GetNumOffsets(resourceKind);
 
-  special = nullptr;
+  const bool bFeedbackOp = hlsl::OP::IsDxilOpFeedback(op);
+  sampledTexHandle = bFeedbackOp ? CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackSampledArgIndex)
+                                 : nullptr;
+  const unsigned kSamplerArgIndex = bFeedbackOp ? HLOperandIndex::kWriteSamplerFeedbackSamplerArgIndex
+                                                : HLOperandIndex::kSampleSamplerArgIndex;
+  samplerHandle = CI->getArgOperand(kSamplerArgIndex);
+
+  const unsigned kCoordArgIdx = bFeedbackOp ? HLOperandIndex::kWriteSamplerFeedbackCoordArgIndex
+                                            : HLOperandIndex::kSampleCoordArgIndex;
+  TranslateCoord(CI, kCoordArgIdx);
 
   switch (op) {
   case OP::OpCode::Sample:
-    TranslateOffset(CI, HLOperandIndex::kSampleOffsetArgIndex,
-                    offsetDimensions);
+    TranslateOffset(CI, HLOperandIndex::kSampleOffsetArgIndex);
     SetClamp(CI, HLOperandIndex::kSampleClampArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleStatusArgIndex);
     break;
   case OP::OpCode::SampleLevel:
-    special = CI->getArgOperand(HLOperandIndex::kSampleLLevelArgIndex);
-    TranslateOffset(CI, HLOperandIndex::kSampleLOffsetArgIndex,
-                    offsetDimensions);
+    SetLOD(CI, HLOperandIndex::kSampleLLevelArgIndex);
+    TranslateOffset(CI, HLOperandIndex::kSampleLOffsetArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleLStatusArgIndex);
     break;
   case OP::OpCode::SampleBias:
-    special = CI->getArgOperand(HLOperandIndex::kSampleBBiasArgIndex);
-    TranslateOffset(CI, HLOperandIndex::kSampleBOffsetArgIndex,
-                    offsetDimensions);
+    SetBias(CI, HLOperandIndex::kSampleBBiasArgIndex);
+    TranslateOffset(CI, HLOperandIndex::kSampleBOffsetArgIndex);
     SetClamp(CI, HLOperandIndex::kSampleBClampArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleBStatusArgIndex);
     break;
   case OP::OpCode::SampleCmp:
-    special = CI->getArgOperand(HLOperandIndex::kSampleCmpCmpValArgIndex);
-    TranslateOffset(CI, HLOperandIndex::kSampleCmpOffsetArgIndex,
-                    offsetDimensions);
+    SetCompareValue(CI, HLOperandIndex::kSampleCmpCmpValArgIndex);
+    TranslateOffset(CI, HLOperandIndex::kSampleCmpOffsetArgIndex);
     SetClamp(CI, HLOperandIndex::kSampleCmpClampArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleCmpStatusArgIndex);
     break;
   case OP::OpCode::SampleCmpLevelZero:
-    special = CI->getArgOperand(HLOperandIndex::kSampleCmpLZCmpValArgIndex);
-    TranslateOffset(CI, HLOperandIndex::kSampleCmpLZOffsetArgIndex,
-                    offsetDimensions);
+    SetCompareValue(CI, HLOperandIndex::kSampleCmpLZCmpValArgIndex);
+    TranslateOffset(CI, HLOperandIndex::kSampleCmpLZOffsetArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleCmpLZStatusArgIndex);
     break;
   case OP::OpCode::SampleGrad:
-    SetDDXY(CI, ddx, CI->getArgOperand(HLOperandIndex::kSampleGDDXArgIndex),
-            offsetDimensions);
-    SetDDXY(CI, ddy, CI->getArgOperand(HLOperandIndex::kSampleGDDYArgIndex),
-            offsetDimensions);
-    TranslateOffset(CI, HLOperandIndex::kSampleGOffsetArgIndex,
-                    offsetDimensions);
+    SetDDX(CI, HLOperandIndex::kSampleGDDXArgIndex);
+    SetDDY(CI, HLOperandIndex::kSampleGDDYArgIndex);
+    TranslateOffset(CI, HLOperandIndex::kSampleGOffsetArgIndex);
     SetClamp(CI, HLOperandIndex::kSampleGClampArgIndex);
     SetStatus(CI, HLOperandIndex::kSampleGStatusArgIndex);
     break;
   case OP::OpCode::CalculateLOD:
     // Only need coord for LOD calculation.
     break;
+  case OP::OpCode::WriteSamplerFeedback:
+    SetClamp(CI, HLOperandIndex::kWriteSamplerFeedback_ClampArgIndex);
+    break;
+  case OP::OpCode::WriteSamplerFeedbackBias:
+    SetBias(CI, HLOperandIndex::kWriteSamplerFeedbackBias_BiasArgIndex);
+    SetClamp(CI, HLOperandIndex::kWriteSamplerFeedbackBias_ClampArgIndex);
+    break;
+  case OP::OpCode::WriteSamplerFeedbackGrad:
+    SetDDX(CI, HLOperandIndex::kWriteSamplerFeedbackGrad_DdxArgIndex);
+    SetDDY(CI, HLOperandIndex::kWriteSamplerFeedbackGrad_DdyArgIndex);
+    SetClamp(CI, HLOperandIndex::kWriteSamplerFeedbackGrad_ClampArgIndex);
+    break;
+  case OP::OpCode::WriteSamplerFeedbackLevel:
+    SetLOD(CI, HLOperandIndex::kWriteSamplerFeedbackLevel_LodArgIndex);
+    break;
   default:
     DXASSERT(0, "invalid opcode for Sample");
     break;
   }
+  DXASSERT(maxHLOperandRead == CI->getNumArgOperands() - 1,
+           "otherwise, unused HL arguments for Sample op");
 }
 
 Value *TranslateCalculateLOD(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
@@ -2909,7 +2963,7 @@ Value *TranslateSample(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
         // Offset.
         sampleHelper.offset[0], sampleHelper.offset[1], sampleHelper.offset[2],
         // LOD.
-        sampleHelper.special};
+        sampleHelper.lod};
     GenerateDxilSample(CI, F, sampleArgs, sampleHelper.status, hlslOP);
   } break;
   case OP::OpCode::SampleGrad: {
@@ -2929,15 +2983,6 @@ Value *TranslateSample(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
     GenerateDxilSample(CI, F, sampleArgs, sampleHelper.status, hlslOP);
   } break;
   case OP::OpCode::SampleBias: {
-    // Clamp bias for immediate.
-    Value *bias = sampleHelper.special;
-    if (ConstantFP *FP = dyn_cast<ConstantFP>(bias)) {
-      float v = FP->getValueAPF().convertToFloat();
-      if (v > DXIL::kMaxMipLodBias)
-        bias = ConstantFP::get(FP->getType(), DXIL::kMaxMipLodBias);
-      if (v < DXIL::kMinMipLodBias)
-        bias = ConstantFP::get(FP->getType(), DXIL::kMinMipLodBias);
-    }
     Value *sampleArgs[] = {
         opArg, sampleHelper.texHandle, sampleHelper.samplerHandle,
         // Coord.
@@ -2946,7 +2991,7 @@ Value *TranslateSample(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
         // Offset.
         sampleHelper.offset[0], sampleHelper.offset[1], sampleHelper.offset[2],
         // Bias.
-        bias,
+        sampleHelper.bias,
         // Clamp.
         sampleHelper.clamp};
     GenerateDxilSample(CI, F, sampleArgs, sampleHelper.status, hlslOP);
@@ -2960,7 +3005,7 @@ Value *TranslateSample(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
         // Offset.
         sampleHelper.offset[0], sampleHelper.offset[1], sampleHelper.offset[2],
         // CmpVal.
-        sampleHelper.special,
+        sampleHelper.compareValue,
         // Clamp.
         sampleHelper.clamp};
     GenerateDxilSample(CI, F, sampleArgs, sampleHelper.status, hlslOP);
@@ -2976,7 +3021,7 @@ Value *TranslateSample(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
         // Offset.
         sampleHelper.offset[0], sampleHelper.offset[1], sampleHelper.offset[2],
         // CmpVal.
-        sampleHelper.special};
+        sampleHelper.compareValue};
     GenerateDxilSample(CI, F, sampleArgs, sampleHelper.status, hlslOP);
   } break;
   }
@@ -3076,9 +3121,6 @@ GatherHelper::GatherHelper(
     CallInst *CI, OP::OpCode op, HLObjectOperationLowerHelper *pObjHelper,
     GatherHelper::GatherChannel ch)
     : opcode(op), special(nullptr), hasSampleOffsets(false) {
-  const unsigned thisIdx =
-      HLOperandIndex::kHandleOpIdx; // opcode takes arg0, this pointer is arg1.
-  const unsigned kSamplerArgIndex = HLOperandIndex::kSampleSamplerArgIndex;
 
   switch (ch) {
   case GatherChannel::GatherAll:
@@ -3099,8 +3141,8 @@ GatherHelper::GatherHelper(
   }
 
   IRBuilder<> Builder(CI);
-  texHandle = CI->getArgOperand(thisIdx);
-  samplerHandle = CI->getArgOperand(kSamplerArgIndex);
+  texHandle = CI->getArgOperand(HLOperandIndex::kHandleOpIdx);
+  samplerHandle = CI->getArgOperand(HLOperandIndex::kSampleSamplerArgIndex);
 
   DXIL::ResourceKind RK = pObjHelper->GetRK(texHandle);
   if (RK == DXIL::ResourceKind::Invalid) {
@@ -3268,64 +3310,76 @@ Value *TranslateGather(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
 }
 
 static Value* TranslateWriteSamplerFeedback(CallInst* CI, IntrinsicOp IOP, OP::OpCode opcode,
-  HLOperationLowerHelper& helper, HLObjectOperationLowerHelper* pObjHelper, bool& Translated) {
+                                            HLOperationLowerHelper& helper,
+                                            HLObjectOperationLowerHelper* pObjHelper,
+                                            bool& Translated) {
+  hlsl::OP *hlslOP = &helper.hlslOP;
+  SampleHelper sampleHelper(CI, opcode, pObjHelper);
 
-  hlsl::OP* hlslOP = &helper.hlslOP;
+  if (sampleHelper.opcode == DXIL::OpCode::NumOpCodes) {
+    Translated = false;
+    return nullptr;
+  }
+  Type *Ty = CI->getType();
 
-  IRBuilder<> Builder(CI);
+  Function *F = hlslOP->GetOpFunc(opcode, Ty->getScalarType());
 
-  // Build the DXIL operands
-  SmallVector<Value*, 8> DxilOperands;
-  DxilOperands.emplace_back(Builder.getInt32((unsigned)opcode));
-  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kHandleOpIdx));
-  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackSampledArgIndex));
-  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackSamplerArgIndex));
-
-  // Coords operands
-  constexpr unsigned NumDxilCoordsOperands = 3;
-  Value* CoordsVec = CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackCoordArgIndex);
-  VectorType *CoordsVecTy = cast<VectorType>(CoordsVec->getType());
-  DXASSERT_NOMSG(CoordsVecTy->getNumElements() <= NumDxilCoordsOperands);
-  for (unsigned i = 0; i < NumDxilCoordsOperands; ++i) {
-    Value *Coord = i < CoordsVecTy->getNumElements()
-      ? Builder.CreateExtractElement(CoordsVec, i)
-      : UndefValue::get(CoordsVecTy->getElementType());
-    DxilOperands.emplace_back(Coord);
-  }
-
-  unsigned LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackCoordArgIndex;
-
-  // Bias/level/grad operands
-  if (opcode == OP::OpCode::WriteSamplerFeedbackBias
-    || opcode == OP::OpCode::WriteSamplerFeedbackLevel) {
-    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackBiasOrLodArgIndex));
-    LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackBiasOrLodArgIndex;
-  }
-  else if (opcode == OP::OpCode::WriteSamplerFeedbackGrad) {
-    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackDdxArgIndex));
-    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackDdyArgIndex));
-    LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackDdyArgIndex;
-  }
-
-  // Append the optional clamp argument as needed.
-  bool HasOptionalClampOperand = opcode == OP::OpCode::WriteSamplerFeedback
-    || opcode == OP::OpCode::WriteSamplerFeedbackBias
-    || opcode == OP::OpCode::WriteSamplerFeedbackGrad;
-  if (HasOptionalClampOperand) {
-    if (LastHLOperandRead == CI->getNumArgOperands() - 1)
-      DxilOperands.emplace_back(UndefValue::get(Builder.getFloatTy()));
-    else {
-      LastHLOperandRead++;
-      DxilOperands.emplace_back(CI->getArgOperand(LastHLOperandRead));
-    }
-  }
+  Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
 
-  DXASSERT(LastHLOperandRead == CI->getNumArgOperands() - 1,
-    "Unexpected trailing hlsl intrinsic arguments.");
+  IRBuilder<> Builder(CI);
 
-  // Call the DXIL operation
-  Function* DxilFunc = hlslOP->GetOpFunc(opcode, Builder.getVoidTy());
-  return Builder.CreateCall(DxilFunc, DxilOperands);
+  switch (opcode) {
+  case OP::OpCode::WriteSamplerFeedback: {
+    Value *samplerFeedbackArgs[] = {
+        opArg, sampleHelper.texHandle, sampleHelper.sampledTexHandle, sampleHelper.samplerHandle,
+        // Coord.
+        sampleHelper.coord[0], sampleHelper.coord[1], sampleHelper.coord[2],
+        sampleHelper.coord[3],
+        // Clamp.
+        sampleHelper.clamp};
+    return Builder.CreateCall(F, samplerFeedbackArgs);
+  } break;
+  case OP::OpCode::WriteSamplerFeedbackBias: {
+    Value *samplerFeedbackArgs[] = {
+        opArg, sampleHelper.texHandle, sampleHelper.sampledTexHandle, sampleHelper.samplerHandle,
+        // Coord.
+        sampleHelper.coord[0], sampleHelper.coord[1], sampleHelper.coord[2],
+        sampleHelper.coord[3],
+        // Bias.
+        sampleHelper.bias,
+        // Clamp.
+        sampleHelper.clamp};
+    return Builder.CreateCall(F, samplerFeedbackArgs);
+  } break;
+  case OP::OpCode::WriteSamplerFeedbackGrad: {
+    Value *samplerFeedbackArgs[] = {
+        opArg, sampleHelper.texHandle, sampleHelper.sampledTexHandle, sampleHelper.samplerHandle,
+        // Coord.
+        sampleHelper.coord[0], sampleHelper.coord[1], sampleHelper.coord[2],
+        sampleHelper.coord[3],
+        // Ddx.
+        sampleHelper.ddx[0], sampleHelper.ddx[1], sampleHelper.ddx[2],
+        // Ddy.
+        sampleHelper.ddy[0], sampleHelper.ddy[1], sampleHelper.ddy[2],
+        // Clamp.
+        sampleHelper.clamp};
+    return Builder.CreateCall(F, samplerFeedbackArgs);
+  } break;
+  case OP::OpCode::WriteSamplerFeedbackLevel: {
+    Value *samplerFeedbackArgs[] = {
+        opArg, sampleHelper.texHandle, sampleHelper.sampledTexHandle, sampleHelper.samplerHandle,
+        // Coord.
+        sampleHelper.coord[0], sampleHelper.coord[1], sampleHelper.coord[2],
+        sampleHelper.coord[3],
+        // LOD.
+        sampleHelper.lod};
+    return Builder.CreateCall(F, samplerFeedbackArgs);
+  } break;
+  default:
+    DXASSERT(false, "otherwise, unknown SamplerFeedback Op");
+    break;
+  }
+  return nullptr;
 }
 
 // Load/Store intrinsics.

+ 8 - 8
tools/clang/lib/Sema/gen_intrin_main_tables_15.h

@@ -5857,8 +5857,8 @@ static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args4[] =
     {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
     {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
     {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
-    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
-    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_VECTOR, 4, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_VECTOR, 5, LICOMPTYPE_FLOAT, 1, 2},
 };
 
 static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args5[] =
@@ -5867,8 +5867,8 @@ static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args5[] =
     {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
     {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
     {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
-    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
-    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_VECTOR, 4, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_VECTOR, 5, LICOMPTYPE_FLOAT, 1, 2},
     {"clamp", AR_QUAL_IN, 6, LITEMPLATE_SCALAR, 6, LICOMPTYPE_FLOAT, 1, 1},
 };
 
@@ -5938,8 +5938,8 @@ static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args4[] =
     {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
     {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
     {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
-    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
-    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_VECTOR, 4, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_VECTOR, 5, LICOMPTYPE_FLOAT, 1, 2},
 };
 
 static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args5[] =
@@ -5948,8 +5948,8 @@ static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args5[] =
     {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
     {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
     {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
-    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
-    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_VECTOR, 4, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_VECTOR, 5, LICOMPTYPE_FLOAT, 1, 2},
     {"clamp", AR_QUAL_IN, 6, LITEMPLATE_SCALAR, 6, LICOMPTYPE_FLOAT, 1, 1},
 };
 

+ 36 - 25
tools/clang/test/CodeGenHLSL/batch/declarations/resources/textures/feedback.hlsl

@@ -16,51 +16,62 @@ float main() : SV_Target
     float2 coords2D = float2(1, 2);
     float3 coords2DArray = float3(1, 2, 3);
     float clamp = 4;
-    float bias = 5;
+    float bias = 0.5F;
     float lod = 6;
-    float ddx = 7;
-    float ddy = 8;
+    float2 ddx = float2(1.0F / 32, 2.0F / 32);
+    float2 ddy = float2(3.0F / 32, 4.0F / 32);
+
+    float idx = 0;  // Make each coord set unique
     
     // Test every dxil intrinsic
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 4.000000e+00)
-    feedbackMinMip.WriteSamplerFeedback(texture2D, samp, coords2D, clamp);
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef, float 4.000000e+00)
+    feedbackMinMip.WriteSamplerFeedback(texture2D, samp, coords2D + (10 * idx++), clamp);
     // CHECK: call void @dx.op.writeSamplerFeedbackBias(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 5.000000e+00, float 4.000000e+00)
-    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D, bias, clamp);
+    // CHECK: float 1.100000e+01, float 1.200000e+01, float undef, float undef, float 5.000000e-01, float 4.000000e+00)
+    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D + (10 * idx++), bias, clamp);
     // CHECK: call void @dx.op.writeSamplerFeedbackLevel(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 6.000000e+00)
-    feedbackMinMip.WriteSamplerFeedbackLevel(texture2D, samp, coords2D, lod);
+    // CHECK: float 2.100000e+01, float 2.200000e+01, float undef, float undef, float 6.000000e+00)
+    feedbackMinMip.WriteSamplerFeedbackLevel(texture2D, samp, coords2D + (10 * idx++), lod);
     // CHECK: call void @dx.op.writeSamplerFeedbackGrad(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 7.000000e+00, float 8.000000e+00, float 4.000000e+00)
-    feedbackMinMip.WriteSamplerFeedbackGrad(texture2D, samp, coords2D, ddx, ddy, clamp);
+    // CHECK: float 3.100000e+01, float 3.200000e+01, float undef, float undef, float 3.125000e-02, float 6.250000e-02, float undef, float 9.375000e-02, float 1.250000e-01, float undef, float 4.000000e+00)
+    feedbackMinMip.WriteSamplerFeedbackGrad(texture2D, samp, coords2D + (10 * idx++), ddx, ddy, clamp);
     
     // Test with undef clamp
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
-    feedbackMinMip.WriteSamplerFeedback(texture2D, samp, coords2D);
+    // CHECK: float 4.100000e+01, float 4.200000e+01, float undef, float undef, float undef)
+    feedbackMinMip.WriteSamplerFeedback(texture2D, samp, coords2D + (10 * idx++));
     // CHECK: call void @dx.op.writeSamplerFeedbackBias(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 5.000000e+00, float undef)
-    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D, bias);
+    // CHECK: float 5.100000e+01, float 5.200000e+01, float undef, float undef, float 5.000000e-01, float undef)
+    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D + (10 * idx++), bias);
     // CHECK: call void @dx.op.writeSamplerFeedbackGrad(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 7.000000e+00, float 8.000000e+00, float undef)
-    feedbackMinMip.WriteSamplerFeedbackGrad(texture2D, samp, coords2D, ddx, ddy);
+    // CHECK: float 6.100000e+01, float 6.200000e+01, float undef, float undef, float 3.125000e-02, float 6.250000e-02, float undef, float 9.375000e-02, float 1.250000e-01, float undef, float undef)
+    feedbackMinMip.WriteSamplerFeedbackGrad(texture2D, samp, coords2D + (10 * idx++), ddx, ddy);
 
     // Test on every FeedbackTexture variant
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
-    feedbackMipRegionUsed.WriteSamplerFeedback(texture2D, samp, coords2D);
+    // CHECK: float 7.100000e+01, float 7.200000e+01, float undef, float undef, float undef)
+    feedbackMipRegionUsed.WriteSamplerFeedback(texture2D, samp, coords2D + (10 * idx++));
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float undef)
-    feedbackMinMipArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray);
+    // CHECK: float 8.100000e+01, float 8.200000e+01, float 8.300000e+01, float undef, float undef)
+    feedbackMinMipArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray + (10 * idx++));
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float undef)
-    feebackMipRegionUsedArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray);
+    // CHECK: float 9.100000e+01, float 9.200000e+01, float 9.300000e+01, float undef, float undef)
+    feebackMipRegionUsedArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray + (10 * idx++));
 
     // Test with overloaded texture type
     // CHECK: call void @dx.op.writeSamplerFeedback(
-    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
-    feedbackMinMip.WriteSamplerFeedback(texture2D_float4, samp, coords2D);
+    // CHECK: float 1.010000e+02, float 1.020000e+02, float undef, float undef, float undef)
+    feedbackMinMip.WriteSamplerFeedback(texture2D_float4, samp, coords2D + (10 * idx++));
+
+    // Test max-clamped bias
+    // CHECK: call void @dx.op.writeSamplerFeedbackBias(
+    // CHECK: float 1.110000e+02, float 1.120000e+02, float undef, float undef, float 0x402FFAE140000000, float undef)
+    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D + (10 * idx++), 27.0);
+    // Test min-clamped bias
+    // CHECK: call void @dx.op.writeSamplerFeedbackBias(
+    // CHECK: float 1.210000e+02, float 1.220000e+02, float undef, float undef, float -1.600000e+01, float undef)
+    feedbackMinMip.WriteSamplerFeedbackBias(texture2D, samp, coords2D + (10 * idx++), -27.0);
 
     return 0;
 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/shader_stages/raytracing/raytracing_callable.hlsl

@@ -11,7 +11,7 @@
 // CHECK:   %[[i_1:[0-9]+]] = load %"class.Texture2D<vector<float, 4> >", %"class.Texture2D<vector<float, 4> >"* @"\01?T@@3V?$Texture2D@V?$vector@M$03@@@@A", align 4
 // CHECK:   %[[i_3:[0-9]+]] = call %dx.types.Handle @"dx.op.createHandleForLib.class.Texture2D<vector<float, 4> >"(i32 160, %"class.Texture2D<vector<float, 4> >" %[[i_1]])
 // CHECK:   %[[i_4:[0-9]+]] = call %dx.types.Handle @dx.op.createHandleForLib.struct.SamplerState(i32 160, %struct.SamplerState %[[i_0]])
-// CHECK:   %[[i_7:[0-9]+]] = call %dx.types.ResRet.f32 @dx.op.sampleLevel.f32(i32 62, %dx.types.Handle %[[i_3]], %dx.types.Handle %[[i_4]], float %[[i_5:[0-9]+]], float %[[i_6:[0-9]+]], float undef, float undef, i32 undef, i32 undef, i32 undef, float 0.000000e+00)
+// CHECK:   %[[i_7:[0-9]+]] = call %dx.types.ResRet.f32 @dx.op.sampleLevel.f32(i32 62, %dx.types.Handle %[[i_3]], %dx.types.Handle %[[i_4]], float %[[i_5:[0-9]+]], float %[[i_6:[0-9]+]], float undef, float undef, i32 0, i32 0, i32 undef, float 0.000000e+00)
 // CHECK:   ret void
 
 struct MyParam {

+ 4 - 4
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -1233,10 +1233,10 @@ static const char *OpCodeSignatures[] = {
   "(outputSigId,rowIndex,colIndex,value,vertexIndex)",  // StoreVertexOutput
   "(outputSigId,rowIndex,colIndex,value,primitiveIndex)",  // StorePrimitiveOutput
   "(threadGroupCountX,threadGroupCountY,threadGroupCountZ,payload)",  // DispatchMesh
-  "(feedbackTex,sampledTex,sampler,c0,c1,c2,clamp)",  // WriteSamplerFeedback
-  "(feedbackTex,sampledTex,sampler,c0,c1,c2,bias,clamp)",  // WriteSamplerFeedbackBias
-  "(feedbackTex,sampledTex,sampler,c0,c1,c2,lod)",  // WriteSamplerFeedbackLevel
-  "(feedbackTex,sampledTex,sampler,c0,c1,c2,ddx,ddy,clamp)",  // WriteSamplerFeedbackGrad
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,clamp)",  // WriteSamplerFeedback
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,bias,clamp)",  // WriteSamplerFeedbackBias
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,lod)",  // WriteSamplerFeedbackLevel
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)",  // WriteSamplerFeedbackGrad
   "(constRayFlags)",  // AllocateRayQuery
   "(rayQueryHandle,accelerationStructure,rayFlags,instanceInclusionMask,origin_X,origin_Y,origin_Z,tMin,direction_X,direction_Y,direction_Z,tMax)",  // RayQuery_TraceRayInline
   "(rayQueryHandle)",  // RayQuery_Proceed

+ 4 - 4
utils/hct/gen_intrin_main.txt

@@ -847,8 +847,8 @@ void [[]] WriteSamplerFeedback(in Texture2D t, in sampler s, in float<2> x);
 void [[]] WriteSamplerFeedback(in Texture2D t, in sampler s, in float<2> x, in float clamp);
 void [[]] WriteSamplerFeedbackBias(in Texture2D t, in sampler s, in float<2> x, in float bias);
 void [[]] WriteSamplerFeedbackBias(in Texture2D t, in sampler s, in float<2> x, in float bias, in float clamp);
-void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float ddx, in float ddy);
-void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float ddx, in float ddy, in float clamp);
+void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float<2> ddx, in float<2> ddy);
+void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float<2> ddx, in float<2> ddy, in float clamp);
 void [[]] WriteSamplerFeedbackLevel(in Texture2D t, in sampler s, in float<2> x, in float lod);
 
 } namespace
@@ -859,8 +859,8 @@ void [[]] WriteSamplerFeedback(in Texture2DArray t, in sampler s, in float<3> x)
 void [[]] WriteSamplerFeedback(in Texture2DArray t, in sampler s, in float<3> x, in float clamp);
 void [[]] WriteSamplerFeedbackBias(in Texture2DArray t, in sampler s, in float<3> x, in float bias);
 void [[]] WriteSamplerFeedbackBias(in Texture2DArray t, in sampler s, in float<3> x, in float bias, in float clamp);
-void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float ddx, in float ddy);
-void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float ddx, in float ddy, in float clamp);
+void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float<2> ddx, in float<2> ddy);
+void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float<2> ddx, in float<2> ddy, in float clamp);
 void [[]] WriteSamplerFeedbackLevel(in Texture2DArray t, in sampler s, in float<3> x, in float lod);
 
 } namespace

+ 18 - 7
utils/hct/hctdb.py

@@ -65,6 +65,7 @@ class db_dxil_inst(object):
         self.fn_attr = ""               # attribute shorthands: rn=does not access memory,ro=only reads from memory,
         self.is_deriv = False           # whether this is some kind of derivative
         self.is_gradient = False        # whether this requires a gradient calculation
+        self.is_feedback = False        # whether this is a sampler feedback op
         self.is_wave = False            # whether this requires in-wave, cross-lane functionality
         self.requires_uniform_inputs = False  # whether this operation requires that all of its inputs are uniform across the wave
         self.shader_stages = ()         # shader stages to which this applies, empty for all.
@@ -401,10 +402,12 @@ class db_dxil(object):
             self.name_idx[i].shader_model = 6,5
         for i in "WriteSamplerFeedback,WriteSamplerFeedbackBias".split(","):
             self.name_idx[i].category = "Sampler Feedback"
+            self.name_idx[i].is_feedback = True
             self.name_idx[i].shader_model = 6,5
             self.name_idx[i].shader_stages = ("library", "pixel",)
         for i in "WriteSamplerFeedbackLevel,WriteSamplerFeedbackGrad".split(","):
             self.name_idx[i].category = "Sampler Feedback"
+            self.name_idx[i].is_feedback = True
             self.name_idx[i].shader_model = 6,5
         for i in ("AllocateRayQuery,RayQuery_TraceRayInline,RayQuery_Proceed,RayQuery_Abort,RayQuery_CommitNonOpaqueTriangleHit,RayQuery_CommitProceduralPrimitiveHit,RayQuery_RayFlags,RayQuery_WorldRayOrigin,RayQuery_WorldRayDirection,RayQuery_RayTMin,"+
                  "RayQuery_CandidateTriangleRayT,RayQuery_CommittedRayT,RayQuery_CandidateInstanceIndex,RayQuery_CandidateInstanceID,RayQuery_CandidateGeometryIndex,RayQuery_CandidatePrimitiveIndex,"+
@@ -1458,7 +1461,8 @@ class db_dxil(object):
             db_dxil_param(5, "f", "c0", "coordinate c0"),
             db_dxil_param(6, "f", "c1", "coordinate c1"),
             db_dxil_param(7, "f", "c2", "coordinate c2"),
-            db_dxil_param(8, "f", "clamp", "clamp")])
+            db_dxil_param(8, "f", "c3", "coordinate c3"),
+            db_dxil_param(9, "f", "clamp", "clamp")])
         next_op_idx += 1
         self.add_dxil_op("WriteSamplerFeedbackBias", next_op_idx, "WriteSamplerFeedbackBias", "updates a feedback texture for a sampling operation with a bias on the mipmap level", "v", "", [
             db_dxil_param(0, "v", "", ""),
@@ -1468,8 +1472,9 @@ class db_dxil(object):
             db_dxil_param(5, "f", "c0", "coordinate c0"),
             db_dxil_param(6, "f", "c1", "coordinate c1"),
             db_dxil_param(7, "f", "c2", "coordinate c2"),
-            db_dxil_param(8, "f", "bias", "bias in [-16.f,15.99f]"),
-            db_dxil_param(9, "f", "clamp", "clamp")])
+            db_dxil_param(8, "f", "c3", "coordinate c3"),
+            db_dxil_param(9, "f", "bias", "bias in [-16.f,15.99f]"),
+            db_dxil_param(10, "f", "clamp", "clamp")])
         next_op_idx += 1
         self.add_dxil_op("WriteSamplerFeedbackLevel", next_op_idx, "WriteSamplerFeedbackLevel", "updates a feedback texture for a sampling operation with a mipmap-level offset", "v", "", [
             db_dxil_param(0, "v", "", ""),
@@ -1479,7 +1484,8 @@ class db_dxil(object):
             db_dxil_param(5, "f", "c0", "coordinate c0"),
             db_dxil_param(6, "f", "c1", "coordinate c1"),
             db_dxil_param(7, "f", "c2", "coordinate c2"),
-            db_dxil_param(8, "f", "lod", "LOD")])
+            db_dxil_param(8, "f", "c3", "coordinate c3"),
+            db_dxil_param(9, "f", "lod", "LOD")])
         next_op_idx += 1
         self.add_dxil_op("WriteSamplerFeedbackGrad", next_op_idx, "WriteSamplerFeedbackGrad", "updates a feedback texture for a sampling operation with explicit gradients", "v", "", [
             db_dxil_param(0, "v", "", ""),
@@ -1489,9 +1495,14 @@ class db_dxil(object):
             db_dxil_param(5, "f", "c0", "coordinate c0"),
             db_dxil_param(6, "f", "c1", "coordinate c1"),
             db_dxil_param(7, "f", "c2", "coordinate c2"),
-            db_dxil_param(8, "f", "ddx", "ddx"),
-            db_dxil_param(9, "f", "ddy", "ddy"),
-            db_dxil_param(10, "f", "clamp", "clamp")])
+            db_dxil_param(8, "f", "c3", "coordinate c3"),
+            db_dxil_param(9, "f", "ddx0", "rate of change of coordinate c0 in the x direction"),
+            db_dxil_param(10, "f", "ddx1", "rate of change of coordinate c1 in the x direction"),
+            db_dxil_param(11, "f", "ddx2", "rate of change of coordinate c2 in the x direction"),
+            db_dxil_param(12, "f", "ddy0", "rate of change of coordinate c0 in the y direction"),
+            db_dxil_param(13, "f", "ddy1", "rate of change of coordinate c1 in the y direction"),
+            db_dxil_param(14, "f", "ddy2", "rate of change of coordinate c2 in the y direction"),
+            db_dxil_param(15, "f", "clamp", "clamp")])
         next_op_idx += 1
 
         # RayQuery