1// RUN: mlir-opt %s -split-input-file -pass-pipeline='spv.module(inline{disable-simplify})' | FileCheck %s
2
3spv.module Logical GLSL450 {
4  spv.func @callee() "None" {
5    spv.Return
6  }
7
8  // CHECK-LABEL: @calling_single_block_ret_func
9  spv.func @calling_single_block_ret_func() "None" {
10    // CHECK-NEXT: spv.Return
11    spv.FunctionCall @callee() : () -> ()
12    spv.Return
13  }
14}
15
16// -----
17
18spv.module Logical GLSL450 {
19  spv.func @callee() -> i32 "None" {
20    %0 = spv.constant 42 : i32
21    spv.ReturnValue %0 : i32
22  }
23
24  // CHECK-LABEL: @calling_single_block_retval_func
25  spv.func @calling_single_block_retval_func() -> i32 "None" {
26    // CHECK-NEXT: %[[CST:.*]] = spv.constant 42
27    %0 = spv.FunctionCall @callee() : () -> (i32)
28    // CHECK-NEXT: spv.ReturnValue %[[CST]]
29    spv.ReturnValue %0 : i32
30  }
31}
32
33// -----
34
35spv.module Logical GLSL450 {
36  spv.globalVariable @data bind(0, 0) : !spv.ptr<!spv.struct<(!spv.rtarray<i32> [0])>, StorageBuffer>
37  spv.func @callee() "None" {
38    %0 = spv.mlir.addressof @data : !spv.ptr<!spv.struct<(!spv.rtarray<i32> [0])>, StorageBuffer>
39    %1 = spv.constant 0: i32
40    %2 = spv.AccessChain %0[%1, %1] : !spv.ptr<!spv.struct<(!spv.rtarray<i32> [0])>, StorageBuffer>, i32, i32
41    spv.Branch ^next
42
43  ^next:
44    %3 = spv.constant 42: i32
45    spv.Store "StorageBuffer" %2, %3 : i32
46    spv.Return
47  }
48
49  // CHECK-LABEL: @calling_multi_block_ret_func
50  spv.func @calling_multi_block_ret_func() "None" {
51    // CHECK-NEXT:   spv.mlir.addressof
52    // CHECK-NEXT:   spv.constant 0
53    // CHECK-NEXT:   spv.AccessChain
54    // CHECK-NEXT:   spv.Branch ^bb1
55    // CHECK-NEXT: ^bb1:
56    // CHECK-NEXT:   spv.constant
57    // CHECK-NEXT:   spv.Store
58    // CHECK-NEXT:   spv.Branch ^bb2
59    spv.FunctionCall @callee() : () -> ()
60    // CHECK-NEXT: ^bb2:
61    // CHECK-NEXT:   spv.Return
62    spv.Return
63  }
64}
65
66// TODO: calling_multi_block_retval_func
67
68// -----
69
70spv.module Logical GLSL450 {
71  spv.func @callee(%cond : i1) -> () "None" {
72    spv.selection {
73      spv.BranchConditional %cond, ^then, ^merge
74    ^then:
75      spv.Return
76    ^merge:
77      spv.mlir.merge
78    }
79    spv.Return
80  }
81
82  // CHECK-LABEL: @calling_selection_ret_func
83  spv.func @calling_selection_ret_func() "None" {
84    %0 = spv.constant true
85    // CHECK: spv.FunctionCall
86    spv.FunctionCall @callee(%0) : (i1) -> ()
87    spv.Return
88  }
89}
90
91// -----
92
93spv.module Logical GLSL450 {
94  spv.func @callee(%cond : i1) -> () "None" {
95    spv.selection {
96      spv.BranchConditional %cond, ^then, ^merge
97    ^then:
98      spv.Branch ^merge
99    ^merge:
100      spv.mlir.merge
101    }
102    spv.Return
103  }
104
105  // CHECK-LABEL: @calling_selection_no_ret_func
106  spv.func @calling_selection_no_ret_func() "None" {
107    // CHECK-NEXT: %[[TRUE:.*]] = spv.constant true
108    %0 = spv.constant true
109    // CHECK-NEXT: spv.selection
110    // CHECK-NEXT:   spv.BranchConditional %[[TRUE]], ^bb1, ^bb2
111    // CHECK-NEXT: ^bb1:
112    // CHECK-NEXT:   spv.Branch ^bb2
113    // CHECK-NEXT: ^bb2:
114    // CHECK-NEXT:   spv.mlir.merge
115    spv.FunctionCall @callee(%0) : (i1) -> ()
116    spv.Return
117  }
118}
119
120// -----
121
122spv.module Logical GLSL450 {
123  spv.func @callee(%cond : i1) -> () "None" {
124    spv.loop {
125      spv.Branch ^header
126    ^header:
127      spv.BranchConditional %cond, ^body, ^merge
128    ^body:
129      spv.Return
130    ^continue:
131      spv.Branch ^header
132    ^merge:
133      spv.mlir.merge
134    }
135    spv.Return
136  }
137
138  // CHECK-LABEL: @calling_loop_ret_func
139  spv.func @calling_loop_ret_func() "None" {
140    %0 = spv.constant true
141    // CHECK: spv.FunctionCall
142    spv.FunctionCall @callee(%0) : (i1) -> ()
143    spv.Return
144  }
145}
146
147// -----
148
149spv.module Logical GLSL450 {
150  spv.func @callee(%cond : i1) -> () "None" {
151    spv.loop {
152      spv.Branch ^header
153    ^header:
154      spv.BranchConditional %cond, ^body, ^merge
155    ^body:
156      spv.Branch ^continue
157    ^continue:
158      spv.Branch ^header
159    ^merge:
160      spv.mlir.merge
161    }
162    spv.Return
163  }
164
165  // CHECK-LABEL: @calling_loop_no_ret_func
166  spv.func @calling_loop_no_ret_func() "None" {
167    // CHECK-NEXT: %[[TRUE:.*]] = spv.constant true
168    %0 = spv.constant true
169    // CHECK-NEXT: spv.loop
170    // CHECK-NEXT:   spv.Branch ^bb1
171    // CHECK-NEXT: ^bb1:
172    // CHECK-NEXT:   spv.BranchConditional %[[TRUE]], ^bb2, ^bb4
173    // CHECK-NEXT: ^bb2:
174    // CHECK-NEXT:   spv.Branch ^bb3
175    // CHECK-NEXT: ^bb3:
176    // CHECK-NEXT:   spv.Branch ^bb1
177    // CHECK-NEXT: ^bb4:
178    // CHECK-NEXT:   spv.mlir.merge
179    spv.FunctionCall @callee(%0) : (i1) -> ()
180    spv.Return
181  }
182}
183
184// -----
185
186spv.module Logical GLSL450 {
187  spv.globalVariable @arg_0 bind(0, 0) : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>
188  spv.globalVariable @arg_1 bind(0, 1) : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>
189
190  // CHECK: @inline_into_selection_region
191  spv.func @inline_into_selection_region() "None" {
192    %1 = spv.constant 0 : i32
193    // CHECK-DAG: [[ADDRESS_ARG0:%.*]] = spv.mlir.addressof @arg_0
194    // CHECK-DAG: [[ADDRESS_ARG1:%.*]] = spv.mlir.addressof @arg_1
195    // CHECK-DAG: [[LOADPTR:%.*]] = spv.AccessChain [[ADDRESS_ARG0]]
196    // CHECK: [[VAL:%.*]] = spv.Load "StorageBuffer" [[LOADPTR]]
197    %2 = spv.mlir.addressof @arg_0 : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>
198    %3 = spv.mlir.addressof @arg_1 : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>
199    %4 = spv.AccessChain %2[%1] : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>, i32
200    %5 = spv.Load "StorageBuffer" %4 : i32
201    %6 = spv.SGreaterThan %5, %1 : i32
202    // CHECK: spv.selection
203    spv.selection {
204      spv.BranchConditional %6, ^bb1, ^bb2
205    ^bb1: // pred: ^bb0
206      // CHECK: [[STOREPTR:%.*]] = spv.AccessChain [[ADDRESS_ARG1]]
207      %7 = spv.AccessChain %3[%1] : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>, i32
208      // CHECK-NOT: spv.FunctionCall
209      // CHECK: spv.AtomicIAdd "Device" "AcquireRelease" [[STOREPTR]], [[VAL]]
210      // CHECK: spv.Branch
211      spv.FunctionCall @atomic_add(%5, %7) : (i32, !spv.ptr<i32, StorageBuffer>) -> ()
212      spv.Branch ^bb2
213    ^bb2 : // 2 preds: ^bb0, ^bb1
214      spv.mlir.merge
215    }
216    // CHECK: spv.Return
217    spv.Return
218  }
219  spv.func @atomic_add(%arg0: i32, %arg1: !spv.ptr<i32, StorageBuffer>) "None" {
220    %0 = spv.AtomicIAdd "Device" "AcquireRelease" %arg1, %arg0 : !spv.ptr<i32, StorageBuffer>
221    spv.Return
222  }
223  spv.EntryPoint "GLCompute" @inline_into_selection_region
224  spv.ExecutionMode @inline_into_selection_region "LocalSize", 32, 1, 1
225}
226
227// TODO: Add tests for inlining structured control flow into
228// structured control flow.
229