i386: return a complex of eight bytes or fewer in EAX:EDX, not through a hidden pointer

abi test: cover bare f16, complex, rawptr, enum and bit_set
This commit is contained in:
kalsprite
2026-08-14 21:09:26 -07:00
parent 1b57f6e092
commit 0fb1721e45
2 changed files with 26 additions and 2 deletions

View File

@@ -499,6 +499,18 @@ namespace lbAbi386 {
}
}
// A complex lowers to a struct of two floats. The struct rule sends every struct through
// a hidden pointer. The psABI gives complex its own rule: one of eight bytes or fewer
// comes back in EAX:EDX, and only the wider ones go through memory. `complex64` is
// returned coerced to `i64` and `complex128` keeps the hidden pointer.
if (return_is_defined && !return_is_tuple &&
return_source != nullptr && is_type_complex(return_source)) {
i64 sz = lb_sizeof(return_type);
if (sz > 0 && sz <= 8) {
ft->ret = lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, cast(unsigned)(sz*8)), nullptr, nullptr);
}
}
ft->calling_convention = calling_convention;
return ft;
}

View File

@@ -310,10 +310,22 @@ build :: proc() {
// 32 bits. A callee compiled to rely on that reads the untouched high bits.
// The sub-32-bit widths are the ones that have it; i32 and f32 are the controls
// that must not.
for tag in ([]string{"i8", "u8", "i16", "u16", "bool", "i32", "u32", "u64", "f32"}) {
for tag in ([]string{
"i8", "u8", "i16", "u16", "bool", "i32", "u32", "u64", "f32",
// the kinds whose BARE form asks a different question from their wrapped one: a complex is
// two floats to the type system and a rule of its own to a psABI, and a bare `f16` is the
// narrowest float there is
"f16", "c64", "c128", "ptr", "enum", "bset",
}) {
s := scalar(tag)
v := val(0, tag)
expected := tag == "bool" ? odin_val(tag, v) : tp("%s(%s)", s.odin, v)
expected: string
switch tag {
case "ptr", "bool", "enum", "c64", "c128", "bset":
expected = odin_val(tag, v)
case:
expected = tp("%s(%s)", s.odin, v)
}
add(
tp("bs_%s", tag),
s.odin,