| ... | ... | @@ -275,8 +275,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) { |
| 275 | 275 | return IrInstructionIdSizeOf; |
| 276 | 276 | } |
| 277 | 277 | |
| 278 | | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNull *) { |
| 279 | | return IrInstructionIdTestNull; |
| 278 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { |
| 279 | return IrInstructionIdTestNonNull; |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) { |
| ... | ... | @@ -1200,7 +1200,7 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *so |
| 1200 | 1200 | } |
| 1201 | 1201 | |
| 1202 | 1202 | static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 1203 | | IrInstructionTestNull *instruction = ir_build_instruction<IrInstructionTestNull>(irb, scope, source_node); |
| 1203 | IrInstructionTestNonNull *instruction = ir_build_instruction<IrInstructionTestNonNull>(irb, scope, source_node); |
| 1204 | 1204 | instruction->value = value; |
| 1205 | 1205 | |
| 1206 | 1206 | ir_ref_instruction(value); |
| ... | ... | @@ -1956,10 +1956,27 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 1956 | 1956 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| 1957 | 1957 | return ir_build_return(irb, scope, node, return_value); |
| 1958 | 1958 | } else if (defer_counts[ReturnKindMaybe] > 0) { |
| 1959 | | // TODO in this situation we need to make a conditional |
| 1960 | | // branch on the maybe value. we potentially must make multiple conditional branches, |
| 1961 | | // if unconditional defers are interleaved with error defers. |
| 1962 | | zig_panic("TODO handle maybe defers"); |
| 1959 | IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull"); |
| 1960 | IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "MaybeRetOk"); |
| 1961 | |
| 1962 | IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, return_value); |
| 1963 | |
| 1964 | IrInstruction *is_comptime; |
| 1965 | if (ir_should_inline(irb)) { |
| 1966 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 1967 | } else { |
| 1968 | is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); |
| 1969 | } |
| 1970 | |
| 1971 | ir_build_cond_br(irb, scope, node, is_non_null, ok_block, null_block, is_comptime); |
| 1972 | |
| 1973 | ir_set_cursor_at_end(irb, null_block); |
| 1974 | ir_gen_defers_for_block(irb, scope, outer_scope, false, true); |
| 1975 | ir_build_return(irb, scope, node, return_value); |
| 1976 | |
| 1977 | ir_set_cursor_at_end(irb, ok_block); |
| 1978 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| 1979 | return ir_build_return(irb, scope, node, return_value); |
| 1963 | 1980 | } else { |
| 1964 | 1981 | // generate unconditional defers |
| 1965 | 1982 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| ... | ... | @@ -1998,12 +2015,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 1998 | 2015 | IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| 1999 | 2016 | if (maybe_val_ptr == irb->codegen->invalid_instruction) |
| 2000 | 2017 | return irb->codegen->invalid_instruction; |
| 2001 | | IrInstruction *is_nonnull_val = ir_build_test_null(irb, scope, node, maybe_val_ptr); |
| 2018 | IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); |
| 2019 | IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val); |
| 2002 | 2020 | |
| 2003 | 2021 | IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); |
| 2004 | 2022 | IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); |
| 2005 | 2023 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb)); |
| 2006 | | ir_build_cond_br(irb, scope, node, is_nonnull_val, continue_block, return_block, is_comptime); |
| 2024 | ir_build_cond_br(irb, scope, node, is_non_null, continue_block, return_block, is_comptime); |
| 2007 | 2025 | |
| 2008 | 2026 | ir_set_cursor_at_end(irb, return_block); |
| 2009 | 2027 | ir_gen_defers_for_block(irb, scope, outer_scope, false, true); |
| ... | ... | @@ -2247,7 +2265,8 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As |
| 2247 | 2265 | if (maybe_ptr == irb->codegen->invalid_instruction) |
| 2248 | 2266 | return irb->codegen->invalid_instruction; |
| 2249 | 2267 | |
| 2250 | | IrInstruction *is_non_null = ir_build_test_null(irb, parent_scope, node, maybe_ptr); |
| 2268 | IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr); |
| 2269 | IrInstruction *is_non_null = ir_build_test_null(irb, parent_scope, node, maybe_val); |
| 2251 | 2270 | |
| 2252 | 2271 | IrInstruction *is_comptime; |
| 2253 | 2272 | if (ir_should_inline(irb)) { |
| ... | ... | @@ -3514,11 +3533,12 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 3514 | 3533 | AstNode *else_node = node->data.if_var_expr.else_node; |
| 3515 | 3534 | bool var_is_ptr = node->data.if_var_expr.var_is_ptr; |
| 3516 | 3535 | |
| 3517 | | IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| 3518 | | if (expr_value == irb->codegen->invalid_instruction) |
| 3519 | | return expr_value; |
| 3536 | IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| 3537 | if (maybe_val_ptr == irb->codegen->invalid_instruction) |
| 3538 | return maybe_val_ptr; |
| 3520 | 3539 | |
| 3521 | | IrInstruction *is_nonnull_value = ir_build_test_null(irb, scope, node, expr_value); |
| 3540 | IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); |
| 3541 | IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val); |
| 3522 | 3542 | |
| 3523 | 3543 | IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen"); |
| 3524 | 3544 | IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse"); |
| ... | ... | @@ -3528,9 +3548,9 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 3528 | 3548 | if (ir_should_inline(irb) || node->data.if_var_expr.is_inline) { |
| 3529 | 3549 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 3530 | 3550 | } else { |
| 3531 | | is_comptime = ir_build_test_comptime(irb, scope, node, is_nonnull_value); |
| 3551 | is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); |
| 3532 | 3552 | } |
| 3533 | | ir_build_cond_br(irb, scope, node, is_nonnull_value, then_block, else_block, is_comptime); |
| 3553 | ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime); |
| 3534 | 3554 | |
| 3535 | 3555 | ir_set_cursor_at_end(irb, then_block); |
| 3536 | 3556 | IrInstruction *var_type = nullptr; |
| ... | ... | @@ -3544,7 +3564,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 3544 | 3564 | VariableTableEntry *var = ir_create_var(irb, node, scope, |
| 3545 | 3565 | var_decl->symbol, is_const, is_const, is_shadowable, is_comptime); |
| 3546 | 3566 | |
| 3547 | | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, expr_value, false); |
| 3567 | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false); |
| 3548 | 3568 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); |
| 3549 | 3569 | ir_build_var_decl(irb, scope, node, var, var_type, var_value); |
| 3550 | 3570 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope); |
| ... | ... | @@ -4440,7 +4460,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 4440 | 4460 | } |
| 4441 | 4461 | |
| 4442 | 4462 | // implicitly take a const pointer to something |
| 4443 | | { |
| 4463 | if (!type_requires_comptime(actual_type)) { |
| 4444 | 4464 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); |
| 4445 | 4465 | if (types_match_const_cast_only(expected_type, const_ptr_actual)) { |
| 4446 | 4466 | return ImplicitCastMatchResultYes; |
| ... | ... | @@ -5230,7 +5250,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 5230 | 5250 | } |
| 5231 | 5251 | |
| 5232 | 5252 | // explicit cast from something to const pointer of it |
| 5233 | | { |
| 5253 | if (!type_requires_comptime(actual_type)) { |
| 5234 | 5254 | TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); |
| 5235 | 5255 | if (types_match_const_cast_only(wanted_type, const_ptr_actual)) { |
| 5236 | 5256 | return ir_analyze_cast_ref(ira, source_instr, value, wanted_type); |
| ... | ... | @@ -7763,39 +7783,36 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 7763 | 7783 | zig_unreachable(); |
| 7764 | 7784 | } |
| 7765 | 7785 | |
| 7766 | | static TypeTableEntry *ir_analyze_instruction_test_null(IrAnalyze *ira, |
| 7767 | | IrInstructionTestNull *test_null_instruction) |
| 7768 | | { |
| 7769 | | IrInstruction *value = test_null_instruction->value->other; |
| 7786 | static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { |
| 7787 | IrInstruction *value = instruction->value->other; |
| 7770 | 7788 | if (value->type_entry->id == TypeTableEntryIdInvalid) |
| 7771 | 7789 | return ira->codegen->builtin_types.entry_invalid; |
| 7772 | 7790 | |
| 7773 | | // This will be a pointer type because test null IR instruction operates on a pointer to a thing. |
| 7774 | | TypeTableEntry *ptr_type = value->type_entry; |
| 7775 | | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7776 | | |
| 7777 | | TypeTableEntry *type_entry = ptr_type->data.pointer.child_type; |
| 7778 | | if (type_entry->id != TypeTableEntryIdMaybe) { |
| 7779 | | add_node_error(ira->codegen, test_null_instruction->base.source_node, |
| 7780 | | buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name))); |
| 7781 | | return ira->codegen->builtin_types.entry_invalid; |
| 7782 | | } |
| 7791 | TypeTableEntry *type_entry = value->type_entry; |
| 7783 | 7792 | |
| 7784 | | if (value->static_value.special != ConstValSpecialRuntime) { |
| 7785 | | ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr; |
| 7786 | | assert(value->static_value.data.x_ptr.index == SIZE_MAX); |
| 7793 | if (type_entry->id == TypeTableEntryIdMaybe) { |
| 7794 | if (instr_is_comptime(value)) { |
| 7795 | ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad); |
| 7796 | if (!maybe_val) |
| 7797 | return ira->codegen->builtin_types.entry_invalid; |
| 7787 | 7798 | |
| 7788 | | if (maybe_val->special != ConstValSpecialRuntime) { |
| 7789 | | bool depends_on_compile_var = maybe_val->depends_on_compile_var; |
| 7790 | | ConstExprValue *out_val = ir_build_const_from(ira, &test_null_instruction->base, |
| 7791 | | depends_on_compile_var); |
| 7792 | | out_val->data.x_bool = (maybe_val->data.x_maybe == nullptr); |
| 7799 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, |
| 7800 | maybe_val->depends_on_compile_var); |
| 7801 | out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr); |
| 7793 | 7802 | return ira->codegen->builtin_types.entry_bool; |
| 7794 | 7803 | } |
| 7795 | | } |
| 7796 | 7804 | |
| 7797 | | ir_build_test_null_from(&ira->new_irb, &test_null_instruction->base, value); |
| 7798 | | return ira->codegen->builtin_types.entry_bool; |
| 7805 | ir_build_test_null_from(&ira->new_irb, &instruction->base, value); |
| 7806 | return ira->codegen->builtin_types.entry_bool; |
| 7807 | } else if (type_entry->id == TypeTableEntryIdNullLit) { |
| 7808 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false); |
| 7809 | out_val->data.x_bool = false; |
| 7810 | return ira->codegen->builtin_types.entry_bool; |
| 7811 | } else { |
| 7812 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false); |
| 7813 | out_val->data.x_bool = true; |
| 7814 | return ira->codegen->builtin_types.entry_bool; |
| 7815 | } |
| 7799 | 7816 | } |
| 7800 | 7817 | |
| 7801 | 7818 | static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, |
| ... | ... | @@ -9689,8 +9706,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 9689 | 9706 | return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction); |
| 9690 | 9707 | case IrInstructionIdSizeOf: |
| 9691 | 9708 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| 9692 | | case IrInstructionIdTestNull: |
| 9693 | | return ir_analyze_instruction_test_null(ira, (IrInstructionTestNull *)instruction); |
| 9709 | case IrInstructionIdTestNonNull: |
| 9710 | return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); |
| 9694 | 9711 | case IrInstructionIdUnwrapMaybe: |
| 9695 | 9712 | return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction); |
| 9696 | 9713 | case IrInstructionIdClz: |
| ... | ... | @@ -9908,7 +9925,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9908 | 9925 | case IrInstructionIdSliceType: |
| 9909 | 9926 | case IrInstructionIdCompileVar: |
| 9910 | 9927 | case IrInstructionIdSizeOf: |
| 9911 | | case IrInstructionIdTestNull: |
| 9928 | case IrInstructionIdTestNonNull: |
| 9912 | 9929 | case IrInstructionIdUnwrapMaybe: |
| 9913 | 9930 | case IrInstructionIdClz: |
| 9914 | 9931 | case IrInstructionIdCtz: |