llvm-project/llvm/test/CodeGen/WebAssembly/expand-variadic-call.ll
Nikita Popov c23b4fbdbb
[IR] Remove size argument from lifetime intrinsics (#150248)
Now that #149310 has restricted lifetime intrinsics to only work on
allocas, we can also drop the explicit size argument. Instead, the size
is implied by the alloca.

This removes the ability to only mark a prefix of an alloca alive/dead.
We never used that capability, so we should remove the need to handle
that possibility everywhere (though many key places, including stack
coloring, did not actually respect this).
2025-08-08 11:09:34 +02:00

484 lines
21 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature
; RUN: opt -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-unknown"
; Check the variables are lowered to the locations this target expects
; The types show the call frames
; CHECK: %single_i32.vararg = type <{ i32 }>
; CHECK: %single_double.vararg = type <{ double }>
; CHECK: %single_v4f32.vararg = type <{ <4 x float> }>
; CHECK: %single_v8f32.vararg = type <{ <8 x float> }>
; CHECK: %single_v16f32.vararg = type <{ <16 x float> }>
; CHECK: %single_v32f32.vararg = type <{ <32 x float> }>
; CHECK: %i32_double.vararg = type <{ i32, [4 x i8], double }>
; CHECK: %double_i32.vararg = type <{ double, i32 }>
; CHECK: %i32_libcS.vararg = type <{ i32, ptr }>
; CHECK: %libcS_i32.vararg = type <{ ptr, i32 }>
; CHECK: %i32_v4f32.vararg = type <{ i32, [12 x i8], <4 x float> }>
; CHECK: %v4f32_i32.vararg = type <{ <4 x float>, i32 }>
; CHECK: %i32_v8f32.vararg = type <{ i32, [28 x i8], <8 x float> }>
; CHECK: %v8f32_i32.vararg = type <{ <8 x float>, i32 }>
; CHECK: %i32_v16f32.vararg = type <{ i32, [60 x i8], <16 x float> }>
; CHECK: %v16f32_i32.vararg = type <{ <16 x float>, i32 }>
; CHECK: %i32_v32f32.vararg = type <{ i32, [124 x i8], <32 x float> }>
; CHECK: %v32f32_i32.vararg = type <{ <32 x float>, i32 }>
; CHECK: %fptr_single_i32.vararg = type <{ i32 }>
; CHECK: %fptr_libcS.vararg = type <{ ptr }>
%struct.libcS = type { i8, i16, i32, i32, float, double }
@vararg_ptr = hidden global ptr @vararg, align 4
define hidden void @copy(ptr noundef %va) {
; CHECK-LABEL: define {{[^@]+}}@copy(ptr noundef %va) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %va.addr = alloca ptr, align 4
; CHECK-NEXT: %cp = alloca ptr, align 4
; CHECK-NEXT: store ptr %va, ptr %va.addr, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull %cp)
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %cp, ptr %va.addr, i32 4, i1 false)
; CHECK-NEXT: %0 = load ptr, ptr %cp, align 4
; CHECK-NEXT: call void @valist(ptr noundef %0)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull %cp)
; CHECK-NEXT: ret void
;
entry:
%va.addr = alloca ptr, align 4
%cp = alloca ptr, align 4
store ptr %va, ptr %va.addr, align 4
call void @llvm.lifetime.start.p0(ptr nonnull %cp)
call void @llvm.va_copy.p0(ptr nonnull %cp, ptr nonnull %va.addr)
%0 = load ptr, ptr %cp, align 4
call void @valist(ptr noundef %0)
call void @llvm.lifetime.end.p0(ptr nonnull %cp)
ret void
}
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.va_copy.p0(ptr, ptr)
declare void @valist(ptr noundef)
declare void @llvm.lifetime.end.p0(ptr nocapture)
define hidden void @start_once(...) {
; CHECK-LABEL: define {{[^@]+}}@start_once(ptr %varargs) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %s = alloca ptr, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull %s)
; CHECK-NEXT: store ptr %varargs, ptr %s, align 4
; CHECK-NEXT: %0 = load ptr, ptr %s, align 4
; CHECK-NEXT: call void @valist(ptr noundef %0)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull %s)
; CHECK-NEXT: ret void
;
entry:
%s = alloca ptr, align 4
call void @llvm.lifetime.start.p0(ptr nonnull %s)
call void @llvm.va_start.p0(ptr nonnull %s)
%0 = load ptr, ptr %s, align 4
call void @valist(ptr noundef %0)
call void @llvm.va_end.p0(ptr %s)
call void @llvm.lifetime.end.p0(ptr nonnull %s)
ret void
}
declare void @llvm.va_start.p0(ptr)
declare void @llvm.va_end.p0(ptr)
define hidden void @start_twice(...) {
; CHECK-LABEL: define {{[^@]+}}@start_twice(ptr %varargs) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %s0 = alloca ptr, align 4
; CHECK-NEXT: %s1 = alloca ptr, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull %s0)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull %s1)
; CHECK-NEXT: store ptr %varargs, ptr %s0, align 4
; CHECK-NEXT: %0 = load ptr, ptr %s0, align 4
; CHECK-NEXT: call void @valist(ptr noundef %0)
; CHECK-NEXT: store ptr %varargs, ptr %s1, align 4
; CHECK-NEXT: %1 = load ptr, ptr %s1, align 4
; CHECK-NEXT: call void @valist(ptr noundef %1)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull %s1)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull %s0)
; CHECK-NEXT: ret void
;
entry:
%s0 = alloca ptr, align 4
%s1 = alloca ptr, align 4
call void @llvm.lifetime.start.p0(ptr nonnull %s0)
call void @llvm.lifetime.start.p0(ptr nonnull %s1)
call void @llvm.va_start.p0(ptr nonnull %s0)
%0 = load ptr, ptr %s0, align 4
call void @valist(ptr noundef %0)
call void @llvm.va_end.p0(ptr %s0)
call void @llvm.va_start.p0(ptr nonnull %s1)
%1 = load ptr, ptr %s1, align 4
call void @valist(ptr noundef %1)
call void @llvm.va_end.p0(ptr %s1)
call void @llvm.lifetime.end.p0(ptr nonnull %s1)
call void @llvm.lifetime.end.p0(ptr nonnull %s0)
ret void
}
define hidden void @single_i32(i32 noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_i32(i32 noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_i32.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x)
ret void
}
declare void @vararg(...)
define hidden void @single_double(double noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_double(double noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_double.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_double.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store double %x, ptr %0, align 8
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(double noundef %x)
ret void
}
define hidden void @single_v4f32(<4 x float> noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_v4f32(<4 x float> noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_v4f32.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_v4f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <4 x float> %x, ptr %0, align 16
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<4 x float> noundef %x)
ret void
}
define hidden void @single_v8f32(<8 x float> noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_v8f32(<8 x float> noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_v8f32.vararg, align 32
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_v8f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <8 x float> %x, ptr %0, align 32
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<8 x float> noundef %x)
ret void
}
define hidden void @single_v16f32(<16 x float> noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_v16f32(<16 x float> noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_v16f32.vararg, align 64
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_v16f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <16 x float> %x, ptr %0, align 64
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<16 x float> noundef %x)
ret void
}
define hidden void @single_v32f32(<32 x float> noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@single_v32f32(<32 x float> noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %single_v32f32.vararg, align 128
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %single_v32f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <32 x float> %x, ptr %0, align 128
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<32 x float> noundef %x)
ret void
}
define hidden void @i32_double(i32 noundef %x, double noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_double(i32 noundef %x, double noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %i32_double.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_double.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_double.vararg, ptr %vararg_buffer, i32 0, i32 2
; CHECK-NEXT: store double %y, ptr %1, align 8
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, double noundef %y)
ret void
}
define hidden void @double_i32(double noundef %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@double_i32(double noundef %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %double_i32.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %double_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store double %x, ptr %0, align 8
; CHECK-NEXT: %1 = getelementptr inbounds nuw %double_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(double noundef %x, i32 noundef %y)
ret void
}
define hidden void @i32_libcS(i32 noundef %x, ptr noundef byval(%struct.libcS) align 8 %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_libcS(i32 noundef %x, ptr noundef byval(%struct.libcS) align 8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %IndirectAlloca = alloca %struct.libcS, align 8
; CHECK-NEXT: %vararg_buffer = alloca %i32_libcS.vararg, align 16
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %IndirectAlloca, ptr %y, i64 24, i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_libcS.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_libcS.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store ptr %IndirectAlloca, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, ptr noundef nonnull byval(%struct.libcS) align 8 %y)
ret void
}
define hidden void @libcS_i32(ptr noundef byval(%struct.libcS) align 8 %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@libcS_i32(ptr noundef byval(%struct.libcS) align 8 %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %IndirectAlloca = alloca %struct.libcS, align 8
; CHECK-NEXT: %vararg_buffer = alloca %libcS_i32.vararg, align 16
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %IndirectAlloca, ptr %x, i64 24, i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %libcS_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store ptr %IndirectAlloca, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %libcS_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(ptr noundef nonnull byval(%struct.libcS) align 8 %x, i32 noundef %y)
ret void
}
define hidden void @i32_v4f32(i32 noundef %x, <4 x float> noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_v4f32(i32 noundef %x, <4 x float> noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %i32_v4f32.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_v4f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_v4f32.vararg, ptr %vararg_buffer, i32 0, i32 2
; CHECK-NEXT: store <4 x float> %y, ptr %1, align 16
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, <4 x float> noundef %y)
ret void
}
define hidden void @v4f32_i32(<4 x float> noundef %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@v4f32_i32(<4 x float> noundef %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %v4f32_i32.vararg, align 16
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %v4f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <4 x float> %x, ptr %0, align 16
; CHECK-NEXT: %1 = getelementptr inbounds nuw %v4f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<4 x float> noundef %x, i32 noundef %y)
ret void
}
define hidden void @i32_v8f32(i32 noundef %x, <8 x float> noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_v8f32(i32 noundef %x, <8 x float> noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %i32_v8f32.vararg, align 32
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_v8f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_v8f32.vararg, ptr %vararg_buffer, i32 0, i32 2
; CHECK-NEXT: store <8 x float> %y, ptr %1, align 32
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, <8 x float> noundef %y)
ret void
}
define hidden void @v8f32_i32(<8 x float> noundef %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@v8f32_i32(<8 x float> noundef %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %v8f32_i32.vararg, align 32
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %v8f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <8 x float> %x, ptr %0, align 32
; CHECK-NEXT: %1 = getelementptr inbounds nuw %v8f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<8 x float> noundef %x, i32 noundef %y)
ret void
}
define hidden void @i32_v16f32(i32 noundef %x, <16 x float> noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_v16f32(i32 noundef %x, <16 x float> noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %i32_v16f32.vararg, align 64
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_v16f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_v16f32.vararg, ptr %vararg_buffer, i32 0, i32 2
; CHECK-NEXT: store <16 x float> %y, ptr %1, align 64
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, <16 x float> noundef %y)
ret void
}
define hidden void @v16f32_i32(<16 x float> noundef %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@v16f32_i32(<16 x float> noundef %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %v16f32_i32.vararg, align 64
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %v16f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <16 x float> %x, ptr %0, align 64
; CHECK-NEXT: %1 = getelementptr inbounds nuw %v16f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<16 x float> noundef %x, i32 noundef %y)
ret void
}
define hidden void @i32_v32f32(i32 noundef %x, <32 x float> noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@i32_v32f32(i32 noundef %x, <32 x float> noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %i32_v32f32.vararg, align 128
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %i32_v32f32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %0, align 4
; CHECK-NEXT: %1 = getelementptr inbounds nuw %i32_v32f32.vararg, ptr %vararg_buffer, i32 0, i32 2
; CHECK-NEXT: store <32 x float> %y, ptr %1, align 128
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(i32 noundef %x, <32 x float> noundef %y)
ret void
}
define hidden void @v32f32_i32(<32 x float> noundef %x, i32 noundef %y) {
; CHECK-LABEL: define {{[^@]+}}@v32f32_i32(<32 x float> noundef %x, i32 noundef %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %v32f32_i32.vararg, align 128
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %0 = getelementptr inbounds nuw %v32f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store <32 x float> %x, ptr %0, align 128
; CHECK-NEXT: %1 = getelementptr inbounds nuw %v32f32_i32.vararg, ptr %vararg_buffer, i32 0, i32 1
; CHECK-NEXT: store i32 %y, ptr %1, align 4
; CHECK-NEXT: call void @vararg(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
tail call void (...) @vararg(<32 x float> noundef %x, i32 noundef %y)
ret void
}
define hidden void @fptr_single_i32(i32 noundef %x) {
; CHECK-LABEL: define {{[^@]+}}@fptr_single_i32(i32 noundef %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %vararg_buffer = alloca %fptr_single_i32.vararg, align 16
; CHECK-NEXT: %0 = load volatile ptr, ptr @vararg_ptr, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %1 = getelementptr inbounds nuw %fptr_single_i32.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store i32 %x, ptr %1, align 4
; CHECK-NEXT: call void %0(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
%0 = load volatile ptr, ptr @vararg_ptr, align 4
tail call void (...) %0(i32 noundef %x)
ret void
}
define hidden void @fptr_libcS(ptr noundef byval(%struct.libcS) align 8 %x) {
; CHECK-LABEL: define {{[^@]+}}@fptr_libcS(ptr noundef byval(%struct.libcS) align 8 %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %IndirectAlloca = alloca %struct.libcS, align 8
; CHECK-NEXT: %vararg_buffer = alloca %fptr_libcS.vararg, align 16
; CHECK-NEXT: %0 = load volatile ptr, ptr @vararg_ptr, align 4
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %IndirectAlloca, ptr %x, i64 24, i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr %vararg_buffer)
; CHECK-NEXT: %1 = getelementptr inbounds nuw %fptr_libcS.vararg, ptr %vararg_buffer, i32 0, i32 0
; CHECK-NEXT: store ptr %IndirectAlloca, ptr %1, align 4
; CHECK-NEXT: call void %0(ptr %vararg_buffer)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %vararg_buffer)
; CHECK-NEXT: ret void
;
entry:
%0 = load volatile ptr, ptr @vararg_ptr, align 4
tail call void (...) %0(ptr noundef nonnull byval(%struct.libcS) align 8 %x)
ret void
}