From e37343fbe3973c991cacad0b9dca77ef40ef6e0a Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 14 Oct 2025 19:38:51 +0200 Subject: [PATCH] Refactor the C ABI conversion to use frontend independent types. --- src/compiler/abi/c_abi.c | 63 +++++++++++++++++++++++--- src/compiler/abi/c_abi_aarch64.c | 24 +++++----- src/compiler/abi/c_abi_riscv.c | 17 +++---- src/compiler/abi/c_abi_wasm.c | 4 +- src/compiler/abi/c_abi_win64.c | 4 +- src/compiler/abi/c_abi_x64.c | 66 ++++++++++++++++------------ src/compiler/abi/c_abi_x86.c | 4 +- src/compiler/c_abi_internal.h | 21 ++++++++- src/compiler/codegen_general.c | 11 +---- src/compiler/codegen_internal.h | 58 +++++++++++++++++------- src/compiler/compiler_internal.h | 28 ++++++++++-- src/compiler/llvm_codegen_expr.c | 4 +- src/compiler/llvm_codegen_function.c | 4 +- src/compiler/llvm_codegen_type.c | 25 +++++++++-- src/compiler/types.c | 16 +++++++ 15 files changed, 248 insertions(+), 101 deletions(-) diff --git a/src/compiler/abi/c_abi.c b/src/compiler/abi/c_abi.c index 1a510f4f4..1170c3f42 100644 --- a/src/compiler/abi/c_abi.c +++ b/src/compiler/abi/c_abi.c @@ -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; } diff --git a/src/compiler/abi/c_abi_aarch64.c b/src/compiler/abi/c_abi_aarch64.c index ae99fed09..93489d799 100644 --- a/src/compiler/abi/c_abi_aarch64.c +++ b/src/compiler/abi/c_abi_aarch64.c @@ -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); diff --git a/src/compiler/abi/c_abi_riscv.c b/src/compiler/abi/c_abi_riscv.c index 02dc10cb2..caf542980 100644 --- a/src/compiler/abi/c_abi_riscv.c +++ b/src/compiler/abi/c_abi_riscv.c @@ -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); } diff --git a/src/compiler/abi/c_abi_wasm.c b/src/compiler/abi/c_abi_wasm.c index e50dade8a..c13c9addc 100644 --- a/src/compiler/abi/c_abi_wasm.c +++ b/src/compiler/abi/c_abi_wasm.c @@ -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) diff --git a/src/compiler/abi/c_abi_win64.c b/src/compiler/abi/c_abi_win64.c index b84d4fd85..32e4a0397 100644 --- a/src/compiler/abi/c_abi_win64.c +++ b/src/compiler/abi/c_abi_win64.c @@ -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; } diff --git a/src/compiler/abi/c_abi_x64.c b/src/compiler/abi/c_abi_x64.c index eeeb929bd..2c496c177 100644 --- a/src/compiler/abi/c_abi_x64.c +++ b/src/compiler/abi/c_abi_x64.c @@ -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 (abi_type_match(result_type, return_type)) { - if (return_type->canonical == result_type.type->canonical) - { - return abi_arg_new_direct(); - } - return abi_arg_new_direct_coerce_type(result_type.type->canonical); + return abi_arg_new_direct(); } - 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) diff --git a/src/compiler/abi/c_abi_x86.c b/src/compiler/abi/c_abi_x86.c index 81175aa29..e43250db3 100644 --- a/src/compiler/abi/c_abi_x86.c +++ b/src/compiler/abi/c_abi_x86.c @@ -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; diff --git a/src/compiler/c_abi_internal.h b/src/compiler/c_abi_internal.h index 9291cb2b6..edd0b9930 100644 --- a/src/compiler/c_abi_internal.h +++ b/src/compiler/c_abi_internal.h @@ -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 }; } } diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index 93df674a5..6a40e6dbb 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -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() { diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index b4242d098..ba7ea757c 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -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) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index a7c55c421..3935fbd8f 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 2ecc2abdf..78abf4143 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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)) diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 25848765c..41ff05f50 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -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; diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index b94805bfb..f684032c1 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -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; } diff --git a/src/compiler/types.c b/src/compiler/types.c index 46ee543ca..a905b9b77 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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));