crystal icon indicating copy to clipboard operation
crystal copied to clipboard

128-bit integers are underaligned on x86-64

Open HertzDevil opened this issue 2 years ago • 2 comments

Consider the following:

@[Extern]
struct Foo
  @x = 0_i64
  @y = 0_i128
end

foo = Foo.new
pointerof(foo.@x) # => Pointer(Int128)@0x7fffd4e08e60
pointerof(foo.@y) # => Pointer(Int128)@0x7fffd4e08e68
offsetof(Foo, @y) # => 8
sizeof(Foo)       # => 24
alignof(Foo)      # => 8

Instead, the address of foo.@y should end with a 0 instead, offsetof(Foo, @y) should be 16, sizeof(Foo) should be 32, and alignof(Foo) should be 16. Underalignment could lead to suboptimal code generation or totally incorrect lib bindings.

This is known to happen on x86-64 Windows and Linux. The Apple M2 (AArch64) does not have this issue:

pointerof(foo.@x) # => Pointer(Int64)@0x16f6d3340
pointerof(foo.@y) # => Pointer(Int128)@0x16f6d3350
offsetof(Foo, @y) # => 16
sizeof(Foo)       # => 32
alignof(Foo)      # => 16

HertzDevil avatar Jun 29 '23 10:06 HertzDevil

This is fixed in LLVM 18, however alignof(Foo | Int32) or even alignof(Foo | Int128) is still 8, since the data storage for mixed unions has the same alignment as size_t:

https://github.com/crystal-lang/crystal/blob/f66312174d0b7dfa30b8795e356c30b9c23e0649/src/compiler/crystal/codegen/unions.cr#L44-L46

HertzDevil avatar Jan 30 '24 16:01 HertzDevil

Rust also backported this to LLVM 17 and below: https://blog.rust-lang.org/2024/03/30/i128-layout-update.html

HertzDevil avatar Aug 14 '24 12:08 HertzDevil