-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Inconsistent claims about padding in structs #49318
Comments
I guess we should change |
You mean to say that This seems undesirable to me - the purpose of FieldFlags.jl is to pack as much data in as little space as possible, to save space in an embedded environment. Primitive types make that MUCH easier to implement than fiddling with an I do want to be clear that having alignment to a multiple of 8 bit i.e. a byte is perfectly fine and acceptable. That is what I take the current behavior to be and is consistent with |
C23 now has a standard ABI for this, so we should follow whatever that is, as per our usual policy |
Are you referring to |
Perhaps I should add that (as I understand it) a |
They map to whatever the relevant C standard says they map to, which at this point in time appears to be the next power-of-two up to a maximum of 64 bytes: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf |
That's fine, I guess, but that still means our padding reflection is inconsistent. If the padding is introduced on the LLVM level after julia, that's ok by me, as long as it's still transparent & consistent on the julia level. The abstraction we're targeting is LLVM after all, and as such, our types should be consistent in whether there is padding, and how much that is (i.e. either return Also, the standard actually says this:
which is the additional complication that "register size" on AVR means "a byte", while it's "8 bytes" on the (64 bit) host system (4 byte on 32 bit). So enforcing/hardcoding the host system behavior here is something I'd rather avoid. |
Ok, so we should switch to computing the size of a primitive type using this algorithm:
So an Int40 is 8 bytes, and the extra 3 bytes are not padding but part of the data itself even though they're not used. |
Well... I think that's actually a bad thing the C standard defines, because on AVR you really don't want to promote an julia> using FieldFlags
# 17 flags need 3 bytes, so this generates a `primitive type Foo 24 end`
julia> @flaggify struct Foo
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
end
julia> sizeof(Foo)
3
julia> f() = Core.Intrinsics.zext_int(Foo, 0x0)
f (generic function with 1 method)
julia> @code_llvm f()
; @ REPL[6]:1 within `f`
define i24 @julia_f_243() #0 {
top:
# ...
ret i24 0
} This only ends up as a 32 bit integer when it's actually compiled to x86_64, on AVR I'd expect this to end up as three bytes, not four. Alternatively, we also change what we emit based on the target architecture.. which seems more complicated than just letting LLVM handle it. |
It does; I believe it follows the C ABI here. In fact we had to specifically fix this in #37974 |
I think LLVM generally expects these to act as padding. In particular, it specifies that their alignment is rounded up to the next power of 2 (https://llvm.org/docs/LangRef.html#data-layout) if using default alignment (somewhat rare these days). and that stores of the value are permitted to clobber extra bytes up their alignment value (https://llvm.org/docs/LangRef.html#store-instruction):
But note also there are explicit semantics on store that clarify further (if alignment is not specified per the default computation):
|
Ah, looks like the logic we're missing is to add padding for values whose alignment is bigger than their size? |
I just don't want to end up in a situation where we specify "no matter where julia runs, we must align a
Yes, that sounds like it will be consistent. We're missing the (reflection on) padding on x86(_64), which is not an issue on AVR due to the alignment there being to 1 byte (instead of 4/8). As long as the padding we add is target-specific, we should be good. |
This came up while experimenting with
@flaggify
and@bitfieldify
from FieldFlags.jl (name pending).How can
Foo_p
grow in size from 5 to 8 bytes, when there isn't supposed to be any padding there?Additionally,
Base.padding
doesn't seem to take this "magic end-struct padding" into account, not even for structs that do claim to have padding:So either
Foo_p
doesn't have padding, which begs the question why it's 8 bytes in size, or it does, which begs the question why it claims that it doesn't.The text was updated successfully, but these errors were encountered: