From 6cef75b608bc4d5882a5c2b716d32709f19370f6 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 6 Feb 2023 18:09:31 +0100 Subject: [PATCH] Removes win x86 target. Add win aarch64. Fixes to jump buffer sizes. Fix returning bool[2] in the SysV ABI. Array comparison now works. Prevent flexible array comparisons. Prevent zero size unions. --- lib/std/libc/libc.c3 | 2 +- src/build/build_options.c | 2 +- src/build/build_options.h | 2 +- src/compiler/compiler.c | 41 +- src/compiler/compiler_internal.h | 5 - src/compiler/llvm_codegen.c | 23 +- src/compiler/llvm_codegen_c_abi_x64.c | 2 +- src/compiler/llvm_codegen_expr.c | 190 +++++++-- src/compiler/llvm_codegen_module.c | 5 +- src/compiler/llvm_codegen_type.c | 2 +- src/compiler/sema_casts.c | 6 +- src/compiler/sema_decls.c | 6 +- src/compiler/sema_expr.c | 12 +- src/compiler/target.c | 2 +- src/compiler/types.c | 20 +- src/version.h | 2 +- .../abi/darwin_return_boolarray.c3t | 17 + test/test_suite/arrays/array_comparison.c3t | 390 ++++++++++++++++++ .../struct/flex_array_comparison.c3 | 15 + test/test_suite/union/union_zero.c3 | 3 + 20 files changed, 655 insertions(+), 92 deletions(-) create mode 100644 test/test_suite/abi/darwin_return_boolarray.c3t create mode 100644 test/test_suite/arrays/array_comparison.c3t create mode 100644 test/test_suite/struct/flex_array_comparison.c3 create mode 100644 test/test_suite/union/union_zero.c3 diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index 2f1718b88..09e563793 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -33,7 +33,7 @@ fn void errno_set(Errno e) define TerminateFunction = fn void(); define CompareFunction = fn int(void*, void*); -define JmpBuf = CInt[$$JMP_BUF_SIZE]; +define JmpBuf = uptr[$$JMP_BUF_SIZE]; $if (env::COMPILER_LIBC_AVAILABLE): diff --git a/src/build/build_options.c b/src/build/build_options.c index 6ac824611..b1827038d 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -46,7 +46,7 @@ char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = { [OPENBSD_X64] = "openbsd-x64", [WASM32] = "wasm32", [WASM64] = "wasm64", - [WINDOWS_X86] = "windows-x86", + [WINDOWS_AARCH64] = "windows-aarch64", [WINDOWS_X64] = "windows-x64", }; diff --git a/src/build/build_options.h b/src/build/build_options.h index 6519c796c..a1a57a3ab 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -253,7 +253,7 @@ typedef enum OPENBSD_X64, WASM32, WASM64, - WINDOWS_X86, + WINDOWS_AARCH64, WINDOWS_X64, ARCH_OS_TARGET_LAST = WINDOWS_X64 } ArchOsTarget; diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 064762a35..b7dafecf6 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -171,7 +171,7 @@ static const char *exe_name(void) } switch (active_target.arch_os_target) { - case WINDOWS_X86: + case WINDOWS_AARCH64: case WINDOWS_X64: case MINGW_X64: return str_cat(name, ".exe"); @@ -207,7 +207,7 @@ static const char *static_lib_name(void) } switch (active_target.arch_os_target) { - case WINDOWS_X86: + case WINDOWS_AARCH64: case WINDOWS_X64: case MINGW_X64: return str_cat(name, ".lib"); @@ -713,34 +713,45 @@ static int jump_buffer_size() case ARCH_OS_TARGET_DEFAULT: return 512; case ELF_RISCV32: - case ELF_RISCV64: case LINUX_RISCV32: + // Godbolt test + return 76; + case ELF_RISCV64: case LINUX_RISCV64: - REMINDER("RISCV jmpbuf size is unknown"); - return 512; - case ELF_X64: - case FREEBSD_X64: - case LINUX_X64: + // Godbolt test + return 43; case MACOS_X64: - case WINDOWS_X64: + return 19; // Actually 18.5 + case WINDOWS_X64: // 16 on x32 case MINGW_X64: + // Godbolt test + return 32; + case ELF_X64: + case LINUX_X64: + // Godbolt test + return 25; + case FREEBSD_X64: case NETBSD_X64: case OPENBSD_X64: - // Based on MacOS headers - return ((9 * 2) + 3 + 16); + REMINDER("Guessing setjmp for platform."); + return 32; case LINUX_AARCH64: case ELF_AARCH64: + return 39; + case WINDOWS_AARCH64: + // Based on Godbolt + return 24; case MACOS_AARCH64: // Based on MacOS headers - return ((14 + 8 + 2) * 2); + return 25; case LINUX_X86: case MCU_X86: case NETBSD_X86: case OPENBSD_X86: - case WINDOWS_X86: case ELF_X86: case FREEBSD_X86: - return 18; + // Early GCC + return 39; case WASM32: case WASM64: REMINDER("WASM setjmp size is unknown"); @@ -838,7 +849,7 @@ const char *get_object_extension(void) switch (active_target.arch_os_target) { case WINDOWS_X64: - case WINDOWS_X86: + case WINDOWS_AARCH64: case MINGW_X64: return ".obj"; default: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 665073a17..06f7b378b 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1789,11 +1789,6 @@ typedef struct FunctionPrototype_ ABIArgInfo *ret_by_ref_abi_info; ABIArgInfo **abi_args; ABIArgInfo **abi_varargs; - union - { - void *tb_prototype; - void *llvm_prototype; - }; Type *raw_type; } FunctionPrototype; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index bd10bf97b..bff771fa1 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -400,10 +400,9 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) } - // TODO fix name LLVMValueRef old = decl->backend_ref; LLVMValueRef global_ref = decl->backend_ref = llvm_add_global_raw(c, - decl->extname, + decl_get_extname(decl), LLVMTypeOf(init_value), decl->alignment); if (decl->var.is_addr) @@ -816,19 +815,19 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl) switch (decl->decl_kind) { case DECL_POISONED: - UNREACHABLE; - case DECL_FUNC: - // TODO - break; case DECL_VAR: - // TODO - break; - case DECL_TYPEDEF: - break; case DECL_ENUM_CONSTANT: case DECL_FAULTVALUE: - // TODO - break;; + UNREACHABLE; + case DECL_TYPEDEF: + if (decl->typedef_decl.is_func) + { + REMINDER("Emit func typeid"); + } + break; + case DECL_FUNC: + // Never directly invoked. + UNREACHABLE case DECL_DISTINCT: case DECL_STRUCT: case DECL_UNION: diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 039affc2c..b8a7dd9eb 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -681,7 +681,7 @@ ABIArgInfo *x64_classify_return(Type *return_type) // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. result_type = x64_get_int_type_at_offset(return_type, 0, return_type, 0); - if (hi_class == CLASS_NO_CLASS && abi_type_is_promotable_integer_or_bool(result_type)) + if (hi_class == CLASS_NO_CLASS && type_is_promotable_integer(return_type)) { return abi_arg_new_direct_coerce_int_ext(return_type); } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index f9ab4b122..cdcb1be78 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1276,7 +1276,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu llvm_emit_vector_to_array_cast(c, value, to_type, from_type); break; case CAST_EUER: - TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type); + REMINDER("Improve fault to err comparison"); + break; case CAST_ERBOOL: case CAST_EUBOOL: { @@ -1712,7 +1713,7 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r } else if (is_array) { - // Todo optimize + REMINDER("Optimize array reference list init"); AlignSize alignment; LLVMValueRef ptr = llvm_emit_array_gep_raw(c, value, llvm_type, i, ref->alignment, &alignment); llvm_value_set_address(&pointer, ptr, element->type, alignment); @@ -2720,7 +2721,6 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) case TYPE_POINTER: start_pointer = llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent.type), parent.value, start.value); break; - TODO default: UNREACHABLE } @@ -3276,7 +3276,92 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) { - TODO + bool want_match = binary_op == BINARYOP_EQ; + ArraySize len = lhs->type->array.len; + Type *array_base_type = type_lowering(lhs->type->array.base); + LLVMTypeRef array_type = llvm_get_type(c, lhs->type); + if (len <= 16) + { + LLVMBasicBlockRef blocks[17]; + LLVMValueRef value_block[17]; + LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "match"); + LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "exit"); + llvm_value_addr(c, lhs); + llvm_value_addr(c, rhs); + LLVMValueRef success = LLVMConstInt(c->bool_type, want_match ? 1 : 0, false); + LLVMValueRef failure = LLVMConstInt(c->bool_type, want_match ? 0 : 1, false); + blocks[0] = c->current_block; + for (unsigned i = 0; i < len; i++) + { + value_block[i] = failure; + AlignSize align_lhs; + BEValue lhs_v; + LLVMValueRef lhs_ptr = llvm_emit_array_gep_raw(c, lhs->value, array_type, i, lhs->alignment, &align_lhs); + llvm_value_set_address(&lhs_v, lhs_ptr, array_base_type, align_lhs); + AlignSize align_rhs; + BEValue rhs_v; + LLVMValueRef rhs_ptr = llvm_emit_array_gep_raw(c, rhs->value, array_type, i, rhs->alignment, &align_rhs); + llvm_value_set_address(&rhs_v, rhs_ptr, array_base_type, align_rhs); + BEValue comp; + llvm_emit_comp(c, &comp, &lhs_v, &rhs_v, BINARYOP_EQ); + LLVMBasicBlockRef block = ok_block; + if (i < len - 1) + { + block = blocks[i + 1] = llvm_basic_block_new(c, "next_check"); + } + llvm_emit_cond_br(c, &comp, block, exit_block); + llvm_emit_block(c, block); + } + llvm_emit_br(c, exit_block); + llvm_emit_block(c, exit_block); + value_block[len] = success; + blocks[len] = ok_block; + LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "array_cmp_phi"); + LLVMAddIncoming(phi, value_block, blocks, len + 1); + llvm_value_set(be_value, phi, type_bool); + return; + } + + LLVMBasicBlockRef exit = llvm_basic_block_new(c, "array_cmp_exit"); + LLVMBasicBlockRef loop_begin = llvm_basic_block_new(c, "array_loop_start"); + LLVMBasicBlockRef comparison = llvm_basic_block_new(c, "array_loop_comparison"); + + LLVMValueRef len_val = llvm_const_int(c, type_usize, len); + LLVMValueRef one = llvm_const_int(c, type_usize, 1); + BEValue index_var; + llvm_value_set_address_abi_aligned(&index_var, llvm_emit_alloca_aligned(c, type_usize, "cmp.idx"), type_usize); + llvm_store_raw(c, &index_var, llvm_get_zero(c, type_usize)); + + llvm_emit_br(c, loop_begin); + llvm_emit_block(c, loop_begin); + + AlignSize align_lhs; + BEValue lhs_v; + LLVMValueRef index = llvm_load_value(c, &index_var); + LLVMValueRef lhs_ptr = llvm_emit_array_gep_raw_index(c, lhs->value, array_type, index, lhs->alignment, &align_lhs); + llvm_value_set_address(&lhs_v, lhs_ptr, array_base_type, align_lhs); + AlignSize align_rhs; + BEValue rhs_v; + LLVMValueRef rhs_ptr = llvm_emit_array_gep_raw_index(c, rhs->value, array_type, index, rhs->alignment, &align_rhs); + llvm_value_set_address(&rhs_v, rhs_ptr, array_base_type, align_rhs); + BEValue comp; + llvm_emit_comp(c, &comp, &lhs_v, &rhs_v, BINARYOP_EQ); + llvm_emit_cond_br(c, &comp, comparison, exit); + llvm_emit_block(c, comparison); + + LLVMValueRef new_index = LLVMBuildAdd(c->builder, index, one, "inc"); + llvm_store_raw(c, &index_var, new_index); + llvm_emit_int_comp_raw(c, &comp, type_usize, type_usize, new_index, len_val, BINARYOP_LT); + llvm_emit_cond_br(c, &comp, loop_begin, exit); + llvm_emit_block(c, exit); + LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "array_cmp_phi"); + + LLVMValueRef success = LLVMConstInt(c->bool_type, want_match ? 1 : 0, false); + LLVMValueRef failure = LLVMConstInt(c->bool_type, want_match ? 0 : 1, false); + LLVMValueRef logic_values[3] = { success, failure }; + LLVMBasicBlockRef blocks[3] = { comparison, loop_begin }; + LLVMAddIncoming(phi, logic_values, blocks, 2); + llvm_value_set(be_value, phi, type_bool); } static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op, Type *vector_type) @@ -3322,45 +3407,64 @@ static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) { assert(binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ); - llvm_value_rvalue(c, lhs); - llvm_value_rvalue(c, rhs); - if (type_is_integer_or_bool_kind(lhs->type)) + switch (lhs->type->type_kind) { - llvm_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op); - return; - } - if (type_is_pointer(lhs->type)) - { - llvm_emit_ptr_comparison(c, result, lhs, rhs, binary_op); - return; - } - if (type_is_float(lhs->type)) - { - llvm_emit_float_comp(c, result, lhs, rhs, binary_op, NULL); - return; - } - if (lhs->type->type_kind == TYPE_SUBARRAY) - { - llvm_emit_subarray_comp(c, result, lhs, rhs, binary_op); - return; - } - if (lhs->type->type_kind == TYPE_VECTOR) - { - Type *type = type_vector_type(lhs->type); - if (type_is_float(type)) - { - llvm_emit_float_comp(c, result, lhs, rhs, binary_op, lhs->type); - } - else - { + case TYPE_POISONED: + case TYPE_VOID: + UNREACHABLE; + case TYPE_BOOL: + case ALL_INTS: + llvm_value_rvalue(c, lhs); + llvm_value_rvalue(c, rhs); llvm_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op); - } - return; - } - if (lhs->type->type_kind == TYPE_ARRAY) - { - llvm_emit_array_comp(c, result, lhs, rhs, binary_op); - return; + return; + case ALL_FLOATS: + llvm_emit_float_comp(c, result, lhs, rhs, binary_op, NULL); + return; + case TYPE_POINTER: + llvm_emit_ptr_comparison(c, result, lhs, rhs, binary_op); + return; + case TYPE_ARRAY: + llvm_emit_array_comp(c, result, lhs, rhs, binary_op); + return; + case TYPE_ANY: + case TYPE_ANYERR: + case TYPE_TYPEID: + case TYPE_ENUM: + case TYPE_FAULTTYPE: + case TYPE_TYPEDEF: + case TYPE_DISTINCT: + case TYPE_INFERRED_ARRAY: + case TYPE_UNTYPED_LIST: + case TYPE_OPTIONAL: + case TYPE_OPTIONAL_ANY: + case TYPE_TYPEINFO: + case TYPE_MEMBER: + case TYPE_INFERRED_VECTOR: + UNREACHABLE + case TYPE_FUNC: + break; + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_BITSTRUCT: + case TYPE_SCALED_VECTOR: + case TYPE_FLEXIBLE_ARRAY: + UNREACHABLE + case TYPE_SUBARRAY: + llvm_emit_subarray_comp(c, result, lhs, rhs, binary_op); + return; + case TYPE_VECTOR: + if (type_is_float(type_vector_type(lhs->type))) + { + llvm_emit_float_comp(c, result, lhs, rhs, binary_op, lhs->type); + } + else + { + llvm_value_rvalue(c, lhs); + llvm_value_rvalue(c, rhs); + llvm_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op); + } + return; } TODO // When updated, also update tilde_codegen_expr } @@ -3561,12 +3665,12 @@ void llvm_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs llvm_emit_expr(c, &lhs, exprptr(expr->binary_expr.left)); } // We need the rvalue. - llvm_value_rvalue(c, &lhs); + if (lhs.type->type_kind != TYPE_ARRAY) llvm_value_rvalue(c, &lhs); // Evaluate rhs BEValue rhs; llvm_emit_expr(c, &rhs, exprptr(expr->binary_expr.right)); - llvm_value_rvalue(c, &rhs); + if (rhs.type->type_kind != TYPE_ARRAY) llvm_value_rvalue(c, &rhs); EMIT_LOC(c, expr); // Comparison <=> diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index df4d233ab..e9a6a6a34 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -108,7 +108,8 @@ void gencontext_begin_module(GenContext *c) type->decl->backend_ref = NULL; break; case TYPE_FUNC: - // TODO + REMINDER("Clear func when it has reflection"); + break; default: break; } @@ -124,7 +125,7 @@ void gencontext_begin_module(GenContext *c) if (active_target.debug_info != DEBUG_INFO_NONE) { - if (active_target.arch_os_target == WINDOWS_X64 || active_target.arch_os_target == WINDOWS_X86) + if (active_target.arch_os_target == WINDOWS_X64 || active_target.arch_os_target == WINDOWS_AARCH64) { setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)1 /* pic */, false)); LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorError, "CodeView", strlen("CodeView"), setting); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index ab49076cc..e6702c5b4 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -274,7 +274,7 @@ LLVMTypeRef llvm_func_type(GenContext *context, FunctionPrototype *prototype) { LLVMTypeRef *params = NULL; LLVMTypeRef ret = llvm_update_prototype_abi(context, prototype, ¶ms); - return prototype->llvm_prototype = LLVMFunctionType(ret, params, vec_size(params), prototype->variadic == VARIADIC_RAW); + return LLVMFunctionType(ret, params, vec_size(params), prototype->variadic == VARIADIC_RAW); } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 80fefea99..cd076df56 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1865,7 +1865,11 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) break; case TYPE_ANYERR: if (to->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type); - if (to->type_kind == TYPE_FAULTTYPE) return insert_cast(expr, CAST_EUER, to_type); + if (to->type_kind == TYPE_FAULTTYPE) + { + REMINDER("Improve anyerr -> fault conversion."); + return insert_cast(expr, CAST_EUER, to_type); + } if (type_is_integer(to)) return insert_cast(expr, CAST_EUINT, to_type); break; case ALL_SIGNED_INTS: diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index e38512407..0bcb1db40 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -253,10 +253,8 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl ** if (!max_size) { - REMINDER("Check if this should really be allowed."); - decl->strukt.size = 0; - decl->alignment = 1; - return true; + SEMA_ERROR(decl, "Zero size unions are not allowed."); + return false; } // The actual size might be larger than the max size due to alignment. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 624657ffd..2d534a141 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -5071,8 +5071,16 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, if (!type_is_comparable(max)) { - SEMA_ERROR(expr, "%s does not support comparisons, you need to manually implement a comparison if you need it.", - type_quoted_error_string(left->type)); + if (type_is_user_defined(max->canonical)) + { + SEMA_ERROR(expr, "%s does not support comparisons, you need to manually implement a comparison if you need it.", + type_quoted_error_string(left->type)); + } + else + { + SEMA_ERROR(expr, "%s does not support comparisons.", + type_quoted_error_string(left->type)); + } return false; } if (!is_equality_type_op) diff --git a/src/compiler/target.c b/src/compiler/target.c index 3933521c8..6acd92ff9 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -552,7 +552,6 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { [OPENBSD_X86] = "i386-unknown-openbsd", [NETBSD_X86] = "i386-unknown-netbsd", [MCU_X86] = "i386-pc-elfiamcu", - [WINDOWS_X86] = "i386-pc-win32", [LINUX_X86] = "i386-unknown-linux", [ELF_X86] = "i386-unknown-elf", [MACOS_X64] = "x86_64-apple-darwin", @@ -566,6 +565,7 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { [LINUX_AARCH64] = "aarch64-unknown-linux-gnu", [MACOS_AARCH64] = "aarch64-apple-darwin", [ELF_AARCH64] = "aarch64-unknown-elf", + [WINDOWS_AARCH64] = "aarch64-pc-windows-msvc", [LINUX_RISCV32] = "riscv32-unknown-linux", [ELF_RISCV32] = "riscv32-unknown-elf", [LINUX_RISCV64] = "riscv64-unknown-linux", diff --git a/src/compiler/types.c b/src/compiler/types.c index fa52d9027..ff8b074b5 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -464,6 +464,7 @@ bool type_is_comparable(Type *type) RETRY: switch (type->type_kind) { + case TYPE_INFERRED_VECTOR: case TYPE_INFERRED_ARRAY: case TYPE_POISONED: UNREACHABLE @@ -471,6 +472,10 @@ bool type_is_comparable(Type *type) case TYPE_UNION: case TYPE_STRUCT: case TYPE_BITSTRUCT: + case TYPE_FLEXIBLE_ARRAY: + case TYPE_OPTIONAL: + case TYPE_OPTIONAL_ANY: + case TYPE_MEMBER: return false; case TYPE_TYPEDEF: type = type->canonical; @@ -483,7 +488,20 @@ bool type_is_comparable(Type *type) case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; goto RETRY; - default: + case TYPE_BOOL: + case ALL_INTS: + case ALL_FLOATS: + case TYPE_ANY: + case TYPE_ANYERR: + case TYPE_TYPEID: + case TYPE_POINTER: + case TYPE_ENUM: + case TYPE_FUNC: + case TYPE_FAULTTYPE: + case TYPE_UNTYPED_LIST: + case TYPE_TYPEINFO: + case TYPE_SCALED_VECTOR: + case TYPE_VECTOR: return true; } } diff --git a/src/version.h b/src/version.h index 76e04106d..990ad5b6d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.48" \ No newline at end of file +#define COMPILER_VERSION "0.4.49" \ No newline at end of file diff --git a/test/test_suite/abi/darwin_return_boolarray.c3t b/test/test_suite/abi/darwin_return_boolarray.c3t new file mode 100644 index 000000000..0b6664587 --- /dev/null +++ b/test/test_suite/abi/darwin_return_boolarray.c3t @@ -0,0 +1,17 @@ +// #target: macos-x64 +module test; + +fn bool[2] get() { return { false, false }; } + +/* #expect: test.ll + +define i16 @test_get() #0 { +entry: + %literal = alloca [2 x i8], align 1 + %0 = getelementptr inbounds [2 x i8], ptr %literal, i64 0, i64 0 + store i8 0, ptr %0, align 1 + %1 = getelementptr inbounds [2 x i8], ptr %literal, i64 0, i64 1 + store i8 0, ptr %1, align 1 + %2 = load i16, ptr %literal, align 1 + ret i16 %2 +} \ No newline at end of file diff --git a/test/test_suite/arrays/array_comparison.c3t b/test/test_suite/arrays/array_comparison.c3t new file mode 100644 index 000000000..a2780a060 --- /dev/null +++ b/test/test_suite/arrays/array_comparison.c3t @@ -0,0 +1,390 @@ +// #target: macos-x64 +module test; + +extern fn void get(double[2]*); +extern fn void get2(int[2]*); +extern fn void get3(bool[2]*); + +fn void test() +{ + double[2] a = void; + double[2] b = void; + get(&a); + get(&b); + bool x = a == b; + bool y = a != b; + + int[2] a2 = void; + int[2] b2 = void; + get2(&a2); + get2(&b2); + bool x2 = a2 == b2; + bool y2 = a2 != b2; + + bool[2] a3 = void; + bool[2] b3 = void; + get3(&a3); + get3(&b3); + + bool x3 = a3 == b3; + bool y3 = a3 != b3; + +} + +extern fn void aget(double[200]*); +extern fn void aget2(int[200]*); +extern fn void aget3(bool[200]*); + +fn void test2() +{ + double[200] a = void; + double[200] b = void; + aget(&a); + aget(&b); + bool x = a == b; + bool y = a != b; + + int[200] a2 = void; + int[200] b2 = void; + aget2(&a2); + aget2(&b2); + bool x2 = a2 == b2; + bool y2 = a2 != b2; + + bool[200] a3 = void; + bool[200] b3 = void; + aget3(&a3); + aget3(&b3); + bool x3 = a3 == b3; + bool y3 = a3 != b3; + +} + +/* #expect: test.ll + +define void @test_test() #0 { +entry: + %a = alloca [2 x double], align 16 + %b = alloca [2 x double], align 16 + %x = alloca i8, align 1 + %y = alloca i8, align 1 + %a2 = alloca [2 x i32], align 4 + %b2 = alloca [2 x i32], align 4 + %x2 = alloca i8, align 1 + %y2 = alloca i8, align 1 + %a3 = alloca [2 x i8], align 1 + %b3 = alloca [2 x i8], align 1 + %x3 = alloca i8, align 1 + %y3 = alloca i8, align 1 + call void @get(ptr %a) + call void @get(ptr %b) + %0 = getelementptr inbounds [2 x double], ptr %a, i64 0, i64 0 + %1 = getelementptr inbounds [2 x double], ptr %b, i64 0, i64 0 + %2 = load double, ptr %0, align 8 + %3 = load double, ptr %1, align 8 + %eq = fcmp oeq double %2, %3 + br i1 %eq, label %next_check, label %exit + +next_check: ; preds = %entry + %4 = getelementptr inbounds [2 x double], ptr %a, i64 0, i64 1 + %5 = getelementptr inbounds [2 x double], ptr %b, i64 0, i64 1 + %6 = load double, ptr %4, align 8 + %7 = load double, ptr %5, align 8 + %eq1 = fcmp oeq double %6, %7 + br i1 %eq1, label %match, label %exit + +match: ; preds = %next_check + br label %exit + +exit: ; preds = %match, %next_check, %entry + %array_cmp_phi = phi i1 [ false, %entry ], [ false, %next_check ], [ true, %match ] + %8 = zext i1 %array_cmp_phi to i8 + store i8 %8, ptr %x, align 1 + %9 = getelementptr inbounds [2 x double], ptr %a, i64 0, i64 0 + %10 = getelementptr inbounds [2 x double], ptr %b, i64 0, i64 0 + %11 = load double, ptr %9, align 8 + %12 = load double, ptr %10, align 8 + %eq2 = fcmp oeq double %11, %12 + br i1 %eq2, label %next_check3, label %exit6 + +next_check3: ; preds = %exit + %13 = getelementptr inbounds [2 x double], ptr %a, i64 0, i64 1 + %14 = getelementptr inbounds [2 x double], ptr %b, i64 0, i64 1 + %15 = load double, ptr %13, align 8 + %16 = load double, ptr %14, align 8 + %eq4 = fcmp oeq double %15, %16 + br i1 %eq4, label %match5, label %exit6 + +match5: ; preds = %next_check3 + br label %exit6 + +exit6: ; preds = %match5, %next_check3, %exit + %array_cmp_phi7 = phi i1 [ true, %exit ], [ true, %next_check3 ], [ false, %match5 ] + %17 = zext i1 %array_cmp_phi7 to i8 + store i8 %17, ptr %y, align 1 + call void @get2(ptr %a2) + call void @get2(ptr %b2) + %18 = getelementptr inbounds [2 x i32], ptr %a2, i64 0, i64 0 + %19 = getelementptr inbounds [2 x i32], ptr %b2, i64 0, i64 0 + %20 = load i32, ptr %18, align 4 + %21 = load i32, ptr %19, align 4 + %eq8 = icmp eq i32 %20, %21 + br i1 %eq8, label %next_check9, label %exit12 + +next_check9: ; preds = %exit6 + %22 = getelementptr inbounds [2 x i32], ptr %a2, i64 0, i64 1 + %23 = getelementptr inbounds [2 x i32], ptr %b2, i64 0, i64 1 + %24 = load i32, ptr %22, align 4 + %25 = load i32, ptr %23, align 4 + %eq10 = icmp eq i32 %24, %25 + br i1 %eq10, label %match11, label %exit12 + +match11: ; preds = %next_check9 + br label %exit12 + +exit12: ; preds = %match11, %next_check9, %exit6 + %array_cmp_phi13 = phi i1 [ false, %exit6 ], [ false, %next_check9 ], [ true, %match11 ] + %26 = zext i1 %array_cmp_phi13 to i8 + store i8 %26, ptr %x2, align 1 + %27 = getelementptr inbounds [2 x i32], ptr %a2, i64 0, i64 0 + %28 = getelementptr inbounds [2 x i32], ptr %b2, i64 0, i64 0 + %29 = load i32, ptr %27, align 4 + %30 = load i32, ptr %28, align 4 + %eq14 = icmp eq i32 %29, %30 + br i1 %eq14, label %next_check15, label %exit18 + +next_check15: ; preds = %exit12 + %31 = getelementptr inbounds [2 x i32], ptr %a2, i64 0, i64 1 + %32 = getelementptr inbounds [2 x i32], ptr %b2, i64 0, i64 1 + %33 = load i32, ptr %31, align 4 + %34 = load i32, ptr %32, align 4 + %eq16 = icmp eq i32 %33, %34 + br i1 %eq16, label %match17, label %exit18 + +match17: ; preds = %next_check15 + br label %exit18 + +exit18: ; preds = %match17, %next_check15, %exit12 + %array_cmp_phi19 = phi i1 [ true, %exit12 ], [ true, %next_check15 ], [ false, %match17 ] + %35 = zext i1 %array_cmp_phi19 to i8 + store i8 %35, ptr %y2, align 1 + call void @get3(ptr %a3) + call void @get3(ptr %b3) + %36 = getelementptr inbounds [2 x i8], ptr %a3, i64 0, i64 0 + %37 = getelementptr inbounds [2 x i8], ptr %b3, i64 0, i64 0 + %38 = load i8, ptr %36, align 1 + %39 = trunc i8 %38 to i1 + %40 = load i8, ptr %37, align 1 + %41 = trunc i8 %40 to i1 + %eq20 = icmp eq i1 %39, %41 + br i1 %eq20, label %next_check21, label %exit24 + +next_check21: ; preds = %exit18 + %42 = getelementptr inbounds [2 x i8], ptr %a3, i64 0, i64 1 + %43 = getelementptr inbounds [2 x i8], ptr %b3, i64 0, i64 1 + %44 = load i8, ptr %42, align 1 + %45 = trunc i8 %44 to i1 + %46 = load i8, ptr %43, align 1 + %47 = trunc i8 %46 to i1 + %eq22 = icmp eq i1 %45, %47 + br i1 %eq22, label %match23, label %exit24 + +match23: ; preds = %next_check21 + br label %exit24 + +exit24: ; preds = %match23, %next_check21, %exit18 + %array_cmp_phi25 = phi i1 [ false, %exit18 ], [ false, %next_check21 ], [ true, %match23 ] + %48 = zext i1 %array_cmp_phi25 to i8 + store i8 %48, ptr %x3, align 1 + %49 = getelementptr inbounds [2 x i8], ptr %a3, i64 0, i64 0 + %50 = getelementptr inbounds [2 x i8], ptr %b3, i64 0, i64 0 + %51 = load i8, ptr %49, align 1 + %52 = trunc i8 %51 to i1 + %53 = load i8, ptr %50, align 1 + %54 = trunc i8 %53 to i1 + %eq26 = icmp eq i1 %52, %54 + br i1 %eq26, label %next_check27, label %exit30 + +next_check27: ; preds = %exit24 + %55 = getelementptr inbounds [2 x i8], ptr %a3, i64 0, i64 1 + %56 = getelementptr inbounds [2 x i8], ptr %b3, i64 0, i64 1 + %57 = load i8, ptr %55, align 1 + %58 = trunc i8 %57 to i1 + %59 = load i8, ptr %56, align 1 + %60 = trunc i8 %59 to i1 + %eq28 = icmp eq i1 %58, %60 + br i1 %eq28, label %match29, label %exit30 + +match29: ; preds = %next_check27 + br label %exit30 + +exit30: ; preds = %match29, %next_check27, %exit24 + %array_cmp_phi31 = phi i1 [ true, %exit24 ], [ true, %next_check27 ], [ false, %match29 ] + %61 = zext i1 %array_cmp_phi31 to i8 + store i8 %61, ptr %y3, align 1 + ret void +} +define void @test_test2() #0 { +entry: + %a = alloca [200 x double], align 16 + %b = alloca [200 x double], align 16 + %x = alloca i8, align 1 + %cmp.idx = alloca i64, align 8 + %y = alloca i8, align 1 + %cmp.idx1 = alloca i64, align 8 + %a2 = alloca [200 x i32], align 16 + %b2 = alloca [200 x i32], align 16 + %x2 = alloca i8, align 1 + %cmp.idx9 = alloca i64, align 8 + %y2 = alloca i8, align 1 + %cmp.idx17 = alloca i64, align 8 + %a3 = alloca [200 x i8], align 16 + %b3 = alloca [200 x i8], align 16 + %x3 = alloca i8, align 1 + %cmp.idx25 = alloca i64, align 8 + %y3 = alloca i8, align 1 + %cmp.idx33 = alloca i64, align 8 + call void @aget(ptr %a) + call void @aget(ptr %b) + store i64 0, ptr %cmp.idx, align 8 + br label %array_loop_start + +array_loop_start: ; preds = %array_loop_comparison, %entry + %0 = load i64, ptr %cmp.idx, align 8 + %1 = getelementptr inbounds [200 x double], ptr %a, i64 0, i64 %0 + %2 = getelementptr inbounds [200 x double], ptr %b, i64 0, i64 %0 + %3 = load double, ptr %1, align 8 + %4 = load double, ptr %2, align 8 + %eq = fcmp oeq double %3, %4 + br i1 %eq, label %array_loop_comparison, label %array_cmp_exit + +array_loop_comparison: ; preds = %array_loop_start + %inc = add i64 %0, 1 + store i64 %inc, ptr %cmp.idx, align 8 + %lt = icmp ult i64 %inc, 200 + br i1 %lt, label %array_loop_start, label %array_cmp_exit + +array_cmp_exit: ; preds = %array_loop_comparison, %array_loop_start + %array_cmp_phi = phi i1 [ true, %array_loop_comparison ], [ false, %array_loop_start ] + %5 = zext i1 %array_cmp_phi to i8 + store i8 %5, ptr %x, align 1 + store i64 0, ptr %cmp.idx1, align 8 + br label %array_loop_start2 + +array_loop_start2: ; preds = %array_loop_comparison4, %array_cmp_exit + %6 = load i64, ptr %cmp.idx1, align 8 + %7 = getelementptr inbounds [200 x double], ptr %a, i64 0, i64 %6 + %8 = getelementptr inbounds [200 x double], ptr %b, i64 0, i64 %6 + %9 = load double, ptr %7, align 8 + %10 = load double, ptr %8, align 8 + %eq3 = fcmp oeq double %9, %10 + br i1 %eq3, label %array_loop_comparison4, label %array_cmp_exit7 + +array_loop_comparison4: ; preds = %array_loop_start2 + %inc5 = add i64 %6, 1 + store i64 %inc5, ptr %cmp.idx1, align 8 + %lt6 = icmp ult i64 %inc5, 200 + br i1 %lt6, label %array_loop_start2, label %array_cmp_exit7 + +array_cmp_exit7: ; preds = %array_loop_comparison4, %array_loop_start2 + %array_cmp_phi8 = phi i1 [ false, %array_loop_comparison4 ], [ true, %array_loop_start2 ] + %11 = zext i1 %array_cmp_phi8 to i8 + store i8 %11, ptr %y, align 1 + call void @aget2(ptr %a2) + call void @aget2(ptr %b2) + store i64 0, ptr %cmp.idx9, align 8 + br label %array_loop_start10 + +array_loop_start10: ; preds = %array_loop_comparison12, %array_cmp_exit7 + %12 = load i64, ptr %cmp.idx9, align 8 + %13 = getelementptr inbounds [200 x i32], ptr %a2, i64 0, i64 %12 + %14 = getelementptr inbounds [200 x i32], ptr %b2, i64 0, i64 %12 + %15 = load i32, ptr %13, align 4 + %16 = load i32, ptr %14, align 4 + %eq11 = icmp eq i32 %15, %16 + br i1 %eq11, label %array_loop_comparison12, label %array_cmp_exit15 + +array_loop_comparison12: ; preds = %array_loop_start10 + %inc13 = add i64 %12, 1 + store i64 %inc13, ptr %cmp.idx9, align 8 + %lt14 = icmp ult i64 %inc13, 200 + br i1 %lt14, label %array_loop_start10, label %array_cmp_exit15 + +array_cmp_exit15: ; preds = %array_loop_comparison12, %array_loop_start10 + %array_cmp_phi16 = phi i1 [ true, %array_loop_comparison12 ], [ false, %array_loop_start10 ] + %17 = zext i1 %array_cmp_phi16 to i8 + store i8 %17, ptr %x2, align 1 + store i64 0, ptr %cmp.idx17, align 8 + br label %array_loop_start18 + +array_loop_start18: ; preds = %array_loop_comparison20, %array_cmp_exit15 + %18 = load i64, ptr %cmp.idx17, align 8 + %19 = getelementptr inbounds [200 x i32], ptr %a2, i64 0, i64 %18 + %20 = getelementptr inbounds [200 x i32], ptr %b2, i64 0, i64 %18 + %21 = load i32, ptr %19, align 4 + %22 = load i32, ptr %20, align 4 + %eq19 = icmp eq i32 %21, %22 + br i1 %eq19, label %array_loop_comparison20, label %array_cmp_exit23 + +array_loop_comparison20: ; preds = %array_loop_start18 + %inc21 = add i64 %18, 1 + store i64 %inc21, ptr %cmp.idx17, align 8 + %lt22 = icmp ult i64 %inc21, 200 + br i1 %lt22, label %array_loop_start18, label %array_cmp_exit23 + +array_cmp_exit23: ; preds = %array_loop_comparison20, %array_loop_start18 + %array_cmp_phi24 = phi i1 [ false, %array_loop_comparison20 ], [ true, %array_loop_start18 ] + %23 = zext i1 %array_cmp_phi24 to i8 + store i8 %23, ptr %y2, align 1 + call void @aget3(ptr %a3) + call void @aget3(ptr %b3) + store i64 0, ptr %cmp.idx25, align 8 + br label %array_loop_start26 + +array_loop_start26: ; preds = %array_loop_comparison28, %array_cmp_exit23 + %24 = load i64, ptr %cmp.idx25, align 8 + %25 = getelementptr inbounds [200 x i8], ptr %a3, i64 0, i64 %24 + %26 = getelementptr inbounds [200 x i8], ptr %b3, i64 0, i64 %24 + %27 = load i8, ptr %25, align 1 + %28 = trunc i8 %27 to i1 + %29 = load i8, ptr %26, align 1 + %30 = trunc i8 %29 to i1 + %eq27 = icmp eq i1 %28, %30 + br i1 %eq27, label %array_loop_comparison28, label %array_cmp_exit31 + +array_loop_comparison28: ; preds = %array_loop_start26 + %inc29 = add i64 %24, 1 + store i64 %inc29, ptr %cmp.idx25, align 8 + %lt30 = icmp ult i64 %inc29, 200 + br i1 %lt30, label %array_loop_start26, label %array_cmp_exit31 + +array_cmp_exit31: ; preds = %array_loop_comparison28, %array_loop_start26 + %array_cmp_phi32 = phi i1 [ true, %array_loop_comparison28 ], [ false, %array_loop_start26 ] + %31 = zext i1 %array_cmp_phi32 to i8 + store i8 %31, ptr %x3, align 1 + store i64 0, ptr %cmp.idx33, align 8 + br label %array_loop_start34 + +array_loop_start34: ; preds = %array_loop_comparison36, %array_cmp_exit31 + %32 = load i64, ptr %cmp.idx33, align 8 + %33 = getelementptr inbounds [200 x i8], ptr %a3, i64 0, i64 %32 + %34 = getelementptr inbounds [200 x i8], ptr %b3, i64 0, i64 %32 + %35 = load i8, ptr %33, align 1 + %36 = trunc i8 %35 to i1 + %37 = load i8, ptr %34, align 1 + %38 = trunc i8 %37 to i1 + %eq35 = icmp eq i1 %36, %38 + br i1 %eq35, label %array_loop_comparison36, label %array_cmp_exit39 + +array_loop_comparison36: ; preds = %array_loop_start34 + %inc37 = add i64 %32, 1 + store i64 %inc37, ptr %cmp.idx33, align 8 + %lt38 = icmp ult i64 %inc37, 200 + br i1 %lt38, label %array_loop_start34, label %array_cmp_exit39 + +array_cmp_exit39: ; preds = %array_loop_comparison36, %array_loop_start34 + %array_cmp_phi40 = phi i1 [ false, %array_loop_comparison36 ], [ true, %array_loop_start34 ] + %39 = zext i1 %array_cmp_phi40 to i8 + store i8 %39, ptr %y3, align 1 + ret void +} diff --git a/test/test_suite/struct/flex_array_comparison.c3 b/test/test_suite/struct/flex_array_comparison.c3 new file mode 100644 index 000000000..ebb66a161 --- /dev/null +++ b/test/test_suite/struct/flex_array_comparison.c3 @@ -0,0 +1,15 @@ +module test; + +struct Abc +{ + int x; + int[*] y; +} + + +fn void test() +{ + Abc x; + Abc y; + bool same = x.y == y.y; // #error: does not support comparisons +} \ No newline at end of file diff --git a/test/test_suite/union/union_zero.c3 b/test/test_suite/union/union_zero.c3 new file mode 100644 index 000000000..a56f039de --- /dev/null +++ b/test/test_suite/union/union_zero.c3 @@ -0,0 +1,3 @@ +union Abs // #error: Zero sized unions +{ +} \ No newline at end of file