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