DirectXShaderCompiler icon indicating copy to clipboard operation
DirectXShaderCompiler copied to clipboard

[Feature Request] A way to obtain/symbolically substitute a Type with its SPIR-V OpType ResultID in Inline Intrinsics

Open devshgraphicsprogramming opened this issue 4 months ago • 1 comments

Is your feature request related to a problem? Please describe.

I'm trying to use VK_KHR_shader_untyped_pointers with HLSL's Inline SPIR-V, but I've hit a roadblock

template<uint32_t StorageClass>
//[[vk::ext_extension("SPV_KHR_untyped_pointers")]] https://github.com/microsoft/DirectXShaderCompiler/issues/6958
//[[vk::ext_capability(spv::CapabilityUntypedPointersKHR)]] https://github.com/microsoft/DirectXShaderCompiler/issues/6958
using pointer_t = vk::SpirvOpaqueType<spv::OpTypeUntypedPointerKHR,vk::Literal<vk::integral_constant<uint32_t,StorageClass> > >;

template<uint32_t StorageClass>
[[vk::ext_extension("SPV_KHR_untyped_pointers")]]
[[vk::ext_capability(spv::CapabilityUntypedPointersKHR)]]
[[vk::ext_instruction(spv::OpUntypedVariableKHR)]]
pointer_t<StorageClass> untypedVariable([[vk::ext_literal]] uint32_t __storageClass=StorageClass/*, can't do DataType because there's no TypeID for vk::SpirvType, can't do initialize cause it comes after*/);

The problem is that I need to use OpUntypedVariable to declare (alloca) a variable, but it has the following SPIR-V signature Image

While the Inline SPIR-V can deduce the type of the return variable, and substitute it as the second operand (first in disassembled SPIR-V), there's no way for me to even symbolically plug even the ResultID of a given vk::SpirvType into the intrinsic (yes I know a regular T will be ambiguous because of layouts, but my own declared SpirvTypes are unambiguous).

Describe the solution you'd like

Syntax, maybe like this

vk::Spirv[Opaque]Type<...>::type_id

to get something like a vk::type_info opaque struct which can symbolically represent my custom type.

Describe alternatives you've considered

Extra template parameters for the intrinsic, but then its unclear what argument is meant to be passed as an actual custom SPIR-V value and the ResultID of the type.

Additional context

I think I've filed an issue for this before with a different motication, but can't find anything with a quick search.

Godbolt with my experiment : https://godbolt.org/z/benq3PW36

This is the SPIR-V I'm trying to achieve https://godbolt.org/z/jKG5EK5x4

               OpCapability Shader
               OpCapability Int16
               OpCapability PhysicalStorageBufferAddresses
               OpCapability UntypedPointersKHR
               OpExtension "SPV_KHR_untyped_pointers"
               OpMemoryModel PhysicalStorageBuffer64 GLSL450
               OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
               OpExecutionMode %main LocalSize 16 16 1
               OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
               OpMemberDecorate %MyThing 0 Offset 0
               OpMemberDecorate %MyThing 1 Offset 4
               OpMemberDecorate %MyThing 2 Offset 6
%_ptr_Function = OpTypeUntypedPointerKHR Function
        %int = OpTypeInt 32 1
      %int_0 = OpConstant %int 0
      %int_1 = OpConstant %int 1
      %int_4 = OpConstant %int 4
      %float = OpTypeFloat 32
       %uint = OpTypeInt 32 0
    %uint_45 = OpConstant %uint 45
     %ushort = OpTypeInt 16 0
      %short = OpTypeInt 16 1
     %v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
       %void = OpTypeVoid
         %67 = OpTypeFunction %void
%_arr_ushort_uint_45 = OpTypeArray %ushort %uint_45
    %MyThing = OpTypeStruct %float %short %ushort
%_ptr_BDA_MyThing = OpTypePointer PhysicalStorageBuffer %MyThing
%_ptr_Function_ushort = OpTypePointer Function %ushort
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
         %71 = OpUndef %ushort
         %72 = OpUndef %float
         %73 = OpUndef %_ptr_BDA_MyThing
%_ptr_Input_uint = OpTypePointer Input %uint
       %main = OpFunction %void None %67
%logical_merge = OpLabel
; declare a local stack of 45 bytes
         %data = OpUntypedVariableKHR %_ptr_Function Function %_arr_ushort_uint_45
; right now the use of KHR_untyped_pointers will prevent some optimization passes,
; but I'd expect this to get optimized out if we don't unpredictably initialize
         %76 = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID %int_0
         %77 = OpLoad %uint %76
%globalInvocationID_x = OpUConvert %ushort %77
; do `data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x`
         %79 = OpUntypedAccessChainKHR %_ptr_Function %_arr_ushort_uint_45 %data %globalInvocationID_x
               OpStore %79 %globalInvocationID_x
; attempting a load of MyThing at 4 bytes relative to data[45]
         %80 = OpUntypedAccessChainKHR %_ptr_Function %_arr_ushort_uint_45 %data %int_4
         %81 = OpLoad %MyThing %80
               OpStore %73 %81 Aligned 4
; special code finish
               OpReturn
               OpFunctionEnd

no clue if thats allowed/legal under the "all variables restrict" Vulkan env rule

(I ran into this trying to alias two access chains before https://github.com/KhronosGroup/SPIRV-Tools/issues/6061)