diff --git a/CMakeLists.txt b/CMakeLists.txt index 3374b4dc1..561afcd28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,11 +33,11 @@ else() set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fno-exceptions") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fno-exceptions") else() - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined -fno-exceptions") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gdwarf-3 -O1 -fsanitize=undefined -fno-exceptions") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined -fno-exceptions") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -O1 -fsanitize=undefined -fno-exceptions") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fno-exceptions") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined,address -fno-exceptions") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gdwarf-3 -O1 -fsanitize=undefined,address -fno-exceptions") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fsanitize=undefined,address -fno-exceptions") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -O1 -fsanitize=undefined,address -fno-exceptions") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined,address -fno-exceptions") endif() endif() diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 8772bc1db..9a99ef487 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -74,6 +74,24 @@ macro any_to_int(any v, $Type) } } +fn bool typeid.is_subtype_of(self, typeid other) +{ + while (self != void.typeid) + { + if (self == other) return true; + self = self.parentof; + } + return false; +} + +macro bool is_subtype_of($Type, $OtherType) +{ + var $typeid = $Type.typeid; + $switch ($Type) + $case $OtherType: return true; + $default: return false; + $endswitch +} macro bool is_numerical($Type) { var $kind = $Type.kindof; diff --git a/lib/std/math/random/math.seeder.c3 b/lib/std/math/random/math.seeder.c3 index f7374d0a2..8786f5daa 100644 --- a/lib/std/math/random/math.seeder.c3 +++ b/lib/std/math/random/math.seeder.c3 @@ -27,6 +27,7 @@ fn void seeder(char[] input, char[] out_buffer) { ulong[] words = tmalloc(ulong, (out_chars + 7) / 8); words[..] = ODD_PHI64; + usz words_len_2 = words.len * 2; // Add word at a time for (usz i = 0; i < input.len / 8; i++) @@ -47,7 +48,7 @@ fn void seeder(char[] input, char[] out_buffer) } // Mix between words - for (isz i = words.len * 2 - 1; i >= 0; i--) + for (isz i = words_len_2 - 1; i >= 0; i--) { isz j = i % words.len; words[j] -= words[(i + 1) % words.len] * MUL_LCG64; @@ -55,7 +56,7 @@ fn void seeder(char[] input, char[] out_buffer) } // Mix within words - for (usz i = 0; i < 2; i++) + for (usz i = 0; i < words_len_2; i++) { usz j = i % words.len; words[j] *= MUL_MCG64; diff --git a/releasenotes.md b/releasenotes.md index adb0659a8..44e9ca683 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -3,6 +3,7 @@ ## 0.5.0 Change List ### Changes / improvements +- Subtype matching in type switches. - Added parentof typeid property. - Slice assignment is expanded. - Strong optional handling requirements. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index c7fe8def9..5827833a3 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3734,13 +3734,33 @@ static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, void llvm_emit_lhs_is_subtype(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs) { + Type *canonical_typeid = type_lowering(type_typeid); llvm_value_rvalue(c, lhs); llvm_value_rvalue(c, rhs); + LLVMValueRef switch_val = lhs->value; + LLVMBasicBlockRef start_block = c->current_block; LLVMBasicBlockRef retry_block = llvm_basic_block_new(c, "check_subtype"); + LLVMBasicBlockRef result_block = llvm_basic_block_new(c, "result_block"); + LLVMBasicBlockRef parent_type_block = llvm_basic_block_new(c, "parent_type_block"); llvm_emit_br(c, retry_block); - llvm_emit_comp(c, result, lhs, rhs, BINARYOP_EQ); - LLVMBasicBlockRef next_block = llvm_basic_block_new(c, "next_block"); - TODO + llvm_emit_block(c, retry_block); + LLVMValueRef phi = LLVMBuildPhi(c->builder, c->typeid_type, ""); + BEValue cond; + llvm_emit_int_comp_raw(c, &cond, canonical_typeid, canonical_typeid, switch_val, phi, BINARYOP_EQ); + llvm_emit_cond_br(c, &cond, result_block, parent_type_block); + llvm_emit_block(c, parent_type_block); + LLVMValueRef introspect_ptr = LLVMBuildIntToPtr(c->builder, phi, c->ptr_type, ""); + AlignSize alignment; + LLVMValueRef parent = llvm_emit_struct_gep_raw(c, introspect_ptr, c->introspect_type, INTROSPECT_INDEX_PARENTOF, + type_abi_alignment(type_voidptr), &alignment); + LLVMValueRef parent_value = llvm_load(c, c->typeid_type, parent, alignment, "typeid.parent"); + LLVMValueRef is_zero = LLVMBuildICmp(c->builder, LLVMIntEQ, parent_value, LLVMConstNull(c->typeid_type), ""); + llvm_emit_cond_br_raw(c, is_zero, result_block, retry_block); + llvm_set_phi(phi, rhs->value, start_block, parent_value, parent_type_block); + llvm_emit_block(c, result_block); + LLVMValueRef phi2 = LLVMBuildPhi(c->builder, c->bool_type, ""); + llvm_set_phi(phi2, LLVMConstNull(c->bool_type), parent_type_block, LLVMConstAllOnes(c->bool_type), retry_block); + llvm_value_set(result, phi2, type_bool); } void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 924b86699..b81bd2387 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -4,7 +4,7 @@ #include "llvm_codegen_internal.h" -static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast); +static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast, bool is_typeid); // Emit a regular compound statement. void llvm_emit_compound_stmt(GenContext *c, Ast *ast) @@ -332,7 +332,7 @@ static void llvm_emit_if_stmt(GenContext *c, Ast *ast) llvm_emit_cond_br(c, &comp, then_block, else_block); llvm_emit_br(c, then_block); llvm_emit_block(c, then_block); - llvm_emit_switch_body(c, &be_value, then_body); + llvm_emit_switch_body(c, &be_value, then_body, false); llvm_emit_br(c, exit_block); goto EMIT_ELSE; } @@ -615,7 +615,8 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, Ast **cases, Ast *default_case, BEValue *switch_value, - LLVMBasicBlockRef exit_block) + LLVMBasicBlockRef exit_block, + bool is_type_switch) { LLVMBasicBlockRef next = NULL; VECEACH(cases, i) @@ -631,6 +632,7 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, Expr *to_expr = exprptrzero(case_stmt->case_stmt.to_expr); if (to_expr) { + assert(!is_type_switch); BEValue to_value; llvm_emit_expr(c, &to_value, to_expr); llvm_value_rvalue(c, &to_value); @@ -642,11 +644,11 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, } else { - /*if (expr->type == type_typeid) + if (is_type_switch) { llvm_emit_lhs_is_subtype(c, &equals, &be_value, switch_value); } - else*/ + else { llvm_emit_comp(c, &equals, &be_value, switch_value, BINARYOP_EQ); } @@ -752,11 +754,10 @@ static void llvm_emit_switch_jump_table(GenContext *c, #endif } -static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast) +static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast, bool is_typeid) { bool is_if_chain = switch_ast->switch_stmt.flow.if_chain; Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyfault) : switch_value->type; - Ast **cases = switch_ast->switch_stmt.cases; ArraySize case_count = vec_size(cases); if (!case_count) @@ -821,9 +822,10 @@ static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *swi if (is_if_chain) { - llvm_emit_switch_body_if_chain(c, cases, default_case, &switch_current_val, exit_block); + llvm_emit_switch_body_if_chain(c, cases, default_case, &switch_current_val, exit_block, is_typeid); return; } + assert(!is_typeid); c->current_block = NULL; LLVMValueRef switch_stmt = LLVMBuildSwitch(c->builder, switch_current_val.value, default_case ? default_case->case_stmt.backend_block : exit_block, case_count); @@ -875,6 +877,7 @@ void llvm_emit_switch(GenContext *c, Ast *ast) { BEValue switch_value; Expr *expr = exprptrzero(ast->switch_stmt.cond); + bool is_typeid = expr && expr->type->canonical == type_typeid; if (expr) { // Regular switch @@ -885,7 +888,7 @@ void llvm_emit_switch(GenContext *c, Ast *ast) // Match switch, so set the value to true llvm_value_set(&switch_value, llvm_const_int(c, type_bool, 1), type_bool); } - llvm_emit_switch_body(c, &switch_value, ast); + llvm_emit_switch_body(c, &switch_value, ast, is_typeid); } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index fe73d779d..6761e4698 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2438,7 +2438,17 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem goto FAILED; } } - if (expr_const_in_range(switch_expr_const, const_expr, const_to_expr)) + if (is_type) + { + assert(const_expr == const_to_expr); + Type *switch_type = switch_expr_const->typeid; + Type *case_type = const_expr->typeid; + if (matched_case > i && type_is_subtype(case_type->canonical, switch_type->canonical)) + { + matched_case = (int)i; + } + } + else if (expr_const_in_range(switch_expr_const, const_expr, const_to_expr)) { matched_case = (int)i; } diff --git a/src/compiler/types.c b/src/compiler/types.c index 373ce2747..5d6856010 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1617,27 +1617,19 @@ Type *type_find_parent_type(Type *type) * Check if a type is contained in another type. * * @param type canonical type - * @param possible_subtype canonical type + * @param possible_subtype is this a subtype of the former, i.e. type is the parent. * @return true if it is a subtype */ bool type_is_subtype(Type *type, Type *possible_subtype) { - assert(type == type->canonical && possible_subtype == possible_subtype->canonical); - while (1) + assert(type == type->canonical); + while (possible_subtype) { + possible_subtype = possible_subtype->canonical; if (type == possible_subtype) return true; - if (type->type_kind != possible_subtype->type_kind) return false; - if (type->type_kind != TYPE_STRUCT) return false; - - if (!possible_subtype->decl->strukt.members) return false; - - Decl *first_element = possible_subtype->decl->strukt.members[0]; - - if (first_element->decl_kind != DECL_VAR) return false; - - possible_subtype = first_element->type->canonical; + possible_subtype = type_find_parent_type(possible_subtype); } - + return false; } Type *type_from_token(TokenType type) diff --git a/src/version.h b/src/version.h index 43d134621..f990ea415 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.622" \ No newline at end of file +#define COMPILER_VERSION "0.4.623" \ No newline at end of file diff --git a/test/test_suite/statements/various_switching.c3t b/test/test_suite/statements/various_switching.c3t index 3122f2ebd..185d7aaea 100644 --- a/test/test_suite/statements/various_switching.c3t +++ b/test/test_suite/statements/various_switching.c3t @@ -79,8 +79,8 @@ entry: %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 + %switch25 = alloca i32, align 4 + %switch35 = alloca i8, align 1 store i64 ptrtoint (ptr @"mymodule.ByeErr$BAR" to i64), ptr %x.f, align 8 store i64 ptrtoint (ptr @"$ct.int" to i64), ptr %z, align 8 br label %testblock @@ -142,104 +142,157 @@ if.exit: ; preds = %switch.exit, %end_b switch.entry5: ; preds = %if.exit %4 = load i64, ptr %switch4, align 8 - %eq6 = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq6, label %switch.case7, label %next_if8 + br label %check_subtype -switch.case7: ; preds = %switch.entry5 +check_subtype: ; preds = %parent_type_block, %switch.entry5 + %5 = phi i64 [ %4, %switch.entry5 ], [ %typeid.parent, %parent_type_block ] + %eq6 = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq6, label %result_block, label %parent_type_block + +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype + +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case7, label %next_if8 + +switch.case7: ; preds = %result_block call void (ptr, ...) @printf(ptr @.str.5) - br label %switch.exit16 + br label %switch.exit24 -next_if8: ; preds = %switch.entry5 - %eq9 = icmp eq i64 ptrtoint (ptr @"$ct.bool" to i64), %4 - br i1 %eq9, label %switch.case10, label %next_if11 +next_if8: ; preds = %result_block + br label %check_subtype9 -switch.case10: ; preds = %next_if8 - br label %switch.case13 +check_subtype9: ; preds = %parent_type_block11, %next_if8 + %10 = phi i64 [ %4, %next_if8 ], [ %typeid.parent12, %parent_type_block11 ] + %eq10 = icmp eq i64 ptrtoint (ptr @"$ct.bool" to i64), %10 + br i1 %eq10, label %result_block13, label %parent_type_block11 -next_if11: ; preds = %next_if8 - %eq12 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq12, label %switch.case13, label %next_if14 +parent_type_block11: ; preds = %check_subtype9 + %11 = inttoptr i64 %10 to ptr + %12 = getelementptr inbounds %.introspect, ptr %11, i32 0, i32 1 + %typeid.parent12 = load i64, ptr %12, align 8 + %13 = icmp eq i64 %typeid.parent12, 0 + br i1 %13, label %result_block13, label %check_subtype9 -switch.case13: ; preds = %next_if11, %switch.case10 - br label %switch.default15 +result_block13: ; preds = %parent_type_block11, %check_subtype9 + %14 = phi i1 [ false, %parent_type_block11 ], [ true, %check_subtype9 ] + br i1 %14, label %switch.case14, label %next_if15 -next_if14: ; preds = %next_if11 - br label %switch.default15 +switch.case14: ; preds = %result_block13 + br label %switch.case21 -switch.default15: ; preds = %next_if14, %switch.case13 +next_if15: ; preds = %result_block13 + br label %check_subtype16 + +check_subtype16: ; preds = %parent_type_block18, %next_if15 + %15 = phi i64 [ %4, %next_if15 ], [ %typeid.parent19, %parent_type_block18 ] + %eq17 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %15 + br i1 %eq17, label %result_block20, label %parent_type_block18 + +parent_type_block18: ; preds = %check_subtype16 + %16 = inttoptr i64 %15 to ptr + %17 = getelementptr inbounds %.introspect, ptr %16, i32 0, i32 1 + %typeid.parent19 = load i64, ptr %17, align 8 + %18 = icmp eq i64 %typeid.parent19, 0 + br i1 %18, label %result_block20, label %check_subtype16 + +result_block20: ; preds = %parent_type_block18, %check_subtype16 + %19 = phi i1 [ false, %parent_type_block18 ], [ true, %check_subtype16 ] + br i1 %19, label %switch.case21, label %next_if22 + +switch.case21: ; preds = %result_block20, %switch.case14 + br label %switch.default23 + +next_if22: ; preds = %result_block20 + br label %switch.default23 + +switch.default23: ; preds = %next_if22, %switch.case21 call void (ptr, ...) @printf(ptr @.str.6) - br label %switch.exit16 + br label %switch.exit24 -switch.exit16: ; preds = %switch.default15, %switch.case7 +switch.exit24: ; preds = %switch.default23, %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 + %20 = load i32, ptr %b, align 4 + %21 = load i32, ptr %a, align 4 + %add = add i32 %20, %21 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 + %22 = load i32, ptr %zy, align 4 + store i32 %22, ptr %switch25, align 4 + br label %switch.entry26 -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.entry26: ; preds = %switch.exit24 + %23 = load i32, ptr %switch25, align 4 + %24 = load i32, ptr %a, align 4 + %eq27 = icmp eq i32 %24, %23 + br i1 %eq27, label %switch.case28, label %next_if29 -switch.case20: ; preds = %switch.entry18 +switch.case28: ; preds = %switch.entry26 call void (ptr, ...) @printf(ptr @.str.7) - br label %switch.exit26 + br label %switch.exit34 -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 +next_if29: ; preds = %switch.entry26 + %25 = load i32, ptr %b, align 4 + %eq30 = icmp eq i32 %25, %23 + br i1 %eq30, label %switch.case31, label %next_if32 -switch.case23: ; preds = %next_if21 +switch.case31: ; preds = %next_if29 call void (ptr, ...) @printf(ptr @.str.8) - br label %switch.exit26 + br label %switch.exit34 -next_if24: ; preds = %next_if21 - br label %switch.default25 +next_if32: ; preds = %next_if29 + br label %switch.default33 -switch.default25: ; preds = %next_if24 +switch.default33: ; preds = %next_if32 call void (ptr, ...) @printf(ptr @.str.9) - br label %switch.exit26 + br label %switch.exit34 -switch.exit26: ; preds = %switch.default25, %switch.case23, %switch.case20 - store i8 1, ptr %switch27, align 1 - br label %switch.entry28 +switch.exit34: ; preds = %switch.default33, %switch.case31, %switch.case28 + store i8 1, ptr %switch35, align 1 + br label %switch.entry36 -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.entry36: ; preds = %switch.exit34 + %26 = load i8, ptr %switch35, align 1 + %27 = trunc i8 %26 to i1 + %28 = load i32, ptr %a, align 4 + %lt = icmp slt i32 %28, 0 + %eq37 = icmp eq i1 %lt, %27 + br i1 %eq37, label %switch.case38, label %next_if39 -switch.case30: ; preds = %switch.entry28 +switch.case38: ; preds = %switch.entry36 call void (ptr, ...) @printf(ptr @.str.10) - br label %switch.exit37 + br label %switch.exit45 -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 +next_if39: ; preds = %switch.entry36 + %29 = load i32, ptr %a, align 4 + %eq40 = icmp eq i32 %29, 1 + %eq41 = icmp eq i1 %eq40, %27 + br i1 %eq41, label %switch.case42, label %next_if43 -switch.case34: ; preds = %next_if31 +switch.case42: ; preds = %next_if39 call void (ptr, ...) @printf(ptr @.str.11) - br label %switch.exit37 + br label %switch.exit45 -next_if35: ; preds = %next_if31 - br label %switch.default36 +next_if43: ; preds = %next_if39 + br label %switch.default44 -switch.default36: ; preds = %next_if35 +switch.default44: ; preds = %next_if43 call void (ptr, ...) @printf(ptr @.str.12) - br label %switch.exit37 + br label %switch.exit45 -switch.exit37: ; preds = %switch.default36, %switch.case34, %switch.case30 +switch.exit45: ; preds = %switch.default44, %switch.case42, %switch.case38 + ret void +} + +; Function Attrs: nounwind +define void @mymodule.main() #0 { +entry: + call void @mymodule.test() + call void (ptr, ...) @printf(ptr @.str.13) ret void } diff --git a/test/test_suite/variant/variant_assign.c3t b/test/test_suite/variant/variant_assign.c3t index cf344de75..ef9eb298d 100644 --- a/test/test_suite/variant/variant_assign.c3t +++ b/test/test_suite/variant/variant_assign.c3t @@ -67,7 +67,7 @@ entry: %z = alloca %any, align 8 %switch = alloca i64, align 8 %z1 = alloca ptr, align 8 - %z4 = alloca ptr, align 8 + %z8 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptroffset = getelementptr inbounds ptr, ptr %z, i64 1 store ptr %1, ptr %ptroffset, align 8 @@ -78,42 +78,73 @@ entry: switch.entry: ; preds = %entry %4 = load i64, ptr %switch, align 8 - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq, label %switch.case, label %next_if + br label %check_subtype -switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 - %6 = load ptr, ptr %5, align 8 - store ptr %6, ptr %z1, align 8 - %7 = load ptr, ptr %z1, align 8 - %8 = load i32, ptr %7, align 4 - call void (ptr, ...) @printf(ptr @.str, i32 %8) +check_subtype: ; preds = %parent_type_block, %switch.entry + %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] + %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq, label %result_block, label %parent_type_block + +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype + +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case, label %next_if + +switch.case: ; preds = %result_block + %10 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 + %11 = load ptr, ptr %10, align 8 + store ptr %11, ptr %z1, align 8 + %12 = load ptr, ptr %z1, align 8 + %13 = load i32, ptr %12, align 4 + call void (ptr, ...) @printf(ptr @.str, i32 %13) br label %switch.exit -next_if: ; preds = %switch.entry - %eq2 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq2, label %switch.case3, label %next_if5 +next_if: ; preds = %result_block + br label %check_subtype2 -switch.case3: ; preds = %next_if - %9 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 - %10 = load ptr, ptr %9, align 8 - store ptr %10, ptr %z4, align 8 - %11 = load ptr, ptr %z4, align 8 - %12 = load double, ptr %11, align 8 - call void (ptr, ...) @printf(ptr @.str.1, double %12) +check_subtype2: ; preds = %parent_type_block4, %next_if + %14 = phi i64 [ %4, %next_if ], [ %typeid.parent5, %parent_type_block4 ] + %eq3 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %14 + br i1 %eq3, label %result_block6, label %parent_type_block4 + +parent_type_block4: ; preds = %check_subtype2 + %15 = inttoptr i64 %14 to ptr + %16 = getelementptr inbounds %.introspect, ptr %15, i32 0, i32 1 + %typeid.parent5 = load i64, ptr %16, align 8 + %17 = icmp eq i64 %typeid.parent5, 0 + br i1 %17, label %result_block6, label %check_subtype2 + +result_block6: ; preds = %parent_type_block4, %check_subtype2 + %18 = phi i1 [ false, %parent_type_block4 ], [ true, %check_subtype2 ] + br i1 %18, label %switch.case7, label %next_if9 + +switch.case7: ; preds = %result_block6 + %19 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 + %20 = load ptr, ptr %19, align 8 + store ptr %20, ptr %z8, align 8 + %21 = load ptr, ptr %z8, align 8 + %22 = load double, ptr %21, align 8 + call void (ptr, ...) @printf(ptr @.str.1, double %22) br label %switch.exit -next_if5: ; preds = %next_if +next_if9: ; preds = %result_block6 br label %switch.default -switch.default: ; preds = %next_if5 +switch.default: ; preds = %next_if9 call void (ptr, ...) @printf(ptr @.str.2) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case3, %switch.case +switch.exit: ; preds = %switch.default, %switch.case7, %switch.case ret void } +; Function Attrs: nounwind define void @foo.test2(i64 %0, ptr %1) #0 { entry: %y = alloca %any, align 8 @@ -121,7 +152,7 @@ entry: %switch = alloca i64, align 8 %z = alloca ptr, align 8 %taddr = alloca i32, align 4 - %z3 = alloca ptr, align 8 + %z7 = alloca ptr, align 8 store i64 %0, ptr %y, align 8 %ptroffset = getelementptr inbounds ptr, ptr %y, i64 1 store ptr %1, ptr %ptroffset, align 8 @@ -133,43 +164,73 @@ entry: switch.entry: ; preds = %entry %4 = load i64, ptr %switch, align 8 - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq, label %switch.case, label %next_if + br label %check_subtype -switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 - %6 = load ptr, ptr %5, align 8 - store ptr %6, ptr %z, align 8 +check_subtype: ; preds = %parent_type_block, %switch.entry + %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] + %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq, label %result_block, label %parent_type_block + +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype + +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case, label %next_if + +switch.case: ; preds = %result_block + %10 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 + %11 = load ptr, ptr %10, align 8 + store ptr %11, ptr %z, align 8 store i32 12, ptr %taddr, align 4 - %7 = insertvalue %any undef, ptr %taddr, 0 - %8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %any %8, ptr %y, align 8 - %9 = load ptr, ptr %z, align 8 - %10 = load i32, ptr %9, align 4 - call void (ptr, ...) @printf(ptr @.str.3, i32 %10) + %12 = insertvalue %any undef, ptr %taddr, 0 + %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %13, ptr %y, align 8 + %14 = load ptr, ptr %z, align 8 + %15 = load i32, ptr %14, align 4 + call void (ptr, ...) @printf(ptr @.str.3, i32 %15) br label %switch.exit -next_if: ; preds = %switch.entry - %eq1 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq1, label %switch.case2, label %next_if4 +next_if: ; preds = %result_block + br label %check_subtype1 -switch.case2: ; preds = %next_if - %11 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 - %12 = load ptr, ptr %11, align 8 - store ptr %12, ptr %z3, align 8 - %13 = load ptr, ptr %z3, align 8 - %14 = load double, ptr %13, align 8 - call void (ptr, ...) @printf(ptr @.str.4, double %14) +check_subtype1: ; preds = %parent_type_block3, %next_if + %16 = phi i64 [ %4, %next_if ], [ %typeid.parent4, %parent_type_block3 ] + %eq2 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %16 + br i1 %eq2, label %result_block5, label %parent_type_block3 + +parent_type_block3: ; preds = %check_subtype1 + %17 = inttoptr i64 %16 to ptr + %18 = getelementptr inbounds %.introspect, ptr %17, i32 0, i32 1 + %typeid.parent4 = load i64, ptr %18, align 8 + %19 = icmp eq i64 %typeid.parent4, 0 + br i1 %19, label %result_block5, label %check_subtype1 + +result_block5: ; preds = %parent_type_block3, %check_subtype1 + %20 = phi i1 [ false, %parent_type_block3 ], [ true, %check_subtype1 ] + br i1 %20, label %switch.case6, label %next_if8 + +switch.case6: ; preds = %result_block5 + %21 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 + %22 = load ptr, ptr %21, align 8 + store ptr %22, ptr %z7, align 8 + %23 = load ptr, ptr %z7, align 8 + %24 = load double, ptr %23, align 8 + call void (ptr, ...) @printf(ptr @.str.4, double %24) br label %switch.exit -next_if4: ; preds = %next_if +next_if8: ; preds = %result_block5 br label %switch.default -switch.default: ; preds = %next_if4 +switch.default: ; preds = %next_if8 call void (ptr, ...) @printf(ptr @.str.5) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case2, %switch.case +switch.exit: ; preds = %switch.default, %switch.case6, %switch.case ret void } @@ -179,7 +240,7 @@ entry: %.anon = alloca %any, align 8 %switch = alloca i64, align 8 %z = alloca i32, align 4 - %z3 = alloca double, align 8 + %z7 = alloca double, align 8 store i64 %0, ptr %y, align 8 %ptroffset = getelementptr inbounds ptr, ptr %y, i64 1 store ptr %1, ptr %ptroffset, align 8 @@ -191,39 +252,69 @@ entry: switch.entry: ; preds = %entry %4 = load i64, ptr %switch, align 8 - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq, label %switch.case, label %next_if + br label %check_subtype -switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 - %6 = load ptr, ptr %5, align 8 - %7 = load i32, ptr %6, align 4 - store i32 %7, ptr %z, align 4 - %8 = load i32, ptr %z, align 4 - call void (ptr, ...) @printf(ptr @.str.6, i32 %8) +check_subtype: ; preds = %parent_type_block, %switch.entry + %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] + %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq, label %result_block, label %parent_type_block + +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype + +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case, label %next_if + +switch.case: ; preds = %result_block + %10 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 + %11 = load ptr, ptr %10, align 8 + %12 = load i32, ptr %11, align 4 + store i32 %12, ptr %z, align 4 + %13 = load i32, ptr %z, align 4 + call void (ptr, ...) @printf(ptr @.str.6, i32 %13) br label %switch.exit -next_if: ; preds = %switch.entry - %eq1 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq1, label %switch.case2, label %next_if4 +next_if: ; preds = %result_block + br label %check_subtype1 -switch.case2: ; preds = %next_if - %9 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 - %10 = load ptr, ptr %9, align 8 - %11 = load double, ptr %10, align 8 - store double %11, ptr %z3, align 8 - %12 = load double, ptr %z3, align 8 - call void (ptr, ...) @printf(ptr @.str.7, double %12) +check_subtype1: ; preds = %parent_type_block3, %next_if + %14 = phi i64 [ %4, %next_if ], [ %typeid.parent4, %parent_type_block3 ] + %eq2 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %14 + br i1 %eq2, label %result_block5, label %parent_type_block3 + +parent_type_block3: ; preds = %check_subtype1 + %15 = inttoptr i64 %14 to ptr + %16 = getelementptr inbounds %.introspect, ptr %15, i32 0, i32 1 + %typeid.parent4 = load i64, ptr %16, align 8 + %17 = icmp eq i64 %typeid.parent4, 0 + br i1 %17, label %result_block5, label %check_subtype1 + +result_block5: ; preds = %parent_type_block3, %check_subtype1 + %18 = phi i1 [ false, %parent_type_block3 ], [ true, %check_subtype1 ] + br i1 %18, label %switch.case6, label %next_if8 + +switch.case6: ; preds = %result_block5 + %19 = getelementptr inbounds %any, ptr %.anon, i32 0, i32 0 + %20 = load ptr, ptr %19, align 8 + %21 = load double, ptr %20, align 8 + store double %21, ptr %z7, align 8 + %22 = load double, ptr %z7, align 8 + call void (ptr, ...) @printf(ptr @.str.7, double %22) br label %switch.exit -next_if4: ; preds = %next_if +next_if8: ; preds = %result_block5 br label %switch.default -switch.default: ; preds = %next_if4 +switch.default: ; preds = %next_if8 call void (ptr, ...) @printf(ptr @.str.8) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case2, %switch.case +switch.exit: ; preds = %switch.default, %switch.case6, %switch.case ret void } diff --git a/test/test_suite/variant/variant_switch.c3t b/test/test_suite/variant/variant_switch.c3t index 8ef1ec0e6..9a2e75f28 100644 --- a/test/test_suite/variant/variant_switch.c3t +++ b/test/test_suite/variant/variant_switch.c3t @@ -39,7 +39,7 @@ entry: %z = alloca %any, align 8 %switch = alloca i64, align 8 %z1 = alloca ptr, align 8 - %z4 = alloca ptr, align 8 + %z8 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptroffset = getelementptr inbounds ptr, ptr %z, i64 1 store ptr %1, ptr %ptroffset, align 8 @@ -50,51 +50,81 @@ entry: switch.entry: ; preds = %entry %4 = load i64, ptr %switch, align 8 - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq, label %switch.case, label %next_if + br label %check_subtype -switch.case: ; preds = %switch.entry - %5 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 - %6 = load ptr, ptr %5, align 8 - store ptr %6, ptr %z1, align 8 - %7 = load ptr, ptr %z1, align 8 - %8 = load i32, ptr %7, align 4 - call void (ptr, ...) @printf(ptr @.str, i32 %8) - %9 = load ptr, ptr %z1, align 8 - store i32 3, ptr %9, align 4 - br label %switch.exit +check_subtype: ; preds = %parent_type_block, %switch.entry + %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] + %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq, label %result_block, label %parent_type_block -next_if: ; preds = %switch.entry - %eq2 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq2, label %switch.case3, label %next_if5 +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype -switch.case3: ; preds = %next_if +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case, label %next_if + +switch.case: ; preds = %result_block %10 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 %11 = load ptr, ptr %10, align 8 - store ptr %11, ptr %z4, align 8 - %12 = load ptr, ptr %z4, align 8 - %13 = load double, ptr %12, align 8 - call void (ptr, ...) @printf(ptr @.str.1, double %13) + store ptr %11, ptr %z1, align 8 + %12 = load ptr, ptr %z1, align 8 + %13 = load i32, ptr %12, align 4 + call void (ptr, ...) @printf(ptr @.str, i32 %13) + %14 = load ptr, ptr %z1, align 8 + store i32 3, ptr %14, align 4 br label %switch.exit -next_if5: ; preds = %next_if +next_if: ; preds = %result_block + br label %check_subtype2 + +check_subtype2: ; preds = %parent_type_block4, %next_if + %15 = phi i64 [ %4, %next_if ], [ %typeid.parent5, %parent_type_block4 ] + %eq3 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %15 + br i1 %eq3, label %result_block6, label %parent_type_block4 + +parent_type_block4: ; preds = %check_subtype2 + %16 = inttoptr i64 %15 to ptr + %17 = getelementptr inbounds %.introspect, ptr %16, i32 0, i32 1 + %typeid.parent5 = load i64, ptr %17, align 8 + %18 = icmp eq i64 %typeid.parent5, 0 + br i1 %18, label %result_block6, label %check_subtype2 + +result_block6: ; preds = %parent_type_block4, %check_subtype2 + %19 = phi i1 [ false, %parent_type_block4 ], [ true, %check_subtype2 ] + br i1 %19, label %switch.case7, label %next_if9 + +switch.case7: ; preds = %result_block6 + %20 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 + %21 = load ptr, ptr %20, align 8 + store ptr %21, ptr %z8, align 8 + %22 = load ptr, ptr %z8, align 8 + %23 = load double, ptr %22, align 8 + call void (ptr, ...) @printf(ptr @.str.1, double %23) + br label %switch.exit + +next_if9: ; preds = %result_block6 br label %switch.default -switch.default: ; preds = %next_if5 +switch.default: ; preds = %next_if9 call void (ptr, ...) @printf(ptr @.str.2) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case3, %switch.case - %14 = getelementptr inbounds %any, ptr %z, i32 0, i32 1 - %15 = load i64, ptr %14, align 8 - %eq6 = icmp eq i64 %15, ptrtoint (ptr @"$ct.int" to i64) - br i1 %eq6, label %if.then, label %if.exit +switch.exit: ; preds = %switch.default, %switch.case7, %switch.case + %24 = getelementptr inbounds %any, ptr %z, i32 0, i32 1 + %25 = load i64, ptr %24, align 8 + %eq10 = icmp eq i64 %25, ptrtoint (ptr @"$ct.int" to i64) + br i1 %eq10, label %if.then, label %if.exit if.then: ; preds = %switch.exit - %16 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 - %17 = load ptr, ptr %16, align 8 - %18 = load i32, ptr %17, align 4 - call void (ptr, ...) @printf(ptr @.str.3, i32 %18) + %26 = getelementptr inbounds %any, ptr %z, i32 0, i32 0 + %27 = load ptr, ptr %26, align 8 + %28 = load i32, ptr %27, align 4 + call void (ptr, ...) @printf(ptr @.str.3, i32 %28) br label %if.exit if.exit: ; preds = %if.then, %switch.exit diff --git a/test/test_suite/variant/variant_test.c3t b/test/test_suite/variant/variant_test.c3t index 62ee1fc73..6df28a180 100644 --- a/test/test_suite/variant/variant_test.c3t +++ b/test/test_suite/variant/variant_test.c3t @@ -86,45 +86,105 @@ entry: switch.entry: ; preds = %entry %4 = load i64, ptr %switch, align 8 - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %4 - br i1 %eq, label %switch.case, label %next_if + br label %check_subtype -switch.case: ; preds = %switch.entry +check_subtype: ; preds = %parent_type_block, %switch.entry + %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] + %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 + br i1 %eq, label %result_block, label %parent_type_block + +parent_type_block: ; preds = %check_subtype + %6 = inttoptr i64 %5 to ptr + %7 = getelementptr inbounds %.introspect, ptr %6, i32 0, i32 1 + %typeid.parent = load i64, ptr %7, align 8 + %8 = icmp eq i64 %typeid.parent, 0 + br i1 %8, label %result_block, label %check_subtype + +result_block: ; preds = %parent_type_block, %check_subtype + %9 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] + br i1 %9, label %switch.case, label %next_if + +switch.case: ; preds = %result_block call void (ptr, ...) @printf(ptr @.str) br label %switch.exit -next_if: ; preds = %switch.entry - %eq1 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %4 - br i1 %eq1, label %switch.case2, label %next_if3 +next_if: ; preds = %result_block + br label %check_subtype1 -switch.case2: ; preds = %next_if +check_subtype1: ; preds = %parent_type_block3, %next_if + %10 = phi i64 [ %4, %next_if ], [ %typeid.parent4, %parent_type_block3 ] + %eq2 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %10 + br i1 %eq2, label %result_block5, label %parent_type_block3 + +parent_type_block3: ; preds = %check_subtype1 + %11 = inttoptr i64 %10 to ptr + %12 = getelementptr inbounds %.introspect, ptr %11, i32 0, i32 1 + %typeid.parent4 = load i64, ptr %12, align 8 + %13 = icmp eq i64 %typeid.parent4, 0 + br i1 %13, label %result_block5, label %check_subtype1 + +result_block5: ; preds = %parent_type_block3, %check_subtype1 + %14 = phi i1 [ false, %parent_type_block3 ], [ true, %check_subtype1 ] + br i1 %14, label %switch.case6, label %next_if7 + +switch.case6: ; preds = %result_block5 call void (ptr, ...) @printf(ptr @.str.1) br label %switch.exit -next_if3: ; preds = %next_if - %eq4 = icmp eq i64 ptrtoint (ptr @"$ct.any" to i64), %4 - br i1 %eq4, label %switch.case5, label %next_if6 +next_if7: ; preds = %result_block5 + br label %check_subtype8 -switch.case5: ; preds = %next_if3 +check_subtype8: ; preds = %parent_type_block10, %next_if7 + %15 = phi i64 [ %4, %next_if7 ], [ %typeid.parent11, %parent_type_block10 ] + %eq9 = icmp eq i64 ptrtoint (ptr @"$ct.any" to i64), %15 + br i1 %eq9, label %result_block12, label %parent_type_block10 + +parent_type_block10: ; preds = %check_subtype8 + %16 = inttoptr i64 %15 to ptr + %17 = getelementptr inbounds %.introspect, ptr %16, i32 0, i32 1 + %typeid.parent11 = load i64, ptr %17, align 8 + %18 = icmp eq i64 %typeid.parent11, 0 + br i1 %18, label %result_block12, label %check_subtype8 + +result_block12: ; preds = %parent_type_block10, %check_subtype8 + %19 = phi i1 [ false, %parent_type_block10 ], [ true, %check_subtype8 ] + br i1 %19, label %switch.case13, label %next_if14 + +switch.case13: ; preds = %result_block12 call void (ptr, ...) @printf(ptr @.str.2) br label %switch.exit -next_if6: ; preds = %next_if3 - %eq7 = icmp eq i64 ptrtoint (ptr @"$ct.p$int" to i64), %4 - br i1 %eq7, label %switch.case8, label %next_if9 +next_if14: ; preds = %result_block12 + br label %check_subtype15 -switch.case8: ; preds = %next_if6 +check_subtype15: ; preds = %parent_type_block17, %next_if14 + %20 = phi i64 [ %4, %next_if14 ], [ %typeid.parent18, %parent_type_block17 ] + %eq16 = icmp eq i64 ptrtoint (ptr @"$ct.p$int" to i64), %20 + br i1 %eq16, label %result_block19, label %parent_type_block17 + +parent_type_block17: ; preds = %check_subtype15 + %21 = inttoptr i64 %20 to ptr + %22 = getelementptr inbounds %.introspect, ptr %21, i32 0, i32 1 + %typeid.parent18 = load i64, ptr %22, align 8 + %23 = icmp eq i64 %typeid.parent18, 0 + br i1 %23, label %result_block19, label %check_subtype15 + +result_block19: ; preds = %parent_type_block17, %check_subtype15 + %24 = phi i1 [ false, %parent_type_block17 ], [ true, %check_subtype15 ] + br i1 %24, label %switch.case20, label %next_if21 + +switch.case20: ; preds = %result_block19 call void (ptr, ...) @printf(ptr @.str.3) br label %switch.exit -next_if9: ; preds = %next_if6 +next_if21: ; preds = %result_block19 br label %switch.default -switch.default: ; preds = %next_if9 +switch.default: ; preds = %next_if21 call void (ptr, ...) @printf(ptr @.str.4) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case8, %switch.case5, %switch.case2, %switch.case +switch.exit: ; preds = %switch.default, %switch.case20, %switch.case13, %switch.case6, %switch.case ret void } diff --git a/test/unit/regression/subtype.c3 b/test/unit/regression/subtype.c3 new file mode 100644 index 000000000..a73c1ac17 --- /dev/null +++ b/test/unit/regression/subtype.c3 @@ -0,0 +1,91 @@ +module switch_subtype @test; + +struct Foo +{ + inline Baz g; + int a; +} +struct Bar +{ + inline Foo f; +} +struct Baz +{ + int z; +} +fn void switch_subtyping() +{ + Foo f = {}; + f.z = 123; + any x = &f; + switch (x) + { + case int: + assert(false); + case Baz: + assert(true); + default: + assert(false); + } + switch (x) + { + case int: + assert(false); + case Foo: + assert(true); + default: + assert(false); + } + switch (x) + { + case int: + assert(false); + case Bar: + assert(false); + default: + assert(true); + } + switch (Bar.typeid) + { + case int: + assert(false); + case Baz: + assert(true); + case Foo: + assert(false); + case Bar: + assert(false); + default: + assert(false); + } + switch (Bar.typeid) + { + case int: + assert(false); + case Foo: + assert(true); + case Bar: + assert(false); + default: + assert(false); + } + $switch (Bar.typeid) + $case Foo: + assert(true); + $case Bar: + assert(false); + $default: + assert(false); + $endswitch +} + +fn void is_subtype() +{ + $assert(types::is_subtype_of(Bar, Baz)); + $assert(!types::is_subtype_of(Baz, Bar)); + typeid baz = Baz.typeid; + typeid bar = Bar.typeid; + assert(bar.is_subtype_of(baz)); + assert(!bar.is_subtype_of(double.typeid)); + assert(!baz.is_subtype_of(bar)); +}