-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Closed
Labels
kind:bugA bug in the code. Does not apply to documentation, specs, etc.A bug in the code. Does not apply to documentation, specs, etc.platform:aarch64topic:compiler:codegen
Description
This example from spec/compiler/codegen/extern_spec.cr
, which currently runs only on x86-64 targets, crashes on AArch64 (both macOS and Alpine):
lib LibMylib
struct Struct
x : Int32
y : Int32
z : Int32
w : Int32
a : Int32
end
end
f = ->{
s = LibMylib::Struct.new
s.x = 1
s.y = 2
s.z = 3
s.w = 4
s.a = 5
s
}
s = f.call
s.x &+ s.y &+ s.z &+ s.w &+ s.a
LibMylib::Struct
must be passed indirectly according to the AArch64 ABI. The generated LLVM IR shows how this is done:
define i32 @__crystal_main(i32 %argc, ptr %argv) {
; ...
%6 = load %"->", ptr %f, align 8
%7 = extractvalue %"->" %6, 0
%8 = extractvalue %"->" %6, 1
%9 = icmp eq ptr %8, null
br i1 %9, label %ctx_is_null, label %ctx_is_not_null
ctx_is_null: ; preds = %entry
call void %7(ptr %1)
br label %exit
ctx_is_not_null: ; preds = %entry
%10 = call %"struct.LibMylib::Struct" %7(ptr %8)
store %"struct.LibMylib::Struct" %10, ptr %2, align 4
br label %exit
exit: ; preds = %ctx_is_not_null, %ctx_is_null
%11 = phi ptr [ %1, %ctx_is_null ], [ %2, %ctx_is_not_null ]
%12 = load %"struct.LibMylib::Struct", ptr %11, align 4
store %"struct.LibMylib::Struct" %12, ptr %s, align 4
; ...
}
define void @"~procProc(LibMylib::Struct)@test.cr:11"(ptr sret(%"struct.LibMylib::Struct") %0) #0 {
alloca:
%s = alloca %"struct.LibMylib::Struct", align 8
%1 = alloca %"struct.LibMylib::Struct", align 8
br label %entry
entry: ; preds = %alloca
%2 = call %"struct.LibMylib::Struct" @"*struct.LibMylib::Struct::new:struct.LibMylib::Struct"()
store %"struct.LibMylib::Struct" %2, ptr %1, align 4
%3 = load %"struct.LibMylib::Struct", ptr %1, align 4
store %"struct.LibMylib::Struct" %3, ptr %s, align 4
%4 = getelementptr inbounds %"struct.LibMylib::Struct", ptr %s, i32 0, i32 0
store i32 1, ptr %4, align 4
%5 = getelementptr inbounds %"struct.LibMylib::Struct", ptr %s, i32 0, i32 1
store i32 2, ptr %5, align 4
%6 = getelementptr inbounds %"struct.LibMylib::Struct", ptr %s, i32 0, i32 2
store i32 3, ptr %6, align 4
%7 = getelementptr inbounds %"struct.LibMylib::Struct", ptr %s, i32 0, i32 3
store i32 4, ptr %7, align 4
%8 = getelementptr inbounds %"struct.LibMylib::Struct", ptr %s, i32 0, i32 4
store i32 5, ptr %8, align 4
%9 = load %"struct.LibMylib::Struct", ptr %s, align 4
store %"struct.LibMylib::Struct" %9, ptr %0, align 4
ret void
}
Apparently, the store %"struct.LibMylib::Struct" %9, ptr %0
instruction is reading %0
from the wrong register, but everything works if the call is adjusted like this:
ctx_is_null: ; preds = %entry
call void %7(ptr sret(%"struct.LibMylib::Struct") %1)
br label %exit
That is, the sret
at the call argument should match the sret
at the function parameter.
Metadata
Metadata
Assignees
Labels
kind:bugA bug in the code. Does not apply to documentation, specs, etc.A bug in the code. Does not apply to documentation, specs, etc.platform:aarch64topic:compiler:codegen