[clang] 9767894 - [HLSL] Implement Texture2D::Gather and Texture2D::GatherCmp (#183323)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 5 12:59:08 PST 2026


Author: Steven Perron
Date: 2026-03-05T20:59:01Z
New Revision: 9767894b859d877da1d8507b384fb879a51379f9

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

LOG: [HLSL] Implement Texture2D::Gather and Texture2D::GatherCmp (#183323)

Add the Gather functions for Texture2D. Variations for all components
are added (Red, Blue, Greed, Alpha). If targeting Vulkan then the
GatherCmp* function for a component other than 0 will result in an
error, as that will lead to invalid SPIR-V.

Part of https://github.com/llvm/llvm-project/issues/175630.

Assisted by: Gemini

Added: 
    clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
    clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
    clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl
    clang/test/SemaHLSL/Texture2D-Gather.hlsl
    clang/test/SemaHLSL/Texture2D-GatherCmp-Vulkan.hlsl

Modified: 
    clang/include/clang/Basic/Builtins.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/CodeGen/CGHLSLBuiltins.cpp
    clang/lib/CodeGen/CGHLSLRuntime.h
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
    clang/lib/Sema/HLSLExternalSemaSource.cpp
    clang/lib/Sema/SemaHLSL.cpp
    llvm/include/llvm/IR/IntrinsicsDirectX.td

Removed: 
    clang/test/AST/HLSL/Texture2D-AST.hlsl


################################################################################
diff  --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 7063d7c06c4ca..62421e5888144 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5072,6 +5072,18 @@ def HLSLResourceSampleCmpLevelZero : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLResourceGather : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_gather"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
+def HLSLResourceGatherCmp : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_gather_cmp"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
   let Attributes = [NoThrow];

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2f8a37e506136..68aec19bcdaf9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13625,6 +13625,8 @@ def err_hlsl_push_constant_unique
 def err_hlsl_samplecmp_requires_float
     : Error<"'SampleCmp' and 'SampleCmpLevelZero' require resource to contain "
             "a floating point type">;
+def err_hlsl_gathercmp_invalid_component
+    : Error<"gatherCmp%select{Red|Green|Blue|Alpha}0 operations on the Vulkan target are not supported; only GatherCmp and GatherCmpRed are allowed">;
 
 // Layout randomization diagnostics.
 def err_non_designated_init_used : Error<

diff  --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 47b7e2b18d942..d6687b8e295e4 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -662,6 +662,54 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
     return Builder.CreateIntrinsic(
         RetTy, CGM.getHLSLRuntime().getSampleCmpLevelZeroIntrinsic(), Args);
   }
+  case Builtin::BI__builtin_hlsl_resource_gather: {
+    Value *HandleOp = EmitScalarExpr(E->getArg(0));
+    Value *SamplerOp = EmitScalarExpr(E->getArg(1));
+    Value *CoordOp = EmitScalarExpr(E->getArg(2));
+    Value *ComponentOp = EmitScalarExpr(E->getArg(3));
+    if (ComponentOp->getType() != Builder.getInt32Ty())
+      ComponentOp = Builder.CreateIntCast(ComponentOp, Builder.getInt32Ty(),
+                                          /*isSigned=*/false);
+
+    SmallVector<Value *, 5> Args;
+    Args.push_back(HandleOp);
+    Args.push_back(SamplerOp);
+    Args.push_back(CoordOp);
+    Args.push_back(ComponentOp);
+    Args.push_back(emitHlslOffset(*this, E, 4));
+
+    llvm::Type *RetTy = ConvertType(E->getType());
+    return Builder.CreateIntrinsic(
+        RetTy, CGM.getHLSLRuntime().getGatherIntrinsic(), Args);
+  }
+  case Builtin::BI__builtin_hlsl_resource_gather_cmp: {
+    Value *HandleOp = EmitScalarExpr(E->getArg(0));
+    Value *SamplerOp = EmitScalarExpr(E->getArg(1));
+    Value *CoordOp = EmitScalarExpr(E->getArg(2));
+    Value *CompareOp = EmitScalarExpr(E->getArg(3));
+    if (CompareOp->getType() != Builder.getFloatTy())
+      CompareOp = Builder.CreateFPCast(CompareOp, Builder.getFloatTy());
+
+    SmallVector<Value *, 6> Args;
+    Args.push_back(HandleOp);
+    Args.push_back(SamplerOp);
+    Args.push_back(CoordOp);
+    Args.push_back(CompareOp);
+
+    if (CGM.getTarget().getTriple().isDXIL()) {
+      Value *ComponentOp = EmitScalarExpr(E->getArg(4));
+      if (ComponentOp->getType() != Builder.getInt32Ty())
+        ComponentOp = Builder.CreateIntCast(ComponentOp, Builder.getInt32Ty(),
+                                            /*isSigned=*/false);
+      Args.push_back(ComponentOp);
+    }
+
+    Args.push_back(emitHlslOffset(*this, E, 5));
+
+    llvm::Type *RetTy = ConvertType(E->getType());
+    return Builder.CreateIntrinsic(
+        RetTy, CGM.getHLSLRuntime().getGatherCmpIntrinsic(), Args);
+  }
   case Builtin::BI__builtin_hlsl_resource_load_with_status:
   case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
     Value *HandleOp = EmitScalarExpr(E->getArg(0));

diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index aa5fed1ad7519..466c809fdef78 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -175,6 +175,8 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(SampleCmpClamp, resource_samplecmp_clamp)
   GENERATE_HLSL_INTRINSIC_FUNCTION(SampleCmpLevelZero,
                                    resource_samplecmplevelzero)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(Gather, resource_gather)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(GatherCmp, resource_gather_cmp)
   GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
                                    resource_handlefrombinding)
   GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,

diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 91b34838d5720..f99c16c8fe92e 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/HLSLResource.h"
 #include "clang/AST/Stmt.h"
@@ -1304,7 +1305,7 @@ BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
   ASTContext &AST = Record->getASTContext();
-  QualType ReturnType = getFirstTemplateTypeParam();
+  QualType ReturnType = getHandleElementType();
   QualType SamplerStateType =
       lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
   uint32_t VecSize = getResourceDimensions(Dim);
@@ -1352,7 +1353,7 @@ BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addSampleBiasMethods(ResourceDimension Dim) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
   ASTContext &AST = Record->getASTContext();
-  QualType ReturnType = getFirstTemplateTypeParam();
+  QualType ReturnType = getHandleElementType();
   QualType SamplerStateType =
       lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
   uint32_t VecSize = getResourceDimensions(Dim);
@@ -1404,7 +1405,7 @@ BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addSampleGradMethods(ResourceDimension Dim) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
   ASTContext &AST = Record->getASTContext();
-  QualType ReturnType = getFirstTemplateTypeParam();
+  QualType ReturnType = getHandleElementType();
   QualType SamplerStateType =
       lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
   uint32_t VecSize = getResourceDimensions(Dim);
@@ -1461,7 +1462,7 @@ BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addSampleLevelMethods(ResourceDimension Dim) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
   ASTContext &AST = Record->getASTContext();
-  QualType ReturnType = getFirstTemplateTypeParam();
+  QualType ReturnType = getHandleElementType();
   QualType SamplerStateType =
       lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
   uint32_t VecSize = getResourceDimensions(Dim);
@@ -1588,6 +1589,129 @@ BuiltinTypeDeclBuilder::addSampleCmpLevelZeroMethods(ResourceDimension Dim) {
       .finalize();
 }
 
+QualType BuiltinTypeDeclBuilder::getGatherReturnType() {
+  ASTContext &AST = SemaRef.getASTContext();
+  QualType T = getHandleElementType();
+  if (T.isNull())
+    return QualType();
+
+  if (const auto *VT = T->getAs<VectorType>())
+    T = VT->getElementType();
+  else if (const auto *DT = T->getAs<DependentSizedExtVectorType>())
+    T = DT->getElementType();
+
+  return AST.getExtVectorType(T, 4);
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addGatherMethods(ResourceDimension Dim) {
+  assert(!Record->isCompleteDefinition() && "record is already complete");
+  ASTContext &AST = Record->getASTContext();
+  QualType ReturnType = getGatherReturnType();
+
+  QualType SamplerStateType =
+      lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
+  uint32_t VecSize = getResourceDimensions(Dim);
+  QualType LocationTy = AST.FloatTy;
+  QualType Float2Ty = AST.getExtVectorType(LocationTy, VecSize);
+  QualType IntTy = AST.IntTy;
+  QualType OffsetTy = AST.getExtVectorType(IntTy, VecSize);
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+  // Overloads for Gather, GatherRed, GatherGreen, GatherBlue, GatherAlpha
+  struct GatherVariant {
+    const char *Name;
+    int Component;
+  };
+  GatherVariant Variants[] = {{"Gather", 0},
+                              {"GatherRed", 0},
+                              {"GatherGreen", 1},
+                              {"GatherBlue", 2},
+                              {"GatherAlpha", 3}};
+
+  for (const auto &V : Variants) {
+    // ret GatherVariant(SamplerState s, float2 location)
+    BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
+        .addParam("Sampler", SamplerStateType)
+        .addParam("Location", Float2Ty)
+        .accessHandleFieldOnResource(PH::_0)
+        .callBuiltin("__builtin_hlsl_resource_gather", ReturnType, PH::Handle,
+                     PH::LastStmt, PH::_1,
+                     getConstantUnsignedIntExpr(V.Component))
+        .finalize();
+
+    // ret GatherVariant(SamplerState s, float2 location, int2 offset)
+    BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
+        .addParam("Sampler", SamplerStateType)
+        .addParam("Location", Float2Ty)
+        .addParam("Offset", OffsetTy)
+        .accessHandleFieldOnResource(PH::_0)
+        .callBuiltin("__builtin_hlsl_resource_gather", ReturnType, PH::Handle,
+                     PH::LastStmt, PH::_1,
+                     getConstantUnsignedIntExpr(V.Component), PH::_2)
+        .finalize();
+  }
+
+  return *this;
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addGatherCmpMethods(ResourceDimension Dim) {
+  assert(!Record->isCompleteDefinition() && "record is already complete");
+  ASTContext &AST = Record->getASTContext();
+  QualType ReturnType = AST.getExtVectorType(AST.FloatTy, 4);
+
+  QualType SamplerComparisonStateType = lookupBuiltinType(
+      SemaRef, "SamplerComparisonState", Record->getDeclContext());
+  uint32_t VecSize = getResourceDimensions(Dim);
+  QualType FloatTy = AST.FloatTy;
+  QualType Float2Ty = AST.getExtVectorType(FloatTy, VecSize);
+  QualType IntTy = AST.IntTy;
+  QualType Int2Ty = AST.getExtVectorType(IntTy, VecSize);
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+  // Overloads for GatherCmp, GatherCmpRed, GatherCmpGreen, GatherCmpBlue,
+  // GatherCmpAlpha
+  struct GatherVariant {
+    const char *Name;
+    int Component;
+  };
+  GatherVariant Variants[] = {{"GatherCmp", 0},
+                              {"GatherCmpRed", 0},
+                              {"GatherCmpGreen", 1},
+                              {"GatherCmpBlue", 2},
+                              {"GatherCmpAlpha", 3}};
+
+  for (const auto &V : Variants) {
+    // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
+    // compare_value)
+    BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
+        .addParam("Sampler", SamplerComparisonStateType)
+        .addParam("Location", Float2Ty)
+        .addParam("CompareValue", FloatTy)
+        .accessHandleFieldOnResource(PH::_0)
+        .callBuiltin("__builtin_hlsl_resource_gather_cmp", ReturnType,
+                     PH::Handle, PH::LastStmt, PH::_1, PH::_2,
+                     getConstantUnsignedIntExpr(V.Component))
+        .finalize();
+
+    // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
+    // compare_value, int2 offset)
+    BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
+        .addParam("Sampler", SamplerComparisonStateType)
+        .addParam("Location", Float2Ty)
+        .addParam("CompareValue", FloatTy)
+        .addParam("Offset", Int2Ty)
+        .accessHandleFieldOnResource(PH::_0)
+        .callBuiltin("__builtin_hlsl_resource_gather_cmp", ReturnType,
+                     PH::Handle, PH::LastStmt, PH::_1, PH::_2,
+                     getConstantUnsignedIntExpr(V.Component), PH::_3)
+        .finalize();
+  }
+
+  return *this;
+}
+
 FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
   auto I = Fields.find("__handle");
   assert(I != Fields.end() &&
@@ -1616,6 +1740,14 @@ QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {
 QualType BuiltinTypeDeclBuilder::getHandleElementType() {
   if (Template)
     return getFirstTemplateTypeParam();
+
+  if (auto *PartialSpec =
+          dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+    const auto &Args = PartialSpec->getTemplateArgs();
+    if (Args.size() > 0 && Args[0].getKind() == TemplateArgument::Type)
+      return Args[0].getAsType();
+  }
+
   // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
   return SemaRef.getASTContext().Char8Ty;
 }
@@ -1642,6 +1774,13 @@ Expr *BuiltinTypeDeclBuilder::getConstantIntExpr(int value) {
       SourceLocation());
 }
 
+Expr *BuiltinTypeDeclBuilder::getConstantUnsignedIntExpr(unsigned value) {
+  ASTContext &AST = SemaRef.getASTContext();
+  return IntegerLiteral::Create(
+      AST, llvm::APInt(AST.getTypeSize(AST.UnsignedIntTy), value),
+      AST.UnsignedIntTy, SourceLocation());
+}
+
 BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
                                                 ConceptDecl *CD = nullptr) {

diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index fcb61731c5416..c27ff30c6ff73 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -100,6 +100,8 @@ class BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &addSampleLevelMethods(ResourceDimension Dim);
   BuiltinTypeDeclBuilder &addSampleCmpMethods(ResourceDimension Dim);
   BuiltinTypeDeclBuilder &addSampleCmpLevelZeroMethods(ResourceDimension Dim);
+  BuiltinTypeDeclBuilder &addGatherMethods(ResourceDimension Dim);
+  BuiltinTypeDeclBuilder &addGatherCmpMethods(ResourceDimension Dim);
   BuiltinTypeDeclBuilder &addIncrementCounterMethod();
   BuiltinTypeDeclBuilder &addDecrementCounterMethod();
   BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
@@ -132,11 +134,13 @@ class BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &
   addCounterHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
                          AccessSpecifier Access = AccessSpecifier::AS_private);
+  QualType getGatherReturnType();
   FieldDecl *getResourceHandleField() const;
   FieldDecl *getResourceCounterHandleField() const;
   QualType getFirstTemplateTypeParam();
   QualType getHandleElementType();
   Expr *getConstantIntExpr(int value);
+  Expr *getConstantUnsignedIntExpr(unsigned value);
   HLSLAttributedResourceType::Attributes getResourceAttrs() const;
 };
 

diff  --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 662627901539a..788a129ec5390 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -15,12 +15,14 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/Sema/TemplateDeduction.h"
 #include "llvm/ADT/SmallVector.h"
 
 using namespace clang;
@@ -265,7 +267,72 @@ static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
       .addSampleGradMethods(Dim)
       .addSampleLevelMethods(Dim)
       .addSampleCmpMethods(Dim)
-      .addSampleCmpLevelZeroMethods(Dim);
+      .addSampleCmpLevelZeroMethods(Dim)
+      .addGatherMethods(Dim)
+      .addGatherCmpMethods(Dim);
+}
+
+// Add a partial specialization for a template. The `TextureTemplate` is
+// `Texture<element_type>`, and it will be specialized for vectors:
+// `Texture<vector<element_type, element_count>>`.
+static ClassTemplatePartialSpecializationDecl *
+addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
+                                      ClassTemplateDecl *TextureTemplate) {
+  ASTContext &AST = S.getASTContext();
+
+  // Create the template parameters: element_type and element_count.
+  auto *ElementType = TemplateTypeParmDecl::Create(
+      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
+      &AST.Idents.get("element_type"), false, false);
+  auto *ElementCount = NonTypeTemplateParmDecl::Create(
+      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
+      &AST.Idents.get("element_count"), AST.IntTy, false,
+      AST.getTrivialTypeSourceInfo(AST.IntTy));
+
+  auto *TemplateParams = TemplateParameterList::Create(
+      AST, SourceLocation(), SourceLocation(), {ElementType, ElementCount},
+      SourceLocation(), nullptr);
+
+  // Create the dependent vector type: vector<element_type, element_count>.
+  QualType VectorType = AST.getDependentSizedExtVectorType(
+      AST.getTemplateTypeParmType(0, 0, false, ElementType),
+      DeclRefExpr::Create(
+          AST, NestedNameSpecifierLoc(), SourceLocation(), ElementCount, false,
+          DeclarationNameInfo(ElementCount->getDeclName(), SourceLocation()),
+          AST.IntTy, VK_LValue),
+      SourceLocation());
+
+  // Create the partial specialization declaration.
+  QualType CanonInjectedTST =
+      AST.getCanonicalType(AST.getTemplateSpecializationType(
+          ElaboratedTypeKeyword::Class, TemplateName(TextureTemplate),
+          {TemplateArgument(VectorType)}, {}));
+
+  auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
+      AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
+      SourceLocation(), TemplateParams, TextureTemplate,
+      {TemplateArgument(VectorType)},
+      CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
+
+  // Set the template arguments as written.
+  TemplateArgument Arg(VectorType);
+  TemplateArgumentLoc ArgLoc =
+      S.getTrivialTemplateArgumentLoc(Arg, QualType(), SourceLocation());
+  TemplateArgumentListInfo ArgsInfo =
+      TemplateArgumentListInfo(SourceLocation(), SourceLocation());
+  ArgsInfo.addArgument(ArgLoc);
+  PartialSpec->setTemplateArgsAsWritten(
+      ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
+
+  PartialSpec->setImplicit(true);
+  PartialSpec->setLexicalDeclContext(HLSLNamespace);
+  PartialSpec->setHasExternalLexicalStorage();
+
+  // Add the partial specialization to the namespace and the class template.
+  HLSLNamespace->addDecl(PartialSpec);
+  TextureTemplate->AddPartialSpecialization(PartialSpec, nullptr);
+
+  return PartialSpec;
 }
 
 // This function is responsible for constructing the constraint expression for
@@ -548,11 +615,20 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
              .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)
              .finalizeForwardDeclaration();
+
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
     setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
                      ResourceDimension::Dim2D)
         .completeDefinition();
   });
+
+  auto *PartialSpec = addVectorTexturePartialSpecialization(
+      *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
+  onCompletion(PartialSpec, [this](CXXRecordDecl *Decl) {
+    setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
+                     ResourceDimension::Dim2D)
+        .completeDefinition();
+  });
 }
 
 void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
@@ -568,8 +644,27 @@ void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
 
   // If this is a specialization, we need to get the underlying templated
   // declaration and complete that.
-  if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
-    Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+  if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+    if (!isa<ClassTemplatePartialSpecializationDecl>(TDecl)) {
+      ClassTemplateDecl *Template = TDecl->getSpecializedTemplate();
+      llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Partials;
+      Template->getPartialSpecializations(Partials);
+      ClassTemplatePartialSpecializationDecl *MatchedPartial = nullptr;
+      for (auto *Partial : Partials) {
+        sema::TemplateDeductionInfo Info(TDecl->getLocation());
+        if (SemaPtr->DeduceTemplateArguments(Partial, TDecl->getTemplateArgs(),
+                                             Info) ==
+            TemplateDeductionResult::Success) {
+          MatchedPartial = Partial;
+          break;
+        }
+      }
+      if (MatchedPartial)
+        Record = MatchedPartial;
+      else
+        Record = Template->getTemplatedDecl();
+    }
+  }
   Record = Record->getCanonicalDecl();
   auto It = Completions.find(Record);
   if (It == Completions.end())

diff  --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f3e6726428162..5701b76427d60 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3326,6 +3326,121 @@ static bool CheckVectorElementCount(Sema *S, QualType PassedType,
 
 enum class SampleKind { Sample, Bias, Grad, Level, Cmp, CmpLevelZero };
 
+static bool CheckTextureSamplerAndLocation(Sema &S, CallExpr *TheCall) {
+  // Check the texture handle.
+  if (CheckResourceHandle(&S, TheCall, 0,
+                          [](const HLSLAttributedResourceType *ResType) {
+                            return ResType->getAttrs().ResourceDimension ==
+                                   llvm::dxil::ResourceDimension::Unknown;
+                          }))
+    return true;
+
+  // Check the sampler handle.
+  if (CheckResourceHandle(&S, TheCall, 1,
+                          [](const HLSLAttributedResourceType *ResType) {
+                            return ResType->getAttrs().ResourceClass !=
+                                   llvm::hlsl::ResourceClass::Sampler;
+                          }))
+    return true;
+
+  auto *ResourceTy =
+      TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+
+  // Check the location.
+  unsigned ExpectedDim =
+      getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
+  if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
+                              S.Context.FloatTy, ExpectedDim,
+                              TheCall->getBeginLoc()))
+    return true;
+
+  return false;
+}
+
+static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp) {
+  if (S.checkArgCountRange(TheCall, IsCmp ? 5 : 4, IsCmp ? 6 : 5))
+    return true;
+
+  if (CheckTextureSamplerAndLocation(S, TheCall))
+    return true;
+
+  unsigned NextIdx = 3;
+  if (IsCmp) {
+    // Check the compare value.
+    QualType CmpTy = TheCall->getArg(NextIdx)->getType();
+    if (!CmpTy->isFloatingType() || CmpTy->isVectorType()) {
+      S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
+             diag::err_typecheck_convert_incompatible)
+          << CmpTy << S.Context.FloatTy << 1 << 0 << 0;
+      return true;
+    }
+    NextIdx++;
+  }
+
+  // Check the component operand.
+  Expr *ComponentArg = TheCall->getArg(NextIdx);
+  QualType ComponentTy = ComponentArg->getType();
+  if (!ComponentTy->isIntegerType() || ComponentTy->isVectorType()) {
+    S.Diag(ComponentArg->getBeginLoc(),
+           diag::err_typecheck_convert_incompatible)
+        << ComponentTy << S.Context.UnsignedIntTy << 1 << 0 << 0;
+    return true;
+  }
+
+  // GatherCmp operations on Vulkan target must use component 0 (Red).
+  if (IsCmp && S.getASTContext().getTargetInfo().getTriple().isSPIRV()) {
+    std::optional<llvm::APSInt> ComponentOpt =
+        ComponentArg->getIntegerConstantExpr(S.getASTContext());
+    if (ComponentOpt) {
+      int64_t ComponentVal = ComponentOpt->getSExtValue();
+      if (ComponentVal != 0) {
+        // Issue an error if the component is not 0 (Red).
+        // 0 -> Red, 1 -> Green, 2 -> Blue, 3 -> Alpha
+        assert(ComponentVal >= 0 && ComponentVal <= 3 &&
+               "The component is not in the expected range.");
+        S.Diag(ComponentArg->getBeginLoc(),
+               diag::err_hlsl_gathercmp_invalid_component)
+            << ComponentVal;
+        return true;
+      }
+    }
+  }
+
+  NextIdx++;
+
+  // Check the offset operand.
+  const HLSLAttributedResourceType *ResourceTy =
+      TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+  if (TheCall->getNumArgs() > NextIdx) {
+    unsigned ExpectedDim =
+        getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
+    if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
+                                S.Context.IntTy, ExpectedDim,
+                                TheCall->getArg(NextIdx)->getBeginLoc()))
+      return true;
+    NextIdx++;
+  }
+
+  assert(ResourceTy->hasContainedType() &&
+         "Expecting a contained type for resource with a dimension "
+         "attribute.");
+  QualType ReturnType = ResourceTy->getContainedType();
+
+  if (IsCmp) {
+    if (!ReturnType->hasFloatingRepresentation()) {
+      S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
+      return true;
+    }
+  }
+
+  if (const auto *VecTy = ReturnType->getAs<VectorType>())
+    ReturnType = VecTy->getElementType();
+  ReturnType = S.Context.getExtVectorType(ReturnType, 4);
+
+  TheCall->setType(ReturnType);
+
+  return false;
+}
 static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
   unsigned MinArgs, MaxArgs;
   if (Kind == SampleKind::Sample) {
@@ -3352,32 +3467,13 @@ static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
   if (S.checkArgCountRange(TheCall, MinArgs, MaxArgs))
     return true;
 
-  // Check the texture handle.
-  if (CheckResourceHandle(&S, TheCall, 0,
-                          [](const HLSLAttributedResourceType *ResType) {
-                            return ResType->getAttrs().ResourceDimension ==
-                                   llvm::dxil::ResourceDimension::Unknown;
-                          }))
-    return true;
-
-  // Check the sampler handle.
-  if (CheckResourceHandle(&S, TheCall, 1,
-                          [](const HLSLAttributedResourceType *ResType) {
-                            return ResType->getAttrs().ResourceClass !=
-                                   llvm::hlsl::ResourceClass::Sampler;
-                          }))
+  if (CheckTextureSamplerAndLocation(S, TheCall))
     return true;
 
-  auto *ResourceTy =
+  const HLSLAttributedResourceType *ResourceTy =
       TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
-
-  // Check the location.
   unsigned ExpectedDim =
       getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
-  if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
-                              S.Context.FloatTy, ExpectedDim,
-                              TheCall->getBeginLoc()))
-    return true;
 
   unsigned NextIdx = 3;
   if (Kind == SampleKind::Bias || Kind == SampleKind::Level ||
@@ -3577,6 +3673,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
     return CheckSamplingBuiltin(SemaRef, TheCall, SampleKind::Cmp);
   case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero:
     return CheckSamplingBuiltin(SemaRef, TheCall, SampleKind::CmpLevelZero);
+  case Builtin::BI__builtin_hlsl_resource_gather:
+    return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/false);
+  case Builtin::BI__builtin_hlsl_resource_gather_cmp:
+    return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/true);
   case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
     assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
     // Update return type to be the attributed resource type from arg0.

diff  --git a/clang/test/AST/HLSL/Texture2D-AST.hlsl b/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
similarity index 58%
rename from clang/test/AST/HLSL/Texture2D-AST.hlsl
rename to clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
index abdf0a8b35ab7..8725bcc05882a 100644
--- a/clang/test/AST/HLSL/Texture2D-AST.hlsl
+++ b/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
@@ -415,7 +415,289 @@
 // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
 // CHECK-NEXT: AlwaysInlineAttr
 
-Texture2D<float4> t;
+// CHECK: CXXMethodDecl {{.*}} Gather 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Gather 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherRed 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherRed 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherGreen 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherGreen 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherBlue 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherBlue 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherAlpha 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherAlpha 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmp 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmp 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpRed 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpGreen 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpBlue 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpAlpha 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+Texture2D<float> t;
 SamplerState s;
 SamplerComparisonState scs;
 
@@ -436,4 +718,5 @@ void main(float2 loc, float cmp) {
   t.SampleCmp(scs, loc, cmp, int2(1, 2), 1.0f);
   t.SampleCmpLevelZero(scs, loc, cmp);
   t.SampleCmpLevelZero(scs, loc, cmp, int2(1, 2));
+  t.Gather(s, loc);
 }

diff  --git a/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl b/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
new file mode 100644
index 0000000000000..4e1c41f05232e
--- /dev/null
+++ b/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
@@ -0,0 +1,726 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -disable-llvm-passes -finclude-default-header -o - %s | FileCheck %s
+
+// CHECK: CXXRecordDecl {{.*}} SamplerState definition
+// CHECK: FinalAttr {{.*}} Implicit final
+// CHECK-NEXT: FieldDecl {{.*}} implicit {{.*}} __handle '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+
+// CHECK: CXXRecordDecl {{.*}} SamplerComparisonState definition
+// CHECK: FinalAttr {{.*}} Implicit final
+// CHECK-NEXT: FieldDecl {{.*}} implicit {{.*}} __handle '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+
+// CHECK: ClassTemplateDecl {{.*}} Texture2D
+// CHECK: TemplateTypeParmDecl {{.*}} element_type
+// CHECK: CXXRecordDecl {{.*}} Texture2D
+// CHECK: FinalAttr {{.*}} Implicit final
+// CHECK: ClassTemplatePartialSpecializationDecl {{.*}} Texture2D definition explicit_specialization
+// CHECK: TemplateArgument type 'vector<element_type, element_count>':'vector<type-parameter-0-0, element_count>'
+// CHECK: TemplateTypeParmDecl {{.*}} element_type
+// CHECK: NonTypeTemplateParmDecl {{.*}} element_count
+// CHECK-NEXT: FieldDecl {{.*}} implicit __handle '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+
+// CHECK: CXXMethodDecl {{.*}} Sample 'vector<element_type (hlsl::SamplerState, vector<float, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Sample 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Sample 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>, float), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Clamp 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Clamp' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleBias 'vector<element_type (hlsl::SamplerState, vector<float, 2>, float), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Bias 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_bias' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Bias' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleBias 'vector<element_type (hlsl::SamplerState, vector<float, 2>, float, vector<int, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Bias 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_bias' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Bias' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleBias 'vector<element_type (hlsl::SamplerState, vector<float, 2>, float, vector<int, 2>, float), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Bias 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Clamp 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_bias' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Bias' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Clamp' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleGrad 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<float, 2>, vector<float, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDX 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDY 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_grad' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDX' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDY' 'vector<float, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleGrad 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<float, 2>, vector<float, 2>, vector<int, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDX 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDY 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_grad' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDX' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDY' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleGrad 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<float, 2>, vector<float, 2>, vector<int, 2>, float), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDX 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} DDY 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Clamp 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_grad' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDX' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'DDY' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Clamp' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleLevel 'vector<element_type (hlsl::SamplerState, vector<float, 2>, float), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} LOD 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_level' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'LOD' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleLevel 'vector<element_type (hlsl::SamplerState, vector<float, 2>, float, vector<int, 2>), element_count>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} LOD 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, element_count>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_level' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'LOD' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleCmp 'float (hlsl::SamplerComparisonState, vector<float, 2>, float)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'float' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleCmp 'float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'float' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleCmp 'float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>, float)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Clamp 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'float' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'Clamp' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleCmpLevelZero 'float (hlsl::SamplerComparisonState, vector<float, 2>, float)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'float' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_cmp_level_zero' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} SampleCmpLevelZero 'float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'float' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_sample_cmp_level_zero' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, element_count>)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<vector<element_type, element_count>>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Gather 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Gather 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherRed 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherRed 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherGreen 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherGreen 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherBlue 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherBlue 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherAlpha 'vector<element_type (hlsl::SamplerState, vector<float, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherAlpha 'vector<element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<element_type, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmp 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmp 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpRed 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpGreen 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpBlue 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} GatherCmpAlpha 'vector<float (hlsl::SamplerComparisonState, vector<float, 2>, float, vector<int, 2>), 4>' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'
+// CHECK-NEXT: ParmVarDecl {{.*}} CompareValue 'float'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'vector<float, 4>' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_gather_cmp' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<{{.*}}>' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::SamplerComparisonState' lvalue ParmVar {{.*}} 'Sampler' 'hlsl::SamplerComparisonState'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>' lvalue ParmVar {{.*}} 'Location' 'vector<float, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'CompareValue' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+Texture2D<float4> t;
+SamplerState s;
+SamplerComparisonState scs;
+
+void main(float2 loc, float cmp) {
+  t.Sample(s, loc);
+  t.Sample(s, loc, int2(1, 2));
+  t.Sample(s, loc, int2(1, 2), 1.0);
+  t.SampleBias(s, loc, 0.0);
+  t.SampleBias(s, loc, 0.0, int2(1, 2));
+  t.SampleBias(s, loc, 0.0, int2(1, 2), 1.0);
+  t.SampleGrad(s, loc, float2(0,0), float2(0,0));
+  t.SampleGrad(s, loc, float2(0,0), float2(0,0), int2(1, 2));
+  t.SampleGrad(s, loc, float2(0,0), float2(0,0), int2(1, 2), 1.0);
+  t.SampleLevel(s, loc, 0.0);
+  t.SampleLevel(s, loc, 0.0, int2(1, 2));
+  t.SampleCmp(scs, loc, cmp);
+  t.SampleCmp(scs, loc, cmp, int2(1, 2));
+  t.SampleCmp(scs, loc, cmp, int2(1, 2), 1.0f);
+  t.SampleCmpLevelZero(scs, loc, cmp);
+  t.SampleCmpLevelZero(scs, loc, cmp, int2(1, 2));
+  t.Gather(s, loc);
+}

diff  --git a/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl
new file mode 100644
index 0000000000000..54d428285d88c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl
@@ -0,0 +1,183 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL
+// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV
+
+// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) }
+// DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) }
+// DXIL: %"class.hlsl::SamplerComparisonState" = type { target("dx.Sampler", 0) }
+
+// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) }
+// SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") }
+// SPIRV: %"class.hlsl::SamplerComparisonState" = type { target("spirv.Sampler") }
+
+Texture2D<float4> t;
+SamplerState s;
+SamplerComparisonState sc;
+
+// CHECK: define hidden {{.*}} <4 x float> @main(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Gather(hlsl::SamplerState, float vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 main(float2 loc : LOC) : SV_Target {
+  return t.Gather(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Gather(hlsl::SamplerState, float vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_offset(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Gather(hlsl::SamplerState, float vector[2], int vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>)
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_offset(float2 loc : LOC) : SV_Target {
+  return t.Gather(s, loc, int2(1, 2));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Gather(hlsl::SamplerState, float vector[2], int vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: %[[OFFSET_ADDR:.*]] = alloca <2 x i32>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: store <2 x i32> %[[OFFSET]], ptr %[[OFFSET_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// CHECK: %[[OFFSET_VAL:.*]] = load <2 x i32>, ptr %[[OFFSET_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> %[[OFFSET_VAL]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> %[[OFFSET_VAL]])
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_green(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherGreen(hlsl::SamplerState, float vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_green(float2 loc : LOC) : SV_Target {
+  return t.GatherGreen(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherGreen(hlsl::SamplerState, float vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 1, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 1, <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_red(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherRed(hlsl::SamplerState, float vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_red(float2 loc : LOC) : SV_Target {
+  return t.GatherRed(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherRed(hlsl::SamplerState, float vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 0, <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_blue(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherBlue(hlsl::SamplerState, float vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_blue(float2 loc : LOC) : SV_Target {
+  return t.GatherBlue(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherBlue(hlsl::SamplerState, float vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 2, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 2, <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_alpha(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherAlpha(hlsl::SamplerState, float vector[2])(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_alpha(float2 loc : LOC) : SV_Target {
+  return t.GatherAlpha(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherAlpha(hlsl::SamplerState, float vector[2])(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 3, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], i32 3, <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_cmp(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherCmp(hlsl::SamplerComparisonState, float vector[2], float)(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerComparisonState") {{.*}}, <2 x float> {{.*}} %{{.*}}, float {{.*}} 5.000000e-01)
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_cmp(float2 loc : LOC) : SV_Target {
+  return t.GatherCmp(sc, loc, 0.5);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::GatherCmp(hlsl::SamplerComparisonState, float vector[2], float)(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerComparisonState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], float {{.*}} %[[CMP:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: %[[CMP_ADDR:.*]] = alloca float
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <2 x float> %[[COORD]], ptr %[[COORD_ADDR]]
+// CHECK: store float %[[CMP]], ptr %[[CMP_ADDR]]
+// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::Texture2D", ptr %[[THIS_VAL]], i32 0, i32 0
+// CHECK: %[[HANDLE:.*]] = load target{{.*}}, ptr %[[HANDLE_GEP]]
+// CHECK: %[[SAMPLER_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::SamplerComparisonState", ptr %[[SAMPLER]], i32 0, i32 0
+// CHECK: %[[SAMPLER_H:.*]] = load target{{.*}}, ptr %[[SAMPLER_GEP]]
+// CHECK: %[[COORD_VAL:.*]] = load <2 x float>, ptr %[[COORD_ADDR]]
+// CHECK: %[[CMP_VAL:.*]] = load float, ptr %[[CMP_ADDR]]
+// CHECK: %[[CONV:.*]] = fpext {{.*}} float %[[CMP_VAL]] to double
+// CHECK: %[[TRUNC:.*]] = fptrunc {{.*}} double %[[CONV]] to float
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.gather.cmp.v4f32.tdx.Texture_v4f32_0_0_0_2t.tdx.Sampler_0t.v2f32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], target("dx.Sampler", 0) %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], float %[[TRUNC]], i32 0, <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.gather.cmp.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.tspirv.Samplert.v2f32.v2i32(target("spirv.Image", float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], target("spirv.Sampler") %[[SAMPLER_H]], <2 x float> %[[COORD_VAL]], float %[[TRUNC]], <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]

diff  --git a/clang/test/SemaHLSL/Texture2D-Gather.hlsl b/clang/test/SemaHLSL/Texture2D-Gather.hlsl
new file mode 100644
index 0000000000000..61b3c28a49e73
--- /dev/null
+++ b/clang/test/SemaHLSL/Texture2D-Gather.hlsl
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -verify -finclude-default-header %s
+
+Texture2D<float4> Tex;
+SamplerState Samp;
+SamplerComparisonState SampCmp;
+
+void main() {
+  float2 uv = float2(0.5, 0.5);
+  int2 offset = int2(1, 1);
+  float compare = 0.5;
+
+  // Gather
+  // Expected: Gather(SamplerState, float2, [int2])
+  Tex.Gather(Samp, uv);
+  Tex.Gather(Samp, uv, offset);
+
+  // Invalid Overloads
+  Tex.Gather(Samp); // expected-error {{no matching member function for call to 'Gather'}}
+  Tex.Gather(Samp, uv, offset, 1); // expected-error {{no matching member function for call to 'Gather'}}
+  
+  // Gather variants
+  Tex.GatherRed(Samp, uv);
+  Tex.GatherGreen(Samp, uv, offset);
+  Tex.GatherBlue(Samp, uv);
+  Tex.GatherAlpha(Samp, uv, offset);
+
+  // GatherCmp
+  // Expected: GatherCmp(SamplerComparisonState, float2, float, [int2])
+  Tex.GatherCmp(SampCmp, uv, compare);
+  Tex.GatherCmp(SampCmp, uv, compare, offset);
+
+  // Invalid Overloads
+  Tex.GatherCmp(SampCmp, uv); // expected-error {{no matching member function for call to 'GatherCmp'}}
+  Tex.GatherCmp(SampCmp, uv, compare, offset, 1); // expected-error {{no matching member function for call to 'GatherCmp'}}
+
+  // GatherCmp variants
+  Tex.GatherCmpRed(SampCmp, uv, compare);
+  Tex.GatherCmpGreen(SampCmp, uv, compare);
+  Tex.GatherCmpBlue(SampCmp, uv, compare, offset);
+  Tex.GatherCmpAlpha(SampCmp, uv, compare);
+  
+  // Type checks
+  // Offset must be int2 (SamplerState fails)
+  Tex.Gather(Samp, uv, Samp); // expected-error {{no matching member function for call to 'Gather'}}
+  
+  // Compare value must be scalar float
+  Tex.GatherCmp(SampCmp, uv, Samp); // expected-error {{no matching member function for call to 'GatherCmp'}}
+}
+
+// expected-note@* 0+{{candidate function not viable}}

diff  --git a/clang/test/SemaHLSL/Texture2D-GatherCmp-Vulkan.hlsl b/clang/test/SemaHLSL/Texture2D-GatherCmp-Vulkan.hlsl
new file mode 100644
index 0000000000000..117686b4ef9ce
--- /dev/null
+++ b/clang/test/SemaHLSL/Texture2D-GatherCmp-Vulkan.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -fsyntax-only -verify -finclude-default-header %s
+
+Texture2D<float4> Tex;
+SamplerComparisonState SampCmp;
+
+void main() {
+  float2 uv = float2(0.5, 0.5);
+  float compare = 0.5;
+
+  Tex.GatherCmp(SampCmp, uv, compare);
+  Tex.GatherCmpRed(SampCmp, uv, compare);
+  
+  // expected-error@* {{gatherCmpGreen operations on the Vulkan target are not supported; only GatherCmp and GatherCmpRed are allowed}}
+  Tex.GatherCmpGreen(SampCmp, uv, compare);
+  
+  // expected-error@* {{gatherCmpBlue operations on the Vulkan target are not supported; only GatherCmp and GatherCmpRed are allowed}}
+  Tex.GatherCmpBlue(SampCmp, uv, compare);
+  
+  // expected-error@* {{gatherCmpAlpha operations on the Vulkan target are not supported; only GatherCmp and GatherCmpRed are allowed}}
+  Tex.GatherCmpAlpha(SampCmp, uv, compare);
+}
+
+// expected-note@* 0+{{in instantiation of member function}}

diff  --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 6774a33556c09..e2b2feb927318 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -138,6 +138,18 @@ def int_dx_resource_samplecmplevelzero
                              llvm_float_ty, llvm_any_ty],
                             [IntrReadMem]>;
 
+def int_dx_resource_gather
+    : DefaultAttrsIntrinsic<[llvm_any_ty],
+                            [llvm_any_ty, llvm_any_ty, llvm_any_ty,
+                             llvm_i32_ty, llvm_any_ty],
+                            [IntrReadMem]>;
+
+def int_dx_resource_gather_cmp
+    : DefaultAttrsIntrinsic<[llvm_any_ty],
+                            [llvm_any_ty, llvm_any_ty, llvm_any_ty,
+                             llvm_float_ty, llvm_i32_ty, llvm_any_ty],
+                            [IntrReadMem]>;
+
 // Cast between target extension handle types and dxil-style opaque handles
 def int_dx_resource_casthandle : Intrinsic<[llvm_any_ty], [llvm_any_ty]>;
 


        


More information about the cfe-commits mailing list