diff --git a/releasenotes.md b/releasenotes.md index 794380d9c..94c29a966 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -27,6 +27,7 @@ - Recursive constant definition not properly detected, leading to assert #2780 - Failed to reject void compile time variables, leading to crash. #2781 - Inferring the size of a slice with an inner inferred array using {} isn't detected as error #2783 +- Bug in sysv abi when passing union in with floats #2784 ### Fixes - Regression with npot vector in struct triggering an assert #2219. diff --git a/src/compiler/abi/c_abi_x64.c b/src/compiler/abi/c_abi_x64.c index 0442045ad..3366863af 100644 --- a/src/compiler/abi/c_abi_x64.c +++ b/src/compiler/abi/c_abi_x64.c @@ -485,8 +485,13 @@ bool x64_contains_float_at_offset(LoweredType *type, unsigned offset) static Type *x64_get_fp_type_at_offset(Type *type, unsigned ir_offset) { + while (type->type_kind == TYPE_UNION) + { + Decl *decl = type->decl; + type = decl->strukt.members[decl->strukt.union_rep]->type; + } if (!ir_offset && type_is_float(type)) return type; - if (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_UNION) + if (type->type_kind == TYPE_STRUCT) { Decl *element = x64_get_member_at_offset(type->decl, ir_offset); return x64_get_fp_type_at_offset(lowered_member_type(element), ir_offset - element->offset); diff --git a/test/test_suite/abi/abi_passing_union_with_float.c3t b/test/test_suite/abi/abi_passing_union_with_float.c3t new file mode 100644 index 000000000..31e994907 --- /dev/null +++ b/test/test_suite/abi/abi_passing_union_with_float.c3t @@ -0,0 +1,42 @@ +// #target: linux-x64 +module test; +union Vec3 +{ + struct + { + float x, y, z; + } + float e; +} +fn void test(Vec3) +{} + +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: + %.anon = alloca %Vec3, align 8 + store <2 x float> %0, ptr %.anon, align 8 + %ptradd = getelementptr inbounds i8, ptr %.anon, i64 8 + store float %1, ptr %ptradd, align 8 + ret void +} + +; Function Attrs: nounwind uwtable +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 +}