; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature ; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT ; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI ; REQUIRES: webassembly-registered-target ; Split variadic functions into two functions: ; - one equivalent to the original, same symbol etc ; - one implementing the contents of the original but taking a valist ; IR here is applicable to any target that uses a ptr for valist ; ; Defines a function with each linkage (in the order of the llvm documentation). ; If split applies it does the same transform to each. ; Whether split applies depends on whether the ABI is being changed or not - e.g. a weak ; function is not normally useful to split as the contents cannot be called from elsewhere. ; If the ABI is being rewritten then the function is still converted. Call sites tested elsewhere. ; Update test checks doesn't emit checks for declares declare void @sink_valist(ptr) declare void @llvm.va_start(ptr) declare void @llvm.va_end(ptr) declare void @decl_simple(...) define void @defn_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_simple(...) { ; OPT-NEXT: entry: ; OPT-NEXT: %va_start = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 ; OPT-NEXT: call void @defn_simple.valist(ptr %0) ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for private define private void @defn_private_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_private_simple(...) { ; OPT-NEXT: entry: ; OPT-NEXT: %va_start = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 ; OPT-NEXT: call void @defn_private_simple.valist(ptr %0) ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_private_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for internal define internal void @defn_internal_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_internal_simple(...) { ; OPT-NEXT: entry: ; OPT-NEXT: %va_start = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 ; OPT-NEXT: call void @defn_internal_simple.valist(ptr %0) ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_internal_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for available_externally define available_externally void @available_externally_simple(...) { ; OPT-LABEL: define {{[^@]+}}@available_externally_simple(...) { ; OPT-NEXT: %va = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va) ; OPT-NEXT: call void @sink_valist(ptr %va) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@available_externally_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for linkonce define linkonce void @defn_linkonce_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_linkonce_simple(...) { ; OPT-NEXT: %va = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va) ; OPT-NEXT: call void @sink_valist(ptr %va) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_linkonce_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for weak define weak void @defn_weak_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_weak_simple(...) { ; OPT-NEXT: %va = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va) ; OPT-NEXT: call void @sink_valist(ptr %va) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_weak_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; common is not applicable to functions ; appending is not applicable to functions declare extern_weak void @decl_extern_weak_simple(...) ; no define for extern_weak ; no declare for linkonce_odr define linkonce_odr void @defn_linkonce_odr_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(...) { ; OPT-NEXT: %va = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va) ; OPT-NEXT: call void @sink_valist(ptr %va) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } ; no declare for weak_odr define weak_odr void @defn_weak_odr_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_weak_odr_simple(...) { ; OPT-NEXT: %va = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va) ; OPT-NEXT: call void @sink_valist(ptr %va) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_weak_odr_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void } declare external void @decl_external_simple(...) define external void @defn_external_simple(...) { ; OPT-LABEL: define {{[^@]+}}@defn_external_simple(...) { ; OPT-NEXT: entry: ; OPT-NEXT: %va_start = alloca ptr, align 4 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start) ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start) ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4 ; OPT-NEXT: call void @defn_external_simple.valist(ptr %0) ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start) ; OPT-NEXT: ret void ; ; ABI-LABEL: define {{[^@]+}}@defn_external_simple(ptr %varargs) { ; ABI-NEXT: %va = alloca ptr, align 4 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4 ; ABI-NEXT: call void @sink_valist(ptr %va) ; ABI-NEXT: ret void ; %va = alloca ptr, align 4 call void @llvm.va_start(ptr %va) call void @sink_valist(ptr %va) call void @llvm.va_end(ptr %va) ret void }