From a44e9328069f4a73e528f2c4e39e45324fe08788 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 16 Apr 2025 15:58:14 +0200 Subject: [PATCH] ABI bug on x64 Linux / MacOS when passing a union containing a struct of 3 floats. #2087 --- releasenotes.md | 1 + src/compiler/abi/c_abi_x64.c | 2 +- test/test_suite/abi/sysv_union_struct_vec.c3t | 47 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test/test_suite/abi/sysv_union_struct_vec.c3t diff --git a/releasenotes.md b/releasenotes.md index 5bd22fe11..51579469b 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -19,6 +19,7 @@ - Incorrect rounding at compile time going from double to int. - Regression with invalid setup of the WASM temp allocator. - Correctly detect multiple overloads of the same type. +- ABI bug on x64 Linux / MacOS when passing a union containing a struct of 3 floats. #2087 ### Stdlib changes - Hash functions for integer vectors and arrays. diff --git a/src/compiler/abi/c_abi_x64.c b/src/compiler/abi/c_abi_x64.c index be1b369c7..744c3d799 100644 --- a/src/compiler/abi/c_abi_x64.c +++ b/src/compiler/abi/c_abi_x64.c @@ -491,7 +491,7 @@ bool x64_contains_float_at_offset(Type *type, unsigned offset) static Type *x64_get_fp_type_at_offset(Type *type, unsigned ir_offset) { if (!ir_offset && type_is_float(type)) return type; - if (type->type_kind == TYPE_STRUCT) + if (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_UNION) { Decl *element = x64_get_member_at_offset(type->decl, ir_offset); return x64_get_fp_type_at_offset(element->type, ir_offset - element->offset); diff --git a/test/test_suite/abi/sysv_union_struct_vec.c3t b/test/test_suite/abi/sysv_union_struct_vec.c3t new file mode 100644 index 000000000..477c6a55d --- /dev/null +++ b/test/test_suite/abi/sysv_union_struct_vec.c3t @@ -0,0 +1,47 @@ +// #target: macos-x64 +// Struct-in-union bug #2087 +module test; + +union Vec3 +{ + struct + { + float x, y, z; + } + float[3] e; +} + +fn void test(Vec3 v) +{ +} +fn int main() +{ + test((Vec3){1,2,3}); + return 0; +} + +/* #expect: test.ll + +define void @test.test(<2 x float> %0, float %1) #0 { +entry: + %v = alloca %Vec3, align 8 + store <2 x float> %0, ptr %v, align 8 + %ptradd = getelementptr inbounds i8, ptr %v, i64 8 + store float %1, ptr %ptradd, align 8 + ret void +} + +define i32 @main() #0 { +entry: + %literal = alloca %Vec3, align 4 + %coerce = alloca %Vec3, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal, ptr align 4 @.__const, i32 12, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %coerce, ptr align 4 %literal, i32 12, i1 false) + %lo = load <2 x float>, ptr %coerce, align 8 + %ptradd = getelementptr inbounds i8, ptr %coerce, i64 8 + %hi = load float, ptr %ptradd, align 8 + call void @test.test(<2 x float> %lo, float %hi) + ret i32 0 +} + +