[clang] [llvm] [HLSL] Implement Texture2D type and Sample method in Clang (PR #177240)
Steven Perron via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 30 07:52:10 PST 2026
https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/177240
>From a27a614c29d8109ad8c34c50be9ad6eb6aca5ee3 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 21 Jan 2026 13:35:18 -0500
Subject: [PATCH 1/7] [HLSL] Implement Texture2D type and Sample method in
Clang
This patch implements the `Texture2D` resource type and its `Sample` member
function in Clang. It includes the necessary AST and Sema changes to support
the new type and its built-in methods, as well as CodeGen support for both
DirectX and SPIR-V targets.
Key changes:
- Added `ResourceDimension` to `HLSLAttributedResourceType` and `HLSLResourceDimension` attribute.
- Implemented `Texture2D` and `SamplerState` in `HLSLExternalSemaSource`.
- Added `__builtin_hlsl_resource_sample` and associated Sema checking.
- Updated `DirectXTargetCodeGenInfo` and `CommonSPIRTargetCodeGenInfo` to handle texture types.
- Added AST, Sema, and CodeGen tests for `Texture2D`.
---
clang/include/clang/AST/TypeBase.h | 27 ++--
clang/include/clang/AST/TypeProperties.td | 8 +-
clang/include/clang/Basic/Attr.td | 23 +++-
clang/include/clang/Basic/Builtins.td | 6 +
clang/lib/AST/TypePrinter.cpp | 8 ++
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 39 ++++++
clang/lib/CodeGen/CGHLSLRuntime.h | 2 +
clang/lib/CodeGen/Targets/DirectX.cpp | 40 +++++-
clang/lib/CodeGen/Targets/SPIR.cpp | 19 ++-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 128 ++++++++++++++++--
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 12 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 40 ++++++
clang/lib/Sema/SemaHLSL.cpp | 88 ++++++++++++
clang/test/AST/HLSL/Texture2D-AST.hlsl | 93 +++++++++++++
.../test/CodeGenHLSL/builtins/Texture2D.hlsl | 90 ++++++++++++
.../ByteAddressBuffers-constructors.hlsl | 4 +-
clang/test/SemaHLSL/Texture2D-Sema.hlsl | 43 ++++++
.../include/llvm/Frontend/HLSL/HLSLResource.h | 1 +
llvm/include/llvm/Support/DXILABI.h | 8 ++
19 files changed, 641 insertions(+), 38 deletions(-)
create mode 100644 clang/test/AST/HLSL/Texture2D-AST.hlsl
create mode 100644 clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
create mode 100644 clang/test/SemaHLSL/Texture2D-Sema.hlsl
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index 279b75f14d7b8..e62ca4a3eb2c0 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6698,6 +6698,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
struct Attributes {
// Data gathered from HLSL resource attributes
llvm::dxil::ResourceClass ResourceClass;
+ llvm::dxil::ResourceDimension ResourceDimension;
LLVM_PREFERRED_TYPE(bool)
uint8_t IsROV : 1;
@@ -6708,18 +6709,27 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
LLVM_PREFERRED_TYPE(bool)
uint8_t IsCounter : 1;
- Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
- bool RawBuffer = false, bool IsCounter = false)
- : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer),
- IsCounter(IsCounter) {}
+ Attributes(llvm::dxil::ResourceClass ResourceClass,
+ llvm::dxil::ResourceDimension ResourceDimension,
+ bool IsROV = false, bool RawBuffer = false,
+ bool IsCounter = false)
+ : ResourceClass(ResourceClass), ResourceDimension(ResourceDimension),
+ IsROV(IsROV), RawBuffer(RawBuffer), IsCounter(IsCounter) {}
+
+ Attributes(llvm::dxil::ResourceClass ResourceClass)
+ : Attributes(ResourceClass,
+ llvm::dxil::ResourceDimension::DimensionUnknown) {}
Attributes()
- : Attributes(llvm::dxil::ResourceClass::UAV, false, false, false) {}
+ : Attributes(llvm::dxil::ResourceClass::UAV,
+ llvm::dxil::ResourceDimension::DimensionUnknown, false,
+ false, false) {}
friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
- return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer,
- LHS.IsCounter) == std::tie(RHS.ResourceClass, RHS.IsROV,
- RHS.RawBuffer, RHS.IsCounter);
+ return std::tie(LHS.ResourceClass, LHS.ResourceDimension, LHS.IsROV,
+ LHS.RawBuffer, LHS.IsCounter) ==
+ std::tie(RHS.ResourceClass, RHS.ResourceDimension, RHS.IsROV,
+ RHS.RawBuffer, RHS.IsCounter);
}
friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
return !(LHS == RHS);
@@ -6758,6 +6768,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
ID.AddPointer(Wrapped.getAsOpaquePtr());
ID.AddPointer(Contained.getAsOpaquePtr());
ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
+ ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceDimension));
ID.AddBoolean(Attrs.IsROV);
ID.AddBoolean(Attrs.RawBuffer);
ID.AddBoolean(Attrs.IsCounter);
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index b150ac2e1cbe3..8c1e9f209e5ad 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -659,6 +659,9 @@ let Class = HLSLAttributedResourceType in {
def : Property<"resClass", UInt32> {
let Read = [{ static_cast<uint32_t>(node->getAttrs().ResourceClass) }];
}
+ def : Property<"resDimension", UInt32> {
+ let Read = [{ static_cast<uint32_t>(node->getAttrs().ResourceDimension) }];
+ }
def : Property<"isROV", Bool> {
let Read = [{ node->getAttrs().IsROV }];
}
@@ -675,7 +678,10 @@ let Class = HLSLAttributedResourceType in {
let Read = [{ node->getContainedType() }];
}
def : Creator<[{
- HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rawBuffer, isCounter);
+ HLSLAttributedResourceType::Attributes attrs(
+ static_cast<llvm::dxil::ResourceClass>(resClass),
+ static_cast<llvm::dxil::ResourceDimension>(resDimension), isROV,
+ rawBuffer, isCounter);
return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs);
}]>;
}
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index ba44266d22c8c..16a7334d20f81 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5093,13 +5093,22 @@ def HLSLROV : TypeAttr {
def HLSLResourceClass : TypeAttr {
let Spellings = [CXX11<"hlsl", "resource_class">];
- let LangOpts = [HLSL];
- let Args = [
- EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass",
- /*is_string=*/true, ["SRV", "UAV", "CBuffer", "Sampler"],
- ["SRV", "UAV", "CBuffer", "Sampler"],
- /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>
- ];
+ let Args = [EnumArgument<
+ "ResourceClass", "llvm::hlsl::ResourceClass",
+ /*is_string=*/true, ["SRV", "UAV", "CBuffer", "Sampler"],
+ ["SRV", "UAV", "CBuffer", "Sampler"],
+ /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>];
+ let Documentation = [InternalOnly];
+}
+
+def HLSLResourceDimension : TypeAttr {
+ let Spellings = [CXX11<"hlsl", "dimension">];
+ let Args = [EnumArgument<
+ "Dimension", "llvm::hlsl::ResourceDimension",
+ /*is_string=*/true, ["Unknown", "1D", "2D", "3D", "Cube"],
+ ["DimensionUnknown", "Dimension1D", "Dimension2D", "Dimension3D",
+ "DimensionCube"],
+ /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>];
let Documentation = [InternalOnly];
}
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index bc8f1474493b0..a9e865eed0818 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5001,6 +5001,12 @@ def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
+def HLSLResourceSample : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_resource_sample"];
+ let Attributes = [NoThrow];
+ let Prototype = "void(...)";
+}
+
def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
let Attributes = [NoThrow];
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 5a0cbc47e7c1a..cd43982bee4e0 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1972,6 +1972,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::HLSLRawBuffer:
case attr::HLSLContainedType:
case attr::HLSLIsCounter:
+ case attr::HLSLResourceDimension:
llvm_unreachable("HLSL resource type attributes handled separately");
case attr::OpenCLPrivateAddressSpace:
@@ -2127,6 +2128,13 @@ void TypePrinter::printHLSLAttributedResourceAfter(
printAfter(ContainedTy, OS);
OS << ")]]";
}
+
+ if (Attrs.ResourceDimension !=
+ llvm::dxil::ResourceDimension::DimensionUnknown)
+ OS << " [[hlsl::resource_dimension("
+ << HLSLResourceDimensionAttr::ConvertResourceDimensionToStr(
+ Attrs.ResourceDimension)
+ << ")]]";
}
void TypePrinter::printHLSLInlineSpirvBefore(const HLSLInlineSpirvType *T,
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 36691c7b72efe..e7597371f01fa 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -440,6 +440,45 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
}
+ case Builtin::BI__builtin_hlsl_resource_sample: {
+ Value *HandleOp = EmitScalarExpr(E->getArg(0));
+ Value *SamplerOp = EmitScalarExpr(E->getArg(1));
+ Value *CoordOp = EmitScalarExpr(E->getArg(2));
+
+ SmallVector<Value *, 4> Args;
+ Args.push_back(HandleOp);
+ Args.push_back(SamplerOp);
+ Args.push_back(CoordOp);
+ if (E->getNumArgs() > 3) {
+ Args.push_back(EmitScalarExpr(E->getArg(3)));
+ } else {
+ // Default offset is 0.
+ // We need to know the type of the offset. It should be a vector of i32
+ // with the same number of elements as the coordinate, or scalar i32.
+ llvm::Type *CoordTy = CoordOp->getType();
+ llvm::Type *Int32Ty = Builder.getInt32Ty();
+ llvm::Type *OffsetTy = Int32Ty;
+ if (auto *VT = dyn_cast<llvm::FixedVectorType>(CoordTy))
+ OffsetTy = llvm::FixedVectorType::get(Int32Ty, VT->getNumElements());
+ Args.push_back(llvm::Constant::getNullValue(OffsetTy));
+ }
+
+ llvm::Type *RetTy = ConvertType(E->getType());
+ if (E->getNumArgs() <= 4) {
+ return Builder.CreateIntrinsic(
+ RetTy, CGM.getHLSLRuntime().getSampleIntrinsic(), Args);
+ }
+
+ llvm::Value *Clamp = EmitScalarExpr(E->getArg(4));
+ // The builtin is defined with variadic arguments, so the clamp parameter
+ // might have been promoted to double. The intrinsic requires a 32-bit
+ // float.
+ if (Clamp->getType() != Builder.getFloatTy())
+ Clamp = Builder.CreateFPCast(Clamp, Builder.getFloatTy());
+ Args.push_back(Clamp);
+ return Builder.CreateIntrinsic(
+ RetTy, CGM.getHLSLRuntime().getSampleClampIntrinsic(), Args);
+ }
case Builtin::BI__builtin_hlsl_resource_load_with_status: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index ba2ca2c358388..03a64ed0fa6bb 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -159,6 +159,8 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
resource_getpointer)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(Sample, resource_sample)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(SampleClamp, resource_sample_clamp)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index a007c90881ab2..13c6862191dd2 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -58,7 +58,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
switch (ResAttrs.ResourceClass) {
case llvm::dxil::ResourceClass::UAV:
case llvm::dxil::ResourceClass::SRV: {
- // TypedBuffer and RawBuffer both need element type
+ // TypedBuffer, RawBuffer and Texture all need element type
QualType ContainedTy = ResType->getContainedType();
if (ContainedTy.isNull())
return nullptr;
@@ -66,12 +66,17 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
// convert element type
llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
- llvm::StringRef TypeName =
- ResAttrs.RawBuffer ? "dx.RawBuffer" : "dx.TypedBuffer";
- SmallVector<unsigned, 3> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
+ llvm::StringRef TypeName = "dx.TypedBuffer";
+ if (ResAttrs.RawBuffer)
+ TypeName = "dx.RawBuffer";
+ else if (ResAttrs.ResourceDimension !=
+ llvm::dxil::ResourceDimension::DimensionUnknown)
+ TypeName = "dx.Texture";
+
+ SmallVector<unsigned, 4> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
llvm::dxil::ResourceClass::UAV,
/*IsROV*/ ResAttrs.IsROV};
- if (!ResAttrs.RawBuffer) {
+ if (TypeName != "dx.RawBuffer") {
const clang::Type *ElemType = ContainedTy->getUnqualifiedDesugaredType();
if (ElemType->isVectorType())
ElemType = cast<clang::VectorType>(ElemType)
@@ -80,6 +85,28 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
Ints.push_back(/*IsSigned*/ ElemType->isSignedIntegerType());
}
+ if (TypeName == "dx.Texture") {
+ // Map ResourceDimension to dxil::ResourceKind
+ llvm::dxil::ResourceKind RK = llvm::dxil::ResourceKind::Invalid;
+ switch (ResAttrs.ResourceDimension) {
+ case llvm::dxil::ResourceDimension::Dimension1D:
+ RK = llvm::dxil::ResourceKind::Texture1D;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension2D:
+ RK = llvm::dxil::ResourceKind::Texture2D;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension3D:
+ RK = llvm::dxil::ResourceKind::Texture3D;
+ break;
+ case llvm::dxil::ResourceDimension::DimensionCube:
+ RK = llvm::dxil::ResourceKind::TextureCube;
+ break;
+ default:
+ break;
+ }
+ Ints.push_back(static_cast<unsigned>(RK));
+ }
+
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
case llvm::dxil::ResourceClass::CBuffer: {
@@ -96,8 +123,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {BufferLayoutTy});
}
case llvm::dxil::ResourceClass::Sampler:
- llvm_unreachable("dx.Sampler handles are not implemented yet");
- break;
+ return llvm::TargetExtType::get(Ctx, "dx.Sampler", {}, {0});
}
llvm_unreachable("Unknown llvm::dxil::ResourceClass enum");
}
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 61ea677292492..d3c1d322aea77 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -861,8 +861,23 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
Ty->isSignedIntegerType() ? "spirv.SignedImage" : "spirv.Image";
// Dim
- // For now we assume everything is a buffer.
- IntParams[0] = 5;
+ switch (attributes.ResourceDimension) {
+ case llvm::dxil::ResourceDimension::Dimension1D:
+ IntParams[0] = 0;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension2D:
+ IntParams[0] = 1;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension3D:
+ IntParams[0] = 2;
+ break;
+ case llvm::dxil::ResourceDimension::DimensionCube:
+ IntParams[0] = 3;
+ break;
+ case llvm::dxil::ResourceDimension::DimensionUnknown:
+ IntParams[0] = 5;
+ break;
+ }
// Depth
// HLSL does not indicate if it is a depth texture or not, so we use unknown.
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index f74aabf08d2c7..a76a1db65ff53 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -206,6 +206,11 @@ struct BuiltinTypeMethodBuilder {
template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
+
+ template <typename T>
+ BuiltinTypeMethodBuilder &accessFieldOnResource(T ResourceRecord,
+ FieldDecl *Field);
+
template <typename T>
BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);
template <typename ResourceT, typename ValueT>
@@ -497,7 +502,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
else
Method = CXXMethodDecl::Create(
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,
- false, false, ConstexprSpecKind::Unspecified, SourceLocation());
+ false, true, ConstexprSpecKind::Unspecified, SourceLocation());
// Create params & set them to the method/constructor and function prototype.
SmallVector<ParmVarDecl *> ParmDecls;
@@ -631,6 +636,23 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
return *this;
}
+template <typename T>
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::accessFieldOnResource(T ResourceRecord,
+ FieldDecl *Field) {
+ ensureCompleteDecl();
+
+ Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
+
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+
+ MemberExpr *FieldExpr =
+ MemberExpr::CreateImplicit(AST, ResourceExpr, false, Field,
+ Field->getType(), VK_LValue, OK_Ordinary);
+ StmtsList.push_back(FieldExpr);
+ return *this;
+}
+
template <typename T>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {
@@ -850,27 +872,46 @@ BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,
bool RawBuffer, bool HasCounter,
AccessSpecifier Access) {
- addHandleMember(RC, IsROV, RawBuffer, Access);
+ addHandleMember(RC, ResourceDimension::DimensionUnknown, IsROV, RawBuffer,
+ Access);
if (HasCounter)
addCounterHandleMember(RC, IsROV, RawBuffer, Access);
return *this;
}
-BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
- ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
- return addResourceMember("__handle", RC, IsROV, RawBuffer,
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addTextureHandle(ResourceClass RC, bool IsROV,
+ ResourceDimension RD,
+ AccessSpecifier Access) {
+ addHandleMember(RC, RD, IsROV, /*RawBuffer=*/false, Access);
+ return *this;
+}
+
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSamplerHandle() {
+ addHandleMember(ResourceClass::Sampler, ResourceDimension::DimensionUnknown,
+ /*IsROV=*/false, /*RawBuffer=*/false);
+ return *this;
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, ResourceDimension RD,
+ bool IsROV, bool RawBuffer,
+ AccessSpecifier Access) {
+ return addResourceMember("__handle", RC, RD, IsROV, RawBuffer,
/*IsCounter=*/false, Access);
}
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(
ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
- return addResourceMember("__counter_handle", RC, IsROV, RawBuffer,
+ return addResourceMember("__counter_handle", RC,
+ ResourceDimension::DimensionUnknown, IsROV,
+ RawBuffer,
/*IsCounter=*/true, Access);
}
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
- StringRef MemberName, ResourceClass RC, bool IsROV, bool RawBuffer,
- bool IsCounter, AccessSpecifier Access) {
+ StringRef MemberName, ResourceClass RC, ResourceDimension RD, bool IsROV,
+ bool RawBuffer, bool IsCounter, AccessSpecifier Access) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &Ctx = SemaRef.getASTContext();
@@ -883,7 +924,10 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
- ElementTypeInfo
+ RD != ResourceDimension::DimensionUnknown
+ ? HLSLResourceDimensionAttr::CreateImplicit(Ctx, RD)
+ : nullptr,
+ ElementTypeInfo && RC != ResourceClass::Sampler
? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
: nullptr};
if (IsCounter)
@@ -1165,6 +1209,72 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
return *this;
}
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSampleMethods() {
+ assert(!Record->isCompleteDefinition() && "record is already complete");
+
+ ASTContext &AST = Record->getASTContext();
+ QualType ReturnType = getFirstTemplateTypeParam();
+
+ // Look up SamplerState
+ IdentifierInfo &SamplerStateII = AST.Idents.get("SamplerState");
+ LookupResult Result(SemaRef, &SamplerStateII, SourceLocation(),
+ Sema::LookupTagName);
+ SemaRef.LookupQualifiedName(Result, Record->getDeclContext());
+ assert(!Result.empty() && "SamplerState not found");
+ QualType SamplerStateType =
+ AST.getTypeDeclType(Result.getAsSingle<TypeDecl>());
+ SemaRef.RequireCompleteType(SourceLocation(), SamplerStateType,
+ diag::err_tentative_def_incomplete_type);
+
+ // TODO: The location type depends on the texture dimension.
+ // For Texture2D it is float2.
+ QualType FloatTy = AST.FloatTy;
+ QualType Float2Ty = AST.getExtVectorType(FloatTy, 2);
+
+ QualType IntTy = AST.IntTy;
+ QualType Int2Ty = AST.getExtVectorType(IntTy, 2);
+
+ auto *RT = SamplerStateType->getAsCXXRecordDecl();
+ assert(RT);
+ assert(!RT->field_empty());
+ FieldDecl *SamplerHandleField = *RT->field_begin();
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+ // T Sample(SamplerState s, float2 location)
+ BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
+ .addParam("Sampler", SamplerStateType)
+ .addParam("Location", Float2Ty)
+ .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
+ PH::LastStmt, PH::_1)
+ .returnValue(PH::LastStmt)
+ .finalize();
+
+ // T Sample(SamplerState s, float2 location, int2 offset)
+ BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
+ .addParam("Sampler", SamplerStateType)
+ .addParam("Location", Float2Ty)
+ .addParam("Offset", Int2Ty)
+ .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
+ PH::LastStmt, PH::_1, PH::_2)
+ .returnValue(PH::LastStmt)
+ .finalize();
+
+ // T Sample(SamplerState s, float2 location, int2 offset, float clamp)
+ return BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
+ .addParam("Sampler", SamplerStateType)
+ .addParam("Location", Float2Ty)
+ .addParam("Offset", Int2Ty)
+ .addParam("Clamp", FloatTy)
+ .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
+ PH::LastStmt, PH::_1, PH::_2, PH::_3)
+ .returnValue(PH::LastStmt)
+ .finalize();
+}
+
FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
auto I = Fields.find("__handle");
assert(I != Fields.end() &&
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 47c8b0e225612..86e50207541ec 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringMap.h"
using llvm::hlsl::ResourceClass;
+using llvm::hlsl::ResourceDimension;
namespace clang {
@@ -75,6 +76,10 @@ class BuiltinTypeDeclBuilder {
addBufferHandles(ResourceClass RC, bool IsROV, bool RawBuffer,
bool HasCounter,
AccessSpecifier Access = AccessSpecifier::AS_private);
+ BuiltinTypeDeclBuilder &
+ addTextureHandle(ResourceClass RC, bool IsROV, ResourceDimension RD,
+ AccessSpecifier Access = AccessSpecifier::AS_private);
+ BuiltinTypeDeclBuilder &addSamplerHandle();
BuiltinTypeDeclBuilder &addArraySubscriptOperators();
// Builtin types constructors
@@ -87,6 +92,7 @@ class BuiltinTypeDeclBuilder {
// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
+ BuiltinTypeDeclBuilder &addSampleMethods();
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
@@ -104,11 +110,13 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addCreateFromBindingWithImplicitCounter();
BuiltinTypeDeclBuilder &addCreateFromImplicitBindingWithImplicitCounter();
BuiltinTypeDeclBuilder &addResourceMember(StringRef MemberName,
- ResourceClass RC, bool IsROV,
+ ResourceClass RC,
+ ResourceDimension RD, bool IsROV,
bool RawBuffer, bool IsCounter,
AccessSpecifier Access);
BuiltinTypeDeclBuilder &
- addHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
+ addHandleMember(ResourceClass RC, ResourceDimension RD, bool IsROV,
+ bool RawBuffer,
AccessSpecifier Access = AccessSpecifier::AS_private);
BuiltinTypeDeclBuilder &
addCounterHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 6be84f19a8f08..db72c0b07aa6b 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -500,6 +500,46 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
.addGetDimensionsMethodForBuffer()
.completeDefinition();
});
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerState")
+ .finalizeForwardDeclaration();
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ BuiltinTypeDeclBuilder(*SemaPtr, Decl)
+ .addSamplerHandle()
+ .addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addStaticInitializationFunctions(false)
+ .completeDefinition();
+ });
+
+ Decl =
+ BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerComparisonState")
+ .finalizeForwardDeclaration();
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ BuiltinTypeDeclBuilder(*SemaPtr, Decl)
+ .addSamplerHandle()
+ .addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addStaticInitializationFunctions(false)
+ .completeDefinition();
+ });
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
+ .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)
+ .finalizeForwardDeclaration();
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ BuiltinTypeDeclBuilder(*SemaPtr, Decl)
+ .addTextureHandle(ResourceClass::SRV, /*IsROV=*/false,
+ ResourceDimension::Dimension2D)
+ .addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addStaticInitializationFunctions(false)
+ .addSampleMethods()
+ .completeDefinition();
+ });
}
void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4d31e26d56e6b..52d6eab10fea5 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2005,6 +2005,7 @@ bool clang::CreateHLSLAttributedResourceType(
HLSLAttributedResourceType::Attributes ResAttrs;
bool HasResourceClass = false;
+ bool HasResourceDimension = false;
for (const Attr *A : AttrList) {
if (!A)
continue;
@@ -2023,6 +2024,20 @@ bool clang::CreateHLSLAttributedResourceType(
HasResourceClass = true;
break;
}
+ case attr::HLSLResourceDimension: {
+ llvm::dxil::ResourceDimension RD =
+ cast<HLSLResourceDimensionAttr>(A)->getDimension();
+ if (HasResourceDimension) {
+ S.Diag(A->getLocation(), ResAttrs.ResourceDimension == RD
+ ? diag::warn_duplicate_attribute_exact
+ : diag::warn_duplicate_attribute)
+ << A;
+ return false;
+ }
+ ResAttrs.ResourceDimension = RD;
+ HasResourceDimension = true;
+ break;
+ }
case attr::HLSLROV:
if (ResAttrs.IsROV) {
S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
@@ -3264,6 +3279,23 @@ static bool CheckResourceHandle(
return false;
}
+static bool CheckVectorElementCount(Sema *S, QualType PassedType,
+ QualType BaseType, unsigned ExpectedCount,
+ SourceLocation Loc) {
+ unsigned PassedCount = 1;
+ if (const auto *VecTy = PassedType->getAs<VectorType>())
+ PassedCount = VecTy->getNumElements();
+
+ if (PassedCount != ExpectedCount) {
+ QualType ExpectedType =
+ S->Context.getExtVectorType(BaseType, ExpectedCount);
+ S->Diag(Loc, diag::err_typecheck_convert_incompatible)
+ << PassedType << ExpectedType << 1 << 0 << 0;
+ return true;
+ }
+ return false;
+}
+
// Note: returning true in this case results in CheckBuiltinFunctionCall
// returning an ExprError
bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
@@ -3334,7 +3366,63 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
+ case Builtin::BI__builtin_hlsl_resource_sample: {
+ if (SemaRef.checkArgCountRange(TheCall, 3, 5) ||
+ CheckResourceHandle(&SemaRef, TheCall, 0) ||
+ CheckResourceHandle(&SemaRef, TheCall, 1,
+ [](const HLSLAttributedResourceType *ResType) {
+ return ResType->getAttrs().ResourceClass !=
+ llvm::hlsl::ResourceClass::Sampler;
+ }))
+ return true;
+ auto *ResourceTy =
+ TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+
+ unsigned ExpectedDim = 0;
+ switch (ResourceTy->getAttrs().ResourceDimension) {
+ case llvm::dxil::ResourceDimension::Dimension1D:
+ ExpectedDim = 1;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension2D:
+ ExpectedDim = 2;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension3D:
+ case llvm::dxil::ResourceDimension::DimensionCube:
+ ExpectedDim = 3;
+ break;
+ case llvm::dxil::ResourceDimension::DimensionUnknown:
+ break;
+ }
+
+ if (ExpectedDim != 0) {
+ if (CheckVectorElementCount(&SemaRef, TheCall->getArg(2)->getType(),
+ SemaRef.Context.FloatTy, ExpectedDim,
+ TheCall->getArg(2)->getBeginLoc()))
+ return true;
+
+ if (TheCall->getNumArgs() > 3) {
+ if (CheckVectorElementCount(&SemaRef, TheCall->getArg(3)->getType(),
+ SemaRef.Context.IntTy, ExpectedDim,
+ TheCall->getArg(3)->getBeginLoc()))
+ return true;
+ }
+ }
+ if (TheCall->getNumArgs() > 4) {
+ QualType ClampTy = TheCall->getArg(4)->getType();
+ if (!ClampTy->isFloatingType() || ClampTy->isVectorType()) {
+ SemaRef.Diag(TheCall->getArg(4)->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ClampTy << SemaRef.Context.FloatTy << 1 << 0 << 0;
+ return true;
+ }
+ }
+
+ QualType ReturnType = ResourceTy->getContainedType();
+ TheCall->setType(ReturnType);
+
+ break;
+ }
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-AST.hlsl
new file mode 100644
index 0000000000000..95343712b72fa
--- /dev/null
+++ b/clang/test/AST/HLSL/Texture2D-AST.hlsl
@@ -0,0 +1,93 @@
+// 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: ClassTemplateDecl {{.*}} Texture2D
+// CHECK: TemplateTypeParmDecl {{.*}} element_type
+// CHECK: CXXRecordDecl {{.*}} Texture2D definition
+// CHECK: FinalAttr {{.*}} Implicit final
+// CHECK-NEXT: FieldDecl {{.*}} implicit __handle '__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: CXXMethodDecl {{.*}} Sample 'element_type (hlsl::SamplerState, vector<float, 2>)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Sampler 'hlsl::SamplerState'
+// CHECK-NEXT: ParmVarDecl {{.*}} Location 'vector<float, 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_sample' '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: 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 'element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>)'
+// 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 {{.*}} 'element_type' <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(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: 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 'element_type (hlsl::SamplerState, vector<float, 2>, vector<int, 2>, float)'
+// 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 {{.*}} 'element_type' <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(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: 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
+
+Texture2D<float4> t;
+SamplerState s;
+
+void main(float2 loc) {
+ t.Sample(s, loc);
+ t.Sample(s, loc, int2(1, 2));
+ t.Sample(s, loc, int2(1, 2), 1.0);
+}
\ No newline at end of file
diff --git a/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl b/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
new file mode 100644
index 0000000000000..88fa2b5f623f8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | 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 | 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) }
+
+// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) }
+// SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") }
+
+Texture2D<float4> t;
+SamplerState s;
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z4mainDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 main(float2 loc : LOC) : SV_Target {
+ return t.Sample(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(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.sample.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]], <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z11test_offsetDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(ptr {{.*}} @_ZL1t, 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.Sample(s, loc, int2(1, 2));
+}
+
+// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(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.sample.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]], <2 x i32> %[[OFFSET_VAL]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> %[[OFFSET_VAL]])
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z10test_clampDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>, float {{.*}} 1.000000e+00)
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_clamp(float2 loc : LOC) : SV_Target {
+ return t.Sample(s, loc, int2(1, 2), 1.0f);
+}
+
+// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^,]+]], float {{.*}} %[[CLAMP:[^)]+]])
+// CHECK: %[[THIS_ADDR:[^ ]+]] = alloca ptr
+// CHECK: %[[COORD_ADDR:[^ ]+]] = alloca <2 x float>
+// CHECK: %[[OFFSET_ADDR:[^ ]+]] = alloca <2 x i32>
+// CHECK: %[[CLAMP_ADDR:[^ ]+]] = alloca float
+// 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: store float %[[CLAMP]], ptr %[[CLAMP_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]]
+// CHECK: %[[CLAMP_VAL:[^ ]+]] = load float, ptr %[[CLAMP_ADDR]]
+// CHECK: %[[CLAMP_CAST:[^ ]+]] = fptrunc {{.*}} double {{.*}} to float
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
+// CHECK: ret <4 x float> %[[RES]]
\ No newline at end of file
diff --git a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-constructors.hlsl
index 9354ee714f86e..4ac71d0093b8b 100644
--- a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-constructors.hlsl
@@ -37,7 +37,7 @@ export void foo() {
// CHECK-SAME: (ptr {{.*}} @Buf1, i32 noundef 1, i32 noundef 2, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]])
// Buf1 initialization part 2 - body of ByteAddressBuffer::__createFromBinding
-// CHECK: define {{.*}} void @hlsl::ByteAddressBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK: define linkonce_odr hidden void @hlsl::ByteAddressBuffer::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::ByteAddressBuffer") align 4 %[[RetValue1:.*]], i32 noundef %registerNo,
// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name)
// CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::ByteAddressBuffer", align 4
@@ -54,7 +54,7 @@ export void foo() {
// CHECK-SAME: (ptr {{.*}} @Buf2, i32 noundef 0, i32 noundef 0, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf2Str]])
// Buf2 initialization part 2 - body of RWByteAddressBuffer::__createFromImplicitBinding
-// CHECK: define hidden void @hlsl::RWByteAddressBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK: define linkonce_odr hidden void @hlsl::RWByteAddressBuffer::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWByteAddressBuffer") align 4 %[[RetValue2:.*]], i32 noundef %orderId,
// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name)
// CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWByteAddressBuffer", align 4
diff --git a/clang/test/SemaHLSL/Texture2D-Sema.hlsl b/clang/test/SemaHLSL/Texture2D-Sema.hlsl
new file mode 100644
index 0000000000000..9013148d901eb
--- /dev/null
+++ b/clang/test/SemaHLSL/Texture2D-Sema.hlsl
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -finclude-default-header -verify %s
+
+Texture2D<float4> t;
+SamplerState s;
+
+void main(float2 loc) {
+ t.Sample(s, loc);
+ t.Sample(s, loc, int2(1, 2));
+
+ // expected-error at +4 {{no matching member function for call to 'Sample'}}
+ // expected-note@*:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+ // expected-note@*:* {{candidate function not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note@*:* {{candidate function not viable: requires 4 arguments, but 1 was provided}}
+ t.Sample(loc);
+
+ t.Sample(s, loc, int2(1, 2), 1.0);
+
+ // expected-error at +4 {{no matching member function for call to 'Sample'}}
+ // expected-note@*:* {{candidate function not viable: requires 4 arguments, but 5 were provided}}
+ // expected-note@*:* {{candidate function not viable: requires 3 arguments, but 5 were provided}}
+ // expected-note@*:* {{candidate function not viable: requires 2 arguments, but 5 were provided}}
+ t.Sample(s, loc, int2(1, 2), 1.0, 1.0);
+
+ // expected-error at +4 {{no matching member function for call to 'Sample'}}
+ // expected-note@*:* {{candidate function not viable: no known conversion from 'SamplerState' to 'vector<int, 2>' (vector of 2 'int' values) for 3rd argument}}
+ // expected-note@*:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note@*:* {{candidate function not viable: requires 4 arguments, but 3 were provided}}
+ t.Sample(s, loc, s);
+
+ // expected-error at +4 {{no matching member function for call to 'Sample'}}
+ // expected-note@*:* {{candidate function not viable: no known conversion from 'SamplerState' to 'float' for 4th argument}}
+ // expected-note@*:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note@*:* {{candidate function not viable: requires 2 arguments, but 4 were provided}}
+ t.Sample(s, loc, int2(1, 2), s);
+
+ // Test with wrong coordinate dimension.
+ // Note: float implicitly converts to float2 (splat), so no error here.
+ t.Sample(s, loc.x);
+
+ // Test with wrong offset dimension.
+ // Note: int implicitly converts to int2 (splat), so no error here.
+ t.Sample(s, loc, 1);
+}
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
index cfa0e957c9589..8849ba880ad11 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
@@ -20,6 +20,7 @@ namespace hlsl {
// For now we use DXIL ABI enum values directly. This may change in the future.
using dxil::ResourceClass;
+using dxil::ResourceDimension;
const unsigned CBufferRowSizeInBytes = 16U;
diff --git a/llvm/include/llvm/Support/DXILABI.h b/llvm/include/llvm/Support/DXILABI.h
index e6600c3406df5..285ac1b663685 100644
--- a/llvm/include/llvm/Support/DXILABI.h
+++ b/llvm/include/llvm/Support/DXILABI.h
@@ -31,6 +31,14 @@ enum class ResourceClass : uint8_t {
LastEntry = Sampler,
};
+enum class ResourceDimension : uint8_t {
+ DimensionUnknown = 0,
+ Dimension1D,
+ Dimension2D,
+ Dimension3D,
+ DimensionCube,
+};
+
/// The kind of resource for an SRV or UAV resource. Sometimes referred to as
/// "Shape" in the DXIL docs.
enum class ResourceKind : uint32_t {
>From 88ace59e60a4bc96ce55df017417f7abd69fe395 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 28 Jan 2026 10:16:23 -0500
Subject: [PATCH 2/7] Changes from the code review.
---
clang/include/clang/AST/HLSLResource.h | 19 +++++
clang/include/clang/Basic/Attr.td | 2 +
clang/lib/CodeGen/Targets/DirectX.cpp | 16 +++--
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 35 ++++++----
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 49 +++++++------
clang/lib/Sema/SemaHLSL.cpp | 70 ++++++++++---------
7 files changed, 117 insertions(+), 76 deletions(-)
diff --git a/clang/include/clang/AST/HLSLResource.h b/clang/include/clang/AST/HLSLResource.h
index 1be1e422f5f12..5cf2eead246ad 100644
--- a/clang/include/clang/AST/HLSLResource.h
+++ b/clang/include/clang/AST/HLSLResource.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Support/Compiler.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
@@ -89,6 +90,24 @@ struct ResourceBindingAttrs {
}
};
+inline uint32_t getResourceDimensions(llvm::dxil::ResourceDimension Dim) {
+ switch (Dim) {
+ case llvm::dxil::ResourceDimension::Dimension1D:
+ return 1;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension2D:
+ return 2;
+ break;
+ case llvm::dxil::ResourceDimension::Dimension3D:
+ case llvm::dxil::ResourceDimension::DimensionCube:
+ return 3;
+ break;
+ case llvm::dxil::ResourceDimension::DimensionUnknown:
+ llvm_unreachable(
+ "We cannot get the dimension of a resource with unknown dimension.");
+ }
+}
+
} // namespace hlsl
} // namespace clang
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 16a7334d20f81..d529976706edb 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5093,6 +5093,7 @@ def HLSLROV : TypeAttr {
def HLSLResourceClass : TypeAttr {
let Spellings = [CXX11<"hlsl", "resource_class">];
+ let LangOpts = [HLSL];
let Args = [EnumArgument<
"ResourceClass", "llvm::hlsl::ResourceClass",
/*is_string=*/true, ["SRV", "UAV", "CBuffer", "Sampler"],
@@ -5103,6 +5104,7 @@ def HLSLResourceClass : TypeAttr {
def HLSLResourceDimension : TypeAttr {
let Spellings = [CXX11<"hlsl", "dimension">];
+ let LangOpts = [HLSL];
let Args = [EnumArgument<
"Dimension", "llvm::hlsl::ResourceDimension",
/*is_string=*/true, ["Unknown", "1D", "2D", "3D", "Cube"],
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 13c6862191dd2..c953498836836 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -66,17 +66,21 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
// convert element type
llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
+ bool IsRawBuffer = ResAttrs.RawBuffer;
+ bool IsTexture = ResAttrs.ResourceDimension !=
+ llvm::dxil::ResourceDimension::DimensionUnknown;
+ assert((!IsRawBuffer || !IsTexture) && "A resource cannot be both a raw "
+ "buffer and a texture.");
llvm::StringRef TypeName = "dx.TypedBuffer";
- if (ResAttrs.RawBuffer)
+ if (IsRawBuffer)
TypeName = "dx.RawBuffer";
- else if (ResAttrs.ResourceDimension !=
- llvm::dxil::ResourceDimension::DimensionUnknown)
+ else if (IsTexture)
TypeName = "dx.Texture";
SmallVector<unsigned, 4> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
llvm::dxil::ResourceClass::UAV,
/*IsROV*/ ResAttrs.IsROV};
- if (TypeName != "dx.RawBuffer") {
+ if (!IsRawBuffer) {
const clang::Type *ElemType = ContainedTy->getUnqualifiedDesugaredType();
if (ElemType->isVectorType())
ElemType = cast<clang::VectorType>(ElemType)
@@ -85,7 +89,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
Ints.push_back(/*IsSigned*/ ElemType->isSignedIntegerType());
}
- if (TypeName == "dx.Texture") {
+ if (IsTexture) {
// Map ResourceDimension to dxil::ResourceKind
llvm::dxil::ResourceKind RK = llvm::dxil::ResourceKind::Invalid;
switch (ResAttrs.ResourceDimension) {
@@ -102,7 +106,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
RK = llvm::dxil::ResourceKind::TextureCube;
break;
default:
- break;
+ llvm_unreachable("Unsupported resource dimension for textur.");
}
Ints.push_back(static_cast<unsigned>(RK));
}
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index a76a1db65ff53..856fb508c4b15 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/HLSLResource.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
@@ -50,6 +51,19 @@ static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
return cast<FunctionDecl>(R.getFoundDecl());
}
+static QualType lookupBuiltinType(Sema &S, StringRef Name, DeclContext *DC) {
+ IdentifierInfo &II =
+ S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
+ LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
+ S.LookupQualifiedName(Result, DC);
+ assert(!Result.empty() && "Builtin type not found");
+ QualType Ty =
+ S.getASTContext().getTypeDeclType(Result.getAsSingle<TypeDecl>());
+ S.RequireCompleteType(SourceLocation(), Ty,
+ diag::err_tentative_def_incomplete_type);
+ return Ty;
+}
+
CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) {
assert(ResTy->isRecordType() && "not a CXXRecord type");
for (auto *CD : ResTy->getAsCXXRecordDecl()->ctors())
@@ -1209,30 +1223,23 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
return *this;
}
-BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSampleMethods() {
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = Record->getASTContext();
QualType ReturnType = getFirstTemplateTypeParam();
- // Look up SamplerState
- IdentifierInfo &SamplerStateII = AST.Idents.get("SamplerState");
- LookupResult Result(SemaRef, &SamplerStateII, SourceLocation(),
- Sema::LookupTagName);
- SemaRef.LookupQualifiedName(Result, Record->getDeclContext());
- assert(!Result.empty() && "SamplerState not found");
QualType SamplerStateType =
- AST.getTypeDeclType(Result.getAsSingle<TypeDecl>());
- SemaRef.RequireCompleteType(SourceLocation(), SamplerStateType,
- diag::err_tentative_def_incomplete_type);
+ lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
+
+ uint32_t VecSize = getResourceDimensions(Dim);
- // TODO: The location type depends on the texture dimension.
- // For Texture2D it is float2.
QualType FloatTy = AST.FloatTy;
- QualType Float2Ty = AST.getExtVectorType(FloatTy, 2);
+ QualType Float2Ty = AST.getExtVectorType(FloatTy, VecSize);
QualType IntTy = AST.IntTy;
- QualType Int2Ty = AST.getExtVectorType(IntTy, 2);
+ QualType Int2Ty = AST.getExtVectorType(IntTy, VecSize);
auto *RT = SamplerStateType->getAsCXXRecordDecl();
assert(RT);
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 86e50207541ec..a505e2fb466dd 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -92,7 +92,7 @@ class BuiltinTypeDeclBuilder {
// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
- BuiltinTypeDeclBuilder &addSampleMethods();
+ BuiltinTypeDeclBuilder &addSampleMethods(ResourceDimension Dim);
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index db72c0b07aa6b..c8b45352ad66a 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -240,6 +240,29 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
.addStaticInitializationFunctions(HasCounter);
}
+/// Set up common members and attributes for sampler types
+static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) {
+ return BuiltinTypeDeclBuilder(S, Decl)
+ .addSamplerHandle()
+ .addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addStaticInitializationFunctions(false);
+}
+
+/// Set up common members and attributes for texture types
+static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
+ ResourceClass RC, bool IsROV,
+ ResourceDimension Dim) {
+ return BuiltinTypeDeclBuilder(S, Decl)
+ .addTextureHandle(RC, IsROV, Dim)
+ .addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addStaticInitializationFunctions(false)
+ .addSampleMethods(Dim);
+}
+
// This function is responsible for constructing the constraint expression for
// this concept:
// template<typename T> concept is_typed_resource_element_compatible =
@@ -504,40 +527,22 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerState")
.finalizeForwardDeclaration();
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- BuiltinTypeDeclBuilder(*SemaPtr, Decl)
- .addSamplerHandle()
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false)
- .completeDefinition();
+ setupSamplerType(Decl, *SemaPtr).completeDefinition();
});
Decl =
BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerComparisonState")
.finalizeForwardDeclaration();
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- BuiltinTypeDeclBuilder(*SemaPtr, Decl)
- .addSamplerHandle()
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false)
- .completeDefinition();
+ setupSamplerType(Decl, *SemaPtr).completeDefinition();
});
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
.addSimpleTemplateParams({"element_type"}, TypedBufferConcept)
.finalizeForwardDeclaration();
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- BuiltinTypeDeclBuilder(*SemaPtr, Decl)
- .addTextureHandle(ResourceClass::SRV, /*IsROV=*/false,
- ResourceDimension::Dimension2D)
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false)
- .addSampleMethods()
+ setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
+ ResourceDimension::Dimension2D)
.completeDefinition();
});
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 52d6eab10fea5..c2a56e5b5d953 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3367,47 +3367,48 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
case Builtin::BI__builtin_hlsl_resource_sample: {
- if (SemaRef.checkArgCountRange(TheCall, 3, 5) ||
- CheckResourceHandle(&SemaRef, TheCall, 0) ||
- CheckResourceHandle(&SemaRef, TheCall, 1,
- [](const HLSLAttributedResourceType *ResType) {
- return ResType->getAttrs().ResourceClass !=
- llvm::hlsl::ResourceClass::Sampler;
- }))
+ if (SemaRef.checkArgCountRange(TheCall, 3, 5))
+ return true;
+
+ if (CheckResourceHandle(
+ &SemaRef, TheCall, 0,
+ [](const HLSLAttributedResourceType *ResType) {
+ if (ResType->getAttrs().ResourceDimension ==
+ llvm::dxil::ResourceDimension::DimensionUnknown) {
+ return true;
+ }
+ return false;
+ }))
+ return true;
+
+ if (CheckResourceHandle(
+ &SemaRef, TheCall, 1,
+ [](const HLSLAttributedResourceType *ResType) {
+ if (ResType->getAttrs().ResourceClass !=
+ llvm::hlsl::ResourceClass::Sampler)
+ return true;
+ llvm::dbgs() << "The sampler has the wrong resource class.\n";
+ return false;
+ }))
return true;
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- unsigned ExpectedDim = 0;
- switch (ResourceTy->getAttrs().ResourceDimension) {
- case llvm::dxil::ResourceDimension::Dimension1D:
- ExpectedDim = 1;
- break;
- case llvm::dxil::ResourceDimension::Dimension2D:
- ExpectedDim = 2;
- break;
- case llvm::dxil::ResourceDimension::Dimension3D:
- case llvm::dxil::ResourceDimension::DimensionCube:
- ExpectedDim = 3;
- break;
- case llvm::dxil::ResourceDimension::DimensionUnknown:
- break;
- }
+ unsigned ExpectedDim =
+ getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
+ if (CheckVectorElementCount(&SemaRef, TheCall->getArg(2)->getType(),
+ SemaRef.Context.FloatTy, ExpectedDim,
+ TheCall->getArg(2)->getBeginLoc()))
+ return true;
- if (ExpectedDim != 0) {
- if (CheckVectorElementCount(&SemaRef, TheCall->getArg(2)->getType(),
- SemaRef.Context.FloatTy, ExpectedDim,
- TheCall->getArg(2)->getBeginLoc()))
+ if (TheCall->getNumArgs() > 3) {
+ if (CheckVectorElementCount(&SemaRef, TheCall->getArg(3)->getType(),
+ SemaRef.Context.IntTy, ExpectedDim,
+ TheCall->getArg(3)->getBeginLoc()))
return true;
-
- if (TheCall->getNumArgs() > 3) {
- if (CheckVectorElementCount(&SemaRef, TheCall->getArg(3)->getType(),
- SemaRef.Context.IntTy, ExpectedDim,
- TheCall->getArg(3)->getBeginLoc()))
- return true;
- }
}
+
if (TheCall->getNumArgs() > 4) {
QualType ClampTy = TheCall->getArg(4)->getType();
if (!ClampTy->isFloatingType() || ClampTy->isVectorType()) {
@@ -3418,6 +3419,9 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
}
+ assert(ResourceTy->hasContainedType() &&
+ "Expecting a contained type for resource with a the dimension "
+ "attribute.");
QualType ReturnType = ResourceTy->getContainedType();
TheCall->setType(ReturnType);
>From d48d43ea7ec2bc3a651964657d8a94de1690ae82 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 28 Jan 2026 11:16:22 -0500
Subject: [PATCH 3/7] move file.
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 2 +-
.../test/CodeGenHLSL/builtins/Texture2D.hlsl | 90 -------------------
.../resources/Texture2D.sample.hlsl | 90 +++++++++++++++++++
3 files changed, 91 insertions(+), 91 deletions(-)
delete mode 100644 clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
create mode 100644 clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 856fb508c4b15..8a71dcf0ad4c2 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -511,7 +511,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
if (IsCtor)
Method = CXXConstructorDecl::Create(
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo,
- ExplicitSpecifier(), false, true, false,
+ ExplicitSpecifier(), false, /*IsInline=*/ true, false,
ConstexprSpecKind::Unspecified);
else
Method = CXXMethodDecl::Create(
diff --git a/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl b/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
deleted file mode 100644
index 88fa2b5f623f8..0000000000000
--- a/clang/test/CodeGenHLSL/builtins/Texture2D.hlsl
+++ /dev/null
@@ -1,90 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | 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 | 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) }
-
-// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) }
-// SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") }
-
-Texture2D<float4> t;
-SamplerState s;
-
-// CHECK: define hidden {{.*}} <4 x float> @_Z4mainDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
-// CHECK: ret <4 x float> %[[CALL]]
-
-float4 main(float2 loc : LOC) : SV_Target {
- return t.Sample(s, loc);
-}
-
-// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(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.sample.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]], <2 x i32> zeroinitializer)
-// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> zeroinitializer)
-// CHECK: ret <4 x float> %[[RES]]
-
-// CHECK: define hidden {{.*}} <4 x float> @_Z11test_offsetDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(ptr {{.*}} @_ZL1t, 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.Sample(s, loc, int2(1, 2));
-}
-
-// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(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.sample.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]], <2 x i32> %[[OFFSET_VAL]])
-// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> %[[OFFSET_VAL]])
-// CHECK: ret <4 x float> %[[RES]]
-
-// CHECK: define hidden {{.*}} <4 x float> @_Z10test_clampDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>, float {{.*}} 1.000000e+00)
-// CHECK: ret <4 x float> %[[CALL]]
-
-float4 test_clamp(float2 loc : LOC) : SV_Target {
- return t.Sample(s, loc, int2(1, 2), 1.0f);
-}
-
-// CHECK: define linkonce_odr hidden noundef nofpclass(nan inf) <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^,]+]], float {{.*}} %[[CLAMP:[^)]+]])
-// CHECK: %[[THIS_ADDR:[^ ]+]] = alloca ptr
-// CHECK: %[[COORD_ADDR:[^ ]+]] = alloca <2 x float>
-// CHECK: %[[OFFSET_ADDR:[^ ]+]] = alloca <2 x i32>
-// CHECK: %[[CLAMP_ADDR:[^ ]+]] = alloca float
-// 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: store float %[[CLAMP]], ptr %[[CLAMP_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]]
-// CHECK: %[[CLAMP_VAL:[^ ]+]] = load float, ptr %[[CLAMP_ADDR]]
-// CHECK: %[[CLAMP_CAST:[^ ]+]] = fptrunc {{.*}} double {{.*}} to float
-// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
-// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
-// CHECK: ret <4 x float> %[[RES]]
\ No newline at end of file
diff --git a/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
new file mode 100644
index 0000000000000..2066ddfb39183
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | 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 | 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) }
+
+// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) }
+// SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") }
+
+Texture2D<float4> t;
+SamplerState s;
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z4mainDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 main(float2 loc : LOC) : SV_Target {
+ return t.Sample(s, loc);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(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.sample.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]], <2 x i32> zeroinitializer)
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> zeroinitializer)
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z11test_offsetDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(ptr {{.*}} @_ZL1t, 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.Sample(s, loc, int2(1, 2));
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(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.sample.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]], <2 x i32> %[[OFFSET_VAL]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> %[[OFFSET_VAL]])
+// CHECK: ret <4 x float> %[[RES]]
+
+// CHECK: define hidden {{.*}} <4 x float> @_Z10test_clampDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>, float {{.*}} 1.000000e+00)
+// CHECK: ret <4 x float> %[[CALL]]
+
+float4 test_clamp(float2 loc : LOC) : SV_Target {
+ return t.Sample(s, loc, int2(1, 2), 1.0f);
+}
+
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^,]+]], float {{.*}} %[[CLAMP:[^)]+]])
+// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
+// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
+// CHECK: %[[OFFSET_ADDR:.*]] = alloca <2 x i32>
+// CHECK: %[[CLAMP_ADDR:.*]] = alloca float
+// 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: store float %[[CLAMP]], ptr %[[CLAMP_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]]
+// CHECK: %[[CLAMP_VAL:.*]] = load float, ptr %[[CLAMP_ADDR]]
+// CHECK: %[[CLAMP_CAST:.*]] = fptrunc {{.*}} double {{.*}} to float
+// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
+// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.clamp.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]], <2 x i32> %[[OFFSET_VAL]], float %[[CLAMP_CAST]])
+// CHECK: ret <4 x float> %[[RES]]
>From 9fe15f3b41e666a6fe82b06e5513a36805d7d9db Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 28 Jan 2026 12:39:54 -0500
Subject: [PATCH 4/7] Use demangled names in codegen tests.
---
clang/lib/Sema/SemaHLSL.cpp | 14 ++++--------
.../resources/Texture2D.sample.hlsl | 22 +++++++++----------
2 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c2a56e5b5d953..2e5768fb184b3 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3373,22 +3373,16 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckResourceHandle(
&SemaRef, TheCall, 0,
[](const HLSLAttributedResourceType *ResType) {
- if (ResType->getAttrs().ResourceDimension ==
- llvm::dxil::ResourceDimension::DimensionUnknown) {
- return true;
- }
- return false;
+ return ResType->getAttrs().ResourceDimension ==
+ llvm::dxil::ResourceDimension::DimensionUnknown;
}))
return true;
if (CheckResourceHandle(
&SemaRef, TheCall, 1,
[](const HLSLAttributedResourceType *ResType) {
- if (ResType->getAttrs().ResourceClass !=
- llvm::hlsl::ResourceClass::Sampler)
- return true;
- llvm::dbgs() << "The sampler has the wrong resource class.\n";
- return false;
+ return ResType->getAttrs().ResourceClass !=
+ llvm::hlsl::ResourceClass::Sampler;
}))
return true;
diff --git a/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
index 2066ddfb39183..93bed2f2b7c27 100644
--- a/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
+++ b/clang/test/CodeGenHLSL/resources/Texture2D.sample.hlsl
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | 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 | FileCheck %s --check-prefixes=CHECK,SPIRV
+// 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) }
@@ -10,15 +10,15 @@
Texture2D<float4> t;
SamplerState s;
-// CHECK: define hidden {{.*}} <4 x float> @_Z4mainDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}})
+// 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]>::Sample(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.Sample(s, loc);
}
-// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_f(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^)]+]])
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Sample(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]]
@@ -33,15 +33,15 @@ float4 main(float2 loc : LOC) : SV_Target {
// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> zeroinitializer)
// CHECK: ret <4 x float> %[[RES]]
-// CHECK: define hidden {{.*}} <4 x float> @_Z11test_offsetDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}} %{{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>)
+// 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]>::Sample(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.Sample(s, loc, int2(1, 2));
}
-// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_i(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^)]+]])
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Sample(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>
@@ -59,15 +59,15 @@ float4 test_offset(float2 loc : LOC) : SV_Target {
// SPIRV: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.spv.resource.sample.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]], <2 x i32> %[[OFFSET_VAL]])
// CHECK: ret <4 x float> %[[RES]]
-// CHECK: define hidden {{.*}} <4 x float> @_Z10test_clampDv2_f(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
-// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} @_ZL1t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>, float {{.*}} 1.000000e+00)
+// CHECK: define hidden {{.*}} <4 x float> @test_clamp(float vector[2])(<2 x float> noundef nofpclass(nan inf) %[[LOC:.*]])
+// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Sample(hlsl::SamplerState, float vector[2], int vector[2], float)(ptr {{.*}} @t, ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}}, <2 x float> {{.*}}, <2 x i32> {{.*}} <i32 1, i32 2>, float {{.*}} 1.000000e+00)
// CHECK: ret <4 x float> %[[CALL]]
float4 test_clamp(float2 loc : LOC) : SV_Target {
return t.Sample(s, loc, int2(1, 2), 1.0f);
}
-// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @_ZN4hlsl9Texture2DIDv4_fE6SampleENS_12SamplerStateEDv2_fDv2_if(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^,]+]], float {{.*}} %[[CLAMP:[^)]+]])
+// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::Sample(hlsl::SamplerState, float vector[2], int vector[2], float)(ptr {{.*}} %[[THIS:[^,]+]], ptr {{.*}} byval(%"class.hlsl::SamplerState") {{.*}} %[[SAMPLER:[^,]+]], <2 x float> {{.*}} %[[COORD:[^,]+]], <2 x i32> {{.*}} %[[OFFSET:[^,]+]], float {{.*}} %[[CLAMP:[^)]+]])
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x float>
// CHECK: %[[OFFSET_ADDR:.*]] = alloca <2 x i32>
>From b2869be5567aa7241f7ba6a0f4a7db00c6853269 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 28 Jan 2026 12:40:12 -0500
Subject: [PATCH 5/7] fix format
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 2 +-
clang/lib/Sema/SemaHLSL.cpp | 15 +++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 8a71dcf0ad4c2..53adf143928bd 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -511,7 +511,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
if (IsCtor)
Method = CXXConstructorDecl::Create(
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo,
- ExplicitSpecifier(), false, /*IsInline=*/ true, false,
+ ExplicitSpecifier(), false, /*IsInline=*/true, false,
ConstexprSpecKind::Unspecified);
else
Method = CXXMethodDecl::Create(
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2e5768fb184b3..6c6ac971b8f6b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3373,17 +3373,16 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckResourceHandle(
&SemaRef, TheCall, 0,
[](const HLSLAttributedResourceType *ResType) {
- return ResType->getAttrs().ResourceDimension ==
- llvm::dxil::ResourceDimension::DimensionUnknown;
+ return ResType->getAttrs().ResourceDimension ==
+ llvm::dxil::ResourceDimension::DimensionUnknown;
}))
return true;
- if (CheckResourceHandle(
- &SemaRef, TheCall, 1,
- [](const HLSLAttributedResourceType *ResType) {
- return ResType->getAttrs().ResourceClass !=
- llvm::hlsl::ResourceClass::Sampler;
- }))
+ if (CheckResourceHandle(&SemaRef, TheCall, 1,
+ [](const HLSLAttributedResourceType *ResType) {
+ return ResType->getAttrs().ResourceClass !=
+ llvm::hlsl::ResourceClass::Sampler;
+ }))
return true;
auto *ResourceTy =
>From cf212dfad21286488973c9cc1d0e7c7e196b7e2a Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 28 Jan 2026 13:06:53 -0500
Subject: [PATCH 6/7] Merge two functions getting the handle fields.
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 49 +++++++------------
1 file changed, 17 insertions(+), 32 deletions(-)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 53adf143928bd..e4b89a26bf5e6 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -221,10 +221,6 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
- template <typename T>
- BuiltinTypeMethodBuilder &accessFieldOnResource(T ResourceRecord,
- FieldDecl *Field);
-
template <typename T>
BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);
template <typename ResourceT, typename ValueT>
@@ -650,34 +646,28 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
return *this;
}
-template <typename T>
-BuiltinTypeMethodBuilder &
-BuiltinTypeMethodBuilder::accessFieldOnResource(T ResourceRecord,
- FieldDecl *Field) {
- ensureCompleteDecl();
-
- Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
-
- ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
-
- MemberExpr *FieldExpr =
- MemberExpr::CreateImplicit(AST, ResourceExpr, false, Field,
- Field->getType(), VK_LValue, OK_Ordinary);
- StmtsList.push_back(FieldExpr);
- return *this;
-}
-
template <typename T>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {
ensureCompleteDecl();
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
- assert(ResourceExpr->getType()->getAsCXXRecordDecl() == DeclBuilder.Record &&
- "Getting the field from the wrong resource type.");
+ auto *ResourceTypeDecl = ResourceExpr->getType()->getAsCXXRecordDecl();
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
- FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+ FieldDecl *HandleField = nullptr;
+
+ if (ResourceTypeDecl == DeclBuilder.Record)
+ HandleField = DeclBuilder.getResourceHandleField();
+ else {
+ IdentifierInfo &II = AST.Idents.get("__handle");
+ for (auto *Decl : ResourceTypeDecl->lookup(&II)) {
+ if ((HandleField = dyn_cast<FieldDecl>(Decl)))
+ break;
+ }
+ assert(HandleField && "Resource handle field not found");
+ }
+
MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
OK_Ordinary);
@@ -1241,18 +1231,13 @@ BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
QualType IntTy = AST.IntTy;
QualType Int2Ty = AST.getExtVectorType(IntTy, VecSize);
- auto *RT = SamplerStateType->getAsCXXRecordDecl();
- assert(RT);
- assert(!RT->field_empty());
- FieldDecl *SamplerHandleField = *RT->field_begin();
-
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
// T Sample(SamplerState s, float2 location)
BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
.addParam("Sampler", SamplerStateType)
.addParam("Location", Float2Ty)
- .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .accessHandleFieldOnResource(PH::_0)
.callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
PH::LastStmt, PH::_1)
.returnValue(PH::LastStmt)
@@ -1263,7 +1248,7 @@ BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
.addParam("Sampler", SamplerStateType)
.addParam("Location", Float2Ty)
.addParam("Offset", Int2Ty)
- .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .accessHandleFieldOnResource(PH::_0)
.callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
PH::LastStmt, PH::_1, PH::_2)
.returnValue(PH::LastStmt)
@@ -1275,7 +1260,7 @@ BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
.addParam("Location", Float2Ty)
.addParam("Offset", Int2Ty)
.addParam("Clamp", FloatTy)
- .accessFieldOnResource(PH::_0, SamplerHandleField)
+ .accessHandleFieldOnResource(PH::_0)
.callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
PH::LastStmt, PH::_1, PH::_2, PH::_3)
.returnValue(PH::LastStmt)
>From f42a3b86794f6c04c742d76a9a33bac6cac6eae2 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Fri, 30 Jan 2026 10:51:53 -0500
Subject: [PATCH 7/7] Rename dimension enum.
---
clang/include/clang/AST/HLSLResource.h | 10 +++++-----
clang/include/clang/AST/TypeBase.h | 7 +++----
clang/include/clang/Basic/Attr.td | 3 +--
clang/lib/AST/TypePrinter.cpp | 3 +--
clang/lib/CodeGen/Targets/DirectX.cpp | 12 ++++++------
clang/lib/CodeGen/Targets/SPIR.cpp | 10 +++++-----
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 12 +++++-------
clang/lib/Sema/HLSLExternalSemaSource.cpp | 2 +-
clang/lib/Sema/SemaHLSL.cpp | 13 ++++++-------
llvm/include/llvm/Support/DXILABI.h | 10 +++++-----
10 files changed, 38 insertions(+), 44 deletions(-)
diff --git a/clang/include/clang/AST/HLSLResource.h b/clang/include/clang/AST/HLSLResource.h
index 5cf2eead246ad..071e59d72d983 100644
--- a/clang/include/clang/AST/HLSLResource.h
+++ b/clang/include/clang/AST/HLSLResource.h
@@ -92,17 +92,17 @@ struct ResourceBindingAttrs {
inline uint32_t getResourceDimensions(llvm::dxil::ResourceDimension Dim) {
switch (Dim) {
- case llvm::dxil::ResourceDimension::Dimension1D:
+ case llvm::dxil::ResourceDimension::Dim1D:
return 1;
break;
- case llvm::dxil::ResourceDimension::Dimension2D:
+ case llvm::dxil::ResourceDimension::Dim2D:
return 2;
break;
- case llvm::dxil::ResourceDimension::Dimension3D:
- case llvm::dxil::ResourceDimension::DimensionCube:
+ case llvm::dxil::ResourceDimension::Dim3D:
+ case llvm::dxil::ResourceDimension::Cube:
return 3;
break;
- case llvm::dxil::ResourceDimension::DimensionUnknown:
+ case llvm::dxil::ResourceDimension::Unknown:
llvm_unreachable(
"We cannot get the dimension of a resource with unknown dimension.");
}
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index e62ca4a3eb2c0..f648232c2949d 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6717,13 +6717,12 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
IsROV(IsROV), RawBuffer(RawBuffer), IsCounter(IsCounter) {}
Attributes(llvm::dxil::ResourceClass ResourceClass)
- : Attributes(ResourceClass,
- llvm::dxil::ResourceDimension::DimensionUnknown) {}
+ : Attributes(ResourceClass, llvm::dxil::ResourceDimension::Unknown) {}
Attributes()
: Attributes(llvm::dxil::ResourceClass::UAV,
- llvm::dxil::ResourceDimension::DimensionUnknown, false,
- false, false) {}
+ llvm::dxil::ResourceDimension::Unknown, false, false,
+ false) {}
friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
return std::tie(LHS.ResourceClass, LHS.ResourceDimension, LHS.IsROV,
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index d529976706edb..2209de79c768c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5108,8 +5108,7 @@ def HLSLResourceDimension : TypeAttr {
let Args = [EnumArgument<
"Dimension", "llvm::hlsl::ResourceDimension",
/*is_string=*/true, ["Unknown", "1D", "2D", "3D", "Cube"],
- ["DimensionUnknown", "Dimension1D", "Dimension2D", "Dimension3D",
- "DimensionCube"],
+ ["Unknown", "Dim1D", "Dim2D", "Dim3D", "Cube"],
/*opt=*/0, /*fake=*/0, /*isExternalType=*/1>];
let Documentation = [InternalOnly];
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index cd43982bee4e0..3a2f6a1486ddf 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2129,8 +2129,7 @@ void TypePrinter::printHLSLAttributedResourceAfter(
OS << ")]]";
}
- if (Attrs.ResourceDimension !=
- llvm::dxil::ResourceDimension::DimensionUnknown)
+ if (Attrs.ResourceDimension != llvm::dxil::ResourceDimension::Unknown)
OS << " [[hlsl::resource_dimension("
<< HLSLResourceDimensionAttr::ConvertResourceDimensionToStr(
Attrs.ResourceDimension)
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index c953498836836..e5b01c21e9e2f 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -67,8 +67,8 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
bool IsRawBuffer = ResAttrs.RawBuffer;
- bool IsTexture = ResAttrs.ResourceDimension !=
- llvm::dxil::ResourceDimension::DimensionUnknown;
+ bool IsTexture =
+ ResAttrs.ResourceDimension != llvm::dxil::ResourceDimension::Unknown;
assert((!IsRawBuffer || !IsTexture) && "A resource cannot be both a raw "
"buffer and a texture.");
llvm::StringRef TypeName = "dx.TypedBuffer";
@@ -93,16 +93,16 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
// Map ResourceDimension to dxil::ResourceKind
llvm::dxil::ResourceKind RK = llvm::dxil::ResourceKind::Invalid;
switch (ResAttrs.ResourceDimension) {
- case llvm::dxil::ResourceDimension::Dimension1D:
+ case llvm::dxil::ResourceDimension::Dim1D:
RK = llvm::dxil::ResourceKind::Texture1D;
break;
- case llvm::dxil::ResourceDimension::Dimension2D:
+ case llvm::dxil::ResourceDimension::Dim2D:
RK = llvm::dxil::ResourceKind::Texture2D;
break;
- case llvm::dxil::ResourceDimension::Dimension3D:
+ case llvm::dxil::ResourceDimension::Dim3D:
RK = llvm::dxil::ResourceKind::Texture3D;
break;
- case llvm::dxil::ResourceDimension::DimensionCube:
+ case llvm::dxil::ResourceDimension::Cube:
RK = llvm::dxil::ResourceKind::TextureCube;
break;
default:
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index d3c1d322aea77..32998bb5d60d5 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -862,19 +862,19 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
// Dim
switch (attributes.ResourceDimension) {
- case llvm::dxil::ResourceDimension::Dimension1D:
+ case llvm::dxil::ResourceDimension::Dim1D:
IntParams[0] = 0;
break;
- case llvm::dxil::ResourceDimension::Dimension2D:
+ case llvm::dxil::ResourceDimension::Dim2D:
IntParams[0] = 1;
break;
- case llvm::dxil::ResourceDimension::Dimension3D:
+ case llvm::dxil::ResourceDimension::Dim3D:
IntParams[0] = 2;
break;
- case llvm::dxil::ResourceDimension::DimensionCube:
+ case llvm::dxil::ResourceDimension::Cube:
IntParams[0] = 3;
break;
- case llvm::dxil::ResourceDimension::DimensionUnknown:
+ case llvm::dxil::ResourceDimension::Unknown:
IntParams[0] = 5;
break;
}
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index e4b89a26bf5e6..e799594023dbc 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -876,8 +876,7 @@ BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,
bool RawBuffer, bool HasCounter,
AccessSpecifier Access) {
- addHandleMember(RC, ResourceDimension::DimensionUnknown, IsROV, RawBuffer,
- Access);
+ addHandleMember(RC, ResourceDimension::Unknown, IsROV, RawBuffer, Access);
if (HasCounter)
addCounterHandleMember(RC, IsROV, RawBuffer, Access);
return *this;
@@ -892,7 +891,7 @@ BuiltinTypeDeclBuilder::addTextureHandle(ResourceClass RC, bool IsROV,
}
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSamplerHandle() {
- addHandleMember(ResourceClass::Sampler, ResourceDimension::DimensionUnknown,
+ addHandleMember(ResourceClass::Sampler, ResourceDimension::Unknown,
/*IsROV=*/false, /*RawBuffer=*/false);
return *this;
}
@@ -907,9 +906,8 @@ BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, ResourceDimension RD,
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(
ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
- return addResourceMember("__counter_handle", RC,
- ResourceDimension::DimensionUnknown, IsROV,
- RawBuffer,
+ return addResourceMember("__counter_handle", RC, ResourceDimension::Unknown,
+ IsROV, RawBuffer,
/*IsCounter=*/true, Access);
}
@@ -928,7 +926,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
- RD != ResourceDimension::DimensionUnknown
+ RD != ResourceDimension::Unknown
? HLSLResourceDimensionAttr::CreateImplicit(Ctx, RD)
: nullptr,
ElementTypeInfo && RC != ResourceClass::Sampler
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index c8b45352ad66a..92a4247e8796a 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -542,7 +542,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
.finalizeForwardDeclaration();
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
- ResourceDimension::Dimension2D)
+ ResourceDimension::Dim2D)
.completeDefinition();
});
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6c6ac971b8f6b..4ba25fbf5693a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3370,12 +3370,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaRef.checkArgCountRange(TheCall, 3, 5))
return true;
- if (CheckResourceHandle(
- &SemaRef, TheCall, 0,
- [](const HLSLAttributedResourceType *ResType) {
- return ResType->getAttrs().ResourceDimension ==
- llvm::dxil::ResourceDimension::DimensionUnknown;
- }))
+ if (CheckResourceHandle(&SemaRef, TheCall, 0,
+ [](const HLSLAttributedResourceType *ResType) {
+ return ResType->getAttrs().ResourceDimension ==
+ llvm::dxil::ResourceDimension::Unknown;
+ }))
return true;
if (CheckResourceHandle(&SemaRef, TheCall, 1,
@@ -3413,7 +3412,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
assert(ResourceTy->hasContainedType() &&
- "Expecting a contained type for resource with a the dimension "
+ "Expecting a contained type for resource with a dimension "
"attribute.");
QualType ReturnType = ResourceTy->getContainedType();
TheCall->setType(ReturnType);
diff --git a/llvm/include/llvm/Support/DXILABI.h b/llvm/include/llvm/Support/DXILABI.h
index 285ac1b663685..1b6ce024e23a3 100644
--- a/llvm/include/llvm/Support/DXILABI.h
+++ b/llvm/include/llvm/Support/DXILABI.h
@@ -32,11 +32,11 @@ enum class ResourceClass : uint8_t {
};
enum class ResourceDimension : uint8_t {
- DimensionUnknown = 0,
- Dimension1D,
- Dimension2D,
- Dimension3D,
- DimensionCube,
+ Unknown = 0,
+ Dim1D,
+ Dim2D,
+ Dim3D,
+ Cube,
};
/// The kind of resource for an SRV or UAV resource. Sometimes referred to as
More information about the cfe-commits
mailing list