mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Refactor the C ABI conversion to use frontend independent types.
This commit is contained in:
@@ -31,13 +31,51 @@ bool abi_type_is_float(AbiType type)
|
||||
TypeSize abi_type_size(AbiType type)
|
||||
{
|
||||
if (abi_type_is_type(type)) return type_size(type.type);
|
||||
return (type.int_bits_plus_1 - 1) / 8;
|
||||
switch (type.abi_type)
|
||||
{
|
||||
case ABI_TYPE_INT_24: return 3;
|
||||
case ABI_TYPE_INT_40: return 5;
|
||||
case ABI_TYPE_INT_48: return 6;
|
||||
case ABI_TYPE_INT_56: return 7;
|
||||
case ABI_TYPE_INT_VEC_2: return 8;
|
||||
case ABI_TYPE_FLOAT_VEC_2: return 8;
|
||||
case ABI_TYPE_FLOAT16_VEC_2: return 4;
|
||||
case ABI_TYPE_FLOAT16_VEC_4: return 8;
|
||||
case ABI_TYPE_BFLOAT16_VEC_2: return 4;
|
||||
case ABI_TYPE_BFLOAT16_VEC_4: return 8;
|
||||
case ABI_TYPE_INT_VEC_4: return 16;
|
||||
case ABI_TYPE_FLOAT_VEC_4: return 16;
|
||||
case ABI_TYPE_DOUBLE_VEC_2: return 16;
|
||||
case ABI_TYPE_LONG_VEC_2: return 16;
|
||||
case ABI_TYPE_DOUBLE_VEC_4: return 32;
|
||||
case ABI_TYPE_DOUBLE_VEC_8: return 64;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
AlignSize abi_type_abi_alignment(AbiType type)
|
||||
{
|
||||
if (abi_type_is_type(type)) return type_abi_alignment(type.type);
|
||||
return type_abi_alignment(type_int_unsigned_by_bitsize(next_highest_power_of_2(type.int_bits_plus_1 - 1)));
|
||||
switch (type.abi_type)
|
||||
{
|
||||
case ABI_TYPE_FLOAT16_VEC_2:
|
||||
case ABI_TYPE_BFLOAT16_VEC_2:
|
||||
case ABI_TYPE_INT_24: return 4;
|
||||
case ABI_TYPE_INT_40:
|
||||
case ABI_TYPE_INT_48:
|
||||
case ABI_TYPE_INT_56:
|
||||
case ABI_TYPE_FLOAT16_VEC_4:
|
||||
case ABI_TYPE_BFLOAT16_VEC_4:
|
||||
case ABI_TYPE_FLOAT_VEC_2:
|
||||
case ABI_TYPE_INT_VEC_2: return 8;
|
||||
case ABI_TYPE_FLOAT_VEC_4:
|
||||
case ABI_TYPE_LONG_VEC_2:
|
||||
case ABI_TYPE_DOUBLE_VEC_2:
|
||||
case ABI_TYPE_INT_VEC_4: return 16;
|
||||
case ABI_TYPE_DOUBLE_VEC_4: return 32;
|
||||
case ABI_TYPE_DOUBLE_VEC_8: return 64;
|
||||
}
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
bool abi_arg_is_indirect(ABIArgInfo *info)
|
||||
@@ -103,7 +141,7 @@ ABIArgInfo *abi_arg_new_direct_coerce_int_ext(Type *int_to_extend)
|
||||
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_int_ext_by_reg(Type *int_to_extend, bool by_reg)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new_direct_coerce_type(int_to_extend);
|
||||
ABIArgInfo *info = abi_arg_new_direct_coerce_type(abi_type_get(int_to_extend));
|
||||
if (type_is_signed(int_to_extend))
|
||||
{
|
||||
info->attributes.signext = true;
|
||||
@@ -173,11 +211,24 @@ ABIArgInfo *abi_arg_new_direct_coerce_int(void)
|
||||
return abi_arg_new(ABI_ARG_DIRECT_COERCE_INT);
|
||||
}
|
||||
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type(Type *type)
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type_spec(AbiSpecType type)
|
||||
{
|
||||
ASSERT(type);
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
info->direct_coerce_type = type->canonical;
|
||||
info->direct_coerce_type = (AbiType){ .abi_type = type };
|
||||
return info;
|
||||
}
|
||||
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type(AbiType type)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
info->direct_coerce_type = type;
|
||||
return info;
|
||||
}
|
||||
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type_bits(int bits)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_DIRECT_COERCE);
|
||||
info->direct_coerce_type = abi_type_get_int_bits(bits);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,15 +63,15 @@ ABIArgInfo *aarch64_coerce_illegal_vector(Type *type)
|
||||
// CLANG: Android promotes char[<2>] to ushort, not uint
|
||||
if ((compiler.platform.environment_type == ENV_TYPE_ANDROID || compiler.platform.os == OS_TYPE_ANDROID) && size <= 2)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_ushort);
|
||||
return abi_arg_new_direct_coerce_type_bits(16);
|
||||
}
|
||||
// 32 bits or fewer? Put in int.
|
||||
if (size <= 4) return abi_arg_new_direct_coerce_type(type_uint);
|
||||
if (size <= 4) return abi_arg_new_direct_coerce_type_bits(32);
|
||||
|
||||
// 64 bits or less? Put in uint[<2>]
|
||||
if (size <= 8) return abi_arg_new_direct_coerce_type(type_get_vector(type_uint, 2));
|
||||
if (size <= 8) return abi_arg_new_direct_coerce_type((AbiType) { .abi_type = ABI_TYPE_INT_VEC_2 });
|
||||
// 128 bits in a single val? Put in uint[<4>]
|
||||
if (size == 128) return abi_arg_new_direct_coerce_type(type_get_vector(type_uint, 4));
|
||||
if (size == 128) return abi_arg_new_direct_coerce_type((AbiType) { .abi_type = ABI_TYPE_INT_VEC_4 });
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
|
||||
@@ -110,9 +110,9 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type)
|
||||
ASSERT(members < 128);
|
||||
if (members > 1)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_get_array(base, members));
|
||||
return abi_arg_new_direct_coerce_type(abi_type_get(type_get_array(base, members)));
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(base);
|
||||
return abi_arg_new_direct_coerce_type(abi_type_get(base));
|
||||
}
|
||||
|
||||
// Aggregates <= in registers
|
||||
@@ -136,10 +136,10 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type)
|
||||
// For aggregates with 16-byte alignment, we use i128.
|
||||
ASSERT(alignment == 8 || alignment == 16);
|
||||
|
||||
if (alignment == 16) return abi_arg_new_direct_coerce_type(type_u128);
|
||||
if (alignment == 16) return abi_arg_new_direct_coerce_type_bits(128);
|
||||
ArraySize m = size / alignment;
|
||||
if (m > 1) return abi_arg_new_direct_coerce_type(type_get_array(type_ulong, m));
|
||||
return abi_arg_new_direct_coerce_type(type_ulong);
|
||||
if (m > 1) return abi_arg_new_direct_coerce_type(abi_type_get(type_get_array(type_ulong, m)));
|
||||
return abi_arg_new_direct_coerce_type_bits(64);
|
||||
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
|
||||
// Large vectors by mem.
|
||||
if (type->type_kind == TYPE_VECTOR && size > 16)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type);
|
||||
return abi_arg_new_direct_coerce_type(abi_type_get(type));
|
||||
}
|
||||
|
||||
if (!type_is_abi_aggregate(type))
|
||||
@@ -204,9 +204,9 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
|
||||
size = aligned_offset(size, 8);
|
||||
if (alignment < 16 && size == 16)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_get_array(type_ulong, size / 8));
|
||||
return abi_arg_new_direct_coerce_type(abi_type_get(type_get_array(type_ulong, size / 8)));
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(size * 8));
|
||||
return abi_arg_new_direct_coerce_type_bits(size * 8);
|
||||
}
|
||||
|
||||
return abi_arg_new_indirect_by_val(type);
|
||||
|
||||
@@ -7,21 +7,18 @@
|
||||
|
||||
static ABIArgInfo *riscv_coerce_and_expand_fpcc_struct(AbiType field1, unsigned field1_offset, AbiType field2, unsigned field2_offset)
|
||||
{
|
||||
ASSERT(abi_type_is_type(field1));
|
||||
if (!abi_type_is_valid(field2))
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(field1.type);
|
||||
return abi_arg_new_direct_coerce_type(field1);
|
||||
}
|
||||
|
||||
ASSERT(abi_type_is_type(field2));
|
||||
Type *type2 = field2.type;
|
||||
ByteSize abi_type_size = type_size(type2);
|
||||
ByteSize abi_size = abi_type_size(field2);
|
||||
// Not on even offset, use packed semantics.
|
||||
if (field2_offset % abi_type_size != 0)
|
||||
if (field2_offset % abi_size != 0)
|
||||
{
|
||||
return abi_arg_new_expand_coerce_pair(field1.type, field2.type, field2_offset, true);
|
||||
}
|
||||
return abi_arg_new_expand_coerce_pair(field1.type, field2.type, field2_offset / abi_type_size, false);
|
||||
return abi_arg_new_expand_coerce_pair(field1.type, field2.type, field2_offset / abi_size, false);
|
||||
}
|
||||
|
||||
static bool riscv_detect_fpcc_struct_internal(Type *type, unsigned current_offset, AbiType *field1_ref, unsigned *field1_offset, AbiType *field2_ref, unsigned *field2_offset)
|
||||
@@ -214,14 +211,14 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig
|
||||
// required, and a 2-field XLen array if only XLen alignment is required.
|
||||
if (size <= xlen)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(xlen * 8));
|
||||
return abi_arg_new_direct_coerce_type_bits(xlen * 8);
|
||||
}
|
||||
if (alignment == 2 * compiler.platform.riscv.xlen)
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(xlen * 16));
|
||||
return abi_arg_new_direct_coerce_type_bits(xlen * 16);
|
||||
}
|
||||
Type *ret_type = type_int_unsigned_by_bitsize(xlen * 8);
|
||||
return abi_arg_new_direct_coerce_type(type_get_array(ret_type, 2));
|
||||
return abi_arg_new_direct_coerce_type(abi_type_get(type_get_array(ret_type, 2)));
|
||||
}
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ static ABIArgInfo *wasm_classify_argument_type(Type *type)
|
||||
// could do reasonable-size multiple-field structs too, using getExpand(),
|
||||
// though watch out for things like bitfields.
|
||||
Type *single_type = type_abi_find_single_struct_element(type);
|
||||
if (single_type) return abi_arg_new_direct_coerce_type(single_type);
|
||||
if (single_type) return abi_arg_new_direct_coerce_type(abi_type_get(single_type));
|
||||
|
||||
// For the experimental multivalue ABI, fully expand all other aggregates
|
||||
/*if (Kind == ABIKind::ExperimentalMV) {
|
||||
@@ -40,7 +40,7 @@ static ABIArgInfo *wasm_classify_return(Type *type)
|
||||
if (type_is_abi_aggregate(type))
|
||||
{
|
||||
Type *single_type = type_abi_find_single_struct_element(type);
|
||||
if (single_type) return abi_arg_new_direct_coerce_type(single_type);
|
||||
if (single_type) return abi_arg_new_direct_coerce_type(abi_type_get(single_type));
|
||||
/*
|
||||
* // For the experimental multivalue ABI, return all other aggregates
|
||||
if (Kind == ABIKind::ExperimentalMV)
|
||||
|
||||
@@ -45,7 +45,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
// Coerce to integer.
|
||||
return abi_arg_new_direct_coerce_type(type_int_unsigned_by_bitsize(size * 8));
|
||||
return abi_arg_new_direct_coerce_type_bits(size * 8);
|
||||
}
|
||||
if (type_is_builtin(type->type_kind))
|
||||
{
|
||||
@@ -58,7 +58,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
// Pass by val since greater than 8 bytes.
|
||||
if (!is_return) return abi_arg_new_indirect_not_by_val(type);
|
||||
// Make i128 return in XMM0
|
||||
return abi_arg_new_direct_coerce_type(type_get_vector(type_long, 2));
|
||||
return abi_arg_new_direct_coerce_type_spec(ABI_TYPE_LONG_VEC_2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -361,11 +361,11 @@ static Decl *x64_get_member_at_offset(Decl *decl, unsigned offset)
|
||||
return last_match;
|
||||
}
|
||||
|
||||
static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X64Class *hi_class, NamedArgument named)
|
||||
static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X64Class *hi_class, NamedArgument named) // NOLINT
|
||||
{
|
||||
*lo_class = CLASS_NO_CLASS;
|
||||
*hi_class = CLASS_NO_CLASS;
|
||||
X64Class *current = offset_base < 8 ? lo_class : hi_class;
|
||||
X64Class *current = offset_base < 8 ? lo_class : hi_class; // NOLINT - avoid incorrect analysis
|
||||
*current = CLASS_MEMORY;
|
||||
type = type_lowering(type);
|
||||
switch (type->type_kind)
|
||||
@@ -497,10 +497,10 @@ static Type *x64_get_fp_type_at_offset(Type *type, unsigned ir_offset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Type *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source_type, unsigned source_offset)
|
||||
static AbiType x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source_type, unsigned source_offset)
|
||||
{
|
||||
Type *float_type = x64_get_fp_type_at_offset(type, ir_offset);
|
||||
if (!float_type || float_type == type_double) return type_double;
|
||||
if (!float_type || float_type == type_double) return abi_type_get(type_double);
|
||||
|
||||
ByteSize size = type_size(float_type);
|
||||
ByteSize source_size = type_size(source_type) - source_offset;
|
||||
@@ -520,25 +520,30 @@ static Type *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *so
|
||||
float_type2 = x64_get_fp_type_at_offset(type, ir_offset + 4);
|
||||
}
|
||||
// If we can't get a second FP type, return a simple half or float.
|
||||
if (!float_type2) return float_type;
|
||||
if (!float_type2) return abi_type_get(float_type);
|
||||
}
|
||||
|
||||
if (float_type == type_float && float_type == float_type2)
|
||||
{
|
||||
return type_get_vector(float_type, 2);
|
||||
return abi_type_spec(ABI_TYPE_FLOAT_VEC_2);
|
||||
}
|
||||
|
||||
if (type_is_16bit_float(float_type) && type_is_16bit_float(float_type2))
|
||||
{
|
||||
bool has_following_float = source_size > 4
|
||||
&& x64_get_fp_type_at_offset(type, ir_offset + 4) != NULL;
|
||||
return type_get_vector(float_type, has_following_float ? 4 : 2);
|
||||
if (float_type->type_kind == TYPE_BF16)
|
||||
{
|
||||
return abi_type_spec(has_following_float ? ABI_TYPE_BFLOAT16_VEC_4 : ABI_TYPE_BFLOAT16_VEC_2);
|
||||
}
|
||||
return abi_type_spec(has_following_float ? ABI_TYPE_FLOAT16_VEC_4 : ABI_TYPE_FLOAT16_VEC_2);
|
||||
}
|
||||
|
||||
if (type_is_16bit_float(float_type) || type_is_16bit_float(float_type2))
|
||||
{
|
||||
return type_get_vector(type_float16, 4);
|
||||
return abi_type_spec(ABI_TYPE_FLOAT16_VEC_4);
|
||||
}
|
||||
return type_double;
|
||||
return abi_type_get(type_double);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -632,7 +637,7 @@ static AbiType x64_get_byte_vector_type(Type *type)
|
||||
if (compiler.platform.x64.pass_int128_vector_in_mem && type_is_int128(element))
|
||||
{
|
||||
// Convert to u64
|
||||
return abi_type_get(type_get_vector(type_ulong, type_size(type) / 8));
|
||||
return (AbiType) { .abi_type = ABI_TYPE_LONG_VEC_2 };
|
||||
}
|
||||
return abi_type_get(type);
|
||||
}
|
||||
@@ -644,7 +649,15 @@ static AbiType x64_get_byte_vector_type(Type *type)
|
||||
ASSERT(size == 16 || size == 32 || size == 64);
|
||||
|
||||
// Return a vector type based on the size.
|
||||
return abi_type_get(type_get_vector(type_double, size / 8));
|
||||
switch (size)
|
||||
{
|
||||
case 16: return (AbiType) { .abi_type = ABI_TYPE_DOUBLE_VEC_2 };
|
||||
case 32: return (AbiType) { .abi_type = ABI_TYPE_DOUBLE_VEC_4 };
|
||||
case 64: return (AbiType) { .abi_type = ABI_TYPE_DOUBLE_VEC_8 };
|
||||
default:
|
||||
UNREACHABLE_VOID;
|
||||
return (AbiType) { .type = NULL };
|
||||
}
|
||||
}
|
||||
|
||||
static ABIArgInfo *x64_get_argument_pair_return(AbiType low_type, AbiType high_type)
|
||||
@@ -695,7 +708,7 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
}
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
result_type = abi_type_get(x64_get_sse_type_at_offset(return_type, 0, return_type, 0));
|
||||
result_type = x64_get_sse_type_at_offset(return_type, 0, return_type, 0);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
@@ -714,7 +727,7 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
ASSERT(lo_class != CLASS_NO_CLASS);
|
||||
high_part = abi_type_get(x64_get_sse_type_at_offset(return_type, 8, return_type, 8));
|
||||
high_part = x64_get_sse_type_at_offset(return_type, 8, return_type, 8);
|
||||
break;
|
||||
case CLASS_SSEUP:
|
||||
// AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
|
||||
@@ -732,16 +745,11 @@ ABIArgInfo *x64_classify_return(Type *return_type)
|
||||
// first class struct aggregate with the high and low part: {low, high}
|
||||
if (abi_type_is_valid(high_part)) return x64_get_argument_pair_return(result_type, high_part);
|
||||
|
||||
if (abi_type_is_type(result_type))
|
||||
{
|
||||
if (return_type->canonical == result_type.type->canonical)
|
||||
if (abi_type_match(result_type, return_type))
|
||||
{
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(result_type.type->canonical);
|
||||
}
|
||||
ASSERT(result_type.int_bits_plus_1 - 1 == type_size(return_type) * 8);
|
||||
return abi_arg_new_direct_coerce_int();
|
||||
return abi_arg_new_direct_coerce_type(result_type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -765,7 +773,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
ASSERT(hi_class != CLASS_MEMORY || lo_class == CLASS_MEMORY);
|
||||
ASSERT(hi_class != CLASS_SSEUP || lo_class == CLASS_SSE);
|
||||
|
||||
AbiType result_type;
|
||||
AbiType result_type = ABI_TYPE_EMPTY;
|
||||
*needed_registers = (Registers) { 0, 0 };
|
||||
|
||||
// Start by checking the lower class.
|
||||
@@ -789,7 +797,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
}
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
result_type = abi_type_get(x64_get_sse_type_at_offset(type, 0, type, 0));
|
||||
result_type = x64_get_sse_type_at_offset(type, 0, type, 0);
|
||||
needed_registers->sse_registers++;
|
||||
break;
|
||||
}
|
||||
@@ -810,7 +818,7 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
break;
|
||||
case CLASS_SSE:
|
||||
needed_registers->sse_registers++;
|
||||
high_part = abi_type_get(x64_get_sse_type_at_offset(type, 8, type, 8));
|
||||
high_part = x64_get_sse_type_at_offset(type, 8, type, 8);
|
||||
ASSERT(lo_class != CLASS_NO_CLASS && "empty first 8 bytes not allowed, this is C++ stuff");
|
||||
break;
|
||||
case CLASS_SSEUP:
|
||||
@@ -824,19 +832,19 @@ static ABIArgInfo *x64_classify_argument_type(Type *type, unsigned free_int_regs
|
||||
// first class struct aggregate with the high and low part: {low, high}
|
||||
if (abi_type_is_valid(high_part)) return x64_get_argument_pair_return(result_type, high_part);
|
||||
|
||||
if (abi_type_match(result_type, type))
|
||||
{
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
if (abi_type_is_type(result_type))
|
||||
{
|
||||
Type *result = result_type.type->canonical;
|
||||
type = type->canonical;
|
||||
if (type == result) return abi_arg_new_direct();
|
||||
if (type_is_integer(type) && type_is_integer(result) && type->builtin.bytesize == result->builtin.bytesize)
|
||||
{
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
return abi_arg_new_direct_coerce_type(result);
|
||||
}
|
||||
ASSERT(result_type.int_bits_plus_1 - 1 == type_size(type) * 8);
|
||||
return abi_arg_new_direct_coerce_int();
|
||||
return abi_arg_new_direct_coerce_type(result_type);
|
||||
}
|
||||
|
||||
bool x64_type_is_structure(Type *type)
|
||||
|
||||
@@ -358,7 +358,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type)
|
||||
// MMX passed as i64
|
||||
if (x86_is_mmxtype(type))
|
||||
{
|
||||
return abi_arg_new_direct_coerce_type(type_ulong);
|
||||
return abi_arg_new_direct_coerce_type_bits(64);
|
||||
}
|
||||
|
||||
// Send as a normal parameter
|
||||
@@ -398,7 +398,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallABI call, Regs *regs, Type
|
||||
}
|
||||
else
|
||||
{
|
||||
info = abi_arg_new_direct_coerce_type(type_uint);
|
||||
info = abi_arg_new_direct_coerce_type_bits(32);
|
||||
}
|
||||
// Not in reg on MCU
|
||||
if (!compiler.platform.x86.is_mcu_api) info->attributes.by_reg = true;
|
||||
|
||||
@@ -22,7 +22,9 @@ ABIArgInfo *abi_arg_new_direct_int_ext_by_reg(Type *int_to_extend, bool by_reg);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_int_ext_by_reg(Type *int_to_extend, bool by_reg);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_int_ext(Type *int_to_extend);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_int(void);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type(Type *type);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type(AbiType type);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type_spec(AbiSpecType type);
|
||||
ABIArgInfo *abi_arg_new_direct_coerce_type_bits(int bits);
|
||||
ABIArgInfo *abi_arg_new_direct_struct_expand_i32(uint8_t elements);
|
||||
ABIArgInfo *abi_arg_new_expand_coerce_pair(Type *first_element, Type *second_element, unsigned hi_offset, bool packed);
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(AlignSize alignment, Type *by_val_type);
|
||||
@@ -60,17 +62,32 @@ static inline AbiType abi_type_get(Type *type)
|
||||
return (AbiType) { .type = type };
|
||||
}
|
||||
|
||||
static inline AbiType abi_type_spec(AbiSpecType type)
|
||||
{
|
||||
return (AbiType) { .abi_type = type };
|
||||
}
|
||||
|
||||
static inline AbiType abi_type_get_int_bits(BitSize bits)
|
||||
{
|
||||
switch (bits)
|
||||
{
|
||||
case 24:
|
||||
return (AbiType) { .abi_type = ABI_TYPE_INT_24 };
|
||||
case 40:
|
||||
return (AbiType) { .abi_type = ABI_TYPE_INT_40 };
|
||||
case 48:
|
||||
return (AbiType) { .abi_type = ABI_TYPE_INT_48 };
|
||||
case 56:
|
||||
return (AbiType) { .abi_type = ABI_TYPE_INT_56 };
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
return (AbiType) { .type = type_int_unsigned_by_bitsize(bits) };
|
||||
default:
|
||||
return (AbiType) { .int_bits_plus_1 = bits + 1 };
|
||||
UNREACHABLE_VOID;
|
||||
return (AbiType) { .type = NULL };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -277,16 +277,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
||||
return type_homogenous_aggregate_small_enough(type, *elements);
|
||||
}
|
||||
|
||||
AlignSize type_alloca_alignment(Type *type)
|
||||
{
|
||||
AlignSize align = type_abi_alignment(type);
|
||||
if (align < 16 && (compiler.platform.abi == ABI_X64 || compiler.platform.abi == ABI_WIN64))
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16;
|
||||
}
|
||||
return align;
|
||||
}
|
||||
|
||||
|
||||
bool codegen_single_obj_output()
|
||||
{
|
||||
|
||||
@@ -89,30 +89,58 @@ static inline Type *type_lowering(Type *type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool abi_type_match(AbiType type, Type *other_type)
|
||||
{
|
||||
other_type = other_type->canonical;
|
||||
if (type.abi_type & 0x01)
|
||||
{
|
||||
switch (type.abi_type)
|
||||
{
|
||||
case ABI_TYPE_INT_24:
|
||||
case ABI_TYPE_INT_40:
|
||||
case ABI_TYPE_INT_48:
|
||||
case ABI_TYPE_INT_56:
|
||||
return false;
|
||||
case ABI_TYPE_INT_VEC_2:
|
||||
return other_type == type_get_vector(type_uint, 2);
|
||||
case ABI_TYPE_INT_VEC_4:
|
||||
return other_type == type_get_vector(type_uint, 4);
|
||||
case ABI_TYPE_FLOAT_VEC_2:
|
||||
return other_type == type_get_vector(type_float, 2);
|
||||
case ABI_TYPE_FLOAT_VEC_4:
|
||||
return other_type == type_get_vector(type_float, 4);
|
||||
case ABI_TYPE_FLOAT16_VEC_2:
|
||||
return other_type == type_get_vector(type_float16, 2);
|
||||
case ABI_TYPE_FLOAT16_VEC_4:
|
||||
return other_type == type_get_vector(type_float16, 4);
|
||||
case ABI_TYPE_BFLOAT16_VEC_2:
|
||||
return other_type == type_get_vector(type_bfloat, 2);
|
||||
case ABI_TYPE_BFLOAT16_VEC_4:
|
||||
return other_type == type_get_vector(type_bfloat, 4);
|
||||
case ABI_TYPE_LONG_VEC_2:
|
||||
return other_type == type_get_vector(type_ulong, 2);
|
||||
case ABI_TYPE_DOUBLE_VEC_2:
|
||||
return other_type == type_get_vector(type_double, 2);
|
||||
case ABI_TYPE_DOUBLE_VEC_4:
|
||||
return other_type == type_get_vector(type_double, 4);
|
||||
case ABI_TYPE_DOUBLE_VEC_8:
|
||||
return other_type == type_get_vector(type_double, 8);
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
return type.type == other_type->canonical;
|
||||
}
|
||||
static inline bool abi_type_is_type(AbiType type)
|
||||
{
|
||||
return !(type.int_bits_plus_1 & 0x01);
|
||||
return !(type.abi_type & 0x01);
|
||||
}
|
||||
|
||||
static inline bool abi_type_is_valid(AbiType type)
|
||||
{
|
||||
return type.int_bits_plus_1 != 0;
|
||||
return type.abi_type != 0;
|
||||
}
|
||||
|
||||
|
||||
UNUSED static inline bool abi_type_is_promotable_integer_or_bool(AbiType type)
|
||||
{
|
||||
if (abi_type_is_type(type))
|
||||
{
|
||||
if (!type_is_integer_or_bool_kind(type.type)) return false;
|
||||
if (type.type == type_bool) return true;
|
||||
return type.type->builtin.bitsize < compiler.platform.width_c_int;
|
||||
}
|
||||
// We should only get npot or > big ints here.
|
||||
ASSERT(!is_power_of_two(type.int_bits_plus_1 - 1) || type.int_bits_plus_1 < compiler.platform.width_c_int);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool expr_is_vector_index_or_swizzle(Expr *expr)
|
||||
{
|
||||
return (expr->expr_kind == EXPR_SUBSCRIPT && type_lowering(exprtype(expr->subscript_expr.expr))->type_kind == TYPE_VECTOR)
|
||||
|
||||
@@ -1820,12 +1820,32 @@ struct SemaContext_
|
||||
} generic;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ABI_TYPE_INT_24 = 1,
|
||||
ABI_TYPE_INT_40 = 3,
|
||||
ABI_TYPE_INT_48 = 5,
|
||||
ABI_TYPE_INT_56 = 7,
|
||||
ABI_TYPE_INT_VEC_2 = 9,
|
||||
ABI_TYPE_INT_VEC_4 = 11,
|
||||
ABI_TYPE_FLOAT_VEC_2 = 13,
|
||||
ABI_TYPE_FLOAT_VEC_4 = 15,
|
||||
ABI_TYPE_LONG_VEC_2 = 17,
|
||||
ABI_TYPE_FLOAT16_VEC_2 = 19,
|
||||
ABI_TYPE_FLOAT16_VEC_4 = 21,
|
||||
ABI_TYPE_BFLOAT16_VEC_2 = 23,
|
||||
ABI_TYPE_BFLOAT16_VEC_4 = 25,
|
||||
ABI_TYPE_DOUBLE_VEC_2 = 27,
|
||||
ABI_TYPE_DOUBLE_VEC_4 = 29,
|
||||
ABI_TYPE_DOUBLE_VEC_8 = 31,
|
||||
} AbiSpecType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
Type *type;
|
||||
uintptr_t int_bits_plus_1;
|
||||
AbiSpecType abi_type;
|
||||
};
|
||||
} AbiType;
|
||||
|
||||
@@ -1856,7 +1876,7 @@ typedef struct ABIArgInfo_
|
||||
Type *lo;
|
||||
Type *hi;
|
||||
} coerce_expand;
|
||||
Type *direct_coerce_type;
|
||||
AbiType direct_coerce_type;
|
||||
uint8_t direct_struct_expand;
|
||||
struct
|
||||
{
|
||||
@@ -2565,7 +2585,6 @@ unsigned type_get_introspection_kind(TypeKind kind);
|
||||
void type_mangle_introspect_name_to_buffer(Type *type);
|
||||
AlignSize type_abi_alignment(Type *type);
|
||||
bool type_func_match(Type *fn_type, Type *rtype, unsigned arg_count, ...);
|
||||
AlignSize type_alloca_alignment(Type *type);
|
||||
Type *type_find_largest_union_element(Type *type);
|
||||
Type *type_find_max_type(Type *type, Type *other, Expr *first, Expr *second);
|
||||
Type *type_find_max_type_may_fail(Type *type, Type *other);
|
||||
@@ -2582,9 +2601,10 @@ Type *type_get_slice(Type *arr_type);
|
||||
Type *type_get_inferred_array(Type *arr_type);
|
||||
Type *type_get_inferred_vector(Type *arr_type);
|
||||
Type *type_get_flexible_array(Type *arr_type);
|
||||
|
||||
AlignSize type_alloca_alignment(Type *type);
|
||||
Type *type_get_optional(Type *optional_type);
|
||||
Type *type_get_vector(Type *vector_type, unsigned len);
|
||||
Type *type_get_simd(Type *vector_type, unsigned len);
|
||||
Type *type_get_vector_bool(Type *original_type);
|
||||
Type *type_int_signed_by_bitsize(BitSize bitsize);
|
||||
Type *type_int_unsigned_by_bitsize(BitSize bit_size);
|
||||
|
||||
@@ -5241,7 +5241,7 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_
|
||||
}
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
{
|
||||
LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type);
|
||||
LLVMTypeRef coerce_type = llvm_abi_type(c, info->direct_coerce_type);
|
||||
if (coerce_type == llvm_get_type(c, type))
|
||||
{
|
||||
args[(*arg_count_ref)++] = llvm_load_value_store(c, be_value);
|
||||
@@ -5507,7 +5507,7 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype
|
||||
// 16. A direct coerce, this is basically "call result" bitcast return type.
|
||||
|
||||
// 16a. Get the type of the return.
|
||||
LLVMTypeRef coerce = llvm_get_type(c, ret_info->direct_coerce_type);
|
||||
LLVMTypeRef coerce = llvm_abi_type(c, ret_info->direct_coerce_type);
|
||||
|
||||
// 16b. If we don't have any coerce type, or the actual LLVM types are the same, we're done.
|
||||
if (coerce == llvm_get_type(c, call_return_type))
|
||||
|
||||
@@ -224,7 +224,7 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, ABIAr
|
||||
}
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
{
|
||||
LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type);
|
||||
LLVMTypeRef coerce_type = llvm_abi_type(c, info->direct_coerce_type);
|
||||
if (coerce_type == llvm_get_type(c, decl->type))
|
||||
{
|
||||
goto DIRECT_FROM_COERCE;
|
||||
@@ -377,7 +377,7 @@ DIRECT_RETURN:
|
||||
}
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
{
|
||||
LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type);
|
||||
LLVMTypeRef coerce_type = llvm_abi_type(c, info->direct_coerce_type);
|
||||
if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN;
|
||||
llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));
|
||||
return;
|
||||
|
||||
@@ -187,7 +187,7 @@ static inline void add_func_type_param(GenContext *c, Type *param_type, ABIArgIn
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
{
|
||||
// Normal direct.
|
||||
vec_add(*params, llvm_get_type(c, arg_info->direct_coerce_type));
|
||||
vec_add(*params, llvm_abi_type(c, arg_info->direct_coerce_type));
|
||||
break;
|
||||
}
|
||||
case ABI_ARG_DIRECT_PAIR:
|
||||
@@ -242,7 +242,7 @@ LLVMTypeRef llvm_update_prototype_abi(GenContext *c, FunctionPrototype *prototyp
|
||||
retval = LLVMIntTypeInContext(c->context, type_size(call_return_type) * 8);
|
||||
break;
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
retval = llvm_get_type(c, ret_arg_info->direct_coerce_type);
|
||||
retval = llvm_abi_type(c, ret_arg_info->direct_coerce_type);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,26 @@ LLVMTypeRef llvm_get_twostruct(GenContext *context, LLVMTypeRef lo, LLVMTypeRef
|
||||
LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type)
|
||||
{
|
||||
if (abi_type_is_type(type)) return llvm_get_type(c, type.type);
|
||||
return LLVMIntTypeInContext(c->context, type.int_bits_plus_1 - 1);
|
||||
switch (type.abi_type)
|
||||
{
|
||||
case ABI_TYPE_INT_24: return LLVMIntTypeInContext(c->context, 24);
|
||||
case ABI_TYPE_INT_40: return LLVMIntTypeInContext(c->context, 40);
|
||||
case ABI_TYPE_INT_48: return LLVMIntTypeInContext(c->context, 48);
|
||||
case ABI_TYPE_INT_56: return LLVMIntTypeInContext(c->context, 56);
|
||||
case ABI_TYPE_INT_VEC_2: return LLVMVectorType(LLVMIntTypeInContext(c->context, 32), 2);
|
||||
case ABI_TYPE_INT_VEC_4: return LLVMVectorType(LLVMIntTypeInContext(c->context, 32), 4);
|
||||
case ABI_TYPE_FLOAT_VEC_2: return LLVMVectorType(LLVMFloatTypeInContext(c->context), 2);
|
||||
case ABI_TYPE_FLOAT_VEC_4: return LLVMVectorType(LLVMFloatTypeInContext(c->context), 4);
|
||||
case ABI_TYPE_FLOAT16_VEC_2: return LLVMVectorType(LLVMHalfTypeInContext(c->context), 2);
|
||||
case ABI_TYPE_FLOAT16_VEC_4: return LLVMVectorType(LLVMHalfTypeInContext(c->context), 4);
|
||||
case ABI_TYPE_BFLOAT16_VEC_2: return LLVMVectorType(LLVMBFloatTypeInContext(c->context), 2);
|
||||
case ABI_TYPE_BFLOAT16_VEC_4: return LLVMVectorType(LLVMBFloatTypeInContext(c->context), 4);
|
||||
case ABI_TYPE_LONG_VEC_2: return LLVMVectorType(LLVMIntTypeInContext(c->context, 64), 2);
|
||||
case ABI_TYPE_DOUBLE_VEC_2: return LLVMVectorType(LLVMDoubleTypeInContext(c->context), 2);
|
||||
case ABI_TYPE_DOUBLE_VEC_4: return LLVMVectorType(LLVMDoubleTypeInContext(c->context), 4);
|
||||
case ABI_TYPE_DOUBLE_VEC_8: return LLVMVectorType(LLVMDoubleTypeInContext(c->context), 8);
|
||||
}
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1057,6 +1057,17 @@ Type *type_get_inferred_vector(Type *arr_type)
|
||||
return type_generate_inferred_vector(arr_type, false);
|
||||
}
|
||||
|
||||
AlignSize type_alloca_alignment(Type *type)
|
||||
{
|
||||
AlignSize align = type_abi_alignment(type);
|
||||
if (align < 16 && (compiler.platform.abi == ABI_X64 || compiler.platform.abi == ABI_WIN64))
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16;
|
||||
}
|
||||
return align;
|
||||
}
|
||||
|
||||
Type *type_get_flexible_array(Type *arr_type)
|
||||
{
|
||||
ASSERT(type_is_valid_for_array(arr_type));
|
||||
@@ -1319,6 +1330,11 @@ Type *type_get_vector_bool(Type *original_type)
|
||||
return type_get_vector(type_int_signed_by_bitsize((unsigned)size * 8), (unsigned)original_type->array.len);
|
||||
}
|
||||
|
||||
Type *type_get_simd(Type *vector_type, unsigned len)
|
||||
{
|
||||
return type_get_vector(vector_type, len);
|
||||
}
|
||||
|
||||
Type *type_get_vector(Type *vector_type, unsigned len)
|
||||
{
|
||||
ASSERT(type_is_valid_for_vector(vector_type));
|
||||
|
||||
Reference in New Issue
Block a user