You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LLVM::ABI is the type used by the compiler to determine the correct LLVM IR signature of C functions, by adding the appropriate sret and byval parameter attributes and turning those parameters into indirectly passed values, according to a given target's calling convention. It however has two problems:
It is the only part of LLVM that consists mainly of Crystal code (in fact, a Rust source port) rather than bindings and wrappers.
Since it operates on LLVM types only, and since LLVM types cannot represent C unions natively, no ABI can account for special rules used by C unions.
As an example, the RISC-V hardfloat calling convention roughly states that, if a struct has at most two nested fields of floats smaller than ABI_FLEN bits or integers smaller than XLEN bits, that entire struct may be passed directly in registers. In particular, for ILP32D (32-bit integers and 64-bit floats), an otherwise indirect parameter could be passed directly this way for e.g. a struct with 2 double fields. This rule doesn't apply to unions though; they are not considered as nested fields in the same way, and always use the integer calling convention. This C snippet demonstrates the differences. (syntacore-scr4-rv32 has 32-bit and 64-bit hardfloat support.)
Crystal and Clang both work around the lack of union support in LLVM by creating a different LLVM struct type with the same size and alignment. Ours looks like this:
libLib
union Foo
x : Float32endstructBar
x : Float64
y : Fooendend
Crystal will produce the following LLVM IR:
%"struct.Lib::Bar" = type { double, %"union.Lib::Foo" }
%"union.Lib::Foo" = type { [1 x i32] }
So Lib::Bar, when flattened, consists of a Float64 field and an Int32 field according to LLVM, and therefore would be passed directly. But this is incorrect; since the union inhibits flattening, and the whole struct exceeds twice XLEN in size, it must be passed indirectly. LLVM::ABI will fail to handle this if it only deals with LLVM::Types. We could circumvent this by assuming all LLVM types whose name starts with union. are C unions, but this is Crystal's convention, not LLVM's, and besides it is still impossible to recover the original variant types in case a calling convention requires this information.
The upstream Rust code uses its own type to represent the C function type, instead of what would correspond to a wrapper over LLVMTypeRef. We should follow suit, but this is only possible by first making LLVM::ABI deprecated and then copying the whole hierarchy into the Crystal namespace.
The text was updated successfully, but these errors were encountered:
LLVM::ABI
is the type used by the compiler to determine the correct LLVM IR signature of C functions, by adding the appropriatesret
andbyval
parameter attributes and turning those parameters into indirectly passed values, according to a given target's calling convention. It however has two problems:LLVM
that consists mainly of Crystal code (in fact, a Rust source port) rather than bindings and wrappers.As an example, the RISC-V hardfloat calling convention roughly states that, if a struct has at most two nested fields of floats smaller than ABI_FLEN bits or integers smaller than XLEN bits, that entire struct may be passed directly in registers. In particular, for ILP32D (32-bit integers and 64-bit floats), an otherwise indirect parameter could be passed directly this way for e.g. a struct with 2
double
fields. This rule doesn't apply to unions though; they are not considered as nested fields in the same way, and always use the integer calling convention. This C snippet demonstrates the differences. (syntacore-scr4-rv32
has 32-bit and 64-bit hardfloat support.)Crystal and Clang both work around the lack of union support in LLVM by creating a different LLVM struct type with the same size and alignment. Ours looks like this:
crystal/src/compiler/crystal/codegen/llvm_typer.cr
Lines 320 to 395 in 558ce7b
Now, given the following types:
Crystal will produce the following LLVM IR:
So
Lib::Bar
, when flattened, consists of aFloat64
field and anInt32
field according to LLVM, and therefore would be passed directly. But this is incorrect; since the union inhibits flattening, and the whole struct exceeds twice XLEN in size, it must be passed indirectly.LLVM::ABI
will fail to handle this if it only deals withLLVM::Type
s. We could circumvent this by assuming all LLVM types whose name starts withunion.
are C unions, but this is Crystal's convention, not LLVM's, and besides it is still impossible to recover the original variant types in case a calling convention requires this information.The upstream Rust code uses its own type to represent the C function type, instead of what would correspond to a wrapper over
LLVMTypeRef
. We should follow suit, but this is only possible by first makingLLVM::ABI
deprecated and then copying the whole hierarchy into theCrystal
namespace.The text was updated successfully, but these errors were encountered: