-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
make >= 128-bit integer types 16-byte aligned #3003
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
make >= 128-bit integer types 16-byte aligned #3003
Conversation
Is the size one necessary? I believe |
I think I might have made a wrong assumption along the way which lead me to implementing the size one. I just checked and it is actually not required to pass the tests. |
Can you add this test case? comptime {
assert(@alignOf(struct { x: u128}) == 16);
} I believe it will trip this assertion: assert(type->abi_align == 0 || type->abi_align == LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type)); That assertion was useful while doing some big changes to the way llvm types were constructed, but now that Zig intentionally disagrees with LLVM about the alignment of types, the assertion should be retired (deleted). |
I will look into that tomorrow. 👍 |
cadb820
to
a65a3b3
Compare
I fixed a bug in my implementation, now things make sense to me. I added some tests as well. |
a65a3b3
to
5a41bc1
Compare
Types can have differnt sizes than LLVM would give them. Added test demonstrates this and would trip said assert.
@@ -7266,8 +7273,6 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r | |||
|
|||
LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) { | |||
assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); | |||
assert(type->abi_size == 0 || type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assertion can stay, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this holds anymore, because a larger alignment required for a field can increase the size of a struct.
It would be possible to assert
assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah that makes sense. Here's another test case to add:
comptime {
expect(@sizeOf(extern struct {
x: u128,
y: u8,
}) == 32);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
std/mutex.zig
Outdated
@@ -122,7 +122,7 @@ else switch (builtin.os) { | |||
}, | |||
}; | |||
|
|||
const TestContext = struct { | |||
const TestContext = packed struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prevents a segfault, probably due to alignment, that otherwise happens here (according to GDB):
testing.expect(context.data == thread_count * TestContext.incr_count);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted this.
test/stage1/behavior/align.zig
Outdated
} | ||
|
||
test "size of struct with non-standard-LLVM alignment" { | ||
expect(@sizeOf(struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zig doesn't guarantee the size of non-extern, non-packed structs. You can fix this test case by making it extern struct
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced this specific test with the other one you suggested above, since 129-bit integers are not allowed in extern structs
which made this specific one obsolete.
I think there is some work left to do here. I fixed the Mutex one with a temporary hack, but I think there is some mismatch of expectations between LLVM and Zig when it comes to types that are presented as integers to LLVM but are some other type to Zig. |
You could be hitting this: Lines 2271 to 2280 in 30466bc
|
Sorry, I think I underestimated the difficulty of this one. |
I do not think this is the issue. I verified this by increasing the default to twice the alignment, which I think should have made the problem go away again, as for types hitting this fall-back would have been sufficiently aligned then. |
Update: In all those cases an instruction is emitted to load a value from memory, for example
but the memory location does not satisfy the alignment requirements of the instruction, which leads to a segfault. It looks like the beginnings of variables do not end up at a memory address which fits with their alignment. |
8ad3c8c
to
9b8fbbf
Compare
In order to support 16-byte aligned integer types, types which contain them as fields would have to make sure that their fields alignment is respected. At runtime every field needs to end up at a memory location which is divisible by its alignment. One way to achieve this is with the following two steps:
I think the first one is satisfied, but the second one currently is not. EDIT2: What is missing in Zig's implementation right now is support for leaving word-sized or larger gaps between members when required. Optionally fields could also be rearranged to minimize gaps. EDIT: Also note that struct alignment still relies on LLVM types and not Zig types. I tried to fix this here, but ran into invalid LLVM which I was unable to fix. |
This PR should resolve #2987 and make >= 128-bit integer types 16-byte aligned. The alignment and size of those types are both changed accordingly.
Some caveats:
For some reason inside
get_llvm_type
I cannot assert that integer types are sized and aligned the same as calculated by the functions I introduce here, so I had to exclude them form those assertions. I am not sure why that is. It would be good to know.There is also no test included yet since the example test @andrewrk provided in #2987 is currently disabled because of #2883. I did run that test locally and it worked.
Maybe this could be covered with a test somehow by asserting how structs are padded.