Author: Steven Perron
Date: 2026-03-12T07:08:26-04:00
New Revision: f3752dcb60fc89d1af7533b9faaa4c53eb1d2118

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

LOG: [HLSL] Implement Texture2D::Load methods and builtin (#185708)

Implements the Textur2D::Load methods. A new HLSL buildin is added to
implement the method. The HLSL builtin is lowered to the
resource_load_level intrinsic.

We chose to have have a single operand hold both the coordinate and the
level in the builtin, as is done in the Load method itself. This was to
make the external sema source easier. It is easier to split the vector
during codegen than in sema.

Assisted-by: Gemini

Added: 
    clang/test/CodeGenHLSL/resources/Texture2D-Load.hlsl
    clang/test/SemaHLSL/Texture2D-Load-errors.hlsl

Modified: 
    clang/include/clang/Basic/Builtins.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
    clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
    clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
    clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
    clang/test/AST/HLSL/TypedBuffers-AST.hlsl

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index dd5bd689c08d2..4805c93eef2bf 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5036,6 +5036,12 @@ def HLSLResourceLoadWithStatusTyped : 
LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLResourceLoadLevel : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_load_level"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 def HLSLResourceSample : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_resource_sample"];
   let Attributes = [NoThrow];

diff  --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp 
b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index a5db9d8562662..677f33eb938a7 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -449,16 +449,18 @@ static std::string 
getSpecConstantFunctionName(clang::QualType SpecConstantType,
   return Name;
 }
 
+static llvm::Type *getOffsetType(CodeGenModule &CGM, llvm::Type *CoordTy) {
+  llvm::Type *Int32Ty = CGM.Int32Ty;
+  if (auto *VT = dyn_cast<llvm::FixedVectorType>(CoordTy))
+    return llvm::FixedVectorType::get(Int32Ty, VT->getNumElements());
+  return Int32Ty;
+}
+
 static Value *emitHlslOffset(CodeGenFunction &CGF, const CallExpr *E,
-                             unsigned OffsetArgIndex) {
+                             unsigned OffsetArgIndex, llvm::Type *OffsetTy) {
   if (E->getNumArgs() > OffsetArgIndex)
     return CGF.EmitScalarExpr(E->getArg(OffsetArgIndex));
 
-  llvm::Type *CoordTy = CGF.ConvertType(E->getArg(2)->getType());
-  llvm::Type *Int32Ty = CGF.Int32Ty;
-  llvm::Type *OffsetTy = Int32Ty;
-  if (auto *VT = dyn_cast<llvm::FixedVectorType>(CoordTy))
-    OffsetTy = llvm::FixedVectorType::get(Int32Ty, VT->getNumElements());
   return llvm::Constant::getNullValue(OffsetTy);
 }
 
@@ -554,7 +556,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(HandleOp);
     Args.push_back(SamplerOp);
     Args.push_back(CoordOp);
-    Args.push_back(emitHlslOffset(*this, E, 3));
+    Args.push_back(
+        emitHlslOffset(*this, E, 3, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     if (E->getNumArgs() <= 4) {
@@ -579,7 +582,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(SamplerOp);
     Args.push_back(CoordOp);
     Args.push_back(BiasOp);
-    Args.push_back(emitHlslOffset(*this, E, 4));
+    Args.push_back(
+        emitHlslOffset(*this, E, 4, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     if (E->getNumArgs() <= 5)
@@ -603,7 +607,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(CoordOp);
     Args.push_back(DDXOp);
     Args.push_back(DDYOp);
-    Args.push_back(emitHlslOffset(*this, E, 5));
+    Args.push_back(
+        emitHlslOffset(*this, E, 5, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
 
@@ -629,12 +634,42 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(SamplerOp);
     Args.push_back(CoordOp);
     Args.push_back(LODOp);
-    Args.push_back(emitHlslOffset(*this, E, 4));
+    Args.push_back(
+        emitHlslOffset(*this, E, 4, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     return Builder.CreateIntrinsic(
         RetTy, CGM.getHLSLRuntime().getSampleLevelIntrinsic(), Args);
   }
+  case Builtin::BI__builtin_hlsl_resource_load_level: {
+    Value *HandleOp = EmitScalarExpr(E->getArg(0));
+    Value *CoordLODOp = EmitScalarExpr(E->getArg(1));
+
+    auto *CoordLODVecTy = cast<llvm::FixedVectorType>(CoordLODOp->getType());
+    unsigned NumElts = CoordLODVecTy->getNumElements();
+    assert(NumElts >= 2 && "CoordLOD must have at least 2 elements");
+
+    // Split CoordLOD into Coord and LOD
+    SmallVector<int, 4> Mask;
+    for (unsigned I = 0; I < NumElts - 1; ++I)
+      Mask.push_back(I);
+
+    Value *CoordOp =
+        Builder.CreateShuffleVector(CoordLODOp, Mask, "hlsl.load.coord");
+    Value *LODOp =
+        Builder.CreateExtractElement(CoordLODOp, NumElts - 1, "hlsl.load.lod");
+
+    SmallVector<Value *, 4> Args;
+    Args.push_back(HandleOp);
+    Args.push_back(CoordOp);
+    Args.push_back(LODOp);
+    Args.push_back(
+        emitHlslOffset(*this, E, 2, getOffsetType(CGM, CoordOp->getType())));
+
+    llvm::Type *RetTy = ConvertType(E->getType());
+    return Builder.CreateIntrinsic(
+        RetTy, CGM.getHLSLRuntime().getLoadLevelIntrinsic(), Args);
+  }
   case Builtin::BI__builtin_hlsl_resource_sample_cmp: {
     Value *HandleOp = EmitScalarExpr(E->getArg(0));
     Value *SamplerOp = EmitScalarExpr(E->getArg(1));
@@ -648,7 +683,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(SamplerOp);
     Args.push_back(CoordOp);
     Args.push_back(CmpOp);
-    Args.push_back(emitHlslOffset(*this, E, 4));
+    Args.push_back(
+        emitHlslOffset(*this, E, 4, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     if (E->getNumArgs() <= 5) {
@@ -674,7 +710,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(CoordOp);
     Args.push_back(CmpOp);
 
-    Args.push_back(emitHlslOffset(*this, E, 4));
+    Args.push_back(
+        emitHlslOffset(*this, E, 4, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     return Builder.CreateIntrinsic(
@@ -694,7 +731,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     Args.push_back(SamplerOp);
     Args.push_back(CoordOp);
     Args.push_back(ComponentOp);
-    Args.push_back(emitHlslOffset(*this, E, 4));
+    Args.push_back(
+        emitHlslOffset(*this, E, 4, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     return Builder.CreateIntrinsic(
@@ -722,7 +760,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
       Args.push_back(ComponentOp);
     }
 
-    Args.push_back(emitHlslOffset(*this, E, 5));
+    Args.push_back(
+        emitHlslOffset(*this, E, 5, getOffsetType(CGM, CoordOp->getType())));
 
     llvm::Type *RetTy = ConvertType(E->getType());
     return Builder.CreateIntrinsic(

diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 4d3e089ca7140..10b72f450dd2c 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -188,6 +188,7 @@ class CGHLSLRuntime {
   GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,
                                    group_memory_barrier_with_group_sync)
   GENERATE_HLSL_INTRINSIC_FUNCTION(GetDimensionsX, resource_getdimensions_x)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(LoadLevel, resource_load_level)
   GENERATE_HLSL_INTRINSIC_FUNCTION(DdxCoarse, ddx_coarse)
   GENERATE_HLSL_INTRINSIC_FUNCTION(DdyCoarse, ddy_coarse)
   GENERATE_HLSL_INTRINSIC_FUNCTION(DdxFine, ddx_fine)

diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index f9f57824bb48c..708b06bc1d03a 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1256,6 +1256,34 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addLoadMethods() {
   return *this;
 }
 
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addTextureLoadMethods(ResourceDimension Dim) {
+  assert(!Record->isCompleteDefinition() && "record is already complete");
+  ASTContext &AST = Record->getASTContext();
+  uint32_t VecSize = getResourceDimensions(Dim);
+  QualType IntTy = AST.IntTy;
+  QualType OffsetTy = AST.getExtVectorType(IntTy, VecSize);
+  QualType LocationTy = AST.getExtVectorType(IntTy, VecSize + 1);
+  QualType ReturnType = getHandleElementType();
+
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+  // T Load(int3 location)
+  BuiltinTypeMethodBuilder(*this, "Load", ReturnType)
+      .addParam("Location", LocationTy)
+      .callBuiltin("__builtin_hlsl_resource_load_level", ReturnType, 
PH::Handle,
+                   PH::_0)
+      .finalize();
+
+  // T Load(int3 location, int2 offset)
+  return BuiltinTypeMethodBuilder(*this, "Load", ReturnType)
+      .addParam("Location", LocationTy)
+      .addParam("Offset", OffsetTy)
+      .callBuiltin("__builtin_hlsl_resource_load_level", ReturnType, 
PH::Handle,
+                   PH::_0, PH::_1)
+      .finalize();
+}
+
 BuiltinTypeDeclBuilder &
 BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
   assert(!Record->isCompleteDefinition() && "record is already complete");

diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 6e68c1f33d723..5a0b9a02defdb 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -95,6 +95,7 @@ class BuiltinTypeDeclBuilder {
 
   // Builtin types methods
   BuiltinTypeDeclBuilder &addLoadMethods();
+  BuiltinTypeDeclBuilder &addTextureLoadMethods(ResourceDimension Dim);
   BuiltinTypeDeclBuilder &addByteAddressBufferLoadMethods();
   BuiltinTypeDeclBuilder &addByteAddressBufferStoreMethods();
   BuiltinTypeDeclBuilder &addSampleMethods(ResourceDimension Dim);

diff  --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp 
b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index bb86ef4e063e8..e2267ac503b73 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -258,6 +258,7 @@ static BuiltinTypeDeclBuilder 
setupTextureType(CXXRecordDecl *Decl, Sema &S,
                                                ResourceDimension Dim) {
   return BuiltinTypeDeclBuilder(S, Decl)
       .addTextureHandle(RC, IsROV, Dim)
+      .addTextureLoadMethods(Dim)
       .addDefaultHandleConstructor()
       .addCopyConstructor()
       .addCopyAssignmentOperator()

diff  --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 413c602febf51..e200c595ab2c2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3507,6 +3507,50 @@ static bool CheckGatherBuiltin(Sema &S, CallExpr 
*TheCall, bool IsCmp) {
 
   return false;
 }
+static bool CheckLoadLevelBuiltin(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountRange(TheCall, 2, 3))
+    return true;
+
+  // Check the texture handle.
+  if (CheckResourceHandle(&S, TheCall, 0,
+                          [](const HLSLAttributedResourceType *ResType) {
+                            return ResType->getAttrs().ResourceDimension ==
+                                   llvm::dxil::ResourceDimension::Unknown;
+                          }))
+    return true;
+
+  auto *ResourceTy =
+      TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+
+  // Check the location + lod (int3 for Texture2D).
+  unsigned ExpectedDim =
+      getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
+  QualType CoordLODTy = TheCall->getArg(1)->getType();
+  if (CheckVectorElementCount(&S, CoordLODTy, S.Context.IntTy, ExpectedDim + 1,
+                              TheCall->getArg(1)->getBeginLoc()))
+    return true;
+
+  QualType EltTy = CoordLODTy;
+  if (const auto *VTy = EltTy->getAs<VectorType>())
+    EltTy = VTy->getElementType();
+  if (!EltTy->isIntegerType()) {
+    S.Diag(TheCall->getArg(1)->getBeginLoc(), diag::err_typecheck_expect_int)
+        << CoordLODTy;
+    return true;
+  }
+
+  // Check the offset operand.
+  if (TheCall->getNumArgs() > 2) {
+    if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
+                                S.Context.IntTy, ExpectedDim,
+                                TheCall->getArg(2)->getBeginLoc()))
+      return true;
+  }
+
+  TheCall->setType(ResourceTy->getContainedType());
+  return false;
+}
+
 static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
   unsigned MinArgs, MaxArgs;
   if (Kind == SampleKind::Sample) {
@@ -3727,6 +3771,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned 
BuiltinID, CallExpr *TheCall) {
 
     break;
   }
+  case Builtin::BI__builtin_hlsl_resource_load_level:
+    return CheckLoadLevelBuiltin(SemaRef, TheCall);
   case Builtin::BI__builtin_hlsl_resource_sample:
     return CheckSamplingBuiltin(SemaRef, TheCall, SampleKind::Sample);
   case Builtin::BI__builtin_hlsl_resource_sample_bias:

diff  --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl 
b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index c6411ccf77075..7ab03bcf8fac1 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -288,7 +288,7 @@ RESOURCE<float> Buffer;
 // CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} 'unsigned int' lvalue ParmVar 
{{.*}} 'Index' 'unsigned int'
 // CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
-// CHECK-SUBSCRIPT-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device 
element_type &(unsigned int)'
+// CHECK-SUBSCRIPT-UAV: CXXMethodDecl {{.*}} operator[] 'hlsl_device 
element_type &(unsigned int)'
 // CHECK-SUBSCRIPT-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
 // CHECK-SUBSCRIPT-UAV-NEXT: CompoundStmt
 // CHECK-SUBSCRIPT-UAV-NEXT: ReturnStmt
@@ -364,7 +364,7 @@ RESOURCE<float> Buffer;
 
 // DecrementCounter method
 
-// CHECK-COUNTER-NEXT: CXXMethodDecl {{.*}} DecrementCounter 'unsigned int ()'
+// CHECK-COUNTER: CXXMethodDecl {{.*}} DecrementCounter 'unsigned int ()'
 // CHECK-COUNTER-NEXT: CompoundStmt
 // CHECK-COUNTER-NEXT: ReturnStmt
 // CHECK-COUNTER-NEXT: CStyleCastExpr {{.*}} 'unsigned int'

diff  --git a/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl 
b/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
index 921c92da5cb2b..a1d0341681df5 100644
--- a/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
+++ b/clang/test/AST/HLSL/Texture2D-scalar-AST.hlsl
@@ -19,6 +19,40 @@
 // CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
 // CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
 
+// CHECK: CXXMethodDecl {{.*}} Load 'element_type (vector<int, 3>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<int, 3>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'element_type' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} 
'__builtin_hlsl_resource_load_level' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<element_type>' lvalue 
implicit this
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 3>' lvalue ParmVar {{.*}} 
'Location' 'vector<int, 3>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Load 'element_type (vector<int, 3>, vector<int, 
2>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<int, 3>'
+// CHECK-NEXT: ParmVarDecl {{.*}} Offset 'vector<int, 2>'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'element_type' <Dependent>
+// CHECK-NEXT: CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} 
'__builtin_hlsl_resource_load_level' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
+// CHECK-SAME: ' lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::Texture2D<element_type>' lvalue 
implicit this
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 3>' lvalue ParmVar {{.*}} 
'Location' 'vector<int, 3>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 
'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
 // CHECK: CXXMethodDecl {{.*}} Sample 'element_type (hlsl::SamplerState, 
vector<float, 2>)'
 // CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
 // CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'

diff  --git a/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl 
b/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
index 0e056009c1a38..097232a50ceb9 100644
--- a/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
+++ b/clang/test/AST/HLSL/Texture2D-vector-AST.hlsl
@@ -23,6 +23,40 @@
 // CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<element_type, 
element_count>)]]
 // CHECK-SAME{LITERAL}: [[hlsl::resource_dimension(2D)]]
 
+// CHECK: CXXMethodDecl {{.*}} Load 'vector<element_type, element_count> 
(vector<int, 3>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<int, 3>'
+// 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_load_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: DeclRefExpr {{.*}} 'vector<int, 3>' lvalue ParmVar {{.*}} 
'Location' 'vector<int, 3>'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// CHECK: CXXMethodDecl {{.*}} Load 'vector<element_type, element_count> 
(vector<int, 3>, vector<int, 2>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<int, 3>'
+// 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_load_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: DeclRefExpr {{.*}} 'vector<int, 3>' lvalue ParmVar {{.*}} 
'Location' 'vector<int, 3>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>' lvalue ParmVar {{.*}} 
'Offset' 'vector<int, 2>'
+// CHECK-NEXT: AlwaysInlineAttr
+
 // CHECK: CXXMethodDecl {{.*}} Sample 'vector<element_type, element_count> 
(hlsl::SamplerState, vector<float, 2>)'
 // CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
 // CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 2>'

diff  --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl 
b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index c2144d230887b..035c4e59844da 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -179,7 +179,7 @@ RESOURCE<float> Buffer;
 // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' lvalue ParmVar {{.*}}  
'Index' 'unsigned int'
 // CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
-// CHECK-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type 
&(unsigned int)'
+// CHECK-UAV: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type 
&(unsigned int)'
 // CHECK-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
 // CHECK-UAV-NEXT: CompoundStmt
 // CHECK-UAV-NEXT: ReturnStmt
@@ -197,7 +197,7 @@ RESOURCE<float> Buffer;
 
 // Load method
 
-// CHECK-NEXT: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)'
+// CHECK: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)'
 // CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
 // CHECK-NEXT: CompoundStmt
 // CHECK-NEXT: ReturnStmt
@@ -235,7 +235,7 @@ RESOURCE<float> Buffer;
 
 // GetDimensions method
 
-// CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
+// CHECK: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
 // CHECK-NEXT: ParmVarDecl {{.*}} dim 'unsigned int &__restrict'
 // CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
 // CHECK-NEXT: CompoundStmt

diff  --git a/clang/test/CodeGenHLSL/resources/Texture2D-Load.hlsl 
b/clang/test/CodeGenHLSL/resources/Texture2D-Load.hlsl
new file mode 100644
index 0000000000000..7c30a211149e7
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/Texture2D-Load.hlsl
@@ -0,0 +1,238 @@
+// 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
+
+Texture2D<float4> t;
+
+// CHECK: define hidden {{.*}} <4 x float> @test_load(int vector[2])
+// CHECK: %[[COORD:.*]] = insertelement <3 x i32> {{.*}}, i32 0, i32 2
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float 
vector[4]>::Load(int vector[3])(ptr {{.*}} @t, <3 x i32> noundef %[[COORD]])
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_load(int2 loc : LOC) : SV_Target {
+  return t.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float 
vector[4]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[LOCATION_ADDR:.*]] = alloca <3 x i32>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <3 x i32> %[[LOCATION]], ptr %[[LOCATION_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("{{(dx.Texture|spirv.Image)}}", 
{{.*}}), ptr %[[HANDLE_GEP]]
+// CHECK: %[[LOCATION_VAL:.*]] = load <3 x i32>, ptr %[[LOCATION_ADDR]]
+// CHECK: %[[COORD:.*]] = shufflevector <3 x i32> %[[LOCATION_VAL]], <3 x i32> 
poison, <2 x i32> <i32 0, i32 1>
+// CHECK: %[[LOD:.*]] = extractelement <3 x i32> %[[LOCATION_VAL]], i64 2
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> 
@llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <4 x float>, 0, 0, 0, 2) %[[HANDLE]], <2 x i32> %[[COORD]], i32 %[[LOD]], <2 x 
i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> 
@llvm.spv.resource.load.level.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], <2 x i32> %[[COORD]], i32 %[[LOD]], <2 x 
i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @test_load_offset(int vector[2])
+// CHECK: %[[COORD:.*]] = insertelement <3 x i32> {{.*}}, i32 0, i32 2
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float 
vector[4]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t, <3 x i32> noundef 
%[[COORD]], <2 x i32> noundef splat (i32 1))
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_load_offset(int2 loc : LOC) : SV_Target {
+  return t.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float 
vector[4]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[LOCATION_ADDR:.*]] = alloca <3 x i32>
+// CHECK: %[[OFFSET_ADDR:.*]] = alloca <2 x i32>
+// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
+// CHECK: store <3 x i32> %[[LOCATION]], ptr %[[LOCATION_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("{{(dx.Texture|spirv.Image)}}", 
{{.*}}), ptr %[[HANDLE_GEP]]
+// CHECK: %[[LOCATION_VAL:.*]] = load <3 x i32>, ptr %[[LOCATION_ADDR]]
+// CHECK: %[[COORD:.*]] = shufflevector <3 x i32> %[[LOCATION_VAL]], <3 x i32> 
poison, <2 x i32> <i32 0, i32 1>
+// CHECK: %[[LOD:.*]] = extractelement <3 x i32> %[[LOCATION_VAL]], i64 2
+// CHECK: %[[OFFSET_VAL:.*]] = load <2 x i32>, ptr %[[OFFSET_ADDR]]
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> 
@llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <4 x float>, 0, 0, 0, 2) %[[HANDLE]], <2 x i32> %[[COORD]], i32 %[[LOD]], <2 x 
i32> %[[OFFSET_VAL]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> 
@llvm.spv.resource.load.level.v4f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %[[HANDLE]], <2 x i32> %[[COORD]], i32 %[[LOD]], <2 x 
i32> %[[OFFSET_VAL]])
+// CHECK: ret <4 x float> %[[RES]]
+
+
+// For the rest of the types, we just check that the call to the member
+// function has the correct return type.
+
+Texture2D<float> t_float;
+
+// CHECK: define hidden {{.*}} float @test_load_float(int vector[2])
+// CHECK: define linkonce_odr hidden {{.*}} float 
@hlsl::Texture2D<float>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> 
{{.*}} %[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} float 
@llvm.dx.resource.load.level.f32.tdx.Texture_f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 float, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} float 
@llvm.spv.resource.load.level.f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret float %[[RES]]
+float test_load_float(int2 loc : LOC) {
+  return t_float.Load(int3(loc, 0));
+}
+
+// CHECK: define hidden {{.*}} float @test_load_offset_float(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} float @hlsl::Texture2D<float>::Load(int 
vector[3], int vector[2])(ptr {{.*}} @t_float, <3 x i32> noundef %{{.*}}, <2 x 
i32> noundef splat (i32 1))
+// CHECK: ret float %[[CALL]]
+float test_load_offset_float(int2 loc : LOC) {
+  return t_float.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} float 
@hlsl::Texture2D<float>::Load(int vector[3], int vector[2])(ptr {{.*}} 
%[[THIS:.*]], <3 x i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} 
%[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} float 
@llvm.dx.resource.load.level.f32.tdx.Texture_f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 float, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> %{{.*}})
+// SPIRV: %[[RES:.*]] = call {{.*}} float 
@llvm.spv.resource.load.level.f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret float %[[RES]]
+
+Texture2D<float2> t_float2;
+
+// CHECK: define hidden {{.*}} <2 x float> @test_load_float2(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <2 x float> @hlsl::Texture2D<float 
vector[2]>::Load(int vector[3])(ptr {{.*}} @t_float2, <3 x i32> noundef %{{.*}})
+// CHECK: ret <2 x float> %[[CALL]]
+float2 test_load_float2(int2 loc : LOC) {
+  return t_float2.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <2 x float> @hlsl::Texture2D<float 
vector[2]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} <2 x float> 
@llvm.dx.resource.load.level.v2f32.tdx.Texture_v2f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <2 x float>, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <2 x float> 
@llvm.spv.resource.load.level.v2f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret <2 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <2 x float> @test_load_offset_float2(int 
vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <2 x float> @hlsl::Texture2D<float 
vector[2]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t_float2, <3 x i32> 
noundef %{{.*}}, <2 x i32> noundef splat (i32 1))
+// CHECK: ret <2 x float> %[[CALL]]
+float2 test_load_offset_float2(int2 loc : LOC) {
+  return t_float2.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <2 x float> @hlsl::Texture2D<float 
vector[2]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} <2 x float> 
@llvm.dx.resource.load.level.v2f32.tdx.Texture_v2f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <2 x float>, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// SPIRV: %[[RES:.*]] = call {{.*}} <2 x float> 
@llvm.spv.resource.load.level.v2f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret <2 x float> %[[RES]]
+
+Texture2D<float3> t_float3;
+
+// CHECK: define hidden {{.*}} <3 x float> @test_load_float3(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <3 x float> @hlsl::Texture2D<float 
vector[3]>::Load(int vector[3])(ptr {{.*}} @t_float3, <3 x i32> noundef %{{.*}})
+// CHECK: ret <3 x float> %[[CALL]]
+float3 test_load_float3(int2 loc : LOC) {
+  return t_float3.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <3 x float> @hlsl::Texture2D<float 
vector[3]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} <3 x float> 
@llvm.dx.resource.load.level.v3f32.tdx.Texture_v3f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <3 x float>, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <3 x float> 
@llvm.spv.resource.load.level.v3f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret <3 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <3 x float> @test_load_offset_float3(int 
vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <3 x float> @hlsl::Texture2D<float 
vector[3]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t_float3, <3 x i32> 
noundef %{{.*}}, <2 x i32> noundef splat (i32 1))
+// CHECK: ret <3 x float> %[[CALL]]
+float3 test_load_offset_float3(int2 loc : LOC) {
+  return t_float3.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <3 x float> @hlsl::Texture2D<float 
vector[3]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call {{.*}} <3 x float> 
@llvm.dx.resource.load.level.v3f32.tdx.Texture_v3f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture",
 <3 x float>, 0, 0, 0, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// SPIRV: %[[RES:.*]] = call {{.*}} <3 x float> 
@llvm.spv.resource.load.level.v3f32.tspirv.Image_f32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.Image",
 float, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret <3 x float> %[[RES]]
+
+Texture2D<int> t_int;
+
+// CHECK: define hidden {{.*}} i32 @test_load_int(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} i32 @hlsl::Texture2D<int>::Load(int 
vector[3])(ptr {{.*}} @t_int, <3 x i32> noundef %{{.*}})
+// CHECK: ret i32 %[[CALL]]
+int test_load_int(int2 loc : LOC) {
+  return t_int.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} i32 
@hlsl::Texture2D<int>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> 
{{.*}} %[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call i32 
@llvm.dx.resource.load.level.i32.tdx.Texture_i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 i32, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call i32 
@llvm.spv.resource.load.level.i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret i32 %[[RES]]
+
+// CHECK: define hidden {{.*}} i32 @test_load_offset_int(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} i32 @hlsl::Texture2D<int>::Load(int 
vector[3], int vector[2])(ptr {{.*}} @t_int, <3 x i32> noundef %{{.*}}, <2 x 
i32> noundef splat (i32 1))
+// CHECK: ret i32 %[[CALL]]
+int test_load_offset_int(int2 loc : LOC) {
+  return t_int.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} i32 
@hlsl::Texture2D<int>::Load(int vector[3], int vector[2])(ptr {{.*}} 
%[[THIS:.*]], <3 x i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} 
%[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call i32 
@llvm.dx.resource.load.level.i32.tdx.Texture_i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 i32, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> %{{.*}})
+// SPIRV: %[[RES:.*]] = call i32 
@llvm.spv.resource.load.level.i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret i32 %[[RES]]
+
+Texture2D<int2> t_int2;
+
+// CHECK: define hidden {{.*}} <2 x i32> @test_load_int2(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <2 x i32> @hlsl::Texture2D<int 
vector[2]>::Load(int vector[3])(ptr {{.*}} @t_int2, <3 x i32> noundef %{{.*}})
+// CHECK: ret <2 x i32> %[[CALL]]
+int2 test_load_int2(int2 loc : LOC) {
+  return t_int2.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <2 x i32> @hlsl::Texture2D<int 
vector[2]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call <2 x i32> 
@llvm.dx.resource.load.level.v2i32.tdx.Texture_v2i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <2 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call <2 x i32> 
@llvm.spv.resource.load.level.v2i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret <2 x i32> %[[RES]]
+
+// CHECK: define hidden {{.*}} <2 x i32> @test_load_offset_int2(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <2 x i32> @hlsl::Texture2D<int 
vector[2]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t_int2, <3 x i32> 
noundef %{{.*}}, <2 x i32> noundef splat (i32 1))
+// CHECK: ret <2 x i32> %[[CALL]]
+int2 test_load_offset_int2(int2 loc : LOC) {
+  return t_int2.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <2 x i32> @hlsl::Texture2D<int 
vector[2]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call <2 x i32> 
@llvm.dx.resource.load.level.v2i32.tdx.Texture_v2i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <2 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// SPIRV: %[[RES:.*]] = call <2 x i32> 
@llvm.spv.resource.load.level.v2i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret <2 x i32> %[[RES]]
+
+Texture2D<int3> t_int3;
+
+// CHECK: define hidden {{.*}} <3 x i32> @test_load_int3(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <3 x i32> @hlsl::Texture2D<int 
vector[3]>::Load(int vector[3])(ptr {{.*}} @t_int3, <3 x i32> noundef %{{.*}})
+// CHECK: ret <3 x i32> %[[CALL]]
+int3 test_load_int3(int2 loc : LOC) {
+  return t_int3.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <3 x i32> @hlsl::Texture2D<int 
vector[3]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call <3 x i32> 
@llvm.dx.resource.load.level.v3i32.tdx.Texture_v3i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <3 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call <3 x i32> 
@llvm.spv.resource.load.level.v3i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret <3 x i32> %[[RES]]
+
+// CHECK: define hidden {{.*}} <3 x i32> @test_load_offset_int3(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <3 x i32> @hlsl::Texture2D<int 
vector[3]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t_int3, <3 x i32> 
noundef %{{.*}}, <2 x i32> noundef splat (i32 1))
+// CHECK: ret <3 x i32> %[[CALL]]
+int3 test_load_offset_int3(int2 loc : LOC) {
+  return t_int3.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <3 x i32> @hlsl::Texture2D<int 
vector[3]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call <3 x i32> 
@llvm.dx.resource.load.level.v3i32.tdx.Texture_v3i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <3 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// SPIRV: %[[RES:.*]] = call <3 x i32> 
@llvm.spv.resource.load.level.v3i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret <3 x i32> %[[RES]]
+
+Texture2D<int4> t_int4;
+
+// CHECK: define hidden {{.*}} <4 x i32> @test_load_int4(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x i32> @hlsl::Texture2D<int 
vector[4]>::Load(int vector[3])(ptr {{.*}} @t_int4, <3 x i32> noundef %{{.*}})
+// CHECK: ret <4 x i32> %[[CALL]]
+int4 test_load_int4(int2 loc : LOC) {
+  return t_int4.Load(int3(loc, 0));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x i32> @hlsl::Texture2D<int 
vector[4]>::Load(int vector[3])(ptr {{.*}} %[[THIS:.*]], <3 x i32> {{.*}} 
%[[LOCATION:.*]])
+// DXIL: %[[RES:.*]] = call <4 x i32> 
@llvm.dx.resource.load.level.v4i32.tdx.Texture_v4i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <4 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// SPIRV: %[[RES:.*]] = call <4 x i32> 
@llvm.spv.resource.load.level.v4i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
zeroinitializer)
+// CHECK: ret <4 x i32> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x i32> @test_load_offset_int4(int vector[2])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x i32> @hlsl::Texture2D<int 
vector[4]>::Load(int vector[3], int vector[2])(ptr {{.*}} @t_int4, <3 x i32> 
noundef %{{.*}}, <2 x i32> noundef splat (i32 1))
+// CHECK: ret <4 x i32> %[[CALL]]
+int4 test_load_offset_int4(int2 loc : LOC) {
+  return t_int4.Load(int3(loc, 0), int2(1, 1));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x i32> @hlsl::Texture2D<int 
vector[4]>::Load(int vector[3], int vector[2])(ptr {{.*}} %[[THIS:.*]], <3 x 
i32> {{.*}} %[[LOCATION:.*]], <2 x i32> {{.*}} %[[OFFSET:.*]])
+// DXIL: %[[RES:.*]] = call <4 x i32> 
@llvm.dx.resource.load.level.v4i32.tdx.Texture_v4i32_0_0_1_2t.v2i32.i32.v2i32(target("dx.Texture",
 <4 x i32>, 0, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// SPIRV: %[[RES:.*]] = call <4 x i32> 
@llvm.spv.resource.load.level.v4i32.tspirv.SignedImage_i32_1_2_0_0_1_0t.v2i32.i32.v2i32(target("spirv.SignedImage",
 i32, 1, 2, 0, 0, 1, 0) %{{.*}}, <2 x i32> %{{.*}}, i32 %{{.*}}, <2 x i32> 
%{{.*}})
+// CHECK: ret <4 x i32> %[[RES]]

diff  --git a/clang/test/SemaHLSL/Texture2D-Load-errors.hlsl 
b/clang/test/SemaHLSL/Texture2D-Load-errors.hlsl
new file mode 100644
index 0000000000000..9027c2ea144b8
--- /dev/null
+++ b/clang/test/SemaHLSL/Texture2D-Load-errors.hlsl
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl 
-finclude-default-header -verify %s
+
+Texture2D<float4> t;
+
+float4 test_too_few_args() {
+  return t.Load(); // expected-error {{no matching member function for call to 
'Load'}}
+  // expected-note@*:* {{candidate function not viable: requires single 
argument 'Location', but no arguments were provided}}
+  // expected-note@*:* {{candidate function not viable: requires 2 arguments, 
but 0 were provided}}
+}
+
+float4 test_too_many_args(int2 loc) {
+  return t.Load(int3(loc, 0), int2(1, 1), 1); // expected-error {{no matching 
member function for call to 'Load'}}
+  // expected-note@*:* {{candidate function not viable: requires 2 arguments, 
but 3 were provided}}
+  // expected-note@*:* {{candidate function not viable: requires single 
argument 'Location', but 3 arguments were provided}}
+}
+
+float4 test_invalid_coord_type(float2 loc) {
+  return t.Load(float3(loc, 0)); // expected-warning {{implicit conversion 
turns floating-point number into integer: 'float3' (aka 'vector<float, 3>') to 
'vector<int, 3>'}}
+}
+
+float4 test_invalid_offset_type(int2 loc, float2 offset) {
+  return t.Load(int3(loc, 0), offset); // expected-warning {{implicit 
conversion turns floating-point number into integer: 'float2' (aka 
'vector<float, 2>') to 'vector<int, 2>'}}
+}
+
+float4 test_invalid_location_count(int2 loc) {
+  return t.Load(loc); // expected-error {{no matching member function for call 
to 'Load'}}
+  // expected-note@*:* {{candidate function not viable: no known conversion 
from 'int2' (aka 'vector<int, 2>') to 'vector<int, 3>' (vector of 3 'int' 
values) for 1st argument}}
+  // expected-note@*:* {{candidate function not viable: requires 2 arguments, 
but 1 was provided}}
+}
+
+float4 test_truncated_location_count(int4 loc) {
+  return t.Load(loc); // expected-warning {{implicit conversion truncates 
vector: 'int4' (aka 'vector<int, 4>') to 'vector<int, 3>' (vector of 3 'int' 
values)}}
+}
+
+float4 test_splatted_offset_count(int3 loc, int offset) {
+  // No errors expected. The vector will be generated by splatting `offset`.
+  return t.Load(loc, offset);
+}
+
+
+float4 test_truncated_offset_count(int2 loc, int3 offset) {
+  return t.Load(int3(loc, 0), offset); // expected-warning {{implicit 
conversion truncates vector: 'int3' (aka 'vector<int, 3>') to 'vector<int, 2>' 
(vector of 2 'int' values)}}
+}


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

Reply via email to