| ; 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(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(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(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(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(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(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(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(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 |
| } |