Skip to content

Commit

Permalink
[Utils][SPIR-V] Adding spirv-sim to LLVM (#107094)
Browse files Browse the repository at this point in the history
### 2nd submission
The buildbots are using python 3.8, and some type annotations I was
using are only available starting 3.9. The last commit on the pile is
the additional changes compared to the original submission
#104020.

### Original text:
Currently, the testing infrastructure for SPIR-V is based on FileCheck.
Those tests are great to check some level of codegen, but when the test
needs check both the CFG layout and the content of each basic-block,
things becomes messy.

Because the CHECK/CHECK-DAG/CHECK-NEXT state is limited, it is sometimes
hard to catch the good block: if 2 basic blocks have similar
instructions, FileCheck can match the wrong one.

Cross-lane interaction can be a bit difficult to understand, and
writting a FileCheck test that is strong enough to catch bad CFG
transforms while not being broken everytime some unrelated codegen part
changes is hard.

And lastly, the spirv-val tooling we have checks that the generated
SPIR-V respects the spec, not that it is correct in regards to the
source IR.

For those reasons, I believe the best way to test the structurizer is
to:

run spirv-val to make sure the CFG respects the spec.
simulate the function to validate result for each lane, making sure the
generated code is correct.
This simulator has no other dependencies than core python. It also only
supports a very limited set of instructions as we can test most features
through control-flow and some basic cross-lane interactions.

As-is, the added tests are just a harness for the simulator itself. If
this gets merged, the structurizer PR will benefit from this as I'll be
able to add extensive testing using this.

---------

Signed-off-by: Nathan Gauër <[email protected]>
  • Loading branch information
Keenuts authored Sep 4, 2024
1 parent 9e08db7 commit 5914566
Show file tree
Hide file tree
Showing 14 changed files with 1,459 additions and 1 deletion.
42 changes: 42 additions & 0 deletions llvm/test/Other/spirv-sim/branch.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=3 --expects=5,6,6 -i %s
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main" %WaveIndex
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
OpDecorate %WaveIndex BuiltIn SubgroupLocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%bool = OpTypeBool
%int_2 = OpConstant %int 2
%int_5 = OpConstant %int 5
%int_6 = OpConstant %int 6
%uint_0 = OpConstant %uint 0
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%uint_iptr = OpTypePointer Input %uint
%WaveIndex = OpVariable %uint_iptr Input
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
%2 = OpLoad %uint %WaveIndex
%3 = OpIEqual %bool %uint_0 %2
OpSelectionMerge %merge None
OpBranchConditional %3 %true %false
%true = OpLabel
OpBranch %merge
%false = OpLabel
OpBranch %merge
%merge = OpLabel
%4 = OpPhi %int %int_5 %true %int_6 %false
OpReturnValue %4
OpFunctionEnd

36 changes: 36 additions & 0 deletions llvm/test/Other/spirv-sim/call.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=1 --expects=2 -i %s
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main" %WaveIndex
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
OpDecorate %WaveIndex BuiltIn SubgroupLocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%sub_type = OpTypeFunction %uint
%uint_iptr = OpTypePointer Input %uint
%WaveIndex = OpVariable %uint_iptr Input
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%sub = OpFunction %uint None %sub_type
%a = OpLabel
OpReturnValue %uint_2
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
%2 = OpFunctionCall %uint %sub
%3 = OpBitcast %int %2
OpReturnValue %3
OpFunctionEnd


36 changes: 36 additions & 0 deletions llvm/test/Other/spirv-sim/constant.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=a --wave=1 --expects=2 -i %s
; RUN: spirv-sim --function=b --wave=1 --expects=1 -i %s
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %a "a"
OpName %b "b"
OpName %main "main"
%int = OpTypeInt 32 1
%s1 = OpTypeStruct %int %int %int
%s2 = OpTypeStruct %s1
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%s1_1_2 = OpConstantComposite %s1 %int_1 %int_2 %int_1
%s2_s1 = OpConstantComposite %s2 %s1_1_2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%a = OpFunction %int None %simple_type
%1 = OpLabel
%2 = OpCompositeExtract %int %s1_1_2 1
OpReturnValue %2
OpFunctionEnd
%b = OpFunction %int None %simple_type
%3 = OpLabel
%4 = OpCompositeExtract %int %s2_s1 0 2
OpReturnValue %4
OpFunctionEnd

8 changes: 8 additions & 0 deletions llvm/test/Other/spirv-sim/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
spirv_sim_root = os.path.join(config.llvm_src_root, "utils", "spirv-sim")
config.substitutions.append(
(
"spirv-sim",
"'%s' %s"
% (config.python_executable, os.path.join(spirv_sim_root, "spirv-sim.py")),
)
)
58 changes: 58 additions & 0 deletions llvm/test/Other/spirv-sim/loop.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=4 --expects=0,2,2,4 -i %s
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main" %WaveIndex
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
OpDecorate %WaveIndex BuiltIn SubgroupLocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%bool = OpTypeBool
%int_2 = OpConstant %int 2
%int_5 = OpConstant %int 5
%int_6 = OpConstant %int 6
%uint_0 = OpConstant %uint 0
%uint_2 = OpConstant %uint 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%uint_iptr = OpTypePointer Input %uint
%uint_fptr = OpTypePointer Function %uint
%WaveIndex = OpVariable %uint_iptr Input
%main = OpFunction %void None %main_type
%unused = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%entry = OpLabel
; uint i = 0;
%i = OpVariable %uint_fptr Function
%1 = OpLoad %uint %WaveIndex
OpStore %i %uint_0
OpBranch %header
%header = OpLabel
%2 = OpLoad %uint %i
%3 = OpULessThan %bool %2 %1
OpLoopMerge %merge %continue None
OpBranchConditional %3 %body %merge
; while (i < WaveGetLaneIndex()) {
; i += 2;
; }
%body = OpLabel
OpBranch %continue
%continue = OpLabel
%4 = OpIAdd %uint %2 %uint_2
OpStore %i %4
OpBranch %header
%merge = OpLabel
; return (int) i;
%5 = OpLoad %uint %i
%6 = OpBitcast %int %5
OpReturnValue %6
OpFunctionEnd


26 changes: 26 additions & 0 deletions llvm/test/Other/spirv-sim/simple-bad-result.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: not spirv-sim --function=simple --wave=1 --expects=1 -i %s 2>&1 | FileCheck %s

; CHECK: Expected != Observed
; CHECK: [1] != [2]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
%int = OpTypeInt 32 1
%int_2 = OpConstant %int 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
OpReturnValue %int_2
OpFunctionEnd

22 changes: 22 additions & 0 deletions llvm/test/Other/spirv-sim/simple.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=1 --expects=2 -i %s
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
%int = OpTypeInt 32 1
%int_2 = OpConstant %int 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
OpReturnValue %int_2
OpFunctionEnd
36 changes: 36 additions & 0 deletions llvm/test/Other/spirv-sim/simulator-args.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; RUN: not spirv-sim --function=simple --wave=a --expects=2 -i %s 2>&1 | FileCheck %s --check-prefixes=CHECK-WAVE
; RUN: not spirv-sim --function=simple --wave=1 --expects=a -i %s 2>&1 | FileCheck %s --check-prefixes=CHECK-EXPECT
; RUN: not spirv-sim --function=simple --wave=1 --expects=1, -i %s 2>&1 | FileCheck %s --check-prefixes=CHECK-EXPECT
; RUN: not spirv-sim --function=simple --wave=2 --expects=1 -i %s 2>&1 | FileCheck %s --check-prefixes=CHECK-SIZE
; RUN: not spirv-sim --function=foo --wave=1 --expects=1 -i %s 2>&1 | FileCheck %s --check-prefixes=CHECK-NAME

; CHECK-WAVE: Invalid format for --wave/-w flag.

; CHECK-EXPECT: Invalid format for --expects/-e flag.

; CHECK-SIZE: Wave size != expected result array size

; CHECK-NAME: 'foo' function not found. Known functions are:
; CHECK-NAME-NEXT: - main
; CHECK-NAME-NEXT: - simple
; CHECK-NANE-NOT-NEXT: -
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
%int = OpTypeInt 32 1
%int_2 = OpConstant %int 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
OpReturnValue %int_2
OpFunctionEnd
42 changes: 42 additions & 0 deletions llvm/test/Other/spirv-sim/switch.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=4 --expects=0,1,2,0 -i %s
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main" %WaveIndex
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
OpDecorate %WaveIndex BuiltIn SubgroupLocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%bool = OpTypeBool
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%uint_0 = OpConstant %uint 0
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%uint_iptr = OpTypePointer Input %uint
%WaveIndex = OpVariable %uint_iptr Input
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
%2 = OpLoad %uint %WaveIndex
OpSelectionMerge %merge None
OpSwitch %2 %default 1 %case_1 2 %case_2
%default = OpLabel
OpBranch %merge
%case_1 = OpLabel
OpBranch %merge
%case_2 = OpLabel
OpBranch %merge
%merge = OpLabel
%4 = OpPhi %int %int_0 %default %int_1 %case_1 %int_2 %case_2
OpReturnValue %4
OpFunctionEnd
30 changes: 30 additions & 0 deletions llvm/test/Other/spirv-sim/wave-get-lane-index.spv
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; RUN: %if spirv-tools %{ spirv-as %s -o - | spirv-val - %}
; RUN: spirv-sim --function=simple --wave=4 --expects=0,1,2,3 -i %s
OpCapability Shader
OpCapability GroupNonUniform
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main" %WaveIndex
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 670
OpName %simple "simple"
OpName %main "main"
OpDecorate %WaveIndex BuiltIn SubgroupLocalInvocationId
%int = OpTypeInt 32 1
%uint = OpTypeInt 32 0
%int_2 = OpConstant %int 2
%void = OpTypeVoid
%main_type = OpTypeFunction %void
%simple_type = OpTypeFunction %int
%uint_iptr = OpTypePointer Input %uint
%WaveIndex = OpVariable %uint_iptr Input
%main = OpFunction %void None %main_type
%entry = OpLabel
OpReturn
OpFunctionEnd
%simple = OpFunction %int None %simple_type
%1 = OpLabel
%2 = OpLoad %uint %WaveIndex
%3 = OpBitcast %int %2
OpReturnValue %3
OpFunctionEnd

Loading

2 comments on commit 5914566

@mmoult
Copy link

@mmoult mmoult commented on 5914566 Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Keenuts Interesting commit you have here. After reading the commit message, it seems like you have a different use case, but if you do want to use a more fully-fledged SPIR-V interpreter/simulator, I am working on one here: https://github.com/mmoult/SPIRV-Interpreter

Also thought it might be helpful to point out that .spv files are typically binary, and .spvasm is used for assembly like you have.

Cheers!

@Keenuts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Thanks, yes the goal was really here just to test cross-wave synchronization in a more suited way than FileCheck.
From the comment I just received on the PR seems at some don't agree with my approach, so I'll open an RFC to gather a broader feedback.
During the backend meetings, some folks at Intel mentioned they might be interested in expending the simulator, so I'll bring up your project as they might not know about it.

Please sign in to comment.