| ... | @@ -226,6 +226,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) { | ... | @@ -226,6 +226,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) { |
| 226 | return IrInstructionIdSizeOf; | 226 | return IrInstructionIdSizeOf; |
| 227 | } | 227 | } |
| 228 | | 228 | |
| | 229 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNull *) { |
| | 230 | return IrInstructionIdTestNull; |
| | 231 | } |
| | 232 | |
| | 233 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) { |
| | 234 | return IrInstructionIdUnwrapMaybe; |
| | 235 | } |
| | 236 | |
| 229 | template<typename T> | 237 | template<typename T> |
| 230 | static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { | 238 | static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { |
| 231 | T *special_instruction = allocate<T>(1); | 239 | T *special_instruction = allocate<T>(1); |
| ... | @@ -878,6 +886,44 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrI | ... | @@ -878,6 +886,44 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrI |
| 878 | return &instruction->base; | 886 | return &instruction->base; |
| 879 | } | 887 | } |
| 880 | | 888 | |
| | 889 | static IrInstruction *ir_build_test_null(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { |
| | 890 | IrInstructionTestNull *instruction = ir_build_instruction<IrInstructionTestNull>(irb, source_node); |
| | 891 | instruction->value = value; |
| | 892 | |
| | 893 | ir_ref_instruction(value); |
| | 894 | |
| | 895 | return &instruction->base; |
| | 896 | } |
| | 897 | |
| | 898 | static IrInstruction *ir_build_test_null_from(IrBuilder *irb, IrInstruction *old_instruction, |
| | 899 | IrInstruction *value) |
| | 900 | { |
| | 901 | IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->source_node, value); |
| | 902 | ir_link_new_instruction(new_instruction, old_instruction); |
| | 903 | return new_instruction; |
| | 904 | } |
| | 905 | |
| | 906 | static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, AstNode *source_node, IrInstruction *value, |
| | 907 | bool safety_check_on) |
| | 908 | { |
| | 909 | IrInstructionUnwrapMaybe *instruction = ir_build_instruction<IrInstructionUnwrapMaybe>(irb, source_node); |
| | 910 | instruction->value = value; |
| | 911 | instruction->safety_check_on = safety_check_on; |
| | 912 | |
| | 913 | ir_ref_instruction(value); |
| | 914 | |
| | 915 | return &instruction->base; |
| | 916 | } |
| | 917 | |
| | 918 | static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *old_instruction, |
| | 919 | IrInstruction *value, bool safety_check_on) |
| | 920 | { |
| | 921 | IrInstruction *new_instruction = ir_build_unwrap_maybe(irb, old_instruction->source_node, |
| | 922 | value, safety_check_on); |
| | 923 | ir_link_new_instruction(new_instruction, old_instruction); |
| | 924 | return new_instruction; |
| | 925 | } |
| | 926 | |
| 881 | static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, | 927 | static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, |
| 882 | bool gen_error_defers, bool gen_maybe_defers) | 928 | bool gen_error_defers, bool gen_maybe_defers) |
| 883 | { | 929 | { |
| ... | @@ -1164,7 +1210,6 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, AstNode *node) { | ... | @@ -1164,7 +1210,6 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, AstNode *node) { |
| 1164 | return ir_build_const_null(irb, node); | 1210 | return ir_build_const_null(irb, node); |
| 1165 | } | 1211 | } |
| 1166 | | 1212 | |
| 1167 | | | |
| 1168 | static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node, | 1213 | static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node, |
| 1169 | LValPurpose lval, BlockContext *scope) | 1214 | LValPurpose lval, BlockContext *scope) |
| 1170 | { | 1215 | { |
| ... | @@ -1502,6 +1547,15 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, AstNode *node, IrUnOp | ... | @@ -1502,6 +1547,15 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, AstNode *node, IrUnOp |
| 1502 | return ir_gen_prefix_op_id_lval(irb, node, op_id, LValPurposeNone); | 1547 | return ir_gen_prefix_op_id_lval(irb, node, op_id, LValPurposeNone); |
| 1503 | } | 1548 | } |
| 1504 | | 1549 | |
| | 1550 | static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, AstNode *node) { |
| | 1551 | AstNode *expr = node->data.prefix_op_expr.primary_expr; |
| | 1552 | IrInstruction *value = ir_gen_node(irb, expr, node->block_context); |
| | 1553 | if (value == irb->codegen->invalid_instruction) |
| | 1554 | return value; |
| | 1555 | |
| | 1556 | return ir_build_unwrap_maybe(irb, node, value, true); |
| | 1557 | } |
| | 1558 | |
| 1505 | static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValPurpose lval) { | 1559 | static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValPurpose lval) { |
| 1506 | assert(node->type == NodeTypePrefixOpExpr); | 1560 | assert(node->type == NodeTypePrefixOpExpr); |
| 1507 | | 1561 | |
| ... | @@ -1531,7 +1585,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValP | ... | @@ -1531,7 +1585,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValP |
| 1531 | case PrefixOpUnwrapError: | 1585 | case PrefixOpUnwrapError: |
| 1532 | return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapError); | 1586 | return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapError); |
| 1533 | case PrefixOpUnwrapMaybe: | 1587 | case PrefixOpUnwrapMaybe: |
| 1534 | return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapMaybe); | 1588 | return ir_gen_prefix_op_unwrap_maybe(irb, node); |
| 1535 | } | 1589 | } |
| 1536 | zig_unreachable(); | 1590 | zig_unreachable(); |
| 1537 | } | 1591 | } |
| ... | @@ -1883,6 +1937,69 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { | ... | @@ -1883,6 +1937,69 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { |
| 1883 | return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile); | 1937 | return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile); |
| 1884 | } | 1938 | } |
| 1885 | | 1939 | |
| | 1940 | static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { |
| | 1941 | assert(node->type == NodeTypeIfVarExpr); |
| | 1942 | |
| | 1943 | AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl; |
| | 1944 | AstNode *expr_node = var_decl->expr; |
| | 1945 | AstNode *then_node = node->data.if_var_expr.then_block; |
| | 1946 | AstNode *else_node = node->data.if_var_expr.else_node; |
| | 1947 | bool var_is_ptr = node->data.if_var_expr.var_is_ptr; |
| | 1948 | |
| | 1949 | IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, node->block_context, LValPurposeAddressOf); |
| | 1950 | if (expr_value == irb->codegen->invalid_instruction) |
| | 1951 | return expr_value; |
| | 1952 | |
| | 1953 | IrInstruction *is_nonnull_value = ir_build_test_null(irb, node, expr_value); |
| | 1954 | |
| | 1955 | IrBasicBlock *then_block = ir_build_basic_block(irb, "MaybeThen"); |
| | 1956 | IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse"); |
| | 1957 | IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf"); |
| | 1958 | |
| | 1959 | bool is_inline = (node->block_context->fn_entry == nullptr); |
| | 1960 | ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline); |
| | 1961 | |
| | 1962 | ir_set_cursor_at_end(irb, then_block); |
| | 1963 | IrInstruction *var_type = nullptr; |
| | 1964 | if (var_decl->type) |
| | 1965 | var_type = ir_gen_node(irb, var_decl->type, node->block_context); |
| | 1966 | BlockContext *child_scope = new_block_context(node, node->block_context); |
| | 1967 | bool is_shadowable = false; |
| | 1968 | bool is_const = var_decl->is_const; |
| | 1969 | VariableTableEntry *var = ir_add_local_var(irb, node, child_scope, |
| | 1970 | var_decl->symbol, is_const, is_const, is_shadowable, is_inline); |
| | 1971 | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, node, expr_value, false); |
| | 1972 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, node, var_ptr_value); |
| | 1973 | ir_build_var_decl(irb, node, var, var_type, var_value); |
| | 1974 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, child_scope); |
| | 1975 | if (then_expr_result == irb->codegen->invalid_instruction) |
| | 1976 | return then_expr_result; |
| | 1977 | IrBasicBlock *after_then_block = irb->current_basic_block; |
| | 1978 | ir_build_br(irb, node, endif_block, is_inline); |
| | 1979 | |
| | 1980 | ir_set_cursor_at_end(irb, else_block); |
| | 1981 | IrInstruction *else_expr_result; |
| | 1982 | if (else_node) { |
| | 1983 | else_expr_result = ir_gen_node(irb, else_node, node->block_context); |
| | 1984 | if (else_expr_result == irb->codegen->invalid_instruction) |
| | 1985 | return else_expr_result; |
| | 1986 | } else { |
| | 1987 | else_expr_result = ir_build_const_void(irb, node); |
| | 1988 | } |
| | 1989 | IrBasicBlock *after_else_block = irb->current_basic_block; |
| | 1990 | ir_build_br(irb, node, endif_block, is_inline); |
| | 1991 | |
| | 1992 | ir_set_cursor_at_end(irb, endif_block); |
| | 1993 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| | 1994 | incoming_values[0] = then_expr_result; |
| | 1995 | incoming_values[1] = else_expr_result; |
| | 1996 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| | 1997 | incoming_blocks[0] = after_then_block; |
| | 1998 | incoming_blocks[1] = after_else_block; |
| | 1999 | |
| | 2000 | return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values); |
| | 2001 | } |
| | 2002 | |
| 1886 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, | 2003 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| 1887 | LValPurpose lval) | 2004 | LValPurpose lval) |
| 1888 | { | 2005 | { |
| ... | @@ -1932,10 +2049,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont | ... | @@ -1932,10 +2049,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1932 | return ir_gen_asm_expr(irb, node); | 2049 | return ir_gen_asm_expr(irb, node); |
| 1933 | case NodeTypeNullLiteral: | 2050 | case NodeTypeNullLiteral: |
| 1934 | return ir_gen_null_literal(irb, node); | 2051 | return ir_gen_null_literal(irb, node); |
| | 2052 | case NodeTypeIfVarExpr: |
| | 2053 | return ir_gen_if_var_expr(irb, node); |
| 1935 | case NodeTypeUnwrapErrorExpr: | 2054 | case NodeTypeUnwrapErrorExpr: |
| 1936 | case NodeTypeDefer: | 2055 | case NodeTypeDefer: |
| 1937 | case NodeTypeSliceExpr: | 2056 | case NodeTypeSliceExpr: |
| 1938 | case NodeTypeIfVarExpr: | | |
| 1939 | case NodeTypeGoto: | 2057 | case NodeTypeGoto: |
| 1940 | case NodeTypeBreak: | 2058 | case NodeTypeBreak: |
| 1941 | case NodeTypeContinue: | 2059 | case NodeTypeContinue: |
| ... | @@ -4488,6 +4606,82 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, | ... | @@ -4488,6 +4606,82 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 4488 | zig_unreachable(); | 4606 | zig_unreachable(); |
| 4489 | } | 4607 | } |
| 4490 | | 4608 | |
| | 4609 | static TypeTableEntry *ir_analyze_instruction_test_null(IrAnalyze *ira, |
| | 4610 | IrInstructionTestNull *test_null_instruction) |
| | 4611 | { |
| | 4612 | IrInstruction *value = test_null_instruction->value->other; |
| | 4613 | if (value->type_entry->id == TypeTableEntryIdInvalid) |
| | 4614 | return ira->codegen->builtin_types.entry_invalid; |
| | 4615 | |
| | 4616 | // This will be a pointer type because test null IR instruction operates on a pointer to a thing. |
| | 4617 | TypeTableEntry *ptr_type = value->type_entry; |
| | 4618 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| | 4619 | |
| | 4620 | TypeTableEntry *type_entry = ptr_type->data.pointer.child_type; |
| | 4621 | if (type_entry->id != TypeTableEntryIdMaybe) { |
| | 4622 | add_node_error(ira->codegen, test_null_instruction->base.source_node, |
| | 4623 | buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name))); |
| | 4624 | return ira->codegen->builtin_types.entry_invalid; |
| | 4625 | } |
| | 4626 | |
| | 4627 | if (value->static_value.special != ConstValSpecialRuntime) { |
| | 4628 | ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr; |
| | 4629 | assert(value->static_value.data.x_ptr.index == SIZE_MAX); |
| | 4630 | |
| | 4631 | if (maybe_val->special != ConstValSpecialRuntime) { |
| | 4632 | bool depends_on_compile_var = maybe_val->depends_on_compile_var; |
| | 4633 | ConstExprValue *out_val = ir_build_const_from(ira, &test_null_instruction->base, |
| | 4634 | depends_on_compile_var); |
| | 4635 | out_val->data.x_bool = (maybe_val->data.x_maybe == nullptr); |
| | 4636 | return ira->codegen->builtin_types.entry_bool; |
| | 4637 | } |
| | 4638 | } |
| | 4639 | |
| | 4640 | ir_build_test_null_from(&ira->new_irb, &test_null_instruction->base, value); |
| | 4641 | return ira->codegen->builtin_types.entry_bool; |
| | 4642 | } |
| | 4643 | |
| | 4644 | static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, |
| | 4645 | IrInstructionUnwrapMaybe *unwrap_maybe_instruction) |
| | 4646 | { |
| | 4647 | IrInstruction *value = unwrap_maybe_instruction->value->other; |
| | 4648 | if (value->type_entry->id == TypeTableEntryIdInvalid) |
| | 4649 | return ira->codegen->builtin_types.entry_invalid; |
| | 4650 | |
| | 4651 | // This will be a pointer type because test null IR instruction operates on a pointer to a thing. |
| | 4652 | TypeTableEntry *ptr_type = value->type_entry; |
| | 4653 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| | 4654 | |
| | 4655 | TypeTableEntry *type_entry = ptr_type->data.pointer.child_type; |
| | 4656 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| | 4657 | return ira->codegen->builtin_types.entry_invalid; |
| | 4658 | } else if (type_entry->id != TypeTableEntryIdMaybe) { |
| | 4659 | add_node_error(ira->codegen, unwrap_maybe_instruction->base.source_node, |
| | 4660 | buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name))); |
| | 4661 | return ira->codegen->builtin_types.entry_invalid; |
| | 4662 | } |
| | 4663 | TypeTableEntry *child_type = type_entry->data.maybe.child_type; |
| | 4664 | TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false); |
| | 4665 | |
| | 4666 | if (value->static_value.special != ConstValSpecialRuntime) { |
| | 4667 | ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr; |
| | 4668 | assert(value->static_value.data.x_ptr.index == SIZE_MAX); |
| | 4669 | |
| | 4670 | if (maybe_val->special != ConstValSpecialRuntime) { |
| | 4671 | bool depends_on_compile_var = maybe_val->depends_on_compile_var; |
| | 4672 | ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base, |
| | 4673 | depends_on_compile_var); |
| | 4674 | out_val->data.x_ptr.base_ptr = maybe_val; |
| | 4675 | out_val->data.x_ptr.index = SIZE_MAX; |
| | 4676 | return result_type; |
| | 4677 | } |
| | 4678 | } |
| | 4679 | |
| | 4680 | ir_build_unwrap_maybe_from(&ira->new_irb, &unwrap_maybe_instruction->base, value, |
| | 4681 | unwrap_maybe_instruction->safety_check_on); |
| | 4682 | return result_type; |
| | 4683 | } |
| | 4684 | |
| 4491 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 4685 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 4492 | switch (instruction->id) { | 4686 | switch (instruction->id) { |
| 4493 | case IrInstructionIdInvalid: | 4687 | case IrInstructionIdInvalid: |
| ... | @@ -4544,6 +4738,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -4544,6 +4738,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4544 | return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction); | 4738 | return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction); |
| 4545 | case IrInstructionIdSizeOf: | 4739 | case IrInstructionIdSizeOf: |
| 4546 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); | 4740 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| | 4741 | case IrInstructionIdTestNull: |
| | 4742 | return ir_analyze_instruction_test_null(ira, (IrInstructionTestNull *)instruction); |
| | 4743 | case IrInstructionIdUnwrapMaybe: |
| | 4744 | return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction); |
| 4547 | case IrInstructionIdSwitchBr: | 4745 | case IrInstructionIdSwitchBr: |
| 4548 | case IrInstructionIdCast: | 4746 | case IrInstructionIdCast: |
| 4549 | case IrInstructionIdContainerInitList: | 4747 | case IrInstructionIdContainerInitList: |
| ... | @@ -4654,6 +4852,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -4654,6 +4852,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 4654 | case IrInstructionIdSliceType: | 4852 | case IrInstructionIdSliceType: |
| 4655 | case IrInstructionIdCompileVar: | 4853 | case IrInstructionIdCompileVar: |
| 4656 | case IrInstructionIdSizeOf: | 4854 | case IrInstructionIdSizeOf: |
| | 4855 | case IrInstructionIdTestNull: |
| | 4856 | case IrInstructionIdUnwrapMaybe: |
| 4657 | return false; | 4857 | return false; |
| 4658 | case IrInstructionIdAsm: | 4858 | case IrInstructionIdAsm: |
| 4659 | { | 4859 | { |
| ... | @@ -6266,32 +6466,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { | ... | @@ -6266,32 +6466,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 6266 | // return result_type; | 6466 | // return result_type; |
| 6267 | //} | 6467 | //} |
| 6268 | // | 6468 | // |
| 6269 | //static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | | |
| 6270 | // TypeTableEntry *expected_type, AstNode *node) | | |
| 6271 | //{ | | |
| 6272 | // assert(node->type == NodeTypeIfVarExpr); | | |
| 6273 | // | | |
| 6274 | // BlockContext *child_context = new_block_context(node, parent_context); | | |
| 6275 | // | | |
| 6276 | // analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true, | | |
| 6277 | // nullptr, node->data.if_var_expr.var_is_ptr); | | |
| 6278 | // VariableTableEntry *var = node->data.if_var_expr.var_decl.variable; | | |
| 6279 | // if (var->type->id == TypeTableEntryIdInvalid) { | | |
| 6280 | // return g->builtin_types.entry_invalid; | | |
| 6281 | // } | | |
| 6282 | // AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr; | | |
| 6283 | // ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val; | | |
| 6284 | // bool cond_is_const = var_const_val->ok; | | |
| 6285 | // bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false; | | |
| 6286 | // | | |
| 6287 | // | | |
| 6288 | // AstNode **then_node = &node->data.if_var_expr.then_block; | | |
| 6289 | // AstNode **else_node = &node->data.if_var_expr.else_node; | | |
| 6290 | // | | |
| 6291 | // return analyze_if(g, import, child_context, expected_type, | | |
| 6292 | // node, then_node, else_node, cond_is_const, cond_bool_val); | | |
| 6293 | //} | | |
| 6294 | // | | |
| 6295 | //static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type, | 6469 | //static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type, |
| 6296 | // TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry) | 6470 | // TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry) |
| 6297 | //{ | 6471 | //{ |
| ... | @@ -7407,92 +7581,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { | ... | @@ -7407,92 +7581,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 7407 | // } | 7581 | // } |
| 7408 | //} | 7582 | //} |
| 7409 | // | 7583 | // |
| 7410 | // | | |
| 7411 | //static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, | | |
| 7412 | // BlockContext *context, AstNode *source_node, | | |
| 7413 | // AstNodeVariableDeclaration *variable_declaration, | | |
| 7414 | // bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr) | | |
| 7415 | //{ | | |
| 7416 | // bool is_const = variable_declaration->is_const; | | |
| 7417 | // bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); | | |
| 7418 | // bool is_extern = variable_declaration->is_extern; | | |
| 7419 | // | | |
| 7420 | // TypeTableEntry *explicit_type = nullptr; | | |
| 7421 | // if (variable_declaration->type != nullptr) { | | |
| 7422 | // explicit_type = analyze_type_expr(g, import, context, variable_declaration->type); | | |
| 7423 | // if (explicit_type->id == TypeTableEntryIdUnreachable) { | | |
| 7424 | // add_node_error(g, variable_declaration->type, | | |
| 7425 | // buf_sprintf("variable of type 'unreachable' not allowed")); | | |
| 7426 | // explicit_type = g->builtin_types.entry_invalid; | | |
| 7427 | // } | | |
| 7428 | // } | | |
| 7429 | // | | |
| 7430 | // TypeTableEntry *implicit_type = nullptr; | | |
| 7431 | // if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { | | |
| 7432 | // implicit_type = explicit_type; | | |
| 7433 | // } else if (variable_declaration->expr) { | | |
| 7434 | // implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr); | | |
| 7435 | // if (implicit_type->id == TypeTableEntryIdInvalid) { | | |
| 7436 | // // ignore the poison value | | |
| 7437 | // } else if (expr_is_maybe) { | | |
| 7438 | // if (implicit_type->id == TypeTableEntryIdMaybe) { | | |
| 7439 | // if (var_is_ptr) { | | |
| 7440 | // // TODO if the expression is constant, can't get pointer to it | | |
| 7441 | // implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false); | | |
| 7442 | // } else { | | |
| 7443 | // implicit_type = implicit_type->data.maybe.child_type; | | |
| 7444 | // } | | |
| 7445 | // } else { | | |
| 7446 | // add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type")); | | |
| 7447 | // implicit_type = g->builtin_types.entry_invalid; | | |
| 7448 | // } | | |
| 7449 | // } else if (implicit_type->id == TypeTableEntryIdUnreachable) { | | |
| 7450 | // add_node_error(g, source_node, | | |
| 7451 | // buf_sprintf("variable initialization is unreachable")); | | |
| 7452 | // implicit_type = g->builtin_types.entry_invalid; | | |
| 7453 | // } else if ((!is_const || is_export) && | | |
| 7454 | // (implicit_type->id == TypeTableEntryIdNumLitFloat || | | |
| 7455 | // implicit_type->id == TypeTableEntryIdNumLitInt)) | | |
| 7456 | // { | | |
| 7457 | // add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); | | |
| 7458 | // implicit_type = g->builtin_types.entry_invalid; | | |
| 7459 | // } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) { | | |
| 7460 | // add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); | | |
| 7461 | // implicit_type = g->builtin_types.entry_invalid; | | |
| 7462 | // } | | |
| 7463 | // if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) { | | |
| 7464 | // ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val; | | |
| 7465 | // if (!const_val->ok) { | | |
| 7466 | // add_node_error(g, first_executing_node(variable_declaration->expr), | | |
| 7467 | // buf_sprintf("global variable initializer requires constant expression")); | | |
| 7468 | // } | | |
| 7469 | // } | | |
| 7470 | // } else if (!is_extern) { | | |
| 7471 | // add_node_error(g, source_node, buf_sprintf("variables must be initialized")); | | |
| 7472 | // implicit_type = g->builtin_types.entry_invalid; | | |
| 7473 | // } | | |
| 7474 | // | | |
| 7475 | // TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type; | | |
| 7476 | // assert(type != nullptr); // should have been caught by the parser | | |
| 7477 | // | | |
| 7478 | // VariableTableEntry *var = add_local_var(g, source_node, import, context, | | |
| 7479 | // variable_declaration->symbol, type, is_const, | | |
| 7480 | // expr_is_maybe ? nullptr : variable_declaration->expr); | | |
| 7481 | // | | |
| 7482 | // variable_declaration->variable = var; | | |
| 7483 | // | | |
| 7484 | // return var; | | |
| 7485 | //} | | |
| 7486 | // | | |
| 7487 | //static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, | | |
| 7488 | // BlockContext *context, TypeTableEntry *expected_type, AstNode *node) | | |
| 7489 | //{ | | |
| 7490 | // AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; | | |
| 7491 | // return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, | | |
| 7492 | // false, nullptr, false); | | |
| 7493 | //} | | |
| 7494 | // | | |
| 7495 | // | | |
| 7496 | //static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 7584 | //static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 7497 | // TypeTableEntry *expected_type, AstNode *node) | 7585 | // TypeTableEntry *expected_type, AstNode *node) |
| 7498 | //{ | 7586 | //{ |
| ... | @@ -8581,64 +8669,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no | ... | @@ -8581,64 +8669,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 8581 | // return nullptr; | 8669 | // return nullptr; |
| 8582 | //} | 8670 | //} |
| 8583 | // | 8671 | // |
| 8584 | //static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { | | |
| 8585 | // assert(node->type == NodeTypeBinOpExpr); | | |
| 8586 | // assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe); | | |
| 8587 | // | | |
| 8588 | // AstNode *op1_node = node->data.bin_op_expr.op1; | | |
| 8589 | // AstNode *op2_node = node->data.bin_op_expr.op2; | | |
| 8590 | // | | |
| 8591 | // LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node); | | |
| 8592 | // | | |
| 8593 | // TypeTableEntry *maybe_type = get_expr_type(op1_node); | | |
| 8594 | // assert(maybe_type->id == TypeTableEntryIdMaybe); | | |
| 8595 | // TypeTableEntry *child_type = maybe_type->data.maybe.child_type; | | |
| 8596 | // | | |
| 8597 | // LLVMValueRef cond_value; | | |
| 8598 | // if (child_type->id == TypeTableEntryIdPointer || | | |
| 8599 | // child_type->id == TypeTableEntryIdFn) | | |
| 8600 | // { | | |
| 8601 | // cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, | | |
| 8602 | // LLVMConstNull(child_type->type_ref), ""); | | |
| 8603 | // } else { | | |
| 8604 | // LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, ""); | | |
| 8605 | // cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | | |
| 8606 | // } | | |
| 8607 | // | | |
| 8608 | // LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull"); | | |
| 8609 | // LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull"); | | |
| 8610 | // LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd"); | | |
| 8611 | // | | |
| 8612 | // bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable; | | |
| 8613 | // | | |
| 8614 | // LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block); | | |
| 8615 | // | | |
| 8616 | // LLVMPositionBuilderAtEnd(g->builder, non_null_block); | | |
| 8617 | // LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref); | | |
| 8618 | // LLVMBuildBr(g->builder, end_block); | | |
| 8619 | // LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder); | | |
| 8620 | // | | |
| 8621 | // LLVMPositionBuilderAtEnd(g->builder, null_block); | | |
| 8622 | // LLVMValueRef null_result = gen_expr(g, op2_node); | | |
| 8623 | // if (null_reachable) { | | |
| 8624 | // LLVMBuildBr(g->builder, end_block); | | |
| 8625 | // } | | |
| 8626 | // LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder); | | |
| 8627 | // | | |
| 8628 | // LLVMPositionBuilderAtEnd(g->builder, end_block); | | |
| 8629 | // if (null_reachable) { | | |
| 8630 | // LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), ""); | | |
| 8631 | // LLVMValueRef incoming_values[2] = {non_null_result, null_result}; | | |
| 8632 | // LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block}; | | |
| 8633 | // LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); | | |
| 8634 | // return phi; | | |
| 8635 | // } else { | | |
| 8636 | // return non_null_result; | | |
| 8637 | // } | | |
| 8638 | // | | |
| 8639 | // return nullptr; | | |
| 8640 | //} | | |
| 8641 | // | | |
| 8642 | //static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { | 8672 | //static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { |
| 8643 | // assert(node->type == NodeTypeUnwrapErrorExpr); | 8673 | // assert(node->type == NodeTypeUnwrapErrorExpr); |
| 8644 | // | 8674 | // |
| ... | @@ -8914,120 +8944,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no | ... | @@ -8914,120 +8944,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 8914 | // } | 8944 | // } |
| 8915 | //} | 8945 | //} |
| 8916 | // | 8946 | // |
| 8917 | //static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTableEntry *variable, bool maybe_is_ptr, | | |
| 8918 | // LLVMValueRef init_val, TypeTableEntry *child_type, AstNode *then_node) | | |
| 8919 | //{ | | |
| 8920 | // if (node->data.if_var_expr.var_is_ptr) { | | |
| 8921 | // LLVMValueRef payload_ptr; | | |
| 8922 | // if (maybe_is_ptr) { | | |
| 8923 | // zig_panic("TODO"); | | |
| 8924 | // } else { | | |
| 8925 | // payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); | | |
| 8926 | // } | | |
| 8927 | // LLVMBuildStore(g->builder, payload_ptr, variable->value_ref); | | |
| 8928 | // } else { | | |
| 8929 | // LLVMValueRef payload_val; | | |
| 8930 | // if (maybe_is_ptr) { | | |
| 8931 | // payload_val = init_val; | | |
| 8932 | // } else { | | |
| 8933 | // LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); | | |
| 8934 | // payload_val = get_handle_value(g, payload_ptr, child_type); | | |
| 8935 | // } | | |
| 8936 | // gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val, | | |
| 8937 | // variable->type, child_type); | | |
| 8938 | // } | | |
| 8939 | // gen_var_debug_decl(g, variable); | | |
| 8940 | // | | |
| 8941 | // return gen_expr(g, then_node); | | |
| 8942 | //} | | |
| 8943 | // | | |
| 8944 | //static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { | | |
| 8945 | // assert(node->type == NodeTypeIfVarExpr); | | |
| 8946 | // assert(node->data.if_var_expr.var_decl.expr); | | |
| 8947 | // | | |
| 8948 | // AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl; | | |
| 8949 | // VariableTableEntry *variable = var_decl->variable; | | |
| 8950 | // | | |
| 8951 | // // test if value is the maybe state | | |
| 8952 | // TypeTableEntry *expr_type = get_expr_type(var_decl->expr); | | |
| 8953 | // TypeTableEntry *child_type = expr_type->data.maybe.child_type; | | |
| 8954 | // | | |
| 8955 | // LLVMValueRef init_val = gen_expr(g, var_decl->expr); | | |
| 8956 | // | | |
| 8957 | // | | |
| 8958 | // AstNode *then_node = node->data.if_var_expr.then_block; | | |
| 8959 | // AstNode *else_node = node->data.if_var_expr.else_node; | | |
| 8960 | // bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; | | |
| 8961 | // | | |
| 8962 | // ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val; | | |
| 8963 | // if (const_val->ok) { | | |
| 8964 | // if (const_val->data.x_maybe) { | | |
| 8965 | // return gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node); | | |
| 8966 | // } else { | | |
| 8967 | // return gen_expr(g, else_node); | | |
| 8968 | // } | | |
| 8969 | // } | | |
| 8970 | // | | |
| 8971 | // LLVMValueRef cond_value; | | |
| 8972 | // if (maybe_is_ptr) { | | |
| 8973 | // cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), ""); | | |
| 8974 | // } else { | | |
| 8975 | // LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, ""); | | |
| 8976 | // cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | | |
| 8977 | // } | | |
| 8978 | // | | |
| 8979 | // TypeTableEntry *then_type = get_expr_type(then_node); | | |
| 8980 | // TypeTableEntry *else_type = get_expr_type(else_node); | | |
| 8981 | // | | |
| 8982 | // bool use_then_value = type_has_bits(then_type); | | |
| 8983 | // bool use_else_value = type_has_bits(else_type); | | |
| 8984 | // | | |
| 8985 | // LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen"); | | |
| 8986 | // LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse"); | | |
| 8987 | // | | |
| 8988 | // LLVMBasicBlockRef endif_block; | | |
| 8989 | // bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable; | | |
| 8990 | // bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable; | | |
| 8991 | // if (then_endif_reachable || else_endif_reachable) { | | |
| 8992 | // endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf"); | | |
| 8993 | // } | | |
| 8994 | // | | |
| 8995 | // LLVMBuildCondBr(g->builder, cond_value, then_block, else_block); | | |
| 8996 | // | | |
| 8997 | // LLVMPositionBuilderAtEnd(g->builder, then_block); | | |
| 8998 | // LLVMValueRef then_expr_result = gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node); | | |
| 8999 | // | | |
| 9000 | // if (then_endif_reachable) { | | |
| 9001 | // LLVMBuildBr(g->builder, endif_block); | | |
| 9002 | // } | | |
| 9003 | // LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder); | | |
| 9004 | // | | |
| 9005 | // | | |
| 9006 | // LLVMPositionBuilderAtEnd(g->builder, else_block); | | |
| 9007 | // LLVMValueRef else_expr_result = gen_expr(g, else_node); | | |
| 9008 | // if (else_endif_reachable) { | | |
| 9009 | // LLVMBuildBr(g->builder, endif_block); | | |
| 9010 | // } | | |
| 9011 | // LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder); | | |
| 9012 | // | | |
| 9013 | // if (then_endif_reachable || else_endif_reachable) { | | |
| 9014 | // LLVMPositionBuilderAtEnd(g->builder, endif_block); | | |
| 9015 | // if (use_then_value && use_else_value) { | | |
| 9016 | // LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), ""); | | |
| 9017 | // LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result}; | | |
| 9018 | // LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block}; | | |
| 9019 | // LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); | | |
| 9020 | // return phi; | | |
| 9021 | // } else if (use_then_value) { | | |
| 9022 | // return then_expr_result; | | |
| 9023 | // } else if (use_else_value) { | | |
| 9024 | // return else_expr_result; | | |
| 9025 | // } | | |
| 9026 | // } | | |
| 9027 | // | | |
| 9028 | // return nullptr; | | |
| 9029 | //} | | |
| 9030 | // | | |
| 9031 | //static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { | 8947 | //static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { |
| 9032 | // assert(block_node->type == NodeTypeBlock); | 8948 | // assert(block_node->type == NodeTypeBlock); |
| 9033 | // | 8949 | // |
| ... | @@ -9667,20 +9583,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no | ... | @@ -9667,20 +9583,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 9667 | // zig_unreachable(); | 9583 | // zig_unreachable(); |
| 9668 | //} | 9584 | //} |
| 9669 | // | 9585 | // |
| 9670 | //static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) { | | |
| 9671 | // TypeTableEntry *type_entry = get_expr_type(node); | | |
| 9672 | // assert(type_entry->id == TypeTableEntryIdMaybe); | | |
| 9673 | // TypeTableEntry *child_type = type_entry->data.maybe.child_type; | | |
| 9674 | // if (child_type->id == TypeTableEntryIdPointer || | | |
| 9675 | // child_type->id == TypeTableEntryIdFn) | | |
| 9676 | // { | | |
| 9677 | // return maybe_struct_ref; | | |
| 9678 | // } else { | | |
| 9679 | // LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); | | |
| 9680 | // return get_handle_value(g, maybe_field_ptr, child_type); | | |
| 9681 | // } | | |
| 9682 | //} | | |
| 9683 | // | | |
| 9684 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { | 9586 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { |
| 9685 | // size_t result = 0; | 9587 | // size_t result = 0; |
| 9686 | // while (inner_block != outer_block) { | 9588 | // while (inner_block != outer_block) { |