Skip to content

Complex layout phase 2 - #159981

Draft
folkertdev wants to merge 25 commits into
rust-lang:mainfrom
folkertdev:complex-layout-phase-2
Draft

Complex layout phase 2#159981
folkertdev wants to merge 25 commits into
rust-lang:mainfrom
folkertdev:complex-layout-phase-2

Conversation

@folkertdev

Copy link
Copy Markdown
Contributor

tracking issue: #154023

Follow-up to #158885

@folkertdev folkertdev added the F-complex_numbers `#![feature(complex_numbers)]` label Jul 26, 2026
@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) A-run-make Area: port run-make Makefiles to rmake.rs A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 26, 2026

@programmerjake programmerjake Jul 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'll also want tests for functions like safe fn complex_float_align2(_: c_float, value: Complex<c_float>) -> Complex<c_float>

also tests for properly handling complex arguments that could be split between registers and the stack (so the previous args take all but 1 fp or int reg), since different ABIs say to do different things (e.g. keep them together on the stack or split between registers and the stack)

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a bunch more tests for that sort of scenario, and integrated my LLVM PRs (for mips, powerpc and sparc) so they now all match.

We should also run abi-cafe (and add complex support) to be fully sure, but for that we'd need to merge this first really.

@rust-log-analyzer

This comment has been minimized.

@folkertdev
folkertdev force-pushed the complex-layout-phase-2 branch from 3026f1f to 7fb70da Compare July 29, 2026 22:45
@rustbot rustbot added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jul 29, 2026
@rust-log-analyzer

This comment has been minimized.

// register alignment of 8 bytes.
//
// NOTE: clang uses a vector (e.g. <2 x f32>) here, but if we try that we run into
// ABI issues because vectors require the altivec target feature.

@programmerjake programmerjake Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk how you're getting that, from my testing clang 22 passes complex f32 via an indirect pointer and doesn't use any vector types:
https://clang.godbolt.org/z/676ajoT6a

assuming clang is correct, we should try to generate the same LLVM IR function signature, since that makes cross-language LTO work much better.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming clang is correct

It is not.

Being compatible with the standard C compiler on the platform (that determines the ABI of libcalls etc) seems more important than LTO for _Complex. Anyhow, I'm trying to fix the discrepancy in that bottom PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matters e.g. for

// main.c
#include <stdio.h>
#include <complex.h>

int main(void) {
    volatile float re = -1.0f, im = 0.0f;
    _Complex float s = csqrtf(re + im * I);
    printf("%f + %fi\n", crealf(s), cimagf(s));
    return 0;
}

with

powerpc-linux-gnu-gcc -O2 main.c -o gcc.out -lm

# Use clang to compile, GCC as the linker.
clang --target=powerpc-linux-gnu -O2 -c main.c -o clang.o
powerpc-linux-gnu-gcc clang.o -o clang.out -lm

echo "gcc"
qemu-ppc -L /usr/powerpc-linux-gnu ./gcc.out
echo "clang"
qemu-ppc -L /usr/powerpc-linux-gnu ./clang.out

returns

gcc
0.000000 + 1.000000i
clang
4.186081 + 0.000000i

The clang result is nonsense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@programmerjake do you know anyone at IBM that could review llvm/llvm-project#208917? It's not getting much attention (equivalent PR for mips and sparc have already been merged).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe lei137, since they reviewed a different PR I'm interested in? I'm not super familiar with who IBM has working on LLVM since I'm not an IBM employee.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I just seem to remember you were working on powerpc related things, so thought you might have some personal connections. Lei is already reviewing some of my other PRs, e.g. llvm/llvm-project#209286. Hopefully they'll have time for this at some point, this kind of breakage is pretty bad...

@folkertdev
folkertdev force-pushed the complex-layout-phase-2 branch from 7fb70da to bc2336f Compare July 30, 2026 22:54
@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

so that we can specify more than one i32 of padding.
C `long double` is IEEE binary128 on 32-bit SPARC, and both GCC and Clang
pass it `byval` and return it through an `sret` pointer (see Clang
`SparcV8ABIInfo::classifyArgumentType` / `classifyReturnType`).

rustc returned `f128` directly. The 32-bit SPARC ABI marks an indirect
return by placing an `unimp <size>` word after the call, which the callee
must skip by returning to `%o7+12`; LLVM keys that off the `sret`
attribute. Without it the caller emitted the marker but the callee
returned to `%o7+8`, landing on the marker word and dying with SIGILL.
GCC and Clang pass by-value aggregate arguments by reference on 32-bit
SPARC: the caller makes a copy and passes its address. Clang's
`SparcV8ABIInfo` falls back to `DefaultABIInfo::classifyArgumentType`,
which makes any aggregate `byval`.

rustc instead cast aggregates to a run of `i32` registers, so every
by-value struct crossing the Rust/C boundary was corrupted, at any size.
Aggregate returns were already indirect and stay that way.

With aggregates and `f128` now all indirect, nothing reads the parameter
array offset any more, so drop the offset tracking.
@folkertdev
folkertdev force-pushed the complex-layout-phase-2 branch from bc2336f to f629989 Compare August 14, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` F-complex_numbers `#![feature(complex_numbers)]` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants