Skip to content

Shape and LLVM disagree about the alignment of 64-bit ints on 32-bit x86 #2303

Closed
@brson

Description

@brson

On x86 our shape code does not agree with llvm, clang, or gcc about the alignment of structs containing 64-bit integer fields.

In C this struct is 4-byte aligned on 32-bit x86:

struct s {
    uint64_t t;
};

When we produce the equivalent struct in Rust, LLVM produces code that uses C's 4-byte alignment, but the shape code thinks it has 8-byte alignment and things go bad. Let's take a look!


// This is the type with the questionable alignment
type inner = {
    c64: u64
};

// This is the type that contains the type with the questionable alignment, for testing
type outer = {
    c8: u8,
    t: inner
};

#[cfg(target_arch = "x86")]
fn main() {

    let x = {c8: 22u8, t: {c64: 44u64}};

    // Send it through the shape code
    let y = #fmt["%?", x];

    #debug("align inner = %?", sys::align_of::<inner>()); // 8
    #debug("size outer = %?", sys::size_of::<outer>());    // 12
    #debug("y = %s", y);                                                        // (22, (0))

    // per clang/gcc the alignment of `inner` is 4 on x86.
    // we say it's 8
    assert sys::align_of::<inner>() == 4u; // fails

    // per clang/gcc the size of `outer` should be 12
    // because `inner`s alignment was 4.
    // LLVM packs the struct the way clang likes, despite
    // our intents regarding the alignment of `inner` and
    // we end up with the same size `outer` as clang
    assert sys::size_of::<outer>() == 12u; // passes

    // But now our shape code doesn't find the inner struct
    // We print (22, (0))
    assert y == "(22, (44))"; // fails
}

This affects enums too.

I think we should just do what LLVM wants us to do and accept the 4-byte alignment.

Interesting tidbit I guess: while clang and gcc agree on the alignment of the struct containing a uint64_t (it's 4), they don't agree on the alignment of uint64_t itself - clang says 4, gcc says 8

Metadata

Metadata

Assignees

Labels

A-codegenArea: Code generationA-runtimeArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions