xref: /llvm-project/mlir/test/Dialect/LLVMIR/func.mlir (revision c9f72b2873d2b3ea777c3ee512696f2259252bce)
1// RUN: mlir-opt -split-input-file -verify-diagnostics %s | mlir-opt | FileCheck %s
2// RUN: mlir-opt -split-input-file -verify-diagnostics -mlir-print-op-generic %s | FileCheck %s --check-prefix=GENERIC
3// RUN: mlir-opt -split-input-file -verify-diagnostics -mlir-print-debuginfo %s | mlir-opt -split-input-file -mlir-print-debuginfo | FileCheck %s --check-prefix=LOCINFO
4// RUN: mlir-translate -mlir-to-llvmir -split-input-file -verify-diagnostics %s | FileCheck %s --check-prefix=CHECK-LLVM
5
6module {
7  // GENERIC: "llvm.func"
8  // GENERIC-SAME: function_type = !llvm.func<void ()>
9  // GENERIC-SAME: sym_name = "foo"
10  // GENERIC: () -> ()
11  // CHECK: llvm.func @foo()
12  "llvm.func" () ({
13  }) {sym_name = "foo", function_type = !llvm.func<void ()>} : () -> ()
14
15  // GENERIC: "llvm.func"
16  // GENERIC-SAME: function_type = !llvm.func<i64 (i64, i64)>
17  // GENERIC-SAME: sym_name = "bar"
18  // GENERIC: () -> ()
19  // CHECK: llvm.func @bar(i64, i64) -> i64
20  "llvm.func"() ({
21  }) {sym_name = "bar", function_type = !llvm.func<i64 (i64, i64)>} : () -> ()
22
23  // GENERIC: "llvm.func"
24  // GENERIC-SAME: function_type = !llvm.func<i64 (i64)>
25  // GENERIC-SAME: sym_name = "baz"
26  // CHECK: llvm.func @baz(%{{.*}}: i64) -> i64
27  "llvm.func"() <{sym_name = "baz", function_type = !llvm.func<i64 (i64)>}> ({
28  // GENERIC: ^bb0
29  ^bb0(%arg0: i64):
30    // GENERIC: llvm.return
31    llvm.return %arg0 : i64
32
33  // GENERIC: () -> ()
34  }) : () -> ()
35
36  // CHECK: llvm.func @qux(!llvm.ptr {llvm.noalias}, i64)
37  // CHECK: attributes {xxx = {yyy = 42 : i64}}
38  "llvm.func"() ({
39  }) {sym_name = "qux", function_type = !llvm.func<void (ptr, i64)>,
40      arg_attrs = [{llvm.noalias}, {}], xxx = {yyy = 42}} : () -> ()
41
42  // CHECK: llvm.func @roundtrip1()
43  llvm.func @roundtrip1()
44
45  // CHECK: llvm.func @roundtrip2(i64, f32) -> f64
46  llvm.func @roundtrip2(i64, f32) -> f64
47
48  // CHECK: llvm.func @roundtrip3(i32, i1)
49  llvm.func @roundtrip3(%a: i32, %b: i1)
50
51  // CHECK: llvm.func @roundtrip4(%{{.*}}: i32, %{{.*}}: i1) {
52  llvm.func @roundtrip4(%a: i32, %b: i1) {
53    llvm.return
54  }
55
56  // CHECK: llvm.func @roundtrip5()
57  // CHECK: attributes {baz = 42 : i64, foo = "bar"}
58  llvm.func @roundtrip5() attributes {foo = "bar", baz = 42}
59
60  // CHECK: llvm.func @roundtrip6()
61  // CHECK: attributes {baz = 42 : i64, foo = "bar"}
62  llvm.func @roundtrip6() attributes {foo = "bar", baz = 42} {
63    llvm.return
64  }
65
66  // CHECK: llvm.func @roundtrip7() {
67  llvm.func @roundtrip7() attributes {} {
68    llvm.return
69  }
70
71  // CHECK: llvm.func @roundtrip8() -> i32
72  llvm.func @roundtrip8() -> i32 attributes {}
73
74  // CHECK: llvm.func @roundtrip9(!llvm.ptr {llvm.noalias})
75  llvm.func @roundtrip9(!llvm.ptr {llvm.noalias})
76
77  // CHECK: llvm.func @roundtrip10(!llvm.ptr {llvm.noalias})
78  llvm.func @roundtrip10(%arg0: !llvm.ptr {llvm.noalias})
79
80  // CHECK: llvm.func @roundtrip11(%{{.*}}: !llvm.ptr {llvm.noalias}) {
81  llvm.func @roundtrip11(%arg0: !llvm.ptr {llvm.noalias}) {
82    llvm.return
83  }
84
85  // CHECK: llvm.func @roundtrip12(%{{.*}}: !llvm.ptr {llvm.noalias})
86  // CHECK: attributes {foo = 42 : i32}
87  llvm.func @roundtrip12(%arg0: !llvm.ptr {llvm.noalias})
88  attributes {foo = 42 : i32} {
89    llvm.return
90  }
91
92  // CHECK: llvm.func @byvalattr(%{{.*}}: !llvm.ptr {llvm.byval = i32})
93  llvm.func @byvalattr(%arg0: !llvm.ptr {llvm.byval = i32}) {
94    llvm.return
95  }
96
97  // CHECK: llvm.func @sretattr(%{{.*}}: !llvm.ptr {llvm.sret = i32})
98  // LOCINFO: llvm.func @sretattr(%{{.*}}: !llvm.ptr {llvm.sret = i32} loc("some_source_loc"))
99  llvm.func @sretattr(%arg0: !llvm.ptr {llvm.sret = i32} loc("some_source_loc")) {
100    llvm.return
101  }
102
103  // CHECK: llvm.func @nestattr(%{{.*}}: !llvm.ptr {llvm.nest})
104  llvm.func @nestattr(%arg0: !llvm.ptr {llvm.nest}) {
105    llvm.return
106  }
107
108  // CHECK: llvm.func @llvm_noalias_decl(!llvm.ptr {llvm.noalias})
109  llvm.func @llvm_noalias_decl(!llvm.ptr {llvm.noalias})
110  // CHECK: llvm.func @byrefattr_decl(!llvm.ptr {llvm.byref = i32})
111  llvm.func @byrefattr_decl(!llvm.ptr {llvm.byref = i32})
112  // CHECK: llvm.func @byvalattr_decl(!llvm.ptr {llvm.byval = i32})
113  llvm.func @byvalattr_decl(!llvm.ptr {llvm.byval = i32})
114  // CHECK: llvm.func @sretattr_decl(!llvm.ptr {llvm.sret = i32})
115  llvm.func @sretattr_decl(!llvm.ptr {llvm.sret = i32})
116  // CHECK: llvm.func @nestattr_decl(!llvm.ptr {llvm.nest})
117  llvm.func @nestattr_decl(!llvm.ptr {llvm.nest})
118  // CHECK: llvm.func @noundefattr_decl(i32 {llvm.noundef})
119  llvm.func @noundefattr_decl(i32 {llvm.noundef})
120  // CHECK: llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4 : i64})
121  llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4})
122  // CHECK: llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32})
123  llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32})
124
125
126  // CHECK: llvm.func @variadic(...)
127  llvm.func @variadic(...)
128
129  // CHECK: llvm.func @variadic_args(i32, i32, ...)
130  llvm.func @variadic_args(i32, i32, ...)
131
132  //
133  // Check that functions can have linkage attributes.
134  //
135
136  // CHECK: llvm.func internal
137  llvm.func internal @internal_func() {
138    llvm.return
139  }
140
141  // CHECK: llvm.func weak
142  llvm.func weak @weak_linkage() {
143    llvm.return
144  }
145
146  // CHECK-LLVM: define ptx_kernel void @calling_conv
147  llvm.func ptx_kernelcc @calling_conv() {
148    llvm.return
149  }
150
151  // Omit the `external` linkage, which is the default, in the custom format.
152  // Check that it is present in the generic format using its numeric value.
153  //
154  // CHECK: llvm.func @external_func
155  // GENERIC: linkage = #llvm.linkage<external>
156  llvm.func external @external_func()
157
158  // CHECK-LABEL: llvm.func @arg_struct_attr(
159  // CHECK-SAME: %{{.*}}: !llvm.struct<(i32)> {llvm.struct_attrs = [{llvm.noalias}]}) {
160  llvm.func @arg_struct_attr(
161      %arg0 : !llvm.struct<(i32)> {llvm.struct_attrs = [{llvm.noalias}]}) {
162    llvm.return
163  }
164
165   // CHECK-LABEL: llvm.func @res_struct_attr(%{{.*}}: !llvm.struct<(i32)>)
166   // CHECK-SAME:-> (!llvm.struct<(i32)> {llvm.struct_attrs = [{llvm.noalias}]}) {
167  llvm.func @res_struct_attr(%arg0 : !llvm.struct<(i32)>)
168      -> (!llvm.struct<(i32)> {llvm.struct_attrs = [{llvm.noalias}]}) {
169    llvm.return %arg0 : !llvm.struct<(i32)>
170  }
171
172  // CHECK: llvm.func @cconv1
173  llvm.func ccc @cconv1() {
174    llvm.return
175  }
176
177  // CHECK: llvm.func weak @cconv2
178  llvm.func weak ccc @cconv2() {
179    llvm.return
180  }
181
182  // CHECK: llvm.func weak fastcc @cconv3
183  llvm.func weak fastcc @cconv3() {
184    llvm.return
185  }
186
187  // CHECK: llvm.func cc_10 @cconv4
188  llvm.func cc_10 @cconv4() {
189    llvm.return
190  }
191
192  // CHECK: llvm.func @test_ccs
193  llvm.func @test_ccs() {
194    // CHECK-NEXT: %[[PTR:.*]] = llvm.mlir.addressof @cconv4 : !llvm.ptr
195    %ptr = llvm.mlir.addressof @cconv4 : !llvm.ptr
196    // CHECK-NEXT: llvm.call        @cconv1() : () -> ()
197    // CHECK-NEXT: llvm.call        @cconv2() : () -> ()
198    // CHECK-NEXT: llvm.call fastcc @cconv3() : () -> ()
199    // CHECK-NEXT: llvm.call cc_10  %[[PTR]]() : !llvm.ptr, () -> ()
200    llvm.call        @cconv1() : () -> ()
201    llvm.call ccc    @cconv2() : () -> ()
202    llvm.call fastcc @cconv3() : () -> ()
203    llvm.call cc_10  %ptr() : !llvm.ptr, () -> ()
204    llvm.return
205  }
206
207  // CHECK-LABEL: llvm.func @variadic_def
208  llvm.func @variadic_def(...) {
209    llvm.return
210  }
211
212  // CHECK-LABEL: llvm.func @memory_attr
213  // CHECK-SAME: attributes {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = readwrite>} {
214  llvm.func @memory_attr() attributes {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = readwrite>} {
215    llvm.return
216  }
217
218  // CHECK-LABEL: llvm.func hidden @hidden
219  llvm.func hidden @hidden() {
220    llvm.return
221  }
222
223  // CHECK-LABEL: llvm.func protected @protected
224  llvm.func protected @protected() {
225    llvm.return
226  }
227
228  // CHECK-LABEL: local_unnamed_addr @local_unnamed_addr_func
229  llvm.func local_unnamed_addr @local_unnamed_addr_func() {
230    llvm.return
231  }
232
233  // CHECK-LABEL: @align_func
234  // CHECK-SAME: attributes {alignment = 2 : i64}
235  llvm.func @align_func() attributes {alignment = 2 : i64} {
236    llvm.return
237  }
238
239  // CHECK: llvm.comdat @__llvm_comdat
240  llvm.comdat @__llvm_comdat {
241    // CHECK: llvm.comdat_selector @any any
242    llvm.comdat_selector @any any
243  }
244  // CHECK: @any() comdat(@__llvm_comdat::@any) attributes
245  llvm.func @any() comdat(@__llvm_comdat::@any) attributes { dso_local } {
246    llvm.return
247  }
248
249  llvm.func @vscale_roundtrip() vscale_range(1, 2) {
250    // CHECK: @vscale_roundtrip
251    // CHECK-SAME: vscale_range(1, 2)
252    llvm.return
253  }
254
255  // CHECK-LABEL: @frame_pointer_roundtrip()
256  // CHECK-SAME: attributes {frame_pointer = #llvm.framePointerKind<"non-leaf">}
257  llvm.func @frame_pointer_roundtrip() attributes {frame_pointer = #llvm.framePointerKind<"non-leaf">} {
258    llvm.return
259  }
260
261  llvm.func @unsafe_fp_math_roundtrip() attributes {unsafe_fp_math = true} {
262    // CHECK: @unsafe_fp_math_roundtrip
263    // CHECK-SAME: attributes {unsafe_fp_math = true}
264    llvm.return
265  }
266
267  llvm.func @no_infs_fp_math_roundtrip() attributes {no_infs_fp_math = true} {
268    // CHECK: @no_infs_fp_math_roundtrip
269    // CHECK-SAME: attributes {no_infs_fp_math = true}
270    llvm.return
271  }
272
273  llvm.func @no_nans_fp_math_roundtrip() attributes {no_nans_fp_math = true} {
274    // CHECK: @no_nans_fp_math_roundtrip
275    // CHECK-SAME: attributes {no_nans_fp_math = true}
276    llvm.return
277  }
278
279  llvm.func @approx_func_fp_math_roundtrip() attributes {approx_func_fp_math = true} {
280    // CHECK: @approx_func_fp_math_roundtrip
281    // CHECK-SAME: attributes {approx_func_fp_math = true}
282    llvm.return
283  }
284
285  llvm.func @no_signed_zeros_fp_math_roundtrip() attributes {no_signed_zeros_fp_math = true} {
286    // CHECK: @no_signed_zeros_fp_math_roundtrip
287    // CHECK-SAME: attributes {no_signed_zeros_fp_math = true}
288    llvm.return
289  }
290
291  llvm.func @convergent_function() attributes {convergent} {
292    // CHECK: @convergent_function
293    // CHECK-SAME: attributes {convergent}
294    llvm.return
295  }
296
297  llvm.func @denormal_fp_math_roundtrip() attributes {denormal_fp_math = "preserve-sign"} {
298    // CHECK: @denormal_fp_math_roundtrip
299    // CHECK-SAME: attributes {denormal_fp_math = "preserve-sign"}
300    llvm.return
301  }
302
303  llvm.func @denormal_fp_math_f32_roundtrip() attributes {denormal_fp_math_f32 = "preserve-sign"} {
304    // CHECK: @denormal_fp_math_f32_roundtrip
305    // CHECK-SAME: attributes {denormal_fp_math_f32 = "preserve-sign"}
306    llvm.return
307  }
308
309  llvm.func @fp_contract_roundtrip() attributes {fp_contract = "fast"} {
310    // CHECK: @fp_contract_roundtrip
311    // CHECK-SAME: attributes {fp_contract = "fast"}
312    llvm.return
313  }
314
315  llvm.func @nounwind_function() attributes {no_unwind} {
316    // CHECK: @nounwind_function
317    // CHECK-SAME: attributes {no_unwind}
318    llvm.return
319  }
320
321  llvm.func @willreturn_function() attributes {will_return} {
322    // CHECK: @willreturn_function
323    // CHECK-SAME: attributes {will_return}
324    llvm.return
325  }
326
327
328}
329
330// -----
331
332module {
333  // expected-error@+1 {{requires one region}}
334  "llvm.func"() {function_type = !llvm.func<void ()>, sym_name = "no_region"} : () -> ()
335}
336
337// -----
338
339module {
340  // expected-error@+1 {{requires attribute 'function_type'}}
341  "llvm.func"() ({}) {sym_name = "missing_type"} : () -> ()
342}
343
344// -----
345
346module {
347  // expected-error@+1 {{attribute 'function_type' failed to satisfy constraint: type attribute of LLVM function type}}
348  "llvm.func"() ({}) {sym_name = "non_llvm_type", function_type = i64} : () -> ()
349}
350
351// -----
352
353module {
354  // expected-error@+1 {{attribute 'function_type' failed to satisfy constraint: type attribute of LLVM function type}}
355  "llvm.func"() ({}) {sym_name = "non_function_type", function_type = i64} : () -> ()
356}
357
358// -----
359
360module {
361  // expected-error@+1 {{entry block must have 0 arguments}}
362  "llvm.func"() ({
363  ^bb0(%arg0: i64):
364    llvm.return
365  }) {function_type = !llvm.func<void ()>, sym_name = "wrong_arg_number"} : () -> ()
366}
367
368// -----
369
370module {
371  // expected-error@+1 {{entry block argument #0('tensor<*xf32>') must match the type of the corresponding argument in function signature('i64')}}
372  "llvm.func"() ({
373  ^bb0(%arg0: tensor<*xf32>):
374    llvm.return
375  }) {function_type = !llvm.func<void (i64)>, sym_name = "wrong_arg_number"} : () -> ()
376}
377
378// -----
379
380module {
381  // expected-error@+1 {{failed to construct function type: expected LLVM type for function arguments}}
382  llvm.func @foo(tensor<*xf32>)
383}
384
385// -----
386
387module {
388  // expected-error@+1 {{failed to construct function type: expected LLVM type for function results}}
389  llvm.func @foo() -> tensor<*xf32>
390}
391
392// -----
393
394module {
395  // expected-error@+1 {{failed to construct function type: expected zero or one function result}}
396  llvm.func @foo() -> (i64, i64)
397}
398
399// -----
400
401module {
402  // expected-error@+1 {{variadic arguments must be in the end of the argument list}}
403  llvm.func @variadic_inside(%arg0: i32, ..., %arg1: i32)
404}
405
406// -----
407
408module {
409  // expected-error@+1 {{external functions must have 'external' or 'extern_weak' linkage}}
410  llvm.func internal @internal_external_func()
411}
412
413// -----
414
415module {
416  // expected-error@+1 {{functions cannot have 'common' linkage}}
417  llvm.func common @common_linkage_func()
418}
419
420// -----
421
422module {
423  // expected-error@+1 {{custom op 'llvm.func' expected valid '@'-identifier for symbol name}}
424  llvm.func cc_12 @unknown_calling_convention()
425}
426
427// -----
428
429module {
430  "llvm.func"() ({
431  // expected-error @below {{invalid Calling Conventions specification: cc_12}}
432  // expected-error @below {{failed to parse CConvAttr parameter 'CallingConv' which is to be a `CConv`}}
433  }) {sym_name = "generic_unknown_calling_convention", CConv = #llvm.cconv<cc_12>, function_type = !llvm.func<i64 (i64, i64)>} : () -> ()
434}
435
436// -----
437
438// CHECK: @vec_type_hint()
439// CHECK-SAME: vec_type_hint = #llvm.vec_type_hint<hint = i32>
440llvm.func @vec_type_hint() attributes {vec_type_hint = #llvm.vec_type_hint<hint = i32>}
441
442// CHECK: @vec_type_hint_signed()
443// CHECK-SAME: vec_type_hint = #llvm.vec_type_hint<hint = i32, is_signed = true>
444llvm.func @vec_type_hint_signed() attributes {vec_type_hint = #llvm.vec_type_hint<hint = i32, is_signed = true>}
445
446// CHECK: @vec_type_hint_signed_vec()
447// CHECK-SAME: vec_type_hint = #llvm.vec_type_hint<hint = vector<2xi32>, is_signed = true>
448llvm.func @vec_type_hint_signed_vec() attributes {vec_type_hint = #llvm.vec_type_hint<hint = vector<2xi32>, is_signed = true>}
449
450// CHECK: @vec_type_hint_float_vec()
451// CHECK-SAME: vec_type_hint = #llvm.vec_type_hint<hint = vector<3xf32>>
452llvm.func @vec_type_hint_float_vec() attributes {vec_type_hint = #llvm.vec_type_hint<hint = vector<3xf32>>}
453
454// CHECK: @vec_type_hint_bfloat_vec()
455// CHECK-SAME: vec_type_hint = #llvm.vec_type_hint<hint = vector<8xbf16>>
456llvm.func @vec_type_hint_bfloat_vec() attributes {vec_type_hint = #llvm.vec_type_hint<hint = vector<8xbf16>>}
457
458// -----
459
460// CHECK: @work_group_size_hint()
461// CHECK-SAME: work_group_size_hint = array<i32: 128, 128, 128>
462llvm.func @work_group_size_hint() attributes {work_group_size_hint = array<i32: 128, 128, 128>}
463
464// -----
465
466// CHECK: @reqd_work_group_size_hint()
467// CHECK-SAME: reqd_work_group_size = array<i32: 128, 256, 128>
468llvm.func @reqd_work_group_size_hint() attributes {reqd_work_group_size = array<i32: 128, 256, 128>}
469
470// -----
471
472// CHECK: @intel_reqd_sub_group_size_hint()
473// CHECK-SAME: intel_reqd_sub_group_size = 32 : i32
474llvm.func @intel_reqd_sub_group_size_hint() attributes {llvm.intel_reqd_sub_group_size = 32 : i32}
475
476// -----
477
478// CHECK: @workgroup_attribution
479// CHECK-SAME: llvm.workgroup_attribution = #llvm.mlir.workgroup_attribution<512 : i64, i32>
480// CHECK-SAME: llvm.workgroup_attribution = #llvm.mlir.workgroup_attribution<128 : i64, !llvm.struct<(i32, i64, f32)>
481llvm.func @workgroup_attribution(%arg0: !llvm.ptr {llvm.workgroup_attribution = #llvm.mlir.workgroup_attribution<512 : i64, i32>}, %arg1: !llvm.ptr {llvm.workgroup_attribution = #llvm.mlir.workgroup_attribution<128 : i64, !llvm.struct<(i32, i64, f32)>>})
482
483// -----
484
485// CHECK: @constant_range_negative
486// CHECK-SAME: llvm.range = #llvm.constant_range<i32, 0, -2147483648>
487llvm.func @constant_range_negative() -> (i32 {llvm.range = #llvm.constant_range<i32, 0, -2147483648>})
488