================ @@ -0,0 +1,273 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py + +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-cpu x86-64-v4 -std=c23 -O1 -ffreestanding -emit-llvm -o - %s | FileCheck %s + +// This test sanity checks calling a variadic function with the expansion transform disabled. +// The IR test cases {arch}/expand-variadic-call-*.ll correspond to IR generated from this test case. + +typedef __builtin_va_list va_list; +#define va_copy(dest, src) __builtin_va_copy(dest, src) +#define va_start(ap, ...) __builtin_va_start(ap, 0) +#define va_end(ap) __builtin_va_end(ap) +#define va_arg(ap, type) __builtin_va_arg(ap, type) + +// 32 bit x86 alignment uses getTypeStackAlign for special cases +// Whitebox testing. +// Needs a type >= 16 which is either a simd or a struct containing a simd +// darwinvectorabi should force 4 bytes +// linux vectors with align 16/32/64 return that alignment + + +void wrapped(va_list); + +// CHECK-LABEL: @codegen_for_copy( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CP:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[CP]]) #[[ATTR7:[0-9]+]] +// CHECK-NEXT: call void @llvm.va_copy(ptr nonnull [[CP]], ptr [[X:%.*]]) +// CHECK-NEXT: call void @wrapped(ptr noundef nonnull [[CP]]) #[[ATTR8:[0-9]+]] +// CHECK-NEXT: call void @llvm.va_end(ptr [[CP]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 24, ptr nonnull [[CP]]) #[[ATTR7]] +// CHECK-NEXT: ret void +// +void codegen_for_copy(va_list x) +{ + va_list cp; + va_copy(cp, x); + wrapped(cp); + va_end(cp); +} + + +// CHECK-LABEL: @vararg( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VA:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[VA]]) #[[ATTR7]] +// CHECK-NEXT: call void @llvm.va_start(ptr nonnull [[VA]]) +// CHECK-NEXT: call void @wrapped(ptr noundef nonnull [[VA]]) #[[ATTR8]] +// CHECK-NEXT: call void @llvm.va_end(ptr [[VA]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 24, ptr nonnull [[VA]]) #[[ATTR7]] +// CHECK-NEXT: ret void +// + void vararg(...) +{ + va_list va; + __builtin_va_start(va, 0); + wrapped(va); + va_end(va); +} + +// vectors with alignment 16/32/64 are natively aligned on linux x86 +// v32f32 would be a m1024 type, larger than x64 defines at time of writing +typedef int i32; +typedef float v4f32 __attribute__((__vector_size__(16), __aligned__(16))); +typedef float v8f32 __attribute__((__vector_size__(32), __aligned__(32))); +typedef float v16f32 __attribute__((__vector_size__(64), __aligned__(64))); +typedef float v32f32 __attribute__((__vector_size__(128), __aligned__(128))); + + +// Pass a single value to wrapped() via vararg(...) +// CHECK-LABEL: @single_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]]) #[[ATTR9:[0-9]+]] +// CHECK-NEXT: ret void +// +void single_i32(i32 x) +{ + vararg(x); +} + +// CHECK-LABEL: @single_double( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(double noundef [[X:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void single_double(double x) +{ + vararg(x); +} + +// CHECK-LABEL: @single_v4f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<4 x float> noundef [[X:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void single_v4f32(v4f32 x) +{ + vararg(x); +} + +// CHECK-LABEL: @single_v8f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<8 x float> noundef [[X:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void single_v8f32(v8f32 x) +{ + vararg(x); +} + +// CHECK-LABEL: @single_v16f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<16 x float> noundef [[X:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void single_v16f32(v16f32 x) +{ + vararg(x); +} + +// CHECK-LABEL: @single_v32f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca <32 x float>, align 128 +// CHECK-NEXT: [[X:%.*]] = load <32 x float>, ptr [[TMP0:%.*]], align 128, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: store <32 x float> [[X]], ptr [[INDIRECT_ARG_TEMP]], align 128, !tbaa [[TBAA2]] +// CHECK-NEXT: tail call void (...) @vararg(ptr noundef nonnull byval(<32 x float>) align 128 [[INDIRECT_ARG_TEMP]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void single_v32f32(v32f32 x) +{ + vararg(x); +} + + + +// CHECK-LABEL: @i32_double( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], double noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_double(i32 x, double y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @double_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(double noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void double_i32(double x, i32 y) +{ + vararg(x, y); +} + + +// A struct used by libc variadic tests + +typedef struct { + char c; + short s; + int i; + long l; + float f; + double d; +} libcS; + +// CHECK-LABEL: @i32_libcS( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], ptr noundef nonnull byval([[STRUCT_LIBCS:%.*]]) align 8 [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_libcS(i32 x, libcS y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @libcS_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(ptr noundef nonnull byval([[STRUCT_LIBCS:%.*]]) align 8 [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void libcS_i32(libcS x, i32 y) +{ + vararg(x, y); +} + + +// CHECK-LABEL: @i32_v4f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_v4f32(i32 x, v4f32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @v4f32_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<4 x float> noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void v4f32_i32(v4f32 x, i32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @i32_v8f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], <8 x float> noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_v8f32(i32 x, v8f32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @v8f32_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<8 x float> noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void v8f32_i32(v8f32 x, i32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @i32_v16f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], <16 x float> noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_v16f32(i32 x, v16f32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @v16f32_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void (...) @vararg(<16 x float> noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void v16f32_i32(v16f32 x, i32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @i32_v32f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca <32 x float>, align 128 +// CHECK-NEXT: [[Y:%.*]] = load <32 x float>, ptr [[TMP0:%.*]], align 128, !tbaa [[TBAA2]] +// CHECK-NEXT: store <32 x float> [[Y]], ptr [[INDIRECT_ARG_TEMP]], align 128, !tbaa [[TBAA2]] +// CHECK-NEXT: tail call void (...) @vararg(i32 noundef [[X:%.*]], ptr noundef nonnull byval(<32 x float>) align 128 [[INDIRECT_ARG_TEMP]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void i32_v32f32(i32 x, v32f32 y) +{ + vararg(x, y); +} + +// CHECK-LABEL: @v32f32_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca <32 x float>, align 128 +// CHECK-NEXT: [[X:%.*]] = load <32 x float>, ptr [[TMP0:%.*]], align 128, !tbaa [[TBAA2]] +// CHECK-NEXT: store <32 x float> [[X]], ptr [[INDIRECT_ARG_TEMP]], align 128, !tbaa [[TBAA2]] +// CHECK-NEXT: tail call void (...) @vararg(ptr noundef nonnull byval(<32 x float>) align 128 [[INDIRECT_ARG_TEMP]], i32 noundef [[Y:%.*]]) #[[ATTR9]] +// CHECK-NEXT: ret void +// +void v32f32_i32(v32f32 x, i32 y) +{ + vararg(x, y); +} ---------------- arsenm wrote:
also get the half and bfloat cases https://github.com/llvm/llvm-project/pull/81058 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits