|
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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:%.*]]) |
| 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 nocapture noundef readonly [[Y:%.*]]) |
| 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 nocapture noundef readonly [[Y:%.*]], ptr nocapture noundef writeonly [[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 nocapture noundef readonly [[X:%.*]], i32 noundef [[Y:%.*]], ptr nocapture noundef writeonly [[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 nocapture noundef readonly [[X:%.*]], i32 noundef returned [[Y:%.*]]) |
| 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 nocapture noundef readonly [[Y:%.*]]) |
| 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 nocapture noundef readonly [[Y:%.*]], ptr nocapture noundef writeonly [[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 nocapture noundef readonly [[X:%.*]], i32 noundef [[Y:%.*]], ptr nocapture noundef writeonly [[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 nocapture noundef readonly [[X:%.*]], i32 noundef returned [[Y:%.*]]) |
| 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 | +} |
0 commit comments