227 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature --check-globals2; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT3; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI4; REQUIRES: webassembly-registered-target5 6; Examples are variadic functions that return the first or the second of an int and a double7; Split the functions into an internal equivalent that takes a va_list and a ABI preserving wrapper8 9define i32 @variadic_int_double_get_firstz(...) !prof !0 {10; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) !prof !0 {11; OPT-NEXT: entry:12; OPT-NEXT: %va_start = alloca ptr, align 413; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)14; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start)15; OPT-NEXT: %0 = load ptr, ptr %va_start, align 416; OPT-NEXT: %1 = call i32 @variadic_int_double_get_firstz.valist(ptr %0)17; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)18; OPT-NEXT: ret i32 %119;20; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) !prof !0 {21; ABI-NEXT: entry:22; ABI-NEXT: %va = alloca ptr, align 423; ABI-NEXT: store ptr %varargs, ptr %va, align 424; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 425; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 426; ABI-NEXT: store ptr %argp.next, ptr %va, align 427; ABI-NEXT: %0 = load i32, ptr %argp.cur, align 428; ABI-NEXT: ret i32 %029;30entry:31 %va = alloca ptr, align 432 call void @llvm.va_start.p0(ptr nonnull %va)33 %argp.cur = load ptr, ptr %va, align 434 %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 435 store ptr %argp.next, ptr %va, align 436 %0 = load i32, ptr %argp.cur, align 437 call void @llvm.va_end.p0(ptr %va)38 ret i32 %039}40 41; CHECK-LABEL: define i32 @variadic_int_double_get_firstz(...) {42; CHECK-NEXT: entry:43; CHECK-NEXT: %va_list = alloca ptr, align 444; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list)45; CHECK-NEXT: %0 = tail call i32 @variadic_int_double_get_firstz.valist(ptr %va_list)46; CHECK-NEXT: ret i32 %047; CHECK-NEXT: }48 49; CHECK-LABEL: define internal i32 @variadic_int_double_get_firstz.valist(ptr noalias %varargs) {50; CHECK-NEXT: entry:51; CHECK-NEXT: %va = alloca ptr, align 452; CHECK-NEXT: store ptr %varargs, ptr %va, align 453; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 454; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 455; CHECK-NEXT: store ptr %argp.next, ptr %va, align 456; CHECK-NEXT: %0 = load i32, ptr %argp.cur, align 457; CHECK-NEXT: ret i32 %058; CHECK-NEXT: }59 60define double @variadic_int_double_get_secondz(...) {61; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(...) {62; OPT-NEXT: entry:63; OPT-NEXT: %va_start = alloca ptr, align 464; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)65; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start)66; OPT-NEXT: %0 = load ptr, ptr %va_start, align 467; OPT-NEXT: %1 = call double @variadic_int_double_get_secondz.valist(ptr %0)68; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)69; OPT-NEXT: ret double %170;71; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(ptr %varargs) {72; ABI-NEXT: entry:73; ABI-NEXT: %va = alloca ptr, align 474; ABI-NEXT: store ptr %varargs, ptr %va, align 475; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 476; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 477; ABI-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 1278; ABI-NEXT: store ptr %argp.next2, ptr %va, align 479; ABI-NEXT: %0 = load double, ptr %argp.next, align 480; ABI-NEXT: ret double %081;82entry:83 %va = alloca ptr, align 484 call void @llvm.va_start.p0(ptr nonnull %va)85 %argp.cur = load ptr, ptr %va, align 486 %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 487 %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 1288 store ptr %argp.next2, ptr %va, align 489 %0 = load double, ptr %argp.next, align 490 call void @llvm.va_end.p0(ptr %va)91 ret double %092}93 94; CHECK-LABEL: define double @variadic_int_double_get_secondz(...) {95; CHECK-NEXT: entry:96; CHECK-NEXT: %va_list = alloca ptr, align 497; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list)98; CHECK-NEXT: %0 = tail call double @variadic_int_double_get_secondz.valist(ptr %va_list)99; CHECK-NEXT: ret double %0100; CHECK-NEXT: }101 102; CHECK-LABEL: define internal double @variadic_int_double_get_secondz.valist(ptr noalias %varargs) {103; CHECK-NEXT: entry:104; CHECK-NEXT: %va = alloca ptr, align 4105; CHECK-NEXT: store ptr %varargs, ptr %va, align 4106; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 4107; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4108; CHECK-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12109; CHECK-NEXT: store ptr %argp.next2, ptr %va, align 4110; CHECK-NEXT: %0 = load double, ptr %argp.next, align 4111; CHECK-NEXT: ret double %0112; CHECK-NEXT: }113 114 115; CHECK-LABEL: @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {116; CHECK-NEXT: entry:117; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16118; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)119; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0120; CHECK-NEXT: store i32 %x, ptr %0, align 4121; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1122; CHECK-NEXT: store double %y, ptr %1, align 4123; CHECK-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer)124; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)125; CHECK-NEXT: %cmp.i = icmp eq i32 %call, %x126; CHECK-NEXT: ret i1 %cmp.i127; CHECK-NEXT: }128 129define zeroext i1 @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {130; OPT-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {131; OPT-NEXT: entry:132; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16133; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)134; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0135; OPT-NEXT: store i32 %x, ptr %0, align 4136; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2137; OPT-NEXT: store double %y, ptr %1, align 8138; OPT-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer)139; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)140; OPT-NEXT: %cmp.i = icmp eq i32 %call, %x141; OPT-NEXT: ret i1 %cmp.i142;143; ABI-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {144; ABI-NEXT: entry:145; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16146; ABI-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)147; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0148; ABI-NEXT: store i32 %x, ptr %0, align 4149; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2150; ABI-NEXT: store double %y, ptr %1, align 8151; ABI-NEXT: %call = call i32 @variadic_int_double_get_firstz(ptr %vararg_buffer)152; ABI-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)153; ABI-NEXT: %cmp.i = icmp eq i32 %call, %x154; ABI-NEXT: ret i1 %cmp.i155;156entry:157 %call = call i32 (...) @variadic_int_double_get_firstz(i32 %x, double %y)158 %cmp.i = icmp eq i32 %call, %x159 ret i1 %cmp.i160}161 162; CHECK-LABEL: @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {163; CHECK-NEXT: entry:164; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16165; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)166; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0167; CHECK-NEXT: store i32 %x, ptr %0, align 4168; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1169; CHECK-NEXT: store double %y, ptr %1, align 4170; CHECK-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer)171; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)172; CHECK-NEXT: %cmp.i = fcmp oeq double %call, %y173; CHECK-NEXT: ret i1 %cmp.i174; CHECK-NEXT: }175 176define zeroext i1 @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {177; OPT-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {178; OPT-NEXT: entry:179; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16180; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)181; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0182; OPT-NEXT: store i32 %x, ptr %0, align 4183; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2184; OPT-NEXT: store double %y, ptr %1, align 8185; OPT-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer)186; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)187; OPT-NEXT: %cmp.i = fcmp oeq double %call, %y188; OPT-NEXT: ret i1 %cmp.i189;190; ABI-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {191; ABI-NEXT: entry:192; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16193; ABI-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)194; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0195; ABI-NEXT: store i32 %x, ptr %0, align 4196; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2197; ABI-NEXT: store double %y, ptr %1, align 8198; ABI-NEXT: %call = call double @variadic_int_double_get_secondz(ptr %vararg_buffer)199; ABI-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)200; ABI-NEXT: %cmp.i = fcmp oeq double %call, %y201; ABI-NEXT: ret i1 %cmp.i202;203entry:204 %call = call double (...) @variadic_int_double_get_secondz(i32 %x, double %y)205 %cmp.i = fcmp oeq double %call, %y206 ret i1 %cmp.i207}208 209; Declaration unchanged210; CHECK: declare void @variadic_without_callers(...)211declare void @variadic_without_callers(...)212 213declare void @llvm.va_start.p0(ptr)214declare void @llvm.va_end.p0(ptr)215 216!0 = !{!"function_entry_count", i64 1000}217;.218; OPT: attributes #0 = { nocallback nofree nosync nounwind willreturn }219; OPT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }220;.221; ABI: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }222;.223; OPT: !0 = !{!"function_entry_count", i64 1000}224;.225; ABI: !0 = !{!"function_entry_count", i64 1000}226;.227