18516f54eSJon Chesterfield // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature 28516f54eSJon Chesterfield // REQUIRES: webassembly-registered-target 38516f54eSJon Chesterfield 48516f54eSJon Chesterfield // Simple calls to known variadic functions that are completely elided when 58516f54eSJon Chesterfield // optimisations are on This is a functional check that the expand-variadic pass 68516f54eSJon Chesterfield // is consistent with clang's va_arg handling 78516f54eSJon Chesterfield 88516f54eSJon Chesterfield // When expand-variadics is added to the default pipeline, clang -O1 will 98516f54eSJon Chesterfield // suffice here -Wno-varargs avoids warning second argument to 'va_start' is not 108516f54eSJon Chesterfield // the last named parameter 118516f54eSJon Chesterfield 128516f54eSJon Chesterfield // 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 138516f54eSJon Chesterfield 148516f54eSJon Chesterfield #include <stdarg.h> 158516f54eSJon Chesterfield #include <stdint.h> 168516f54eSJon Chesterfield 178516f54eSJon Chesterfield template <typename X, typename Y> static X first(...) { 188516f54eSJon Chesterfield va_list va; 198516f54eSJon Chesterfield __builtin_va_start(va, 0); 208516f54eSJon Chesterfield X r = va_arg(va, X); 218516f54eSJon Chesterfield va_end(va); 228516f54eSJon Chesterfield return r; 238516f54eSJon Chesterfield } 248516f54eSJon Chesterfield 258516f54eSJon Chesterfield template <typename X, typename Y> static Y second(...) { 268516f54eSJon Chesterfield va_list va; 278516f54eSJon Chesterfield __builtin_va_start(va, 0); 288516f54eSJon Chesterfield va_arg(va, X); 298516f54eSJon Chesterfield Y r = va_arg(va, Y); 308516f54eSJon Chesterfield va_end(va); 318516f54eSJon Chesterfield return r; 328516f54eSJon Chesterfield } 338516f54eSJon Chesterfield 348516f54eSJon Chesterfield extern "C" { 358516f54eSJon Chesterfield 368516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_pair_i32 37a79ae862SNikita Popov // CHECK-SAME: (i32 noundef returned [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { 388516f54eSJon Chesterfield // CHECK-NEXT: entry: 398516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[X]] 408516f54eSJon Chesterfield // 418516f54eSJon Chesterfield int first_pair_i32(int x, int y) { return first<int, int>(x, y); } 428516f54eSJon Chesterfield 438516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_pair_i32 44a79ae862SNikita Popov // CHECK-SAME: (i32 noundef [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 458516f54eSJon Chesterfield // CHECK-NEXT: entry: 468516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[Y]] 478516f54eSJon Chesterfield // 488516f54eSJon Chesterfield int second_pair_i32(int x, int y) { return second<int, int>(x, y); } 498516f54eSJon Chesterfield 508516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_pair_f64 51a79ae862SNikita Popov // CHECK-SAME: (double noundef returned [[X:%.*]], double noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 528516f54eSJon Chesterfield // CHECK-NEXT: entry: 538516f54eSJon Chesterfield // CHECK-NEXT: ret double [[X]] 548516f54eSJon Chesterfield // 558516f54eSJon Chesterfield double first_pair_f64(double x, double y) { 568516f54eSJon Chesterfield return first<double, double>(x, y); 578516f54eSJon Chesterfield } 588516f54eSJon Chesterfield 598516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_pair_f64 60a79ae862SNikita Popov // CHECK-SAME: (double noundef [[X:%.*]], double noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 618516f54eSJon Chesterfield // CHECK-NEXT: entry: 628516f54eSJon Chesterfield // CHECK-NEXT: ret double [[Y]] 638516f54eSJon Chesterfield // 648516f54eSJon Chesterfield double second_pair_f64(double x, double y) { 658516f54eSJon Chesterfield return second<double, double>(x, y); 668516f54eSJon Chesterfield } 678516f54eSJon Chesterfield } 688516f54eSJon Chesterfield 698516f54eSJon Chesterfield extern "C" { 708516f54eSJon Chesterfield 718516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_i32_f64 72a79ae862SNikita Popov // CHECK-SAME: (i32 noundef returned [[X:%.*]], double noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 738516f54eSJon Chesterfield // CHECK-NEXT: entry: 748516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[X]] 758516f54eSJon Chesterfield // 768516f54eSJon Chesterfield int first_i32_f64(int x, double y) { return first<int, double>(x, y); } 778516f54eSJon Chesterfield 788516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_i32_f64 79a79ae862SNikita Popov // CHECK-SAME: (i32 noundef [[X:%.*]], double noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 808516f54eSJon Chesterfield // CHECK-NEXT: entry: 818516f54eSJon Chesterfield // CHECK-NEXT: ret double [[Y]] 828516f54eSJon Chesterfield // 838516f54eSJon Chesterfield double second_i32_f64(int x, double y) { return second<int, double>(x, y); } 848516f54eSJon Chesterfield 858516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_f64_i32 86a79ae862SNikita Popov // CHECK-SAME: (double noundef returned [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 878516f54eSJon Chesterfield // CHECK-NEXT: entry: 888516f54eSJon Chesterfield // CHECK-NEXT: ret double [[X]] 898516f54eSJon Chesterfield // 908516f54eSJon Chesterfield double first_f64_i32(double x, int y) { return first<double, int>(x, y); } 918516f54eSJon Chesterfield 928516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_f64_i32 93a79ae862SNikita Popov // CHECK-SAME: (double noundef [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 948516f54eSJon Chesterfield // CHECK-NEXT: entry: 958516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[Y]] 968516f54eSJon Chesterfield // 978516f54eSJon Chesterfield int second_f64_i32(double x, int y) { return second<double, int>(x, y); } 988516f54eSJon Chesterfield } 998516f54eSJon Chesterfield 1008516f54eSJon Chesterfield extern "C" { 1018516f54eSJon Chesterfield typedef uint64_t ulong2 __attribute__((__vector_size__(16), __aligned__(16))); 1028516f54eSJon Chesterfield 1038516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_i32_ulong2 104*29441e4fSNikita Popov // CHECK-SAME: (i32 noundef returned [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 1058516f54eSJon Chesterfield // CHECK-NEXT: entry: 1068516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[X]] 1078516f54eSJon Chesterfield // 1088516f54eSJon Chesterfield int first_i32_ulong2(int x, ulong2 *y) { return first<int, ulong2>(x, *y); } 1098516f54eSJon Chesterfield 1108516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_i32_ulong2 111*29441e4fSNikita Popov // 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]+]] { 1128516f54eSJon Chesterfield // CHECK-NEXT: entry: 1138516f54eSJon Chesterfield // CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[Y]], align 16, !tbaa [[TBAA2:![0-9]+]] 1148516f54eSJon Chesterfield // CHECK-NEXT: store <2 x i64> [[TMP0]], ptr [[R]], align 16, !tbaa [[TBAA2]] 1158516f54eSJon Chesterfield // CHECK-NEXT: ret void 1168516f54eSJon Chesterfield // 1178516f54eSJon Chesterfield void second_i32_ulong2(int x, ulong2 *y, ulong2 *r) { 1188516f54eSJon Chesterfield *r = second<int, ulong2>(x, *y); 1198516f54eSJon Chesterfield } 1208516f54eSJon Chesterfield 1218516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_ulong2_i32 122*29441e4fSNikita Popov // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 16)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] { 1238516f54eSJon Chesterfield // CHECK-NEXT: entry: 1248516f54eSJon Chesterfield // CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[X]], align 16, !tbaa [[TBAA2]] 1258516f54eSJon Chesterfield // CHECK-NEXT: store <2 x i64> [[TMP0]], ptr [[R]], align 16, !tbaa [[TBAA2]] 1268516f54eSJon Chesterfield // CHECK-NEXT: ret void 1278516f54eSJon Chesterfield // 1288516f54eSJon Chesterfield void first_ulong2_i32(ulong2 *x, int y, ulong2 *r) { 1298516f54eSJon Chesterfield *r = first<ulong2, int>(*x, y); 1308516f54eSJon Chesterfield } 1318516f54eSJon Chesterfield 1328516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_ulong2_i32 133*29441e4fSNikita Popov // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 1348516f54eSJon Chesterfield // CHECK-NEXT: entry: 1358516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[Y]] 1368516f54eSJon Chesterfield // 1378516f54eSJon Chesterfield int second_ulong2_i32(ulong2 *x, int y) { return second<ulong2, int>(*x, y); } 1388516f54eSJon Chesterfield } 1398516f54eSJon Chesterfield 1408516f54eSJon Chesterfield // ascending alignment 1418516f54eSJon Chesterfield typedef struct { 1428516f54eSJon Chesterfield char c; 1438516f54eSJon Chesterfield short s; 1448516f54eSJon Chesterfield int i; 1458516f54eSJon Chesterfield long l; 1468516f54eSJon Chesterfield float f; 1478516f54eSJon Chesterfield double d; 1488516f54eSJon Chesterfield } asc; 1498516f54eSJon Chesterfield 1508516f54eSJon Chesterfield extern "C" { 1518516f54eSJon Chesterfield 1528516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_i32_asc 153*29441e4fSNikita Popov // CHECK-SAME: (i32 noundef returned [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 1548516f54eSJon Chesterfield // CHECK-NEXT: entry: 1558516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[X]] 1568516f54eSJon Chesterfield // 1578516f54eSJon Chesterfield int first_i32_asc(int x, asc *y) { return first<int, asc>(x, *y); } 1588516f54eSJon Chesterfield 1598516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_i32_asc 160*29441e4fSNikita Popov // CHECK-SAME: (i32 noundef [[X:%.*]], ptr noundef readonly captures(none) [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 24)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] { 1618516f54eSJon Chesterfield // CHECK-NEXT: entry: 1628516f54eSJon Chesterfield // 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) 1638516f54eSJon Chesterfield // CHECK-NEXT: ret void 1648516f54eSJon Chesterfield // 1658516f54eSJon Chesterfield void second_i32_asc(int x, asc *y, asc *r) { *r = second<int, asc>(x, *y); } 1668516f54eSJon Chesterfield 1678516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@first_asc_i32 168*29441e4fSNikita Popov // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef [[Y:%.*]], ptr noundef writeonly captures(none) initializes((0, 24)) [[R:%.*]]) local_unnamed_addr #[[ATTR1]] { 1698516f54eSJon Chesterfield // CHECK-NEXT: entry: 1708516f54eSJon Chesterfield // 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) 1718516f54eSJon Chesterfield // CHECK-NEXT: ret void 1728516f54eSJon Chesterfield // 1738516f54eSJon Chesterfield void first_asc_i32(asc *x, int y, asc *r) { *r = first<asc, int>(*x, y); } 1748516f54eSJon Chesterfield 1758516f54eSJon Chesterfield // CHECK-LABEL: define {{[^@]+}}@second_asc_i32 176*29441e4fSNikita Popov // CHECK-SAME: (ptr noundef readonly captures(none) [[X:%.*]], i32 noundef returned [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { 1778516f54eSJon Chesterfield // CHECK-NEXT: entry: 1788516f54eSJon Chesterfield // CHECK-NEXT: ret i32 [[Y]] 1798516f54eSJon Chesterfield // 1808516f54eSJon Chesterfield int second_asc_i32(asc *x, int y) { return second<asc, int>(*x, y); } 1818516f54eSJon Chesterfield } 182