Browse Source

[spirv] Support six texture methods (#576)

This commit add support for the following methods on textures:
* .Sample()
* .SampleLevel()
* .SampleGrad()
* .SampleBias()
* .Load()
* .Gather()
Lei Zhang 8 years ago
parent
commit
2b3be347a9

+ 26 - 0
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -144,6 +144,31 @@ public:
   uint32_t createBinaryOp(spv::Op op, uint32_t resultType, uint32_t lhs,
                           uint32_t rhs);
 
+  /// \brief Creates SPIR-V instructions for sampling the given image.
+  ///
+  /// If lod or grad is given a non-zero value, *ExplicitLod variants of
+  /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will
+  /// be generated.
+  ///
+  /// If bias, lod, or grad is given a non-zero value, an additional image
+  /// operands, Bias, Lod, or Grad, will be attached to the current instruction,
+  /// respectively.
+  uint32_t createImageSample(uint32_t texelType, uint32_t imageType,
+                             uint32_t image, uint32_t sampler,
+                             uint32_t coordinate, uint32_t bias, uint32_t lod,
+                             std::pair<uint32_t, uint32_t> grad,
+                             uint32_t offset);
+
+  /// \brief Creates SPIR-V instructions for fetching the given image.
+  uint32_t createImageFetch(uint32_t texelType, uint32_t image,
+                            uint32_t coordinate, uint32_t lod, uint32_t offset);
+
+  /// \brief Creates SPIR-V instructions for sampling the given image.
+  uint32_t createImageGather(uint32_t texelType, uint32_t imageType,
+                             uint32_t image, uint32_t sampler,
+                             uint32_t coordinate, uint32_t component,
+                             uint32_t offset);
+
   /// \brief Creates a select operation with the given values for true and false
   /// cases and returns the <result-id> for the result.
   uint32_t createSelect(uint32_t resultType, uint32_t condition,
@@ -260,6 +285,7 @@ public:
                            llvm::ArrayRef<uint32_t> paramTypes);
   uint32_t getImageType(uint32_t sampledType, spv::Dim, bool isArray);
   uint32_t getSamplerType();
+  uint32_t getSampledImageType(uint32_t imageType);
 
   // === Constant ===
   uint32_t getConstantBool(bool value);

+ 126 - 0
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -210,6 +210,124 @@ uint32_t ModuleBuilder::createBinaryOp(spv::Op op, uint32_t resultType,
   return id;
 }
 
+namespace {
+spv::ImageOperandsMask composeImageOperandsMask(
+    uint32_t bias, uint32_t lod, const std::pair<uint32_t, uint32_t> &grad,
+    uint32_t constOffset, llvm::SmallVectorImpl<uint32_t> *orderedParams) {
+  using spv::ImageOperandsMask;
+  // SPIR-V Image Operands from least significant bit to most significant bit
+  // Bias, Lod, Grad, ConstOffset, Offset, ConstOffsets, Sample, MinLod
+
+  auto mask = ImageOperandsMask::MaskNone;
+  orderedParams->clear();
+
+  if (bias) {
+    mask = mask | ImageOperandsMask::Bias;
+    orderedParams->push_back(bias);
+  }
+
+  if (lod) {
+    mask = mask | ImageOperandsMask::Lod;
+    orderedParams->push_back(lod);
+  }
+
+  if (grad.first && grad.second) {
+    mask = mask | ImageOperandsMask::Grad;
+    orderedParams->push_back(grad.first);
+    orderedParams->push_back(grad.second);
+  }
+
+  if (constOffset) {
+    mask = mask | ImageOperandsMask::ConstOffset;
+    orderedParams->push_back(constOffset);
+  }
+
+  return mask;
+}
+} // anonymous namespace
+
+uint32_t ModuleBuilder::createImageSample(uint32_t texelType,
+                                          uint32_t imageType, uint32_t image,
+                                          uint32_t sampler, uint32_t coordinate,
+                                          uint32_t bias, uint32_t lod,
+                                          std::pair<uint32_t, uint32_t> grad,
+                                          uint32_t offset) {
+  assert(insertPoint && "null insert point");
+
+  // An OpSampledImage is required to do the image sampling.
+  const uint32_t sampledImgId = theContext.takeNextId();
+  const uint32_t sampledImgTy = getSampledImageType(imageType);
+  instBuilder.opSampledImage(sampledImgTy, sampledImgId, image, sampler).x();
+  insertPoint->appendInstruction(std::move(constructSite));
+
+  const uint32_t texelId = theContext.takeNextId();
+  llvm::SmallVector<uint32_t, 4> params;
+  const auto mask = composeImageOperandsMask(bias, lod, grad, offset, &params);
+  // The Lod and Grad image operands requires explicit-lod instructions.
+  if (lod || (grad.first && grad.second)) {
+    instBuilder.opImageSampleExplicitLod(texelType, texelId, sampledImgId,
+                                         coordinate, mask);
+  } else {
+    instBuilder.opImageSampleImplicitLod(
+        texelType, texelId, sampledImgId, coordinate,
+        llvm::Optional<spv::ImageOperandsMask>(mask));
+  }
+  for (const auto param : params)
+    instBuilder.idRef(param);
+  instBuilder.x();
+  insertPoint->appendInstruction(std::move(constructSite));
+
+  return texelId;
+}
+
+uint32_t ModuleBuilder::createImageFetch(uint32_t texelType, uint32_t image,
+                                         uint32_t coordinate, uint32_t lod,
+                                         uint32_t offset) {
+  assert(insertPoint && "null insert point");
+
+  llvm::SmallVector<uint32_t, 2> params;
+  const auto mask =
+      llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask(
+          /*bias*/ 0, lod, std::make_pair(0, 0), offset, &params));
+
+  const uint32_t texelId = theContext.takeNextId();
+  instBuilder.opImageFetch(texelType, texelId, image, coordinate, mask);
+  for (const auto param : params)
+    instBuilder.idRef(param);
+  instBuilder.x();
+  insertPoint->appendInstruction(std::move(constructSite));
+
+  return texelId;
+}
+
+uint32_t ModuleBuilder::createImageGather(uint32_t texelType,
+                                          uint32_t imageType, uint32_t image,
+                                          uint32_t sampler, uint32_t coordinate,
+                                          uint32_t component, uint32_t offset) {
+  assert(insertPoint && "null insert point");
+
+  // An OpSampledImage is required to do the image sampling.
+  const uint32_t sampledImgId = theContext.takeNextId();
+  const uint32_t sampledImgTy = getSampledImageType(imageType);
+  instBuilder.opSampledImage(sampledImgTy, sampledImgId, image, sampler).x();
+  insertPoint->appendInstruction(std::move(constructSite));
+
+  llvm::SmallVector<uint32_t, 2> params;
+
+  const auto mask =
+      llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask(
+          /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), offset, &params));
+  const uint32_t texelId = theContext.takeNextId();
+  instBuilder.opImageGather(texelType, texelId, sampledImgId, coordinate,
+                            component, mask);
+  for (const auto param : params)
+    instBuilder.idRef(param);
+  instBuilder.x();
+  insertPoint->appendInstruction(std::move(constructSite));
+
+  return texelId;
+}
+
 uint32_t ModuleBuilder::createSelect(uint32_t resultType, uint32_t condition,
                                      uint32_t trueValue, uint32_t falseValue) {
   assert(insertPoint && "null insert point");
@@ -526,6 +644,14 @@ uint32_t ModuleBuilder::getSamplerType() {
   return typeId;
 }
 
+uint32_t ModuleBuilder::getSampledImageType(uint32_t imageType) {
+  const Type *type = Type::getSampledImage(theContext, imageType);
+  const uint32_t typeId = theContext.getResultIdForType(type);
+  theModule.addType(type, typeId);
+  theModule.addDebugName(typeId, "type.sampled.image");
+  return typeId;
+}
+
 uint32_t ModuleBuilder::getConstantBool(bool value) {
   const uint32_t typeId = getBoolType();
   const Constant *constant = value ? Constant::getTrue(theContext, typeId)

+ 191 - 4
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1029,6 +1029,9 @@ uint32_t SPIRVEmitter::doCallExpr(const CallExpr *callExpr) {
   if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(callExpr))
     return doCXXOperatorCallExpr(operatorCall);
 
+  if (const auto *memberCall = dyn_cast<CXXMemberCallExpr>(callExpr))
+    return doCXXMemberCallExpr(memberCall);
+
   const FunctionDecl *callee = callExpr->getDirectCallee();
 
   // Intrinsic functions such as 'dot' or 'mul'
@@ -1281,6 +1284,163 @@ uint32_t SPIRVEmitter::doConditionalOperator(const ConditionalOperator *expr) {
   return theBuilder.createSelect(type, condition, trueBranch, falseBranch);
 }
 
+uint32_t SPIRVEmitter::doCXXMemberCallExpr(const CXXMemberCallExpr *expr) {
+  using namespace hlsl;
+
+  const FunctionDecl *callee = expr->getDirectCallee();
+  const auto retType = typeTranslator.translateType(callee->getReturnType());
+
+  // TODO: For the following method calls, offset is not always constant.
+  // In SPIR-V, there are two image operands, ConstOffset and Offset.
+  // We are translating all into ConstOffset right now, which is incorrect
+  // for non-constant offset.
+
+  llvm::StringRef group;
+  uint32_t opcode = static_cast<uint32_t>(IntrinsicOp::Num_Intrinsics);
+  if (GetIntrinsicOp(callee, opcode, group)) {
+    switch (static_cast<IntrinsicOp>(opcode)) {
+    case IntrinsicOp::MOP_Sample:
+    case IntrinsicOp::MOP_Gather: {
+      // Signatures:
+      // DXGI_FORMAT Object.Sample(sampler_state S,
+      //                           float Location
+      //                           [, int Offset]);
+      //
+      // <Template Type>4 Object.Gather(sampler_state S,
+      //                                float2|3|4 Location
+      //                                [, int2 Offset]);
+
+      const auto *imageExpr = expr->getImplicitObjectArgument();
+
+      const uint32_t imageType =
+          typeTranslator.translateType(imageExpr->getType());
+
+      const uint32_t image = loadIfGLValue(imageExpr);
+      const uint32_t sampler = doExpr(expr->getArg(0));
+      const uint32_t coordinate = doExpr(expr->getArg(1));
+      // .Sample()/.Gather() has a third optional paramter for offset, which
+      // should be translated into SPIR-V ConstOffset image operands.
+      const uint32_t offset =
+          expr->getNumArgs() == 3 ? doExpr(expr->getArg(2)) : 0;
+
+      if (opcode == static_cast<uint32_t>(IntrinsicOp::MOP_Sample)) {
+        return theBuilder.createImageSample(retType, imageType, image, sampler,
+                                            coordinate, /*bias*/ 0, /*lod*/ 0,
+                                            std::make_pair(0, 0), offset);
+      } else {
+        return theBuilder.createImageGather(
+            retType, imageType, image, sampler, coordinate,
+            // .Gather() doc says we return four components of red data.
+            theBuilder.getConstantInt32(0), offset);
+      }
+    }
+    case IntrinsicOp::MOP_SampleBias:
+    case IntrinsicOp::MOP_SampleLevel: {
+      // Signatures:
+      // DXGI_FORMAT Object.SampleBias(sampler_state S,
+      //                               float Location,
+      //                               float Bias
+      //                               [, int Offset]);
+      //
+      // DXGI_FORMAT Object.SampleLevel(sampler_state S,
+      //                                float Location,
+      //                                float LOD
+      //                                [, int Offset]);
+      const auto *imageExpr = expr->getImplicitObjectArgument();
+
+      const uint32_t imageType =
+          typeTranslator.translateType(imageExpr->getType());
+
+      const uint32_t image = loadIfGLValue(imageExpr);
+      const uint32_t sampler = doExpr(expr->getArg(0));
+      const uint32_t coordinate = doExpr(expr->getArg(1));
+      uint32_t lod = 0;
+      uint32_t bias = 0;
+      if (opcode == static_cast<uint32_t>(IntrinsicOp::MOP_SampleBias)) {
+        bias = doExpr(expr->getArg(2));
+      } else {
+        lod = doExpr(expr->getArg(2));
+      }
+      // .Bias()/.SampleLevel() has a fourth optional paramter for offset,
+      // which should be translated into SPIR-V ConstOffset image operands.
+      const uint32_t offset =
+          expr->getNumArgs() == 4 ? doExpr(expr->getArg(3)) : 0;
+
+      return theBuilder.createImageSample(retType, imageType, image, sampler,
+                                          coordinate, bias, lod,
+                                          std::make_pair(0, 0), offset);
+    }
+    case IntrinsicOp::MOP_SampleGrad: {
+      // Signature:
+      // DXGI_FORMAT Object.SampleGrad(sampler_state S,
+      //                               float Location,
+      //                               float DDX,
+      //                               float DDY
+      //                               [, int Offset]);
+
+      const auto *imageExpr = expr->getImplicitObjectArgument();
+
+      const uint32_t imageType =
+          typeTranslator.translateType(imageExpr->getType());
+
+      const uint32_t image = loadIfGLValue(imageExpr);
+      const uint32_t sampler = doExpr(expr->getArg(0));
+      const uint32_t coordinate = doExpr(expr->getArg(1));
+      const uint32_t ddx = doExpr(expr->getArg(2));
+      const uint32_t ddy = doExpr(expr->getArg(3));
+      // .SampleGrad() has a fifth optional paramter for offset, which
+      // should be translated into SPIR-V ConstOffset image operands.
+      const uint32_t offset =
+          expr->getNumArgs() == 5 ? doExpr(expr->getArg(4)) : 0;
+
+      return theBuilder.createImageSample(retType, imageType, image, sampler,
+                                          coordinate, /*bias*/ 0, /*lod*/ 0,
+                                          std::make_pair(ddx, ddy), offset);
+    }
+    case IntrinsicOp::MOP_Load: {
+      // Signature:
+      // ret Object.Load(int Location
+      //                 [, int SampleIndex,]
+      //                 [, int Offset]);
+
+      // SampleIndex is only available when the Object is of Texture2DMS or
+      // Texture2DMSArray types. Under those cases, Offset will be the third
+      // parameter. Otherwise, Offset should be the second parameter.
+      if (expr->getNumArgs() == 3) {
+        emitError("Texture2DMS[Array].Load() not implemented yet");
+        return 0;
+      }
+
+      const auto *imageExpr = expr->getImplicitObjectArgument();
+      const uint32_t image = loadIfGLValue(imageExpr);
+
+      // The location parameter is a vector that consists of both the coordinate
+      // and the mipmap level (via the last vector element). We need to split it
+      // here since the OpImageFetch SPIR-V instruction encodes them as separate
+      // arguments.
+      const uint32_t location = doExpr(expr->getArg(0));
+      uint32_t coordinate = 0, lod = 0;
+      splitVecLastElement(expr->getArg(0)->getType(), location, &coordinate,
+                          &lod);
+
+      const uint32_t offset =
+          expr->getNumArgs() == 2 ? doExpr(expr->getArg(1)) : 0;
+
+      return theBuilder.createImageFetch(retType, image, coordinate, lod,
+                                         offset);
+    }
+    default:
+      emitError("HLSL intrinsic member call unimplemented: %0")
+          << callee->getName();
+      return 0;
+    }
+  } else {
+    emitError("C++ member function call unimplemented: %0")
+        << callee->getName();
+    return 0;
+  }
+}
+
 uint32_t SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
   { // First try to handle vector/matrix indexing
     const Expr *baseExpr = nullptr;
@@ -1965,6 +2125,31 @@ uint32_t SPIRVEmitter::createVectorSplat(const Expr *scalarExpr, uint32_t size,
   }
 }
 
+void SPIRVEmitter::splitVecLastElement(QualType vecType, uint32_t vec,
+                                       uint32_t *residual,
+                                       uint32_t *lastElement) {
+  assert(hlsl::IsHLSLVecType(vecType));
+
+  const uint32_t count = hlsl::GetHLSLVecSize(vecType);
+  assert(count > 1);
+  const uint32_t elemTypeId =
+      typeTranslator.translateType(hlsl::GetHLSLVecElementType(vecType));
+
+  if (count == 2) {
+    *residual = theBuilder.createCompositeExtract(elemTypeId, vec, 0);
+  } else {
+    llvm::SmallVector<uint32_t, 4> indices;
+    for (uint32_t i = 0; i < count - 1; ++i)
+      indices.push_back(i);
+
+    const uint32_t typeId = theBuilder.getVecType(elemTypeId, count - 1);
+    *residual = theBuilder.createVectorShuffle(typeId, vec, vec, indices);
+  }
+
+  *lastElement =
+      theBuilder.createCompositeExtract(elemTypeId, vec, {count - 1});
+}
+
 uint32_t SPIRVEmitter::tryToGenFloatVectorScale(const BinaryOperator *expr) {
   const QualType type = expr->getType();
   // We can only translate floatN * float into OpVectorTimesScalar.
@@ -2387,6 +2572,12 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
 
   const bool isFloatType = isFloatOrVecMatOfFloatType(callExpr->getType());
   const bool isSintType = isSintOrVecMatOfSintType(callExpr->getType());
+
+  // Figure out which intrinsic function to translate.
+  llvm::StringRef group;
+  uint32_t opcode = static_cast<uint32_t>(hlsl::IntrinsicOp::Num_Intrinsics);
+  hlsl::GetIntrinsicOp(callee, opcode, group);
+
   GLSLstd450 glslOpcode = GLSLstd450Bad;
 
 #define INTRINSIC_OP_CASE(intrinsicOp, glslOp, doEachVec)                      \
@@ -2413,10 +2604,6 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     return processIntrinsicUsingGLSLInst(callExpr, glslOpcode, doEachVec);     \
   } break
 
-  // Figure out which intrinsic function to translate.
-  llvm::StringRef group;
-  uint32_t opcode = static_cast<uint32_t>(hlsl::IntrinsicOp::Num_Intrinsics);
-  hlsl::GetIntrinsicOp(callee, opcode, group);
   switch (static_cast<hlsl::IntrinsicOp>(opcode)) {
   case hlsl::IntrinsicOp::IOP_dot:
     return processIntrinsicDot(callExpr);

+ 6 - 6
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -91,6 +91,7 @@ private:
   uint32_t doCastExpr(const CastExpr *expr);
   uint32_t doCompoundAssignOperator(const CompoundAssignOperator *expr);
   uint32_t doConditionalOperator(const ConditionalOperator *expr);
+  uint32_t doCXXMemberCallExpr(const CXXMemberCallExpr *expr);
   uint32_t doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr);
   uint32_t doExtMatrixElementExpr(const ExtMatrixElementExpr *expr);
   uint32_t doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr);
@@ -98,12 +99,6 @@ private:
   uint32_t doMemberExpr(const MemberExpr *expr);
   uint32_t doUnaryOperator(const UnaryOperator *expr);
 
-private:
-  /// Translates the return statement into its SPIR-V equivalent. Also generates
-  /// necessary instructions for the entry function ensuring that the signature
-  /// matches the SPIR-V requirements.
-  void processReturnStmt(const ReturnStmt *stmt);
-
 private:
   /// Translates the given frontend binary operator into its SPIR-V equivalent
   /// taking consideration of the operand type.
@@ -171,6 +166,11 @@ private:
   uint32_t createVectorSplat(const Expr *scalarExpr, uint32_t size,
                              bool *resultIsConstant = nullptr);
 
+  /// Splits the given vector into the last element and the rest (as a new
+  /// vector).
+  void splitVecLastElement(QualType vecType, uint32_t vec, uint32_t *residual,
+                           uint32_t *lastElement);
+
   /// Translates a floatN * float multiplication into SPIR-V instructions and
   /// returns the <result-id>. Returns 0 if the given binary operation is not
   /// floatN * float.

+ 27 - 0
tools/clang/test/CodeGenSPIRV/texture.array.gather.hlsl

@@ -0,0 +1,27 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+Texture2DArray   <float4> t2 : register(t2);
+TextureCubeArray <float4> t4 : register(t4);
+// .Gather() does not support Texture1DArray.
+
+// CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_0_4
+
+float4 main(float3 location: A) : SV_Target {
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageGather %v4float [[sampledImg]] [[loc]] %int_0
+    float4 val2 = t2.Gather(gSampler, location);
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image_array %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageGather %v4float [[sampledImg]] [[v4fc]] %int_0
+    float4 val4 = t4.Gather(gSampler, float4(0.1, 0.2, 0.3, 0.4));
+
+    return 1.0;
+}

+ 29 - 0
tools/clang/test/CodeGenSPIRV/texture.array.load.hlsl

@@ -0,0 +1,29 @@
+// Run: %dxc -T ps_6_0 -E main
+
+Texture1DArray <float4> t1 : register(t1);
+Texture2DArray <float4> t2 : register(t2);
+// .Load() does not support TextureCubeArray.
+
+// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3
+
+float4 main(int4 location: A) : SV_Target {
+
+// CHECK:         [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v2int [[v3ic]] [[v3ic]] 0 1
+// CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[v3ic]] 2
+// CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t1]] [[coord]] Lod|ConstOffset [[lod]] %int_10
+    float4 val1 = t1.Load(int3(1, 2, 3), 10);
+
+// CHECK:         [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[loc:%\d+]] = OpLoad %v4int %location
+// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v3int [[loc]] [[loc]] 0 1 2
+// CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 3
+// CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]]
+    float4 val2 = t2.Load(location);
+
+    return 1.0;
+}
+
+
+
+

+ 39 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-bias.hlsl

@@ -0,0 +1,39 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float4> t2 : register(t2);
+TextureCubeArray <float4> t3 : register(t3);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
+// CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v2fc]] Bias|ConstOffset %float_0_5 %int_1
+    float4 val1 = t1.SampleBias(gSampler, float2(0.1, 1), 0.5, 1);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] Bias %float_0_5
+    float4 val2 = t2.SampleBias(gSampler, float3(0.1, 0.2, 1), 0.5);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v4fc]] Bias %float_0_5
+    float4 val3 = t3.SampleBias(gSampler, float4(0.1, 0.2, 0.3, 1), 0.5);
+
+    return 1.0;
+}

+ 43 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-grad.hlsl

@@ -0,0 +1,43 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float4> t2 : register(t2);
+TextureCubeArray <float4> t3 : register(t3);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image
+
+// CHECK: [[v2f_0_1:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_1
+// CHECK: [[v3f_0_1:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_1 %float_0_1
+// CHECK: [[v2f_0_2:%\d+]] = OpConstantComposite %v2float %float_0_2 %float_0_2
+// CHECK: [[v2f_0_3:%\d+]] = OpConstantComposite %v2float %float_0_3 %float_0_3
+// CHECK: [[v4f_0_1:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_1 %float_0_1 %float_0_1
+// CHECK: [[v3f_0_2:%\d+]] = OpConstantComposite %v3float %float_0_2 %float_0_2 %float_0_2
+// CHECK: [[v3f_0_3:%\d+]] = OpConstantComposite %v3float %float_0_3 %float_0_3 %float_0_3
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v2f_0_1]] Grad|ConstOffset %float_0_2 %float_0_3 %int_1
+    float4 val1 = t1.SampleGrad(gSampler, float2(0.1, 0.1), 0.2, 0.3, 1);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3f_0_1]] Grad [[v2f_0_2]] [[v2f_0_3]]
+    float4 val2 = t2.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float2(0.2, 0.2), float2(0.3, 0.3));
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v4f_0_1]] Grad [[v3f_0_2]] [[v3f_0_3]]
+    float4 val3 = t3.SampleGrad(gSampler, float4(0.1, 0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3));
+
+    return 1.0;
+}

+ 39 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample-level.hlsl

@@ -0,0 +1,39 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float4> t2 : register(t2);
+TextureCubeArray <float4> t3 : register(t3);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
+// CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v2fc]] Lod|ConstOffset %float_10 %int_1
+    float4 val1 = t1.SampleLevel(gSampler, float2(0.1, 1), 10, 1);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3fc]] Lod %float_20
+    float4 val2 = t2.SampleLevel(gSampler, float3(0.1, 0.2, 1), 20);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v4fc]] Lod %float_30
+    float4 val3 = t3.SampleLevel(gSampler, float4(0.1, 0.2, 0.3, 1), 30);
+
+    return 1.0;
+}

+ 39 - 0
tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl

@@ -0,0 +1,39 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1DArray   <float4> t1 : register(t1);
+Texture2DArray   <float4> t2 : register(t2);
+TextureCubeArray <float4> t3 : register(t3);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image_array
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_array
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_cube_image_array
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_1
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_1
+// CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_0_1 %float_0_2 %float_0_3 %float_1
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v2fc]] ConstOffset %int_1
+    float4 val1 = t1.Sample(gSampler, float2(0.1, 1), 1);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]]
+    float4 val2 = t2.Sample(gSampler, float3(0.1, 0.2, 1));
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_cube_image_array %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v4fc]]
+    float4 val3 = t3.Sample(gSampler, float4(0.1, 0.2, 0.3, 1));
+
+    return 1.0;
+}

+ 28 - 0
tools/clang/test/CodeGenSPIRV/texture.gather.hlsl

@@ -0,0 +1,28 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+Texture2D   <float4> t2 : register(t2);
+TextureCube <float4> t4 : register(t4);
+// .Gather() does not support Texture1D and Texture3D.
+
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+
+float4 main(float2 location: A) : SV_Target {
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageGather %v4float [[sampledImg]] [[loc]] %int_0 ConstOffset [[v2ic]]
+    float4 val2 = t2.Gather(gSampler, location, int2(1, 2));
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageGather %v4float [[sampledImg]] [[v3fc]] %int_0
+    float4 val4 = t4.Gather(gSampler, float3(0.1, 0.2, 0.3));
+
+    return 1.0;
+}

+ 34 - 0
tools/clang/test/CodeGenSPIRV/texture.load.hlsl

@@ -0,0 +1,34 @@
+// Run: %dxc -T ps_6_0 -E main
+
+Texture1D <float4> t1 : register(t1);
+Texture2D <float4> t2 : register(t2);
+Texture3D <float4> t3 : register(t3);
+// .Load() does not support TextureCube.
+
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[v4ic:%\d+]] = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
+// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
+
+float4 main(int3 location: A) : SV_Target {
+
+// CHECK:         [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT: [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
+// CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
+// CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t1]] [[coord]] Lod|ConstOffset [[lod]] %int_1
+    float4 val1 = t1.Load(int2(1, 2), 1);
+
+// CHECK:         [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[loc:%\d+]] = OpLoad %v3int %location
+// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v2int [[loc]] [[loc]] 0 1
+// CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 2
+// CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]]
+    float4 val2 = t2.Load(location);
+
+// CHECK:         [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v3int [[v4ic]] [[v4ic]] 0 1 2
+// CHECK-NEXT:   [[lod:%\d+]] = OpCompositeExtract %int [[v4ic]] 3
+// CHECK-NEXT:       {{%\d+}} = OpImageFetch %v4float [[t3]] [[coord]] Lod|ConstOffset [[lod]] [[v3ic]]
+    float4 val3 = t3.Load(int4(1, 2, 3, 4), 3);
+
+    return 1.0;
+}

+ 50 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-bias.hlsl

@@ -0,0 +1,50 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float4> t2 : register(t2);
+Texture3D   <float4> t3 : register(t3);
+TextureCube <float4> t4 : register(t4);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
+// CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] %float_0_1 Bias %float_0_5
+    float4 val1 = t1.SampleBias(gSampler, 0.1, 0.5);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v2fc]] Bias|ConstOffset %float_0_5 [[v2ic]]
+    float4 val2 = t2.SampleBias(gSampler, float2(0.1, 0.2), 0.5, 2);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] Bias|ConstOffset %float_0_5 [[v3ic]]
+    float4 val3 = t3.SampleBias(gSampler, float3(0.1, 0.2, 0.3), 0.5, 3);
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] Bias %float_0_5
+    float4 val4 = t4.SampleBias(gSampler, float3(0.1, 0.2, 0.3), 0.5);
+
+    return 1.0;
+}
+
+

+ 52 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-grad.hlsl

@@ -0,0 +1,52 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float4> t2 : register(t2);
+Texture3D   <float4> t3 : register(t3);
+TextureCube <float4> t4 : register(t4);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
+// CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
+
+// CHECK: [[v2f_0_1:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_1
+// CHECK: [[v2f_0_2:%\d+]] = OpConstantComposite %v2float %float_0_2 %float_0_2
+// CHECK: [[v2f_0_3:%\d+]] = OpConstantComposite %v2float %float_0_3 %float_0_3
+// CHECK: [[v2i_2:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
+// CHECK: [[v3f_0_1:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_1 %float_0_1
+// CHECK: [[v3f_0_2:%\d+]] = OpConstantComposite %v3float %float_0_2 %float_0_2 %float_0_2
+// CHECK: [[v3f_0_3:%\d+]] = OpConstantComposite %v3float %float_0_3 %float_0_3 %float_0_3
+// CHECK: [[v3i_3:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] %float_0_1 Grad %float_0_2 %float_0_3
+    float4 val1 = t1.SampleGrad(gSampler, 0.1, 0.2, 0.3);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v2f_0_1]] Grad|ConstOffset [[v2f_0_2]] [[v2f_0_3]] [[v2i_2]]
+    float4 val2 = t2.SampleGrad(gSampler, float2(0.1, 0.1), float2(0.2, 0.2), float2(0.3, 0.3), 2);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3f_0_1]] Grad|ConstOffset [[v3f_0_2]] [[v3f_0_3]] [[v3i_3]]
+    float4 val3 = t3.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3), 3);
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3f_0_1]] Grad [[v3f_0_2]] [[v3f_0_3]]
+    float4 val4 = t4.SampleGrad(gSampler, float3(0.1, 0.1, 0.1), float3(0.2, 0.2, 0.2), float3(0.3, 0.3, 0.3));
+
+    return 1.0;
+}

+ 48 - 0
tools/clang/test/CodeGenSPIRV/texture.sample-level.hlsl

@@ -0,0 +1,48 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float4> t2 : register(t2);
+Texture3D   <float4> t3 : register(t3);
+TextureCube <float4> t4 : register(t4);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
+// CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] %float_0_1 Lod %float_10
+    float4 val1 = t1.SampleLevel(gSampler, 0.1, 10);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v2fc]] Lod|ConstOffset %float_10 [[v2ic]]
+    float4 val2 = t2.SampleLevel(gSampler, float2(0.1, 0.2), 10, 2);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3fc]] Lod|ConstOffset %float_10 [[v3ic]]
+    float4 val3 = t3.SampleLevel(gSampler, float3(0.1, 0.2, 0.3), 10, 3);
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleExplicitLod %v4float [[sampledImg]] [[v3fc]] Lod %float_10
+    float4 val4 = t4.SampleLevel(gSampler, float3(0.1, 0.2, 0.3), 10);
+
+    return 1.0;
+}

+ 48 - 0
tools/clang/test/CodeGenSPIRV/texture.sample.hlsl

@@ -0,0 +1,48 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerState gSampler : register(s1);
+
+// Note: The front end forbids sampling from non-floating-point texture formats.
+
+Texture1D   <float4> t1 : register(t1);
+Texture2D   <float4> t2 : register(t2);
+Texture3D   <float4> t3 : register(t3);
+TextureCube <float4> t4 : register(t4);
+
+// CHECK: %type_sampled_image = OpTypeSampledImage %type_1d_image
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image
+// CHECK: %type_sampled_image_1 = OpTypeSampledImage %type_3d_image
+// CHECK: %type_sampled_image_2 = OpTypeSampledImage %type_cube_image
+
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_2 %int_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
+
+float4 main() : SV_Target {
+// CHECK:              [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t1]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] %float_0_1
+    float4 val1 = t1.Sample(gSampler, 0.1);
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v2fc]] ConstOffset [[v2ic]]
+    float4 val2 = t2.Sample(gSampler, float2(0.1, 0.2), 2);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_1 [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]] ConstOffset [[v3ic]]
+    float4 val3 = t3.Sample(gSampler, float3(0.1, 0.2, 0.3), 3);
+
+// CHECK:              [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_2 [[t4]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageSampleImplicitLod %v4float [[sampledImg]] [[v3fc]]
+    float4 val4 = t4.Sample(gSampler, float3(0.1, 0.2, 0.3));
+
+    return 1.0;
+}

+ 26 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -293,6 +293,32 @@ TEST_F(FileTest, SemanticDuplication) {
   runFileTest("semantic.duplication.hlsl", /*expectSuccess*/ false);
 }
 
+// For texture methods
+TEST_F(FileTest, TextureSample) { runFileTest("texture.sample.hlsl"); }
+TEST_F(FileTest, TextureArraySample) {
+  runFileTest("texture.array.sample.hlsl");
+}
+TEST_F(FileTest, TextureLoad) { runFileTest("texture.load.hlsl"); }
+TEST_F(FileTest, TextureArrayLoad) { runFileTest("texture.array.load.hlsl"); }
+TEST_F(FileTest, TextureGather) { runFileTest("texture.gather.hlsl"); }
+TEST_F(FileTest, TextureArrayGather) {
+  runFileTest("texture.array.gather.hlsl");
+}
+TEST_F(FileTest, TextureSampleLevel) {
+  runFileTest("texture.sample-level.hlsl");
+}
+TEST_F(FileTest, TextureArraySampleLevel) {
+  runFileTest("texture.array.sample-level.hlsl");
+}
+TEST_F(FileTest, TextureSampleBias) { runFileTest("texture.sample-bias.hlsl"); }
+TEST_F(FileTest, TextureArraySampleBias) {
+  runFileTest("texture.array.sample-bias.hlsl");
+}
+TEST_F(FileTest, TextureSampleGrad) { runFileTest("texture.sample-grad.hlsl"); }
+TEST_F(FileTest, TextureArraySampleGrad) {
+  runFileTest("texture.array.sample-grad.hlsl");
+}
+
 // For intrinsic functions
 TEST_F(FileTest, IntrinsicsDot) { runFileTest("intrinsics.dot.hlsl"); }
 TEST_F(FileTest, IntrinsicsMul) { runFileTest("intrinsics.mul.hlsl"); }