xref: /llvm-project/llvm/test/CodeGen/SPIRV/instructions/atomic.ll (revision 3cfd0c0d36975504099034ce11f4df07c5a7eba7)
1; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
2; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3
4; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
5; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
6
7; CHECK-DAG: OpName [[ADD:%.*]] "test_add"
8; CHECK-DAG: OpName [[SUB:%.*]] "test_sub"
9; CHECK-DAG: OpName [[MIN:%.*]] "test_min"
10; CHECK-DAG: OpName [[MAX:%.*]] "test_max"
11; CHECK-DAG: OpName [[UMIN:%.*]] "test_umin"
12; CHECK-DAG: OpName [[UMAX:%.*]] "test_umax"
13; CHECK-DAG: OpName [[AND:%.*]] "test_and"
14; CHECK-DAG: OpName [[OR:%.*]] "test_or"
15; CHECK-DAG: OpName [[XOR:%.*]] "test_xor"
16
17; CHECK-DAG: [[I32Ty:%.*]] = OpTypeInt 32 0
18; CHECK-DAG: [[PtrI32Ty:%.*]] = OpTypePointer Function [[I32Ty]]
19; CHECK-DAG: [[I64Ty:%.*]] = OpTypeInt 64 0
20; CHECK-DAG: [[PtrI64Ty:%.*]] = OpTypePointer Generic [[I64Ty]]
21; CHECK-DAG: [[CROSSDEVICESCOPE:%.*]] = OpConstantNull [[I32Ty]]
22; CHECK-DAG: [[DEVICESCOPE:%.*]] = OpConstant [[I32Ty]] 1
23;; "monotonic" maps to the relaxed memory semantics, encoded with constant 0
24
25; CHECK:      [[ADD]] = OpFunction [[I32Ty]]
26; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
27; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
28; CHECK-NEXT: OpLabel
29; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
30; CHECK-NEXT: OpReturnValue [[R]]
31; CHECK-NEXT: OpFunctionEnd
32define i32 @test_add(i32* %ptr, i32 %val) {
33  %r = atomicrmw add i32* %ptr, i32 %val monotonic
34  ret i32 %r
35}
36
37; CHECK:      [[SUB]] = OpFunction [[I32Ty]]
38; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
39; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
40; CHECK-NEXT: OpLabel
41; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
42; CHECK-NEXT: OpReturnValue [[R]]
43; CHECK-NEXT: OpFunctionEnd
44define i32 @test_sub(i32* %ptr, i32 %val) {
45  %r = atomicrmw sub i32* %ptr, i32 %val monotonic
46  ret i32 %r
47}
48
49; CHECK:      [[MIN]] = OpFunction [[I32Ty]]
50; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
51; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
52; CHECK-NEXT: OpLabel
53; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
54; CHECK-NEXT: OpReturnValue [[R]]
55; CHECK-NEXT: OpFunctionEnd
56define i32 @test_min(i32* %ptr, i32 %val) {
57  %r = atomicrmw min i32* %ptr, i32 %val monotonic
58  ret i32 %r
59}
60
61; CHECK:      [[MAX]] = OpFunction [[I32Ty]]
62; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
63; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
64; CHECK-NEXT: OpLabel
65; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
66; CHECK-NEXT: OpReturnValue [[R]]
67; CHECK-NEXT: OpFunctionEnd
68define i32 @test_max(i32* %ptr, i32 %val) {
69  %r = atomicrmw max i32* %ptr, i32 %val monotonic
70  ret i32 %r
71}
72
73; CHECK:      [[UMIN]] = OpFunction [[I32Ty]]
74; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
75; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
76; CHECK-NEXT: OpLabel
77; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
78; CHECK-NEXT: OpReturnValue [[R]]
79; CHECK-NEXT: OpFunctionEnd
80define i32 @test_umin(i32* %ptr, i32 %val) {
81  %r = atomicrmw umin i32* %ptr, i32 %val monotonic
82  ret i32 %r
83}
84
85; CHECK:      [[UMAX]] = OpFunction [[I32Ty]]
86; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
87; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
88; CHECK-NEXT: OpLabel
89; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
90; CHECK-NEXT: OpReturnValue [[R]]
91; CHECK-NEXT: OpFunctionEnd
92define i32 @test_umax(i32* %ptr, i32 %val) {
93  %r = atomicrmw umax i32* %ptr, i32 %val monotonic
94  ret i32 %r
95}
96
97; CHECK:      [[AND]] = OpFunction [[I32Ty]]
98; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
99; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
100; CHECK-NEXT: OpLabel
101; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
102; CHECK-NEXT: OpReturnValue [[R]]
103; CHECK-NEXT: OpFunctionEnd
104define i32 @test_and(i32* %ptr, i32 %val) {
105  %r = atomicrmw and i32* %ptr, i32 %val monotonic
106  ret i32 %r
107}
108
109; CHECK:      [[OR]] = OpFunction [[I32Ty]]
110; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
111; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
112; CHECK-NEXT: OpLabel
113; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
114; CHECK-NEXT: OpReturnValue [[R]]
115; CHECK-NEXT: OpFunctionEnd
116define i32 @test_or(i32* %ptr, i32 %val) {
117  %r = atomicrmw or i32* %ptr, i32 %val monotonic
118  ret i32 %r
119}
120
121; CHECK:      [[XOR]] = OpFunction [[I32Ty]]
122; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]]
123; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]]
124; CHECK-NEXT: OpLabel
125; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]]
126; CHECK-NEXT: OpReturnValue [[R]]
127; CHECK-NEXT: OpFunctionEnd
128define i32 @test_xor(i32* %ptr, i32 %val) {
129  %r = atomicrmw xor i32* %ptr, i32 %val monotonic
130  ret i32 %r
131}
132
133; CHECK: OpFunction
134; CHECK-NEXT: [[Arg1:%.*]] = OpFunctionParameter [[PtrI64Ty]]
135; CHECK-NEXT: [[Arg2:%.*]] = OpFunctionParameter [[I64Ty]]
136; CHECK-NEXT: OpLabel
137; CHECK-NEXT: OpAtomicSMin [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]]
138; CHECK-NEXT: OpAtomicSMax [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]]
139; CHECK-NEXT: OpAtomicUMin [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]]
140; CHECK-NEXT: OpAtomicUMax [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]]
141; CHECK-NEXT: OpReturn
142; CHECK-NEXT: OpFunctionEnd
143define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %val) {
144  %r1 = call spir_func i64 @__spirv_AtomicSMin(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val)
145  %r2 = call spir_func i64 @__spirv_AtomicSMax(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val)
146  %r3 = call spir_func i64 @__spirv_AtomicUMin(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val)
147  %r4 = call spir_func i64 @__spirv_AtomicUMax(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val)
148  ret void
149}
150
151declare dso_local spir_func i64 @__spirv_AtomicSMin(ptr addrspace(4), i32, i32, i64)
152declare dso_local spir_func i64 @__spirv_AtomicSMax(ptr addrspace(4), i32, i32, i64)
153declare dso_local spir_func i64 @__spirv_AtomicUMin(ptr addrspace(4), i32, i32, i64)
154declare dso_local spir_func i64 @__spirv_AtomicUMax(ptr addrspace(4), i32, i32, i64)
155