Skip to content

Commit c118215

Browse files
authored
[HLSL][SPIRV] Add -fspv-use-unknown-image-format option (#155664)
This option allows users to control the image format used for HLSL resources when targeting SPIR-V. When the option is enabled, the unknown image format is used. Otherwise, the image format is guessed based on the input type. Fixes #148270
1 parent 8c1e62b commit c118215

File tree

8 files changed

+149
-12
lines changed

8 files changed

+149
-12
lines changed

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ LANGOPT(HLSL, 1, 0, NotCompatible, "HLSL")
241241
ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, NotCompatible, "HLSL Version")
242242
LANGOPT(HLSLStrictAvailability, 1, 0, NotCompatible,
243243
"Strict availability diagnostic mode for HLSL built-in functions.")
244+
LANGOPT(HLSLSpvUseUnknownImageFormat, 1, 0, NotCompatible, "For storage images and texel buffers, sets the default format to 'Unknown' when not specified via the `vk::image_format` attribute. If this option is not used, the format is inferred from the resource's data type.")
244245

245246
LANGOPT(CUDAIsDevice , 1, 0, NotCompatible, "compiling for CUDA device")
246247
LANGOPT(CUDAAllowVariadicFunctions, 1, 0, NotCompatible, "allowing variadic functions in CUDA device code")

clang/include/clang/Driver/Options.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9512,6 +9512,16 @@ def fvk_use_scalar_layout
95129512
: DXCFlag<"fvk-use-scalar-layout">,
95139513
HelpText<"Use scalar memory layout for Vulkan resources.">;
95149514

9515+
def fhlsl_spv_use_unknown_image_format
9516+
: Flag<["-"], "fspv-use-unknown-image-format">,
9517+
Group<dxc_Group>,
9518+
Visibility<[CC1Option, DXCOption]>,
9519+
HelpText<"For storage images and texel buffers, sets the default format "
9520+
"to 'Unknown' when not specified via the `vk::image_format` "
9521+
"attribute. If this option is not used, the format is inferred "
9522+
"from the resource's data type.">,
9523+
MarshallingInfoFlag<LangOpts<"HLSLSpvUseUnknownImageFormat">>;
9524+
95159525
def no_wasm_opt : Flag<["--"], "no-wasm-opt">,
95169526
Group<m_Group>,
95179527
HelpText<"Disable the wasm-opt optimizer">,

clang/lib/CodeGen/Targets/SPIR.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -513,14 +513,65 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
513513
return nullptr;
514514
}
515515

516+
static unsigned
517+
getImageFormat(const LangOptions &LangOpts,
518+
const HLSLAttributedResourceType::Attributes &attributes,
519+
llvm::Type *SampledType, QualType Ty, unsigned NumChannels) {
520+
// For images with `Sampled` operand equal to 2, there are restrictions on
521+
// using the Unknown image format. To avoid these restrictions in common
522+
// cases, we guess an image format for them based on the sampled type and the
523+
// number of channels. This is intended to match the behaviour of DXC.
524+
if (LangOpts.HLSLSpvUseUnknownImageFormat ||
525+
attributes.ResourceClass != llvm::dxil::ResourceClass::UAV) {
526+
return 0; // Unknown
527+
}
528+
529+
if (SampledType->isIntegerTy(32)) {
530+
if (Ty->isSignedIntegerType()) {
531+
if (NumChannels == 1)
532+
return 24; // R32i
533+
if (NumChannels == 2)
534+
return 25; // Rg32i
535+
if (NumChannels == 4)
536+
return 21; // Rgba32i
537+
} else {
538+
if (NumChannels == 1)
539+
return 33; // R32ui
540+
if (NumChannels == 2)
541+
return 35; // Rg32ui
542+
if (NumChannels == 4)
543+
return 30; // Rgba32ui
544+
}
545+
} else if (SampledType->isIntegerTy(64)) {
546+
if (NumChannels == 1) {
547+
if (Ty->isSignedIntegerType()) {
548+
return 41; // R64i
549+
}
550+
return 40; // R64ui
551+
}
552+
} else if (SampledType->isFloatTy()) {
553+
if (NumChannels == 1)
554+
return 3; // R32f
555+
if (NumChannels == 2)
556+
return 6; // Rg32f
557+
if (NumChannels == 4)
558+
return 1; // Rgba32f
559+
}
560+
561+
return 0; // Unknown
562+
}
563+
516564
llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
517565
const HLSLAttributedResourceType::Attributes &attributes, QualType Ty,
518566
CodeGenModule &CGM) const {
519567
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
520568

569+
unsigned NumChannels = 1;
521570
Ty = Ty->getCanonicalTypeUnqualified();
522-
if (const VectorType *V = dyn_cast<VectorType>(Ty))
571+
if (const VectorType *V = dyn_cast<VectorType>(Ty)) {
572+
NumChannels = V->getNumElements();
523573
Ty = V->getElementType();
574+
}
524575
assert(!Ty->isVectorType() && "We still have a vector type.");
525576

526577
llvm::Type *SampledType = CGM.getTypes().ConvertTypeForMem(Ty);
@@ -556,8 +607,8 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
556607
attributes.ResourceClass == llvm::dxil::ResourceClass::UAV ? 2 : 1;
557608

558609
// Image format.
559-
// Setting to unknown for now.
560-
IntParams[5] = 0;
610+
IntParams[5] = getImageFormat(CGM.getLangOpts(), attributes, SampledType, Ty,
611+
NumChannels);
561612

562613
llvm::TargetExtType *ImageType =
563614
llvm::TargetExtType::get(Ctx, Name, {SampledType}, IntParams);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3802,7 +3802,8 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
38023802
options::OPT_fnative_half_type,
38033803
options::OPT_hlsl_entrypoint,
38043804
options::OPT_fdx_rootsignature_define,
3805-
options::OPT_fdx_rootsignature_version};
3805+
options::OPT_fdx_rootsignature_version,
3806+
options::OPT_fhlsl_spv_use_unknown_image_format};
38063807
if (!types::isHLSL(InputType))
38073808
return;
38083809
for (const auto &Arg : ForwardedArguments)

clang/test/CodeGenHLSL/resources/RWBuffer-elementtype.hlsl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818

1919
// SPIRV: %"class.hlsl::RWBuffer" = type { target("spirv.SignedImage", i16, 5, 2, 0, 0, 2, 0) }
2020
// SPIRV: %"class.hlsl::RWBuffer.0" = type { target("spirv.Image", i16, 5, 2, 0, 0, 2, 0) }
21-
// SPIRV: %"class.hlsl::RWBuffer.1" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 0) }
22-
// SPIRV: %"class.hlsl::RWBuffer.2" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) }
23-
// SPIRV: %"class.hlsl::RWBuffer.3" = type { target("spirv.SignedImage", i64, 5, 2, 0, 0, 2, 0) }
24-
// SPIRV: %"class.hlsl::RWBuffer.4" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 0) }
21+
// SPIRV: %"class.hlsl::RWBuffer.1" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) }
22+
// SPIRV: %"class.hlsl::RWBuffer.2" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) }
23+
// SPIRV: %"class.hlsl::RWBuffer.3" = type { target("spirv.SignedImage", i64, 5, 2, 0, 0, 2, 41) }
24+
// SPIRV: %"class.hlsl::RWBuffer.4" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 40) }
2525
// SPIRV: %"class.hlsl::RWBuffer.5" = type { target("spirv.Image", half, 5, 2, 0, 0, 2, 0) }
26-
// SPIRV: %"class.hlsl::RWBuffer.6" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0) }
26+
// SPIRV: %"class.hlsl::RWBuffer.6" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 3) }
2727
// SPIRV: %"class.hlsl::RWBuffer.7" = type { target("spirv.Image", double, 5, 2, 0, 0, 2, 0) }
2828
// SPIRV: %"class.hlsl::RWBuffer.8" = type { target("spirv.SignedImage", i16, 5, 2, 0, 0, 2, 0) }
2929
// SPIRV: %"class.hlsl::RWBuffer.9" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) }
3030
// SPIRV: %"class.hlsl::RWBuffer.10" = type { target("spirv.Image", half, 5, 2, 0, 0, 2, 0) }
3131
// SPIRV: %"class.hlsl::RWBuffer.11" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0) }
32-
// SPIRV: %"class.hlsl::RWBuffer.12" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 0) }
32+
// SPIRV: %"class.hlsl::RWBuffer.12" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 21) }
3333

3434
RWBuffer<int16_t> BufI16;
3535
RWBuffer<uint16_t> BufU16;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s
2+
3+
// Signed integers
4+
// CHECK: %"class.hlsl::RWBuffer" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) }
5+
RWBuffer<int> rwb_int;
6+
// CHECK: %"class.hlsl::RWBuffer.0" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 25) }
7+
RWBuffer<int2> rwb_int2;
8+
// CHECK: %"class.hlsl::RWBuffer.1" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 0) }
9+
RWBuffer<int3> rwb_int3;
10+
// CHECK: %"class.hlsl::RWBuffer.2" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 21) }
11+
RWBuffer<int4> rwb_int4;
12+
13+
// Unsigned integers
14+
// CHECK: %"class.hlsl::RWBuffer.3" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) }
15+
RWBuffer<uint> rwb_uint;
16+
// CHECK: %"class.hlsl::RWBuffer.4" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 35) }
17+
RWBuffer<uint2> rwb_uint2;
18+
// CHECK: %"class.hlsl::RWBuffer.5" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) }
19+
RWBuffer<uint3> rwb_uint3;
20+
// CHECK: %"class.hlsl::RWBuffer.6" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 30) }
21+
RWBuffer<uint4> rwb_uint4;
22+
23+
// 64-bit integers
24+
// CHECK: %"class.hlsl::RWBuffer.7" = type { target("spirv.SignedImage", i64, 5, 2, 0, 0, 2, 41) }
25+
RWBuffer<int64_t> rwb_i64;
26+
// CHECK: %"class.hlsl::RWBuffer.8" = type { target("spirv.SignedImage", i64, 5, 2, 0, 0, 2, 0) }
27+
RWBuffer<int64_t2> rwb_i64_2;
28+
// CHECK: %"class.hlsl::RWBuffer.9" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 40) }
29+
RWBuffer<uint64_t> rwb_u64;
30+
// CHECK: %"class.hlsl::RWBuffer.10" = type { target("spirv.Image", i64, 5, 2, 0, 0, 2, 0) }
31+
RWBuffer<uint64_t2> rwb_u64_2;
32+
33+
// Floats
34+
// CHECK: %"class.hlsl::RWBuffer.11" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 3) }
35+
RWBuffer<float> rwb_float;
36+
// CHECK: %"class.hlsl::RWBuffer.12" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 6) }
37+
RWBuffer<float2> rwb_float2;
38+
// CHECK: %"class.hlsl::RWBuffer.13" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0) }
39+
RWBuffer<float3> rwb_float3;
40+
// CHECK: %"class.hlsl::RWBuffer.14" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 1) }
41+
RWBuffer<float4> rwb_float4;
42+
43+
// Other types that should get Unknown format
44+
// CHECK: %"class.hlsl::RWBuffer.15" = type { target("spirv.Image", half, 5, 2, 0, 0, 2, 0) }
45+
RWBuffer<half> rwb_half;
46+
// CHECK: %"class.hlsl::RWBuffer.16" = type { target("spirv.Image", double, 5, 2, 0, 0, 2, 0) }
47+
RWBuffer<double> rwb_double;
48+
49+
// Non-UAV resource
50+
// CHECK: %"class.hlsl::Buffer" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 1, 0) }
51+
Buffer<int> b_int;
52+
53+
[numthreads(1,1,1)]
54+
void main(int GI : SV_GroupIndex) {
55+
rwb_int[GI] = 0;
56+
rwb_int2[GI] = 0;
57+
rwb_int3[GI] = 0;
58+
rwb_int4[GI] = 0;
59+
rwb_uint[GI] = 0;
60+
rwb_uint2[GI] = 0;
61+
rwb_uint3[GI] = 0;
62+
rwb_uint4[GI] = 0;
63+
rwb_i64[GI] = 0;
64+
rwb_i64_2[GI] = 0;
65+
rwb_u64[GI] = 0;
66+
rwb_u64_2[GI] = 0;
67+
rwb_float[GI] = 0;
68+
rwb_float2[GI] = 0;
69+
rwb_float3[GI] = 0;
70+
rwb_float4[GI] = 0;
71+
rwb_half[GI] = 0;
72+
rwb_double[GI] = 0;
73+
int val = b_int[GI];
74+
}

clang/test/CodeGenHLSL/resources/RWBuffer-subscript.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -o - -O0 %s | FileCheck %s --check-prefixes=DXC,CHECK
2-
// RUN: %clang_cc1 -triple spirv1.6-pc-vulkan1.3-compute -emit-llvm -o - -O0 %s | FileCheck %s --check-prefixes=SPIRV,CHECK
2+
// RUN: %clang_cc1 -triple spirv1.6-pc-vulkan1.3-compute -fspv-use-unknown-image-format -emit-llvm -o - -O0 %s | FileCheck %s --check-prefixes=SPIRV,CHECK
33

44
RWBuffer<int> In;
55
RWBuffer<int> Out;

clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
22
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
3-
// RUN: -o - | FileCheck %s
3+
// RUN: -fspv-use-unknown-image-format -o - | FileCheck %s
44

55
template<class T, uint64_t Size>
66
using Array = vk::SpirvOpaqueType</* OpTypeArray */ 28, T, vk::integral_constant<uint64_t, Size>>;

0 commit comments

Comments
 (0)