[HLSL] Add sema for use of samplers and gathers on textures of doubles and ints (#212613)
Fixes https://github.com/llvm/llvm-project/issues/198882 and https://github.com/llvm/llvm-project/issues/198883 This PR: - Implements sema checks to reject the use of samplers and gathers on textures of doubles. - Implements sema checks to reject use of samplers on textures of integers before shader model 6.7 Assisted by: Claude Opus 5
This commit is contained in:
parent
c4dbdfc12e
commit
2815f298d1
4 changed files with 237 additions and 0 deletions
|
|
@ -13852,6 +13852,11 @@ def warn_hlsl_assigning_local_resource_is_not_unique
|
|||
|
||||
def err_hlsl_push_constant_unique
|
||||
: Error<"cannot have more than one push constant block">;
|
||||
def err_hlsl_sample_double_element_type
|
||||
: Error<"'%0' is not supported for resources containing %1">;
|
||||
def err_hlsl_sample_integer_element_type
|
||||
: Error<"'%0' on resources containing %1 requires shader model 6.7 or "
|
||||
"newer; the target shader model is %2">;
|
||||
def err_hlsl_samplecmp_requires_float
|
||||
: Error<"'SampleCmp' and 'SampleCmpLevelZero' require resource to contain "
|
||||
"a floating point type">;
|
||||
|
|
|
|||
|
|
@ -3770,6 +3770,96 @@ static bool CheckVectorElementCount(Sema *S, QualType PassedType,
|
|||
|
||||
enum class SampleKind { Sample, Bias, Grad, Level, Cmp, CmpLevelZero };
|
||||
|
||||
static StringRef getSampleMethodName(SampleKind Kind) {
|
||||
switch (Kind) {
|
||||
case SampleKind::Sample:
|
||||
return "Sample";
|
||||
case SampleKind::Bias:
|
||||
return "SampleBias";
|
||||
case SampleKind::Grad:
|
||||
return "SampleGrad";
|
||||
case SampleKind::Level:
|
||||
return "SampleLevel";
|
||||
case SampleKind::Cmp:
|
||||
return "SampleCmp";
|
||||
case SampleKind::CmpLevelZero:
|
||||
return "SampleCmpLevelZero";
|
||||
}
|
||||
llvm_unreachable("Invalid SampleKind");
|
||||
}
|
||||
|
||||
// Returns the name of the resource method whose body the sampling or gather
|
||||
// builtin is being emitted into, which is the name the user called. This
|
||||
// matters for methods that share a builtin, like 'Gather' and 'GatherRed'.
|
||||
// Falls back to DefaultName if the builtin is used outside of a resource
|
||||
// method.
|
||||
static StringRef getCurrentResourceMethodName(Sema &S, StringRef DefaultName) {
|
||||
const auto *MD = dyn_cast_if_present<CXXMethodDecl>(S.getCurFunctionDecl());
|
||||
if (!MD || !MD->getDeclName().isIdentifier())
|
||||
return DefaultName;
|
||||
|
||||
QualType RecordTy = S.Context.getCanonicalTagType(MD->getParent());
|
||||
if (!RecordTy->isHLSLResourceRecord())
|
||||
return DefaultName;
|
||||
|
||||
return MD->getName();
|
||||
}
|
||||
|
||||
// Returns the element type of a typed resource's contained type. Typed resource
|
||||
// element types are scalars or vectors of scalars, so anything that is not a
|
||||
// vector is already the element type.
|
||||
static QualType getTypedResourceElementType(QualType ContainedType) {
|
||||
if (const auto *VecTy = ContainedType->getAs<VectorType>())
|
||||
return VecTy->getElementType();
|
||||
return ContainedType;
|
||||
}
|
||||
|
||||
// Sampling from and gathering on resources with a 'double' element type is not
|
||||
// supported. Such resources are still valid declarations whose contents can be
|
||||
// accessed by other means, like Load or the subscript operator.
|
||||
static bool CheckNoDoubleElementType(Sema &S, CallExpr *TheCall,
|
||||
QualType ContainedType,
|
||||
StringRef DefaultName) {
|
||||
QualType EltTy = getTypedResourceElementType(ContainedType);
|
||||
if (!EltTy->isSpecificBuiltinType(BuiltinType::Double))
|
||||
return false;
|
||||
|
||||
S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_sample_double_element_type)
|
||||
<< getCurrentResourceMethodName(S, DefaultName) << ContainedType;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sampling textures with an integer element type was introduced in SM 6.7 as
|
||||
// part of Advanced Texture Operations. The shader model only applies to DirectX
|
||||
// targets; Vulkan has no such restriction.
|
||||
static bool CheckIntegerElementTypeShaderModel(Sema &S, CallExpr *TheCall,
|
||||
QualType ContainedType,
|
||||
SampleKind Kind) {
|
||||
// Comparison sampling requires a floating point element type at every shader
|
||||
// model, which the caller diagnoses.
|
||||
if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero)
|
||||
return false;
|
||||
|
||||
// 'bool' is an integer type in HLSL, but sampling bool resources is never
|
||||
// allowed, so it must not be reported as requiring shader model 6.7.
|
||||
QualType EltTy = getTypedResourceElementType(ContainedType);
|
||||
if (!EltTy->isIntegerType() || EltTy->isBooleanType())
|
||||
return false;
|
||||
|
||||
const TargetInfo &TI = S.Context.getTargetInfo();
|
||||
if (!TI.getTriple().isDXIL())
|
||||
return false;
|
||||
|
||||
VersionTuple SMVersion = TI.getPlatformMinVersion();
|
||||
if (SMVersion >= VersionTuple(6, 7))
|
||||
return false;
|
||||
|
||||
S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_sample_integer_element_type)
|
||||
<< getCurrentResourceMethodName(S, getSampleMethodName(Kind))
|
||||
<< ContainedType << SMVersion.getAsString();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckTextureSamplerAndLocation(Sema &S, CallExpr *TheCall,
|
||||
bool IncludeArraySlice = true) {
|
||||
// Check the texture handle.
|
||||
|
|
@ -3885,6 +3975,10 @@ static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp) {
|
|||
"attribute.");
|
||||
QualType ReturnType = ResourceTy->getContainedType();
|
||||
|
||||
if (CheckNoDoubleElementType(S, TheCall, ReturnType,
|
||||
IsCmp ? "GatherCmp" : "Gather"))
|
||||
return true;
|
||||
|
||||
if (IsCmp) {
|
||||
if (!ReturnType->hasFloatingRepresentation()) {
|
||||
S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
|
||||
|
|
@ -4033,6 +4127,14 @@ static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
|
|||
"Expecting a contained type for resource with a dimension "
|
||||
"attribute.");
|
||||
QualType ReturnType = ResourceTy->getContainedType();
|
||||
|
||||
if (CheckNoDoubleElementType(S, TheCall, ReturnType,
|
||||
getSampleMethodName(Kind)))
|
||||
return true;
|
||||
|
||||
if (CheckIntegerElementTypeShaderModel(S, TheCall, ReturnType, Kind))
|
||||
return true;
|
||||
|
||||
if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
|
||||
if (!ReturnType->hasFloatingRepresentation()) {
|
||||
S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -DTEXTURE=Texture2D -DCOORD_TYPE=float2 -DLOCATION=int3 -DINDEX=uint2 -verify %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -DTEXTURE=Texture2DArray -DCOORD_TYPE=float3 -DLOCATION=int4 -DINDEX=uint3 -verify %s
|
||||
|
||||
// Textures with a 'double' element type are valid declarations, but sampling
|
||||
// from them and gathering on them is not supported.
|
||||
|
||||
TEXTURE<double2> TexVec;
|
||||
TEXTURE<double> Tex;
|
||||
SamplerState Samp;
|
||||
SamplerComparisonState SampCmp;
|
||||
|
||||
void main(COORD_TYPE uv) {
|
||||
float compare = 0.5f;
|
||||
|
||||
// expected-error@* {{'Sample' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::Sample' requested here}}
|
||||
Tex.Sample(Samp, uv);
|
||||
|
||||
// expected-error@* {{'SampleBias' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::SampleBias' requested here}}
|
||||
Tex.SampleBias(Samp, uv, 0.5f);
|
||||
|
||||
// expected-error@* {{'SampleGrad' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::SampleGrad' requested here}}
|
||||
Tex.SampleGrad(Samp, uv, float2(0, 0), float2(0, 0));
|
||||
|
||||
// expected-error@* {{'SampleLevel' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::SampleLevel' requested here}}
|
||||
Tex.SampleLevel(Samp, uv, 0.0f);
|
||||
|
||||
// expected-error@* {{'SampleCmp' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::SampleCmp' requested here}}
|
||||
Tex.SampleCmp(SampCmp, uv, compare);
|
||||
|
||||
// expected-error@* {{'SampleCmpLevelZero' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::SampleCmpLevelZero' requested here}}
|
||||
Tex.SampleCmpLevelZero(SampCmp, uv, compare);
|
||||
|
||||
// expected-error@* {{'Gather' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::Gather' requested here}}
|
||||
Tex.Gather(Samp, uv);
|
||||
|
||||
// expected-error@* {{'GatherRed' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::GatherRed' requested here}}
|
||||
Tex.GatherRed(Samp, uv);
|
||||
|
||||
// expected-error@* {{'GatherCmp' is not supported for resources containing 'double'}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<double>::GatherCmp' requested here}}
|
||||
Tex.GatherCmp(SampCmp, uv, compare);
|
||||
|
||||
// Textures containing vectors of doubles are rejected as well.
|
||||
// expected-error@* {{'Sample' is not supported for resources containing 'vector<double, 2>' (vector of 2 'double' values)}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<vector<double, 2>>::Sample' requested here}}
|
||||
TexVec.Sample(Samp, uv);
|
||||
|
||||
// expected-error@* {{'SampleLevel' is not supported for resources containing 'vector<double, 2>' (vector of 2 'double' values)}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<vector<double, 2>>::SampleLevel' requested here}}
|
||||
TexVec.SampleLevel(Samp, uv, 0.0f);
|
||||
|
||||
// expected-error@* {{'Gather' is not supported for resources containing 'vector<double, 2>' (vector of 2 'double' values)}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<vector<double, 2>>::Gather' requested here}}
|
||||
TexVec.Gather(Samp, uv);
|
||||
|
||||
// Loading from and subscripting textures containing doubles is allowed.
|
||||
double a = Tex.Load((LOCATION)0);
|
||||
double b = Tex[(INDEX)0];
|
||||
double2 c = TexVec.Load((LOCATION)0);
|
||||
double2 d = TexVec[(INDEX)0];
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -x hlsl -fsyntax-only -finclude-default-header -fnative-half-type -fnative-int16-type -DTEXTURE=Texture2D -DCOORD_TYPE=float2 -verify=sm66,expected %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -x hlsl -fsyntax-only -finclude-default-header -fnative-half-type -fnative-int16-type -DTEXTURE=Texture2DArray -DCOORD_TYPE=float3 -verify=sm66,expected %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -x hlsl -fsyntax-only -finclude-default-header -fnative-half-type -fnative-int16-type -DTEXTURE=Texture2D -DCOORD_TYPE=float2 -verify=expected %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -x hlsl -fsyntax-only -finclude-default-header -fnative-half-type -fnative-int16-type -DTEXTURE=Texture2DArray -DCOORD_TYPE=float3 -verify=expected %s
|
||||
// RUN: %clang_cc1 -triple spirv-unknown-vulkan-library -x hlsl -fsyntax-only -finclude-default-header -fnative-half-type -fnative-int16-type -DTEXTURE=Texture2D -DCOORD_TYPE=float2 -verify=expected %s
|
||||
|
||||
// Sampling textures with an integer element type was introduced in shader model
|
||||
// 6.7, so the `sm66` diagnostics are only expected in the shader model 6.6 runs.
|
||||
// The Vulkan target has no shader model and does not restrict integer sampling.
|
||||
// Comparison sampling requires a floating point element type at every shader
|
||||
// model, so those diagnostics use the `expected` prefix.
|
||||
|
||||
TEXTURE<int4> TexVec;
|
||||
TEXTURE<uint> Tex;
|
||||
TEXTURE<int16_t> TexShort;
|
||||
SamplerState Samp;
|
||||
SamplerComparisonState SampCmp;
|
||||
|
||||
void main(COORD_TYPE uv) {
|
||||
float compare = 0.5f;
|
||||
|
||||
// sm66-error@* {{'Sample' on resources containing 'unsigned int' requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::Sample' requested here}}
|
||||
Tex.Sample(Samp, uv);
|
||||
|
||||
// sm66-error@* {{'SampleBias' on resources containing 'unsigned int' requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::SampleBias' requested here}}
|
||||
Tex.SampleBias(Samp, uv, 0.5f);
|
||||
|
||||
// sm66-error@* {{'SampleGrad' on resources containing 'unsigned int' requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::SampleGrad' requested here}}
|
||||
Tex.SampleGrad(Samp, uv, float2(0, 0), float2(0, 0));
|
||||
|
||||
// sm66-error@* {{'SampleLevel' on resources containing 'unsigned int' requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::SampleLevel' requested here}}
|
||||
Tex.SampleLevel(Samp, uv, 0.0f);
|
||||
|
||||
// Textures containing vectors of integers and 16-bit integers are gated the
|
||||
// same way.
|
||||
// sm66-error@* {{'Sample' on resources containing 'vector<int, 4>' (vector of 4 'int' values) requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<vector<int, 4>>::Sample' requested here}}
|
||||
TexVec.Sample(Samp, uv);
|
||||
|
||||
// sm66-error@* {{'SampleLevel' on resources containing 'short' requires shader model 6.7 or newer; the target shader model is 6.6}}
|
||||
// sm66-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<short>::SampleLevel' requested here}}
|
||||
TexShort.SampleLevel(Samp, uv, 0.0f);
|
||||
|
||||
// Comparison sampling rejects integer element types at every shader model.
|
||||
// expected-error@* {{'SampleCmp' and 'SampleCmpLevelZero' require resource to contain a floating point type}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::SampleCmp' requested here}}
|
||||
Tex.SampleCmp(SampCmp, uv, compare);
|
||||
|
||||
// expected-error@* {{'SampleCmp' and 'SampleCmpLevelZero' require resource to contain a floating point type}}
|
||||
// expected-note-re@*:* {{in instantiation of member function 'hlsl::Texture{{.+}}<unsigned int>::SampleCmpLevelZero' requested here}}
|
||||
Tex.SampleCmpLevelZero(SampCmp, uv, compare);
|
||||
|
||||
// Gathering on textures with an integer element type is allowed at every
|
||||
// shader model.
|
||||
Tex.Gather(Samp, uv);
|
||||
TexVec.Gather(Samp, uv);
|
||||
}
|
||||
Loading…
Reference in a new issue