Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
brson opened this issue Apr 26, 2012 · 10 comments
Closed

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

brson opened this issue Apr 26, 2012 · 10 comments
Assignees
Labels
A-codegen Area: Code generation A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows
Milestone

Comments

@brson
Copy link
Contributor

brson commented Apr 26, 2012

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

@brson
Copy link
Contributor Author

brson commented Apr 26, 2012

If you replace all the u64s in that test with u32s then the results are still the same - the alignment is off and the shape code doesn't print the value correctly.

@brson
Copy link
Contributor Author

brson commented Apr 26, 2012

I'm not sure how closely related sys::align_of and the shape code are any more. align_of is using llalign_of_real to get the alignment, which gets the 'preferred' alignment. Feeling baffled about alignment in general right now.

@nikomatsakis
Copy link
Contributor

We should do what C does. That said, I don't know what "preferred" alignment means.

@nikomatsakis
Copy link
Contributor

But my guess is it means the alignment the type should have. They probably say "preferred" because they themselves to do not guarantee this alignment?

@nikomatsakis
Copy link
Contributor

Just saw that clang and gcc don't agree. Woah. That surprises me.

@nikomatsakis
Copy link
Contributor

Sorry for the repeated comments... one last thought: it seems to me that gcc is internally inconsistent. As I understand the C alignment rules, the alignment of a struct is the maximum alignment of any of its members. So the alignment of uint64_t can't be 8 if the alignment of a struct w/ uint64_t within is only 4... something's fishy.

@nikomatsakis
Copy link
Contributor

one last thought about preferred alignment---also, the user can typically override the alignment of a given field etc with pragmas, so maybe that's why LLVM terms it the 'preferred' alignment

@brson
Copy link
Contributor Author

brson commented Apr 27, 2012

bbc4a74 fixes the issue in the shape code. it does not fix the issue that align_of is reporting 8 when it should probably be 4

@brson
Copy link
Contributor Author

brson commented Apr 27, 2012

The above test had to be xfailed on windows. Have to investigate.

@brson
Copy link
Contributor Author

brson commented May 1, 2012

This is fixed.

@brson brson closed this as completed May 1, 2012
jieyouxu pushed a commit to jieyouxu/rust that referenced this issue Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows
Projects
None yet
Development

No branches or pull requests

2 participants