Refactor the C ABI conversion to use frontend independent types.

This commit is contained in:
Christoffer Lerno
2025-10-14 19:38:51 +02:00
parent 7b02907830
commit e37343fbe3
15 changed files with 248 additions and 101 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 };
}
}

View File

@@ -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()
{

View File

@@ -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)

View File

@@ -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);

View File

@@ -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))

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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));