18516f54eSJon Chesterfield; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature 28516f54eSJon Chesterfield; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT 38516f54eSJon Chesterfield; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI 48516f54eSJon Chesterfield; REQUIRES: webassembly-registered-target 58516f54eSJon Chesterfield 68516f54eSJon Chesterfield; Examples are variadic functions that return the first or the second of an int and a double 78516f54eSJon Chesterfield; Split the functions into an internal equivalent that takes a va_list and a ABI preserving wrapper 88516f54eSJon Chesterfield 98516f54eSJon Chesterfielddefine i32 @variadic_int_double_get_firstz(...) { 108516f54eSJon Chesterfield; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) { 118516f54eSJon Chesterfield; OPT-NEXT: entry: 128516f54eSJon Chesterfield; OPT-NEXT: %va_start = alloca ptr, align 4 138516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) 148516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) 158516f54eSJon Chesterfield; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 168516f54eSJon Chesterfield; OPT-NEXT: %1 = call i32 @variadic_int_double_get_firstz.valist(ptr %0) 178516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) 188516f54eSJon Chesterfield; OPT-NEXT: ret i32 %1 198516f54eSJon Chesterfield; 208516f54eSJon Chesterfield; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) { 218516f54eSJon Chesterfield; ABI-NEXT: entry: 228516f54eSJon Chesterfield; ABI-NEXT: %va = alloca ptr, align 4 238516f54eSJon Chesterfield; ABI-NEXT: store ptr %varargs, ptr %va, align 4 248516f54eSJon Chesterfield; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 4 258516f54eSJon Chesterfield; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 268516f54eSJon Chesterfield; ABI-NEXT: store ptr %argp.next, ptr %va, align 4 278516f54eSJon Chesterfield; ABI-NEXT: %0 = load i32, ptr %argp.cur, align 4 288516f54eSJon Chesterfield; ABI-NEXT: ret i32 %0 298516f54eSJon Chesterfield; 308516f54eSJon Chesterfieldentry: 318516f54eSJon Chesterfield %va = alloca ptr, align 4 328516f54eSJon Chesterfield call void @llvm.va_start.p0(ptr nonnull %va) 338516f54eSJon Chesterfield %argp.cur = load ptr, ptr %va, align 4 348516f54eSJon Chesterfield %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 358516f54eSJon Chesterfield store ptr %argp.next, ptr %va, align 4 368516f54eSJon Chesterfield %0 = load i32, ptr %argp.cur, align 4 378516f54eSJon Chesterfield call void @llvm.va_end.p0(ptr %va) 388516f54eSJon Chesterfield ret i32 %0 398516f54eSJon Chesterfield} 408516f54eSJon Chesterfield 418516f54eSJon Chesterfield; CHECK-LABEL: define i32 @variadic_int_double_get_firstz(...) { 428516f54eSJon Chesterfield; CHECK-NEXT: entry: 438516f54eSJon Chesterfield; CHECK-NEXT: %va_list = alloca ptr, align 4 448516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list) 458516f54eSJon Chesterfield; CHECK-NEXT: %0 = tail call i32 @variadic_int_double_get_firstz.valist(ptr %va_list) 468516f54eSJon Chesterfield; CHECK-NEXT: ret i32 %0 478516f54eSJon Chesterfield; CHECK-NEXT: } 488516f54eSJon Chesterfield 498516f54eSJon Chesterfield; CHECK-LABEL: define internal i32 @variadic_int_double_get_firstz.valist(ptr noalias %varargs) { 508516f54eSJon Chesterfield; CHECK-NEXT: entry: 518516f54eSJon Chesterfield; CHECK-NEXT: %va = alloca ptr, align 4 528516f54eSJon Chesterfield; CHECK-NEXT: store ptr %varargs, ptr %va, align 4 538516f54eSJon Chesterfield; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 4 548516f54eSJon Chesterfield; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 558516f54eSJon Chesterfield; CHECK-NEXT: store ptr %argp.next, ptr %va, align 4 568516f54eSJon Chesterfield; CHECK-NEXT: %0 = load i32, ptr %argp.cur, align 4 578516f54eSJon Chesterfield; CHECK-NEXT: ret i32 %0 588516f54eSJon Chesterfield; CHECK-NEXT: } 598516f54eSJon Chesterfield 608516f54eSJon Chesterfielddefine double @variadic_int_double_get_secondz(...) { 618516f54eSJon Chesterfield; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(...) { 628516f54eSJon Chesterfield; OPT-NEXT: entry: 638516f54eSJon Chesterfield; OPT-NEXT: %va_start = alloca ptr, align 4 648516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) 658516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) 668516f54eSJon Chesterfield; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 678516f54eSJon Chesterfield; OPT-NEXT: %1 = call double @variadic_int_double_get_secondz.valist(ptr %0) 688516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) 698516f54eSJon Chesterfield; OPT-NEXT: ret double %1 708516f54eSJon Chesterfield; 718516f54eSJon Chesterfield; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(ptr %varargs) { 728516f54eSJon Chesterfield; ABI-NEXT: entry: 738516f54eSJon Chesterfield; ABI-NEXT: %va = alloca ptr, align 4 748516f54eSJon Chesterfield; ABI-NEXT: store ptr %varargs, ptr %va, align 4 758516f54eSJon Chesterfield; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 4 768516f54eSJon Chesterfield; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 778516f54eSJon Chesterfield; ABI-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12 788516f54eSJon Chesterfield; ABI-NEXT: store ptr %argp.next2, ptr %va, align 4 798516f54eSJon Chesterfield; ABI-NEXT: %0 = load double, ptr %argp.next, align 4 808516f54eSJon Chesterfield; ABI-NEXT: ret double %0 818516f54eSJon Chesterfield; 828516f54eSJon Chesterfieldentry: 838516f54eSJon Chesterfield %va = alloca ptr, align 4 848516f54eSJon Chesterfield call void @llvm.va_start.p0(ptr nonnull %va) 858516f54eSJon Chesterfield %argp.cur = load ptr, ptr %va, align 4 868516f54eSJon Chesterfield %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 878516f54eSJon Chesterfield %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12 888516f54eSJon Chesterfield store ptr %argp.next2, ptr %va, align 4 898516f54eSJon Chesterfield %0 = load double, ptr %argp.next, align 4 908516f54eSJon Chesterfield call void @llvm.va_end.p0(ptr %va) 918516f54eSJon Chesterfield ret double %0 928516f54eSJon Chesterfield} 938516f54eSJon Chesterfield 948516f54eSJon Chesterfield; CHECK-LABEL: define double @variadic_int_double_get_secondz(...) { 958516f54eSJon Chesterfield; CHECK-NEXT: entry: 968516f54eSJon Chesterfield; CHECK-NEXT: %va_list = alloca ptr, align 4 978516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list) 988516f54eSJon Chesterfield; CHECK-NEXT: %0 = tail call double @variadic_int_double_get_secondz.valist(ptr %va_list) 998516f54eSJon Chesterfield; CHECK-NEXT: ret double %0 1008516f54eSJon Chesterfield; CHECK-NEXT: } 1018516f54eSJon Chesterfield 1028516f54eSJon Chesterfield; CHECK-LABEL: define internal double @variadic_int_double_get_secondz.valist(ptr noalias %varargs) { 1038516f54eSJon Chesterfield; CHECK-NEXT: entry: 1048516f54eSJon Chesterfield; CHECK-NEXT: %va = alloca ptr, align 4 1058516f54eSJon Chesterfield; CHECK-NEXT: store ptr %varargs, ptr %va, align 4 1068516f54eSJon Chesterfield; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 4 1078516f54eSJon Chesterfield; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4 1088516f54eSJon Chesterfield; CHECK-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12 1098516f54eSJon Chesterfield; CHECK-NEXT: store ptr %argp.next2, ptr %va, align 4 1108516f54eSJon Chesterfield; CHECK-NEXT: %0 = load double, ptr %argp.next, align 4 1118516f54eSJon Chesterfield; CHECK-NEXT: ret double %0 1128516f54eSJon Chesterfield; CHECK-NEXT: } 1138516f54eSJon Chesterfield 1148516f54eSJon Chesterfield 1158516f54eSJon Chesterfield; CHECK-LABEL: @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) { 1168516f54eSJon Chesterfield; CHECK-NEXT: entry: 1178516f54eSJon Chesterfield; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16 1188516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr %vararg_buffer) 1198516f54eSJon Chesterfield; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1208516f54eSJon Chesterfield; CHECK-NEXT: store i32 %x, ptr %0, align 4 1218516f54eSJon Chesterfield; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1 1228516f54eSJon Chesterfield; CHECK-NEXT: store double %y, ptr %1, align 4 1238516f54eSJon Chesterfield; CHECK-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer) 1248516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr %vararg_buffer) 1258516f54eSJon Chesterfield; CHECK-NEXT: %cmp.i = icmp eq i32 %call, %x 1268516f54eSJon Chesterfield; CHECK-NEXT: ret i1 %cmp.i 1278516f54eSJon Chesterfield; CHECK-NEXT: } 1288516f54eSJon Chesterfield 1298516f54eSJon Chesterfielddefine zeroext i1 @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) { 1308516f54eSJon Chesterfield; OPT-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) { 1318516f54eSJon Chesterfield; OPT-NEXT: entry: 1328516f54eSJon Chesterfield; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16 1338516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer) 134*94473f4dSHari Limaye; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1358516f54eSJon Chesterfield; OPT-NEXT: store i32 %x, ptr %0, align 4 136*94473f4dSHari Limaye; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2 1378516f54eSJon Chesterfield; OPT-NEXT: store double %y, ptr %1, align 8 1388516f54eSJon Chesterfield; OPT-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer) 1398516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer) 1408516f54eSJon Chesterfield; OPT-NEXT: %cmp.i = icmp eq i32 %call, %x 1418516f54eSJon Chesterfield; OPT-NEXT: ret i1 %cmp.i 1428516f54eSJon Chesterfield; 1438516f54eSJon Chesterfield; ABI-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) { 1448516f54eSJon Chesterfield; ABI-NEXT: entry: 1458516f54eSJon Chesterfield; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16 1468516f54eSJon Chesterfield; ABI-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer) 147*94473f4dSHari Limaye; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1488516f54eSJon Chesterfield; ABI-NEXT: store i32 %x, ptr %0, align 4 149*94473f4dSHari Limaye; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2 1508516f54eSJon Chesterfield; ABI-NEXT: store double %y, ptr %1, align 8 1518516f54eSJon Chesterfield; ABI-NEXT: %call = call i32 @variadic_int_double_get_firstz(ptr %vararg_buffer) 1528516f54eSJon Chesterfield; ABI-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer) 1538516f54eSJon Chesterfield; ABI-NEXT: %cmp.i = icmp eq i32 %call, %x 1548516f54eSJon Chesterfield; ABI-NEXT: ret i1 %cmp.i 1558516f54eSJon Chesterfield; 1568516f54eSJon Chesterfieldentry: 1578516f54eSJon Chesterfield %call = call i32 (...) @variadic_int_double_get_firstz(i32 %x, double %y) 1588516f54eSJon Chesterfield %cmp.i = icmp eq i32 %call, %x 1598516f54eSJon Chesterfield ret i1 %cmp.i 1608516f54eSJon Chesterfield} 1618516f54eSJon Chesterfield 1628516f54eSJon Chesterfield; CHECK-LABEL: @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) { 1638516f54eSJon Chesterfield; CHECK-NEXT: entry: 1648516f54eSJon Chesterfield; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16 1658516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr %vararg_buffer) 1668516f54eSJon Chesterfield; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1678516f54eSJon Chesterfield; CHECK-NEXT: store i32 %x, ptr %0, align 4 1688516f54eSJon Chesterfield; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1 1698516f54eSJon Chesterfield; CHECK-NEXT: store double %y, ptr %1, align 4 1708516f54eSJon Chesterfield; CHECK-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer) 1718516f54eSJon Chesterfield; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr %vararg_buffer) 1728516f54eSJon Chesterfield; CHECK-NEXT: %cmp.i = fcmp oeq double %call, %y 1738516f54eSJon Chesterfield; CHECK-NEXT: ret i1 %cmp.i 1748516f54eSJon Chesterfield; CHECK-NEXT: } 1758516f54eSJon Chesterfield 1768516f54eSJon Chesterfielddefine zeroext i1 @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) { 1778516f54eSJon Chesterfield; OPT-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) { 1788516f54eSJon Chesterfield; OPT-NEXT: entry: 1798516f54eSJon Chesterfield; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16 1808516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer) 181*94473f4dSHari Limaye; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1828516f54eSJon Chesterfield; OPT-NEXT: store i32 %x, ptr %0, align 4 183*94473f4dSHari Limaye; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2 1848516f54eSJon Chesterfield; OPT-NEXT: store double %y, ptr %1, align 8 1858516f54eSJon Chesterfield; OPT-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer) 1868516f54eSJon Chesterfield; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer) 1878516f54eSJon Chesterfield; OPT-NEXT: %cmp.i = fcmp oeq double %call, %y 1888516f54eSJon Chesterfield; OPT-NEXT: ret i1 %cmp.i 1898516f54eSJon Chesterfield; 1908516f54eSJon Chesterfield; ABI-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) { 1918516f54eSJon Chesterfield; ABI-NEXT: entry: 1928516f54eSJon Chesterfield; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16 1938516f54eSJon Chesterfield; ABI-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer) 194*94473f4dSHari Limaye; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0 1958516f54eSJon Chesterfield; ABI-NEXT: store i32 %x, ptr %0, align 4 196*94473f4dSHari Limaye; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2 1978516f54eSJon Chesterfield; ABI-NEXT: store double %y, ptr %1, align 8 1988516f54eSJon Chesterfield; ABI-NEXT: %call = call double @variadic_int_double_get_secondz(ptr %vararg_buffer) 1998516f54eSJon Chesterfield; ABI-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer) 2008516f54eSJon Chesterfield; ABI-NEXT: %cmp.i = fcmp oeq double %call, %y 2018516f54eSJon Chesterfield; ABI-NEXT: ret i1 %cmp.i 2028516f54eSJon Chesterfield; 2038516f54eSJon Chesterfieldentry: 2048516f54eSJon Chesterfield %call = call double (...) @variadic_int_double_get_secondz(i32 %x, double %y) 2058516f54eSJon Chesterfield %cmp.i = fcmp oeq double %call, %y 2068516f54eSJon Chesterfield ret i1 %cmp.i 2078516f54eSJon Chesterfield} 2088516f54eSJon Chesterfield 2098516f54eSJon Chesterfield; Declaration unchanged 2108516f54eSJon Chesterfield; CHECK: declare void @variadic_without_callers(...) 2118516f54eSJon Chesterfielddeclare void @variadic_without_callers(...) 2128516f54eSJon Chesterfield 2138516f54eSJon Chesterfielddeclare void @llvm.va_start.p0(ptr) 2148516f54eSJon Chesterfielddeclare void @llvm.va_end.p0(ptr) 215