Poor codegen due to dropped type information in ABI calculation
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
On x86_64-unknown-linux-gnu, Clang lowers this C code
https://godbolt.org/z/78qYTh76E
struct S { float a; float b; };
float second(struct S s) { return s.b; }
to this LLVM IR
define dso_local float @second(<2 x float> %s.coerce) local_unnamed_addr {
entry:
%s.sroa.0.4.vec.extract = extractelement <2 x float> %s.coerce, i64 1
ret float %s.sroa.0.4.vec.extract
}
and ultimately to a single instruction:
second:
shufps xmm0, xmm0, 85
ret
Rust instead lowers
https://godbolt.org/z/WhedT1r66
#[repr(C)]
struct S {
a: f32,
b: f32,
}
#[unsafe(no_mangle)]
extern "C" fn second(s: S) -> f32 { s.b }
to
define noundef float @second(double %0) unnamed_addr {
start:
%1 = bitcast double %0 to i64
%2 = lshr i64 %1, 32
%3 = trunc nuw i64 %2 to i32
%4 = bitcast i32 %3 to float
ret float %4
}
and ultimately
second:
movq rax, xmm0
shr rax, 32
movd xmm0, eax
ret
<2 x float> and double are perfectly ABI-compatible, but llvm overfits on clang and we generate 3 instructions versus clang's one.
We currently drop a lot of type information in our ABI calculation code, and prefer to coerce to abi-compatible but relatively opaque types (e.g. [8 x i8] instead of [2 x i32] even if the latter more accurately represents the source type). The assumption is that this is free, this example shows that it is not.
What can we do about this? In theory LLVM could pattern match on our bitcast-shift-trunc-bitcast pattern, but that seems very ad-hoc. But rustc using vectors here would add a bunch of complexity. So, I'm not sure.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the x86_64 examples from the two linked Godbolt cases and compare the generated LLVM IR and assembly. Then trace the ABI calculation code that drops source type information and investigate how the opaque coercions arise. Done means the Rust example preserves enough ABI type information to avoid the demonstrated three-instruction sequence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100