diff --git a/releasenotes.md b/releasenotes.md index f8d240ea4..f8b2d18ed 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -131,8 +131,10 @@ - Add checks to prevent incorrect alignment on malloc. - Updated clamp. - Added `Clock` and `DateTime`. +- Added posix socket functions. ### Fixes +- Fix to bug when comparing nested arrays. - Fix to bug when a macro is using rethrow. - Fixes bug initializing a const struct with a const struct value. - Fixes bug when `void` is passed to an "any"-vararg. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 3199e49d8..b249b11f6 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3509,13 +3509,25 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l } +INLINE bool should_inline_array_comp(ArraySize len, Type *base_type_lowered) +{ + switch (base_type_lowered->type_kind) + { + case TYPE_ARRAY: + return should_inline_array_comp(base_type_lowered->array.len * len, type_lowering(base_type_lowered->array.base)); + case TYPE_SUBARRAY: + return len <= 4; + default: + return len <= 16; + } +} static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) { 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) + if (should_inline_array_comp(len, array_base_type)) { LLVMBasicBlockRef blocks[17]; LLVMValueRef value_block[17]; @@ -3525,7 +3537,7 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *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; @@ -3539,11 +3551,9 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, 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); + blocks[i] = c->current_block; LLVMBasicBlockRef block = ok_block; - if (i < len - 1) - { - block = blocks[i + 1] = llvm_basic_block_new(c, "next_check"); - } + block = i < len - 1 ? llvm_basic_block_new(c, "next_check") : block; llvm_emit_cond_br(c, &comp, block, exit_block); llvm_emit_block(c, block); } @@ -3560,7 +3570,8 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, 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"); - + LLVMBasicBlockRef comparison_phi; + LLVMBasicBlockRef loop_begin_phi; LLVMValueRef len_val = llvm_const_int(c, type_usz, len); LLVMValueRef one = llvm_const_int(c, type_usz, 1); BEValue index_var; @@ -3581,12 +3592,14 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, 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); + loop_begin_phi = c->current_block; 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_usz, type_usz, new_index, len_val, BINARYOP_LT); + comparison_phi = c->current_block; 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"); @@ -3594,7 +3607,7 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, 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 }; + LLVMBasicBlockRef blocks[3] = { comparison_phi, loop_begin_phi }; LLVMAddIncoming(phi, logic_values, blocks, 2); llvm_value_set(be_value, phi, type_bool); } diff --git a/src/version.h b/src/version.h index b135b24d0..f0497df4c 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.553" \ No newline at end of file +#define COMPILER_VERSION "0.4.554" \ No newline at end of file diff --git a/test/test_suite/arrays/array_comparison_2.c3t b/test/test_suite/arrays/array_comparison_2.c3t new file mode 100644 index 000000000..60a1faa9a --- /dev/null +++ b/test/test_suite/arrays/array_comparison_2.c3t @@ -0,0 +1,156 @@ +// #target: macos-x64 +module test; + +fn void main() +{ + int[2][2] x; + int[2][2] y; + bool match = x == y; + int[2][2][8] z; + int[2][2][8] w; + match = z == w; +} + +/* #expect: test.ll + +define void @test.main() #0 { +entry: + %x = alloca [2 x [2 x i32]], align 16 + %y = alloca [2 x [2 x i32]], align 16 + %match = alloca i8, align 1 + %z = alloca [8 x [2 x [2 x i32]]], align 16 + %w = alloca [8 x [2 x [2 x i32]]], align 16 + %cmp.idx = alloca i64, align 8 + %0 = getelementptr inbounds [2 x [2 x i32]], ptr %x, i64 0, i64 0 + %1 = getelementptr inbounds [2 x i32], ptr %0, i64 0, i64 0 + store i32 0, ptr %1, align 4 + %2 = getelementptr inbounds [2 x i32], ptr %0, i64 0, i64 1 + store i32 0, ptr %2, align 4 + %3 = getelementptr inbounds [2 x [2 x i32]], ptr %x, i64 0, i64 1 + %4 = getelementptr inbounds [2 x i32], ptr %3, i64 0, i64 0 + store i32 0, ptr %4, align 4 + %5 = getelementptr inbounds [2 x i32], ptr %3, i64 0, i64 1 + store i32 0, ptr %5, align 4 + %6 = getelementptr inbounds [2 x [2 x i32]], ptr %y, i64 0, i64 0 + %7 = getelementptr inbounds [2 x i32], ptr %6, i64 0, i64 0 + store i32 0, ptr %7, align 4 + %8 = getelementptr inbounds [2 x i32], ptr %6, i64 0, i64 1 + store i32 0, ptr %8, align 4 + %9 = getelementptr inbounds [2 x [2 x i32]], ptr %y, i64 0, i64 1 + %10 = getelementptr inbounds [2 x i32], ptr %9, i64 0, i64 0 + store i32 0, ptr %10, align 4 + %11 = getelementptr inbounds [2 x i32], ptr %9, i64 0, i64 1 + store i32 0, ptr %11, align 4 + %12 = getelementptr inbounds [2 x [2 x i32]], ptr %x, i64 0, i64 0 + %13 = getelementptr inbounds [2 x [2 x i32]], ptr %y, i64 0, i64 0 + %14 = getelementptr inbounds [2 x i32], ptr %12, i64 0, i64 0 + %15 = getelementptr inbounds [2 x i32], ptr %13, i64 0, i64 0 + %16 = load i32, ptr %14, align 4 + %17 = load i32, ptr %15, align 4 + %eq = icmp eq i32 %16, %17 + br i1 %eq, label %next_check, label %exit +next_check: ; preds = %entry + %18 = getelementptr inbounds [2 x i32], ptr %12, i64 0, i64 1 + %19 = getelementptr inbounds [2 x i32], ptr %13, i64 0, i64 1 + %20 = load i32, ptr %18, align 4 + %21 = load i32, ptr %19, align 4 + %eq1 = icmp eq i32 %20, %21 + br i1 %eq1, label %match2, label %exit +match2: ; preds = %next_check + br label %exit +exit: ; preds = %match2, %next_check, %entry + %array_cmp_phi = phi i1 [ false, %entry ], [ false, %next_check ], [ true, %match2 ] + br i1 %array_cmp_phi, label %next_check3, label %exit11 +next_check3: ; preds = %exit + %22 = getelementptr inbounds [2 x [2 x i32]], ptr %x, i64 0, i64 1 + %23 = getelementptr inbounds [2 x [2 x i32]], ptr %y, i64 0, i64 1 + %24 = getelementptr inbounds [2 x i32], ptr %22, i64 0, i64 0 + %25 = getelementptr inbounds [2 x i32], ptr %23, i64 0, i64 0 + %26 = load i32, ptr %24, align 4 + %27 = load i32, ptr %25, align 4 + %eq4 = icmp eq i32 %26, %27 + br i1 %eq4, label %next_check5, label %exit8 +next_check5: ; preds = %next_check3 + %28 = getelementptr inbounds [2 x i32], ptr %22, i64 0, i64 1 + %29 = getelementptr inbounds [2 x i32], ptr %23, i64 0, i64 1 + %30 = load i32, ptr %28, align 4 + %31 = load i32, ptr %29, align 4 + %eq6 = icmp eq i32 %30, %31 + br i1 %eq6, label %match7, label %exit8 +match7: ; preds = %next_check5 + br label %exit8 +exit8: ; preds = %match7, %next_check5, %next_check3 + %array_cmp_phi9 = phi i1 [ false, %next_check3 ], [ false, %next_check5 ], [ true, %match7 ] + br i1 %array_cmp_phi9, label %match10, label %exit11 +match10: ; preds = %exit8 + br label %exit11 +exit11: ; preds = %match10, %exit8, %exit + %array_cmp_phi12 = phi i1 [ false, %exit ], [ false, %exit8 ], [ true, %match10 ] + %32 = zext i1 %array_cmp_phi12 to i8 + store i8 %32, ptr %match, align 1 + call void @llvm.memset.p0.i64(ptr align 16 %z, i8 0, i64 128, i1 false) + call void @llvm.memset.p0.i64(ptr align 16 %w, i8 0, i64 128, i1 false) + store i64 0, ptr %cmp.idx, align 8 + br label %array_loop_start +array_loop_start: ; preds = %array_loop_comparison, %exit11 + %33 = load i64, ptr %cmp.idx, align 8 + %34 = getelementptr inbounds [8 x [2 x [2 x i32]]], ptr %z, i64 0, i64 %33 + %35 = getelementptr inbounds [8 x [2 x [2 x i32]]], ptr %w, i64 0, i64 %33 + %36 = getelementptr inbounds [2 x [2 x i32]], ptr %34, i64 0, i64 0 + %37 = getelementptr inbounds [2 x [2 x i32]], ptr %35, i64 0, i64 0 + %38 = getelementptr inbounds [2 x i32], ptr %36, i64 0, i64 0 + %39 = getelementptr inbounds [2 x i32], ptr %37, i64 0, i64 0 + %40 = load i32, ptr %38, align 4 + %41 = load i32, ptr %39, align 4 + %eq13 = icmp eq i32 %40, %41 + br i1 %eq13, label %next_check14, label %exit17 +next_check14: ; preds = %array_loop_start + %42 = getelementptr inbounds [2 x i32], ptr %36, i64 0, i64 1 + %43 = getelementptr inbounds [2 x i32], ptr %37, i64 0, i64 1 + %44 = load i32, ptr %42, align 4 + %45 = load i32, ptr %43, align 4 + %eq15 = icmp eq i32 %44, %45 + br i1 %eq15, label %match16, label %exit17 +match16: ; preds = %next_check14 + br label %exit17 +exit17: ; preds = %match16, %next_check14, %array_loop_start + %array_cmp_phi18 = phi i1 [ false, %array_loop_start ], [ false, %next_check14 ], [ true, %match16 ] + br i1 %array_cmp_phi18, label %next_check19, label %exit27 +next_check19: ; preds = %exit17 + %46 = getelementptr inbounds [2 x [2 x i32]], ptr %34, i64 0, i64 1 + %47 = getelementptr inbounds [2 x [2 x i32]], ptr %35, i64 0, i64 1 + %48 = getelementptr inbounds [2 x i32], ptr %46, i64 0, i64 0 + %49 = getelementptr inbounds [2 x i32], ptr %47, i64 0, i64 0 + %50 = load i32, ptr %48, align 4 + %51 = load i32, ptr %49, align 4 + %eq20 = icmp eq i32 %50, %51 + br i1 %eq20, label %next_check21, label %exit24 +next_check21: ; preds = %next_check19 + %52 = getelementptr inbounds [2 x i32], ptr %46, i64 0, i64 1 + %53 = getelementptr inbounds [2 x i32], ptr %47, i64 0, i64 1 + %54 = load i32, ptr %52, align 4 + %55 = load i32, ptr %53, align 4 + %eq22 = icmp eq i32 %54, %55 + br i1 %eq22, label %match23, label %exit24 +match23: ; preds = %next_check21 + br label %exit24 +exit24: ; preds = %match23, %next_check21, %next_check19 + %array_cmp_phi25 = phi i1 [ false, %next_check19 ], [ false, %next_check21 ], [ true, %match23 ] + br i1 %array_cmp_phi25, label %match26, label %exit27 +match26: ; preds = %exit24 + br label %exit27 +exit27: ; preds = %match26, %exit24, %exit17 + %array_cmp_phi28 = phi i1 [ false, %exit17 ], [ false, %exit24 ], [ true, %match26 ] + br i1 %array_cmp_phi28, label %array_loop_comparison, label %array_cmp_exit +array_loop_comparison: ; preds = %exit27 + %inc = add i64 %33, 1 + store i64 %inc, ptr %cmp.idx, align 8 + %lt = icmp ult i64 %inc, 8 + br i1 %lt, label %array_loop_start, label %array_cmp_exit +array_cmp_exit: ; preds = %array_loop_comparison, %exit27 + %array_cmp_phi29 = phi i1 [ true, %array_loop_comparison ], [ false, %exit27 ] + %56 = zext i1 %array_cmp_phi29 to i8 + store i8 %56, ptr %match, align 1 + ret void +} +