rust-lang / rust-lang/rust

Poor codegen due to dropped type information in ABI calculation

Open
#162,739 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-ABI A-codegen A-LLVM needs-triage
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.