diff --git a/spec/std/llvm/x86_64_abi_spec.cr b/spec/std/llvm/x86_64_abi_spec.cr index 2e2514e209d2..7c0344769aa3 100644 --- a/spec/std/llvm/x86_64_abi_spec.cr +++ b/spec/std/llvm/x86_64_abi_spec.cr @@ -144,6 +144,30 @@ class LLVM::ABI info.arg_types[0].should eq(ArgType.indirect(str, Attribute::ByVal)) info.return_type.should eq(ArgType.indirect(str, Attribute::StructRet)) end + + test "does with packed struct containing unaligned fields (#9873)" do |abi, ctx| + str = ctx.struct([ctx.int8, ctx.int16], packed: true) + arg_types = [str] + return_type = str + + info = abi.abi_info(arg_types, return_type, true, ctx) + info.arg_types.size.should eq(1) + + info.arg_types[0].should eq(ArgType.indirect(str, Attribute::ByVal)) + info.return_type.should eq(ArgType.indirect(str, Attribute::StructRet)) + end + + test "does with packed struct not containing unaligned fields" do |abi, ctx| + str = ctx.struct([ctx.int16, ctx.int8], packed: true) + arg_types = [str] + return_type = str + + info = abi.abi_info(arg_types, return_type, true, ctx) + info.arg_types.size.should eq(1) + + info.arg_types[0].should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) + info.return_type.should eq(ArgType.direct(str, cast: ctx.struct([ctx.int64]))) + end end {% end %} end diff --git a/src/llvm/abi/x86_64.cr b/src/llvm/abi/x86_64.cr index e1e996f178e7..5dff628655be 100644 --- a/src/llvm/abi/x86_64.cr +++ b/src/llvm/abi/x86_64.cr @@ -100,7 +100,7 @@ class LLVM::ABI::X86_64 < LLVM::ABI def classify(type) words = (size(type) + 7) // 8 reg_classes = Array.new(words, RegClass::NoClass) - if words > 4 + if words > 4 || has_misaligned_fields?(type) all_mem(reg_classes) else classify(type, reg_classes, 0, 0) @@ -275,6 +275,16 @@ class LLVM::ABI::X86_64 < LLVM::ABI size(type, 8) end + def has_misaligned_fields?(type : Type) : Bool + return false unless type.packed_struct? + offset = 0 + type.struct_element_types.each do |elem| + return true unless offset.divisible_by?(align(elem)) + offset += size(elem) + end + false + end + enum RegClass NoClass Int