xref: /llvm-project/clang/test/CodeGenCXX/inline-then-fold-variadics.cpp (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
2 // REQUIRES: webassembly-registered-target
3 
4 // Simple calls to known variadic functions that are completely elided when
5 // optimisations are on This is a functional check that the expand-variadic pass
6 // is consistent with clang's va_arg handling
7 
8 // When expand-variadics is added to the default pipeline, clang -O1 will
9 // suffice here -Wno-varargs avoids warning second argument to 'va_start' is not
10 // the last named parameter
11 
12 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -Wno-varargs -O1 -emit-llvm -o - | opt - -S --passes='module(expand-variadics,default<O1>)' --expand-variadics-override=optimize -o - | FileCheck %s
13 
14 #include <stdarg.h>
15 #include <stdint.h>
16 
17 template <typename X, typename Y> static X first(...) {
18   va_list va;
19   __builtin_va_start(va, 0);
20   X r = va_arg(va, X);
21   va_end(va);
22   return r;
23 }
24 
25 template <typename X, typename Y> static Y second(...) {
26   va_list va;
27   __builtin_va_start(va, 0);
28   va_arg(va, X);
29   Y r = va_arg(va, Y);
30   va_end(va);
31   return r;
32 }
33 
34 extern "C" {
35 
36 // CHECK-LABEL: define {{[^@]+}}@first_pair_i32
37 // CHECK-SAME: (i32 noundef returned [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
38 // CHECK-NEXT:  entry:
39 // CHECK-NEXT:    ret i32 [[X]]
40 //
41 int first_pair_i32(int x, int y) { return first<int, int>(x, y); }
42 
43 // CHECK-LABEL: define {{[^@]+}}@second_pair_i32
44 // CHECK-SAME: (i32 noundef [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
45 // CHECK-NEXT:  entry:
46 // CHECK-NEXT:    ret i32 [[Y]]
47 //
48 int second_pair_i32(int x, int y) { return second<int, int>(x, y); }
49 
50 // CHECK-LABEL: define {{[^@]+}}@first_pair_f64
51 // CHECK-SAME: (double noundef returned [[X:%.*]], double noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
52 // CHECK-NEXT:  entry:
53 // CHECK-NEXT:    ret double [[X]]
54 //
55 double first_pair_f64(double x, double y) {
56   return first<double, double>(x, y);
57 }
58 
59 // CHECK-LABEL: define {{[^@]+}}@second_pair_f64
60 // CHECK-SAME: (double noundef [[X:%.*]], double noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
61 // CHECK-NEXT:  entry:
62 // CHECK-NEXT:    ret double [[Y]]
63 //
64 double second_pair_f64(double x, double y) {
65   return second<double, double>(x, y);
66 }
67 }
68 
69 extern "C" {
70 
71 // CHECK-LABEL: define {{[^@]+}}@first_i32_f64
72 // CHECK-SAME: (i32 noundef returned [[X:%.*]], double noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
73 // CHECK-NEXT:  entry:
74 // CHECK-NEXT:    ret i32 [[X]]
75 //
76 int first_i32_f64(int x, double y) { return first<int, double>(x, y); }
77 
78 // CHECK-LABEL: define {{[^@]+}}@second_i32_f64
79 // CHECK-SAME: (i32 noundef [[X:%.*]], double noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
80 // CHECK-NEXT:  entry:
81 // CHECK-NEXT:    ret double [[Y]]
82 //
83 double second_i32_f64(int x, double y) { return second<int, double>(x, y); }
84 
85 // CHECK-LABEL: define {{[^@]+}}@first_f64_i32
86 // CHECK-SAME: (double noundef returned [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
87 // CHECK-NEXT:  entry:
88 // CHECK-NEXT:    ret double [[X]]
89 //
90 double first_f64_i32(double x, int y) { return first<double, int>(x, y); }
91 
92 // CHECK-LABEL: define {{[^@]+}}@second_f64_i32
93 // CHECK-SAME: (double noundef [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
94 // CHECK-NEXT:  entry:
95 // CHECK-NEXT:    ret i32 [[Y]]
96 //
97 int second_f64_i32(double x, int y) { return second<double, int>(x, y); }
98 }
99 
100 extern "C" {
101 typedef uint64_t ulong2 __attribute__((__vector_size__(16), __aligned__(16)));
102 
103 // CHECK-LABEL: define {{[^@]+}}@first_i32_ulong2
104 // CHECK-SAME: (i32 noundef returned [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
105 // CHECK-NEXT:  entry:
106 // CHECK-NEXT:    ret i32 [[X]]
107 //
108 int first_i32_ulong2(int x, ulong2 *y) { return first<int, ulong2>(x, *y); }
109 
110 // CHECK-LABEL: define {{[^@]+}}@second_i32_ulong2
111 // CHECK-SAME: (i32 noundef [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 16)) [[R:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
112 // CHECK-NEXT:  entry:
113 // CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[Y]], align 16, !tbaa [[TBAA2:![0-9]+]]
114 // CHECK-NEXT:    store <2 x i64> [[TMP0]], ptr [[R]], align 16, !tbaa [[TBAA2]]
115 // CHECK-NEXT:    ret void
116 //
117 void second_i32_ulong2(int x, ulong2 *y, ulong2 *r) {
118   *r = second<int, ulong2>(x, *y);
119 }
120 
121 // CHECK-LABEL: define {{[^@]+}}@first_ulong2_i32
122 // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 16)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] {
123 // CHECK-NEXT:  entry:
124 // CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[X]], align 16, !tbaa [[TBAA2]]
125 // CHECK-NEXT:    store <2 x i64> [[TMP0]], ptr [[R]], align 16, !tbaa [[TBAA2]]
126 // CHECK-NEXT:    ret void
127 //
128 void first_ulong2_i32(ulong2 *x, int y, ulong2 *r) {
129   *r = first<ulong2, int>(*x, y);
130 }
131 
132 // CHECK-LABEL: define {{[^@]+}}@second_ulong2_i32
133 // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
134 // CHECK-NEXT:  entry:
135 // CHECK-NEXT:    ret i32 [[Y]]
136 //
137 int second_ulong2_i32(ulong2 *x, int y) { return second<ulong2, int>(*x, y); }
138 }
139 
140 // ascending alignment
141 typedef struct {
142   char c;
143   short s;
144   int i;
145   long l;
146   float f;
147   double d;
148 } asc;
149 
150 extern "C" {
151 
152 // CHECK-LABEL: define {{[^@]+}}@first_i32_asc
153 // CHECK-SAME: (i32 noundef returned [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
154 // CHECK-NEXT:  entry:
155 // CHECK-NEXT:    ret i32 [[X]]
156 //
157 int first_i32_asc(int x, asc *y) { return first<int, asc>(x, *y); }
158 
159 // CHECK-LABEL: define {{[^@]+}}@second_i32_asc
160 // CHECK-SAME: (i32 noundef [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 24)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] {
161 // CHECK-NEXT:  entry:
162 // CHECK-NEXT:    tail call void @llvm.memmove.p0.p0.i32(ptr noundef nonnull align 8 dereferenceable(24) [[R]], ptr noundef nonnull align 1 dereferenceable(24) [[Y]], i32 24, i1 false)
163 // CHECK-NEXT:    ret void
164 //
165 void second_i32_asc(int x, asc *y, asc *r) { *r = second<int, asc>(x, *y); }
166 
167 // CHECK-LABEL: define {{[^@]+}}@first_asc_i32
168 // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 24)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] {
169 // CHECK-NEXT:  entry:
170 // CHECK-NEXT:    tail call void @llvm.memmove.p0.p0.i32(ptr noundef nonnull align 8 dereferenceable(24) [[R]], ptr noundef nonnull align 1 dereferenceable(24) [[X]], i32 24, i1 false)
171 // CHECK-NEXT:    ret void
172 //
173 void first_asc_i32(asc *x, int y, asc *r) { *r = first<asc, int>(*x, y); }
174 
175 // CHECK-LABEL: define {{[^@]+}}@second_asc_i32
176 // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
177 // CHECK-NEXT:  entry:
178 // CHECK-NEXT:    ret i32 [[Y]]
179 //
180 int second_asc_i32(asc *x, int y) { return second<asc, int>(*x, y); }
181 }
182