diff --git a/lib/std/io_printf.c3 b/lib/std/io_printf.c3 index cddd34dba..918cb1e81 100644 --- a/lib/std/io_printf.c3 +++ b/lib/std/io_printf.c3 @@ -76,7 +76,7 @@ private fn void! out_str(PrintParam* param, variant arg) if (inner.kind == TypeKind.ARRAY && inner.inner == char.typeid) { char *ptr = *(char**)arg.ptr; - return out_substr(param, ptr[0..inner.len - 1]); + return out_substr(param, ptr[:inner.len]); } return ntoa_variant(param, arg, 16); case SIGNED_INT: @@ -272,7 +272,7 @@ private fn void! ntoa_format(PrintParam* param, char[] buf, usize len, bool nega buf[len++] = ' '; } if (!len) return; - return param.out_reverse(buf[0..len - 1]); + return param.out_reverse(buf[:len]); } $if (env::I128_SUPPORT): @@ -309,7 +309,7 @@ private fn void! ntoa(PrintParam* param, NtoaType value, bool negative, uint bas } while (value); } - return ntoa_format(param, buf[..PRINTF_NTOA_BUFFER_SIZE - 1], len, negative, base); + return ntoa_format(param, buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base); } @@ -449,7 +449,7 @@ private fn void! ftoa(PrintParam* param, FloatType value) if (len >= PRINTF_FTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!; buf[len++] = next; } - return param.out_reverse(buf[..len-1]); + return param.out_reverse(buf[:len]); } union ConvUnion diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 273420200..758f087a8 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -708,6 +708,7 @@ typedef struct { bool start_from_back : 1; bool end_from_back : 1; + bool is_lenrange : 1; ExprId expr; ExprId start; ExprId end; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index db29c8179..cb11dab1e 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2265,7 +2265,7 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type } } -static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_ref, BEValue *start_ref, BEValue *end_ref) +static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_ref, BEValue *start_ref, BEValue *end_ref, bool *is_exclusive) { assert(slice->expr_kind == EXPR_SLICE); @@ -2351,7 +2351,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r Type *end_type; BEValue end_index; - + bool is_len_range = *is_exclusive = slice->slice_expr.is_lenrange; if (end) { // Get the index. @@ -2365,9 +2365,13 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r end_index.value = llvm_emit_sub_int(c, end_type, len.value, end_index.value, slice->span); llvm_value_rvalue(c, &end_index); } + if (is_len_range) + { + end_index.value = llvm_emit_add_int(c, end_type, start_index.value, end_index.value, slice->span); + } // This will trap any bad negative index, so we're fine. - if (active_target.feature.safe_mode) + if (active_target.feature.safe_mode && !is_len_range) { BEValue excess; llvm_emit_int_comparison(c, &excess, &start_index, &end_index, BINARYOP_GT); @@ -2375,7 +2379,6 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r if (len.value) { - llvm_emit_int_comparison(c, &excess, &len, &end_index, BINARYOP_LT); llvm_emit_panic_if_true(c, &excess, "Size exceeds index", slice->span); } @@ -2384,9 +2387,10 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r else { assert(len.value && "Pointer should never end up here."); - // Otherwise everything is fine and dandy. Our len - 1 is our end index. - end_index.value = LLVMBuildSub(c->builder, len.value, LLVMConstInt(LLVMTypeOf(len.value), 1, false), ""); + end_index.value = len.value; end_type = type_usize; + // Use "len-range" when implicit, this avoids len - 1 here. + *is_exclusive = true; } llvm_value_set(end_ref, end_index.value, end_type); @@ -2400,13 +2404,22 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) BEValue parent; BEValue start; BEValue end; - llvm_emit_slice_values(c, expr, &parent, &start, &end); + bool is_exclusive; + llvm_emit_slice_values(c, expr, &parent, &start, &end, &is_exclusive); llvm_value_rvalue(c, &start); llvm_value_rvalue(c, &end); // Calculate the size - LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end.value, llvm_const_int(c, start.type, 1), ""), start.value, "size"); + LLVMValueRef size; + if (is_exclusive) + { + size = LLVMBuildSub(c->builder, end.value, start.value, "size"); + } + else + { + size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end.value, llvm_const_int(c, start.type, 1), ""), start.value, "size"); + } LLVMValueRef start_pointer; Type *type = type_lowering(parent.type); switch (type->type_kind) @@ -2452,7 +2465,8 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) BEValue start; BEValue end; // Use general function to get all the values we need (a lot!) - llvm_emit_slice_values(c, exprptr(expr->slice_assign_expr.left), &parent, &start, &end); + bool is_exclusive; + llvm_emit_slice_values(c, exprptr(expr->slice_assign_expr.left), &parent, &start, &end, &is_exclusive); llvm_value_rvalue(c, &start); llvm_value_rvalue(c, &end); @@ -2468,6 +2482,11 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) assert(start_val <= INT64_MAX); assert(end_val <= INT64_MAX); if (start_val > end_val) return; + if (is_exclusive) + { + if (start_val == end_val) return; + end_val--; + } if (end_val - start_val < SLICE_MAX_UNROLL) { BEValue addr; @@ -2503,7 +2522,8 @@ static void llvm_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) // Check if we're not at the end. BEValue value; - llvm_emit_int_comp(c, &value, start.type, end.type, offset, end.value, BINARYOP_LE); + BinaryOp op = is_exclusive ? BINARYOP_LT : BINARYOP_LE; + llvm_emit_int_comp(c, &value, start.type, end.type, offset, end.value, op); // If jump to the assign block if we're not at the end index. EMIT_LOC(c, expr); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 2742c632c..8ff8f3429 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -827,14 +827,16 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As llvm_value_rvalue(c, &be_value); case_value = be_value.value; LLVMAddCase(switch_stmt, case_value, block); - Expr *to = case_stmt->case_stmt.to_expr; - if (to) + Expr *to_expr =case_stmt->case_stmt.to_expr; + if (to_expr) { BEValue to_value; - llvm_emit_expr(c, &to_value, case_stmt->case_stmt.to_expr); - assert(LLVMIsAConstant(to_value.value)); + llvm_emit_expr(c, &to_value, to_expr); + llvm_value_rvalue(c, &to_value); + LLVMValueRef to = to_value.value; + assert(LLVMIsAConstant(to)); LLVMValueRef one = llvm_const_int(c, to_value.type, 1); - while (LLVMConstIntGetZExtValue(LLVMConstICmp(LLVMIntEQ, to_value.value, case_value)) != 1) + while (LLVMConstIntGetZExtValue(LLVMConstICmp(LLVMIntEQ, to, case_value)) != 1) { case_value = LLVMConstAdd(case_value, one); LLVMAddCase(switch_stmt, case_value, block); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index dbdafafea..eed2fb6c6 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -752,7 +752,7 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) Expr *end = NULL; // Not range with missing entry - if (!tok_is(c, TOKEN_DOTDOT)) + if (!tok_is(c, TOKEN_DOTDOT) && !tok_is(c, TOKEN_COLON)) { // Might be ^ prefix from_back = try_consume(c, TOKEN_BIT_XOR); @@ -765,7 +765,8 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) index->resolve_status = RESOLVE_DONE; expr_const_set_int(&index->const_expr, 0, type_uint->type_kind); } - if (try_consume(c, TOKEN_DOTDOT)) + bool is_len_range = try_consume(c, TOKEN_COLON); + if (is_len_range || try_consume(c, TOKEN_DOTDOT)) { is_range = true; if (!tok_is(c, TOKEN_RBRACKET)) @@ -785,6 +786,7 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) subs_expr->slice_expr.start_from_back = from_back; subs_expr->slice_expr.end = end ? exprid(end) : 0; subs_expr->slice_expr.end_from_back = end_from_back; + subs_expr->slice_expr.is_lenrange = is_len_range; } else { diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 33eaa10dd..57a1afba1 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -296,9 +296,21 @@ static inline Ast* parse_switch_stmt(ParseContext *c) Ast *switch_ast = new_ast(AST_SWITCH_STMT, c->span); advance_and_verify(c, TOKEN_SWITCH); ASSIGN_DECL_OR_RET(switch_ast->switch_stmt.flow.label, parse_optional_label(c, switch_ast), poisoned_ast); - CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast); - CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); + if (!try_consume(c, TOKEN_LPAREN)) + { + Expr *cond = expr_new(EXPR_COND, switch_ast->span); + Expr *expr = expr_new(EXPR_CONST, switch_ast->span); + expr_const_set_bool(&expr->const_expr, true); + expr->resolve_status = RESOLVE_DONE; + expr->type = type_bool; + vec_add(cond->cond_expr, expr); + switch_ast->switch_stmt.cond = exprid(cond); + } + else + { + ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast); + CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); + } if (!parse_switch_body(c, &switch_ast->switch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT)) return poisoned_ast; return switch_ast; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 5b4062d55..20d0eaa0e 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2479,6 +2479,64 @@ static void sema_deref_array_pointers(Expr *expr) } } +static bool expr_check_len_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end) +{ + assert(type == type->canonical); + if (len_expr->expr_kind != EXPR_CONST) return true; + + Int const_len = len_expr->const_expr.ixx; + if (!int_fits(const_len, TYPE_I64)) + { + SEMA_ERROR(len_expr, "The length cannot be stored in a 64-signed integer, which isn't supported."); + return false; + } + if (int_is_neg(const_len)) + { + SEMA_ERROR(len_expr, "The length may not be negative."); + return false; + } + MemberIndex len_val = (MemberIndex)const_len.i.low; + switch (type->type_kind) + { + case TYPE_POINTER: + case TYPE_FLEXIBLE_ARRAY: + assert(!from_end); + FALLTHROUGH; + case TYPE_SUBARRAY: + return true; + case TYPE_ARRAY: + case TYPE_VECTOR: + { + MemberIndex len = (MemberIndex)type->array.len; + bool is_vector = type->type_kind == TYPE_VECTOR; + if (from_end) + { + if (len_val > len) + { + SEMA_ERROR(len_expr, "This would result in a negative length."); + return false; + } + len_expr->const_expr.ixx.i.low = len - len_val; + *remove_from_end = true; + return true; + } + // Checking end can only be done for arrays and vectors. + if (len_val > len) + { + SEMA_ERROR(len_expr, + is_vector ? "Length out of bounds, was %lld, exceeding vector length %lld." + : "Array length out of bounds, was %lld, exceeding array length %lld.", + (long long)len_val, (long long)len); + return false; + } + return true; + } + default: + UNREACHABLE + } + UNREACHABLE +} + static bool expr_check_index_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end) { assert(type == type->canonical); @@ -2799,6 +2857,11 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) // Fix index sizes if (!expr_cast_to_index(start)) return false; if (end && !expr_cast_to_index(end)) return false; + if (end && end->type != start->type) + { + Type *common = type_find_max_type(start->type, end->type); + if (!common || !cast_implicit(start, common) || !cast_implicit(end, common)) return false; + } // Check range if (type->type_kind == TYPE_POINTER) @@ -2819,30 +2882,27 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) return false; } } + bool is_lenrange = expr->slice_expr.is_lenrange; bool remove_from_end = false; if (!expr_check_index_in_range(context, type, start, false, expr->slice_expr.start_from_back, &remove_from_end)) return false; if (remove_from_end) expr->slice_expr.start_from_back = false; remove_from_end = false; - if (end && !expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back, &remove_from_end)) return false; + if (end) + { + if (is_lenrange) + { + if (!expr_check_len_in_range(context, type, end, expr->slice_expr.end_from_back, &remove_from_end)) return false; + } + else + { + if (!expr_check_index_in_range(context, type, end, true, expr->slice_expr.end_from_back, &remove_from_end)) return false; + } + } if (remove_from_end) expr->slice_expr.end_from_back = false; if (start && end && start->expr_kind == EXPR_CONST && end->expr_kind == EXPR_CONST) { - if (type->type_kind == TYPE_ARRAY) - { - Int128 len = { 0, type->array.len }; - if (expr->slice_expr.start_from_back) - { - start->const_expr.ixx.i = i128_sub(len, start->const_expr.ixx.i); - expr->slice_expr.start_from_back = false; - } - if (expr->slice_expr.end_from_back) - { - end->const_expr.ixx.i = i128_sub(len, end->const_expr.ixx.i); - expr->slice_expr.end_from_back = false; - } - } - if (expr->slice_expr.start_from_back && expr->slice_expr.end_from_back) + if (!is_lenrange && expr->slice_expr.start_from_back && expr->slice_expr.end_from_back) { if (expr_const_compare(&start->const_expr, &end->const_expr, BINARYOP_LT)) { @@ -2850,7 +2910,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) return false; } } - else if (!expr->slice_expr.start_from_back && !expr->slice_expr.end_from_back) + else if (!is_lenrange && !expr->slice_expr.start_from_back && !expr->slice_expr.end_from_back) { if (expr_const_compare(&start->const_expr, &end->const_expr, BINARYOP_GT)) { @@ -2858,6 +2918,17 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) return false; } } + // If both are + if (type->type_kind == TYPE_ARRAY || type->type_kind == TYPE_VECTOR) + { + assert(!expr->slice_expr.start_from_back); + assert(!expr->slice_expr.end_from_back); + if (!is_lenrange) + { + end->const_expr.ixx = int_sub(int_add64(end->const_expr.ixx, 1), start->const_expr.ixx); + is_lenrange = expr->slice_expr.is_lenrange = true; + } + } } diff --git a/src/version.h b/src/version.h index e5586af61..ce0eaa6a5 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.2.15" \ No newline at end of file +#define COMPILER_VERSION "0.2.16" \ No newline at end of file diff --git a/test/test_suite/slices/slice_assign.c3t b/test/test_suite/slices/slice_assign.c3t index f6a70acba..665f0d5f3 100644 --- a/test/test_suite/slices/slice_assign.c3t +++ b/test/test_suite/slices/slice_assign.c3t @@ -18,10 +18,6 @@ fn void main() /* #expect: test.ll -@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 - -declare void @printf(i8*, ...) #0 - define void @test.main() #0 { entry: %x = alloca [8 x i32], align 16 @@ -45,12 +41,10 @@ entry: store i32 52, i32* %7, align 4 store i64 0, i64* %anon, align 8 br label %loop.cond - loop.cond: ; preds = %loop.body, %entry %8 = load i64, i64* %anon, align 8 %gt = icmp ugt i64 8, %8 br i1 %gt, label %loop.body, label %loop.exit - loop.body: ; preds = %loop.cond %9 = load i64, i64* %anon, align 8 %10 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %9 @@ -62,27 +56,18 @@ loop.body: ; preds = %loop.cond %add = add i64 %13, 1 store i64 %add, i64* %anon, align 8 br label %loop.cond - loop.exit: ; preds = %loop.cond br label %cond - cond: ; preds = %assign, %loop.exit %14 = phi i64 [ 0, %loop.exit ], [ %add1, %assign ] - %le = icmp sle i64 %14, 7 - br i1 %le, label %assign, label %exit - + %lt = icmp slt i64 %14, 8 + br i1 %lt, label %assign, label %exit assign: ; preds = %cond %15 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %14 store i32 123, i32* %15, align 4 %add1 = add i64 %14, 1 br label %cond - exit: ; preds = %cond ret void } -define i32 @main(i32 %0, i8** %1) #0 { -entry: - call void @test.main() - ret i32 0 -} diff --git a/test/test_suite/statements/various_switching.c3t b/test/test_suite/statements/various_switching.c3t index 4378e0e54..b662847ac 100644 --- a/test/test_suite/statements/various_switching.c3t +++ b/test/test_suite/statements/various_switching.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 module mymodule; extern fn void printf(char *, ...); @@ -49,9 +50,195 @@ fn void test() default: printf("None of the above\n"); } + switch + { + case a < 0: + printf("A negative\n"); + case a == 1: + printf("A is 1\n"); + default: + printf("Unexpected a\n"); + } } fn void main() { test(); printf("Hello!\n"); } + +/* #expect: mymodule.ll + +define void @mymodule.test() #0 { +entry: + %x = alloca i32, align 4 + %x.f = alloca i64, align 8 + %z = alloca i64, align 8 + %err = alloca i64, align 8 + %switch = alloca i64, align 8 + %switch4 = alloca i64, align 8 + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %zy = alloca i32, align 4 + %switch17 = alloca i32, align 4 + %switch27 = alloca i8, align 1 + store i64 ptrtoint (i8* @mymodule.ByeErr.BAR to i64), i64* %x.f, align 8 + store i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), i64* %z, align 8 + br label %testblock + +testblock: ; preds = %entry + %0 = load i64, i64* %x.f, align 8 + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after_check, label %error + +error: ; preds = %testblock + store i64 %0, i64* %err, align 8 + br label %end_block + +after_check: ; preds = %testblock + store i64 0, i64* %err, align 8 + br label %end_block + +end_block: ; preds = %after_check, %error + %1 = load i64, i64* %err, align 8 + %neq = icmp ne i64 %1, 0 + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + store i64 %1, i64* %switch, align 8 + br label %switch.entry + +switch.entry: ; preds = %if.then + %2 = load i64, i64* %switch, align 8 + %eq = icmp eq i64 ptrtoint (i8* @mymodule.HelloErr.FOO to i64), %2 + br i1 %eq, label %switch.case, label %next_if + +switch.case: ; preds = %switch.entry + call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0)) + br label %switch.exit + +next_if: ; preds = %switch.entry + %eq1 = icmp eq i64 ptrtoint (i8* @mymodule.ByeErr.BAR to i64), %2 + br i1 %eq1, label %switch.case2, label %next_if3 + +switch.case2: ; preds = %next_if + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0)) + br label %switch.exit + +next_if3: ; preds = %next_if + br label %switch.default + +switch.default: ; preds = %next_if3 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.2, i32 0, i32 0)) + br label %switch.exit + +switch.exit: ; preds = %switch.default, %switch.case2, %switch.case + br label %if.exit + +if.exit: ; preds = %switch.exit, %end_block + %3 = load i64, i64* %z, align 8 + store i64 %3, i64* %switch4, align 8 + br label %switch.entry5 + +switch.entry5: ; preds = %if.exit + %4 = load i64, i64* %switch4, align 8 + %eq6 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.int to i64), %4 + br i1 %eq6, label %switch.case7, label %next_if8 + +switch.case7: ; preds = %switch.entry5 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0)) + br label %switch.exit16 + +next_if8: ; preds = %switch.entry5 + %eq9 = icmp eq i64 ptrtoint ({ i8 }* @.typeid.bool to i64), %4 + br i1 %eq9, label %switch.case10, label %next_if11 + +switch.case10: ; preds = %next_if8 + br label %switch.case13 + +next_if11: ; preds = %next_if8 + %eq12 = icmp eq i64 ptrtoint ({ i8, i16 }* @.typeid.double to i64), %4 + br i1 %eq12, label %switch.case13, label %next_if14 + +switch.case13: ; preds = %next_if11, %switch.case10 + br label %switch.default15 + +next_if14: ; preds = %next_if11 + br label %switch.default15 + +switch.default15: ; preds = %next_if14, %switch.case13 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.4, i32 0, i32 0)) + br label %switch.exit16 + +switch.exit16: ; preds = %switch.default15, %switch.case7 + store i32 1, i32* %a, align 4 + store i32 2, i32* %b, align 4 + %5 = load i32, i32* %b, align 4 + %6 = load i32, i32* %a, align 4 + %add = add i32 %5, %6 + store i32 %add, i32* %zy, align 4 + %7 = load i32, i32* %zy, align 4 + store i32 %7, i32* %switch17, align 4 + br label %switch.entry18 + +switch.entry18: ; preds = %switch.exit16 + %8 = load i32, i32* %switch17, align 4 + %9 = load i32, i32* %a, align 4 + %eq19 = icmp eq i32 %9, %8 + br i1 %eq19, label %switch.case20, label %next_if21 + +switch.case20: ; preds = %switch.entry18 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0)) + br label %switch.exit26 + +next_if21: ; preds = %switch.entry18 + %10 = load i32, i32* %b, align 4 + %eq22 = icmp eq i32 %10, %8 + br i1 %eq22, label %switch.case23, label %next_if24 + +switch.case23: ; preds = %next_if21 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.6, i32 0, i32 0)) + br label %switch.exit26 + +next_if24: ; preds = %next_if21 + br label %switch.default25 + +switch.default25: ; preds = %next_if24 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.7, i32 0, i32 0)) + br label %switch.exit26 + +switch.exit26: ; preds = %switch.default25, %switch.case23, %switch.case20 + store i8 1, i8* %switch27, align 1 + br label %switch.entry28 + +switch.entry28: ; preds = %switch.exit26 + %11 = load i8, i8* %switch27, align 1 + %12 = trunc i8 %11 to i1 + %13 = load i32, i32* %a, align 4 + %lt = icmp slt i32 %13, 0 + %eq29 = icmp eq i1 %lt, %12 + br i1 %eq29, label %switch.case30, label %next_if31 + +switch.case30: ; preds = %switch.entry28 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.8, i32 0, i32 0)) + br label %switch.exit37 + +next_if31: ; preds = %switch.entry28 + %14 = load i32, i32* %a, align 4 + %eq32 = icmp eq i32 %14, 1 + %eq33 = icmp eq i1 %eq32, %12 + br i1 %eq33, label %switch.case34, label %next_if35 + +switch.case34: ; preds = %next_if31 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.9, i32 0, i32 0)) + br label %switch.exit37 + +next_if35: ; preds = %next_if31 + br label %switch.default36 + +switch.default36: ; preds = %next_if35 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.10, i32 0, i32 0)) + br label %switch.exit37 + +switch.exit37: ; preds = %switch.default36, %switch.case34, %switch.case30 + ret void +} \ No newline at end of file diff --git a/test/test_suite2/slices/slice_assign.c3t b/test/test_suite2/slices/slice_assign.c3t index 913087c15..334be2059 100644 --- a/test/test_suite2/slices/slice_assign.c3t +++ b/test/test_suite2/slices/slice_assign.c3t @@ -23,7 +23,6 @@ fn void main() ; Function Attrs: nounwind declare void @printf(ptr, ...) #0 -; Function Attrs: nounwind define void @test.main() #0 { entry: %x = alloca [8 x i32], align 16 @@ -69,8 +68,8 @@ loop.exit: ; preds = %loop.cond cond: ; preds = %assign, %loop.exit %13 = phi i64 [ 0, %loop.exit ], [ %add1, %assign ] - %le = icmp sle i64 %13, 7 - br i1 %le, label %assign, label %exit + %lt = icmp slt i64 %13, 8 + br i1 %lt, label %assign, label %exit assign: ; preds = %cond %14 = getelementptr inbounds [8 x i32], ptr %x, i64 0, i64 %13 diff --git a/test/test_suite2/statements/various_switching.c3t b/test/test_suite2/statements/various_switching.c3t index 4378e0e54..f6ceb8fe4 100644 --- a/test/test_suite2/statements/various_switching.c3t +++ b/test/test_suite2/statements/various_switching.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 module mymodule; extern fn void printf(char *, ...); @@ -49,9 +50,195 @@ fn void test() default: printf("None of the above\n"); } + switch + { + case a < 0: + printf("A negative\n"); + case a == 1: + printf("A is 1\n"); + default: + printf("Unexpected a\n"); + } } fn void main() { test(); printf("Hello!\n"); } + +/* #expect: mymodule.ll + +define void @mymodule.test() #0 { +entry: + %x = alloca i32, align 4 + %x.f = alloca i64, align 8 + %z = alloca i64, align 8 + %err = alloca i64, align 8 + %switch = alloca i64, align 8 + %switch4 = alloca i64, align 8 + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %zy = alloca i32, align 4 + %switch17 = alloca i32, align 4 + %switch27 = alloca i8, align 1 + store i64 ptrtoint (ptr @mymodule.ByeErr.BAR to i64), ptr %x.f, align 8 + store i64 ptrtoint (ptr @.typeid.int to i64), ptr %z, align 8 + br label %testblock + +testblock: ; preds = %entry + %0 = load i64, ptr %x.f, align 8 + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after_check, label %error + +error: ; preds = %testblock + store i64 %0, ptr %err, align 8 + br label %end_block + +after_check: ; preds = %testblock + store i64 0, ptr %err, align 8 + br label %end_block + +end_block: ; preds = %after_check, %error + %1 = load i64, ptr %err, align 8 + %neq = icmp ne i64 %1, 0 + br i1 %neq, label %if.then, label %if.exit + +if.then: ; preds = %end_block + store i64 %1, ptr %switch, align 8 + br label %switch.entry + +switch.entry: ; preds = %if.then + %2 = load i64, ptr %switch, align 8 + %eq = icmp eq i64 ptrtoint (ptr @mymodule.HelloErr.FOO to i64), %2 + br i1 %eq, label %switch.case, label %next_if + +switch.case: ; preds = %switch.entry + call void (ptr, ...) @printf(ptr @.str) + br label %switch.exit + +next_if: ; preds = %switch.entry + %eq1 = icmp eq i64 ptrtoint (ptr @mymodule.ByeErr.BAR to i64), %2 + br i1 %eq1, label %switch.case2, label %next_if3 + +switch.case2: ; preds = %next_if + call void (ptr, ...) @printf(ptr @.str.1) + br label %switch.exit + +next_if3: ; preds = %next_if + br label %switch.default + +switch.default: ; preds = %next_if3 + call void (ptr, ...) @printf(ptr @.str.2) + br label %switch.exit + +switch.exit: ; preds = %switch.default, %switch.case2, %switch.case + br label %if.exit + +if.exit: ; preds = %switch.exit, %end_block + %3 = load i64, ptr %z, align 8 + store i64 %3, ptr %switch4, align 8 + br label %switch.entry5 + +switch.entry5: ; preds = %if.exit + %4 = load i64, ptr %switch4, align 8 + %eq6 = icmp eq i64 ptrtoint (ptr @.typeid.int to i64), %4 + br i1 %eq6, label %switch.case7, label %next_if8 + +switch.case7: ; preds = %switch.entry5 + call void (ptr, ...) @printf(ptr @.str.3) + br label %switch.exit16 + +next_if8: ; preds = %switch.entry5 + %eq9 = icmp eq i64 ptrtoint (ptr @.typeid.bool to i64), %4 + br i1 %eq9, label %switch.case10, label %next_if11 + +switch.case10: ; preds = %next_if8 + br label %switch.case13 + +next_if11: ; preds = %next_if8 + %eq12 = icmp eq i64 ptrtoint (ptr @.typeid.double to i64), %4 + br i1 %eq12, label %switch.case13, label %next_if14 + +switch.case13: ; preds = %next_if11, %switch.case10 + br label %switch.default15 + +next_if14: ; preds = %next_if11 + br label %switch.default15 + +switch.default15: ; preds = %next_if14, %switch.case13 + call void (ptr, ...) @printf(ptr @.str.4) + br label %switch.exit16 + +switch.exit16: ; preds = %switch.default15, %switch.case7 + store i32 1, ptr %a, align 4 + store i32 2, ptr %b, align 4 + %5 = load i32, ptr %b, align 4 + %6 = load i32, ptr %a, align 4 + %add = add i32 %5, %6 + store i32 %add, ptr %zy, align 4 + %7 = load i32, ptr %zy, align 4 + store i32 %7, ptr %switch17, align 4 + br label %switch.entry18 + +switch.entry18: ; preds = %switch.exit16 + %8 = load i32, ptr %switch17, align 4 + %9 = load i32, ptr %a, align 4 + %eq19 = icmp eq i32 %9, %8 + br i1 %eq19, label %switch.case20, label %next_if21 + +switch.case20: ; preds = %switch.entry18 + call void (ptr, ...) @printf(ptr @.str.5) + br label %switch.exit26 + +next_if21: ; preds = %switch.entry18 + %10 = load i32, ptr %b, align 4 + %eq22 = icmp eq i32 %10, %8 + br i1 %eq22, label %switch.case23, label %next_if24 + +switch.case23: ; preds = %next_if21 + call void (ptr, ...) @printf(ptr @.str.6) + br label %switch.exit26 + +next_if24: ; preds = %next_if21 + br label %switch.default25 + +switch.default25: ; preds = %next_if24 + call void (ptr, ...) @printf(ptr @.str.7) + br label %switch.exit26 + +switch.exit26: ; preds = %switch.default25, %switch.case23, %switch.case20 + store i8 1, ptr %switch27, align 1 + br label %switch.entry28 + +switch.entry28: ; preds = %switch.exit26 + %11 = load i8, ptr %switch27, align 1 + %12 = trunc i8 %11 to i1 + %13 = load i32, ptr %a, align 4 + %lt = icmp slt i32 %13, 0 + %eq29 = icmp eq i1 %lt, %12 + br i1 %eq29, label %switch.case30, label %next_if31 + +switch.case30: ; preds = %switch.entry28 + call void (ptr, ...) @printf(ptr @.str.8) + br label %switch.exit37 + +next_if31: ; preds = %switch.entry28 + %14 = load i32, ptr %a, align 4 + %eq32 = icmp eq i32 %14, 1 + %eq33 = icmp eq i1 %eq32, %12 + br i1 %eq33, label %switch.case34, label %next_if35 + +switch.case34: ; preds = %next_if31 + call void (ptr, ...) @printf(ptr @.str.9) + br label %switch.exit37 + +next_if35: ; preds = %next_if31 + br label %switch.default36 + +switch.default36: ; preds = %next_if35 + call void (ptr, ...) @printf(ptr @.str.10) + br label %switch.exit37 + +switch.exit37: ; preds = %switch.default36, %switch.case34, %switch.case30 + ret void +}