[PATCH] D116465: [SPIRV 6/6] Add 2 essential passes and the simplest tests

Aleksandr Bezzubikov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 2 09:49:50 PST 2022


zuban32 added a comment.

In D116465#3290818 <https://reviews.llvm.org/D116465#3290818>, @rengolin wrote:

> In D116465#3290716 <https://reviews.llvm.org/D116465#3290716>, @zuban32 wrote:
>
>> @rengolin what would be considered as a proper implementation?
>
> I don't think I have quite understood what the problem is, tbh.
>
> If this is just some global value numbering, why is it being done so late (ie, not in IR)?
>
> If this is a SPIR-V hardware requirement, that needs a specific guaranteed shape that cannot rely on the state of IR->MIR conversions (especially the generic parts), then there may not be another way out.
>
> But I'll leave for others to express their opinions, as I'm not familiar with the problem.

Then let me describe the problem in more details, I'd like us all to be on the same page with this.

This patch adds 2 passes SPIRVGlobalTypesAndRegNumPass and SPIRVBlockLabelerPass.

The latter seems to be a minor problem - the reason for it to exist is SPIRV binary format requiring global numbering of all the defined values, i.e. if there're 2 functions each containing only 1 instruction then these instructions can't be both numbered %0.

The former one introduces a bigger problem. Basically the SPIRV binary is structured as following:

  ...
  types, constants
  ...
  functions definitions

Let me provide a short example in SPIR-V:

  %0 = OpTypeInt 32
  %1 = OpTypeInt 64
  %2 = OpConstant %1, 5
  
  %3 = OpFunction %1 ...
  %4 = OpFunctionParameter %0
  %5 = OpFunctionParameter %1
  %6 = OpUConvert %1 %4
  %7 = OpIAdd %1 %6 %5
  %8 = OpIMul %1 %7 %2
  OpReturnValue %8
  OpFunctionEnd
  
  %9 = OpFunction %1 ...
  %10 = OpFunctionParameter %0
  %11 = OpFunctionParameter %1
  %12 = OpUConvert %1 %10
  %13 = OpISub %1 %12 %11
  %14 = OpIMul%1 %13 %2
  OpReturnValue %14
  OpFunctionEnd

The LLVM IR counterparts for the functions above are the following:

  define i64 @foo(i32 %a, i64 %b)
    %0 = i64 zext i32 %a to i64
    %1 = i64 add %0, %b
    %2 = i64 mul %1, 5
    ret %2
  
  define i64 @bar(i32 %a, i64 %b)
    %0 = i64 zext i32 %a to i64
    %1 = i64 sub %0, %b
    %2 = i64 mul %1, 5
    ret %2

In the example above you can see that OpType*, OpConstant are out of any function's scope, they're global to the whole module, and this can't be natively expressed in MIR. Because of that in our approach each MachineFunction has its own copies of type decls and constants (and other stuff like that) during the whole translation process, but eventually they need to be deduplicated and 'globalized'. That can be done either on MIR level or during binary emission, but it has done be done anyway.

Hope this helps


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116465/new/

https://reviews.llvm.org/D116465



More information about the llvm-commits mailing list