| ... | @@ -6510,7 +6510,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit | ... | @@ -6510,7 +6510,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 6510 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, | 6510 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, |
| 6511 | IrInstruction *target_value_ptr, IrInstruction **prong_values, size_t prong_values_len, | 6511 | IrInstruction *target_value_ptr, IrInstruction **prong_values, size_t prong_values_len, |
| 6512 | ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values, | 6512 | ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values, |
| 6513 | IrInstructionSwitchElseVar **out_switch_else_var) | 6513 | IrInstructionSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) |
| 6514 | { | 6514 | { |
| 6515 | assert(switch_node->type == NodeTypeSwitchExpr); | 6515 | assert(switch_node->type == NodeTypeSwitchExpr); |
| 6516 | assert(prong_node->type == NodeTypeSwitchProng); | 6516 | assert(prong_node->type == NodeTypeSwitchProng); |
| ... | @@ -6528,27 +6528,27 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit | ... | @@ -6528,27 +6528,27 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 6528 | ZigVar *var = ir_create_var(irb, var_symbol_node, scope, | 6528 | ZigVar *var = ir_create_var(irb, var_symbol_node, scope, |
| 6529 | var_name, is_const, is_const, is_shadowable, var_is_comptime); | 6529 | var_name, is_const, is_const, is_shadowable, var_is_comptime); |
| 6530 | child_scope = var->child_scope; | 6530 | child_scope = var->child_scope; |
| 6531 | IrInstruction *var_value; | 6531 | IrInstruction *var_ptr; |
| 6532 | if (out_switch_else_var != nullptr) { | 6532 | if (out_switch_else_var != nullptr) { |
| 6533 | IrInstructionSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, | 6533 | IrInstructionSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, |
| 6534 | target_value_ptr); | 6534 | target_value_ptr); |
| 6535 | *out_switch_else_var = switch_else_var; | 6535 | *out_switch_else_var = switch_else_var; |
| 6536 | IrInstruction *var_ptr_value = &switch_else_var->base; | 6536 | IrInstruction *payload_ptr = &switch_else_var->base; |
| 6537 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); | 6537 | var_ptr = var_is_ptr ? ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; |
| 6538 | } else if (prong_values != nullptr) { | 6538 | } else if (prong_values != nullptr) { |
| 6539 | IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, | 6539 | IrInstruction *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, |
| 6540 | prong_values, prong_values_len); | 6540 | prong_values, prong_values_len); |
| 6541 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); | 6541 | var_ptr = var_is_ptr ? ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; |
| 6542 | } else { | 6542 | } else { |
| 6543 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, | 6543 | var_ptr = var_is_ptr ? |
| 6544 | target_value_ptr); | 6544 | ir_build_ref(irb, scope, var_symbol_node, target_value_ptr, true, false) : target_value_ptr; |
| 6545 | } | 6545 | } |
| 6546 | ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_value); | 6546 | ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_ptr); |
| 6547 | } else { | 6547 | } else { |
| 6548 | child_scope = scope; | 6548 | child_scope = scope; |
| 6549 | } | 6549 | } |
| 6550 | | 6550 | |
| 6551 | IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope); | 6551 | IrInstruction *expr_result = ir_gen_node_extra(irb, expr_node, child_scope, lval, result_loc); |
| 6552 | if (expr_result == irb->codegen->invalid_instruction) | 6552 | if (expr_result == irb->codegen->invalid_instruction) |
| 6553 | return false; | 6553 | return false; |
| 6554 | if (!instr_is_unreachable(expr_result)) | 6554 | if (!instr_is_unreachable(expr_result)) |
| ... | @@ -6558,7 +6558,15 @@ target_value_ptr); | ... | @@ -6558,7 +6558,15 @@ target_value_ptr); |
| 6558 | return true; | 6558 | return true; |
| 6559 | } | 6559 | } |
| 6560 | | 6560 | |
| 6561 | static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 6561 | static void next_peer_block(ZigList<ResultLocPeer> *list, IrBasicBlock *next_bb) { |
| | 6562 | if (list->length >= 2) { |
| | 6563 | list->at(list->length - 2).next_bb = next_bb; |
| | 6564 | } |
| | 6565 | } |
| | 6566 | |
| | 6567 | static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| | 6568 | ResultLoc *result_loc) |
| | 6569 | { |
| 6562 | assert(node->type == NodeTypeSwitchExpr); | 6570 | assert(node->type == NodeTypeSwitchExpr); |
| 6563 | | 6571 | |
| 6564 | AstNode *target_node = node->data.switch_expr.expr; | 6572 | AstNode *target_node = node->data.switch_expr.expr; |
| ... | @@ -6589,6 +6597,12 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6589,6 +6597,12 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6589 | | 6597 | |
| 6590 | IrInstructionSwitchElseVar *switch_else_var = nullptr; | 6598 | IrInstructionSwitchElseVar *switch_else_var = nullptr; |
| 6591 | | 6599 | |
| | 6600 | ResultLocPeerParent *peer_parent = allocate<ResultLocPeerParent>(1); |
| | 6601 | peer_parent->base.id = ResultLocIdPeerParent; |
| | 6602 | peer_parent->parent = result_loc; |
| | 6603 | |
| | 6604 | ZigList<ResultLocPeer> peer_result_locs = {}; |
| | 6605 | |
| 6592 | // First do the else and the ranges | 6606 | // First do the else and the ranges |
| 6593 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); | 6607 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); |
| 6594 | Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); | 6608 | Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); |
| ... | @@ -6597,6 +6611,9 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6597,6 +6611,9 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6597 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); | 6611 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 6598 | size_t prong_item_count = prong_node->data.switch_prong.items.length; | 6612 | size_t prong_item_count = prong_node->data.switch_prong.items.length; |
| 6599 | if (prong_item_count == 0) { | 6613 | if (prong_item_count == 0) { |
| | 6614 | ResultLocPeer *this_peer_result_loc = peer_result_locs.add_one(); |
| | 6615 | this_peer_result_loc->base.id = ResultLocIdPeer; |
| | 6616 | this_peer_result_loc->parent = peer_parent; |
| 6600 | if (else_prong) { | 6617 | if (else_prong) { |
| 6601 | ErrorMsg *msg = add_node_error(irb->codegen, prong_node, | 6618 | ErrorMsg *msg = add_node_error(irb->codegen, prong_node, |
| 6602 | buf_sprintf("multiple else prongs in switch expression")); | 6619 | buf_sprintf("multiple else prongs in switch expression")); |
| ... | @@ -6607,15 +6624,20 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6607,15 +6624,20 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6607 | else_prong = prong_node; | 6624 | else_prong = prong_node; |
| 6608 | | 6625 | |
| 6609 | IrBasicBlock *prev_block = irb->current_basic_block; | 6626 | IrBasicBlock *prev_block = irb->current_basic_block; |
| | 6627 | next_peer_block(&peer_result_locs, else_block); |
| 6610 | ir_set_cursor_at_end_and_append_block(irb, else_block); | 6628 | ir_set_cursor_at_end_and_append_block(irb, else_block); |
| 6611 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6629 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6612 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, | 6630 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, |
| 6613 | &switch_else_var)) | 6631 | &switch_else_var, lval, &this_peer_result_loc->base)) |
| 6614 | { | 6632 | { |
| 6615 | return irb->codegen->invalid_instruction; | 6633 | return irb->codegen->invalid_instruction; |
| 6616 | } | 6634 | } |
| 6617 | ir_set_cursor_at_end(irb, prev_block); | 6635 | ir_set_cursor_at_end(irb, prev_block); |
| 6618 | } else if (prong_node->data.switch_prong.any_items_are_range) { | 6636 | } else if (prong_node->data.switch_prong.any_items_are_range) { |
| | 6637 | ResultLocPeer *this_peer_result_loc = peer_result_locs.add_one(); |
| | 6638 | this_peer_result_loc->base.id = ResultLocIdPeer; |
| | 6639 | this_peer_result_loc->parent = peer_parent; |
| | 6640 | |
| 6619 | IrInstruction *ok_bit = nullptr; | 6641 | IrInstruction *ok_bit = nullptr; |
| 6620 | AstNode *last_item_node = nullptr; | 6642 | AstNode *last_item_node = nullptr; |
| 6621 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { | 6643 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { |
| ... | @@ -6675,10 +6697,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6675,10 +6697,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6675 | ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes, | 6697 | ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes, |
| 6676 | range_block_no, is_comptime)); | 6698 | range_block_no, is_comptime)); |
| 6677 | | 6699 | |
| | 6700 | next_peer_block(&peer_result_locs, range_block_yes); |
| 6678 | ir_set_cursor_at_end_and_append_block(irb, range_block_yes); | 6701 | ir_set_cursor_at_end_and_append_block(irb, range_block_yes); |
| 6679 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6702 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6680 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, | 6703 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, |
| 6681 | &incoming_blocks, &incoming_values, nullptr)) | 6704 | &incoming_blocks, &incoming_values, nullptr, lval, &this_peer_result_loc->base)) |
| 6682 | { | 6705 | { |
| 6683 | return irb->codegen->invalid_instruction; | 6706 | return irb->codegen->invalid_instruction; |
| 6684 | } | 6707 | } |
| ... | @@ -6696,6 +6719,10 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6696,6 +6719,10 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6696 | if (prong_node->data.switch_prong.any_items_are_range) | 6719 | if (prong_node->data.switch_prong.any_items_are_range) |
| 6697 | continue; | 6720 | continue; |
| 6698 | | 6721 | |
| | 6722 | ResultLocPeer *this_peer_result_loc = peer_result_locs.add_one(); |
| | 6723 | this_peer_result_loc->base.id = ResultLocIdPeer; |
| | 6724 | this_peer_result_loc->parent = peer_parent; |
| | 6725 | |
| 6699 | IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); | 6726 | IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); |
| 6700 | IrInstruction **items = allocate<IrInstruction *>(prong_item_count); | 6727 | IrInstruction **items = allocate<IrInstruction *>(prong_item_count); |
| 6701 | | 6728 | |
| ... | @@ -6719,10 +6746,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6719,10 +6746,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6719 | } | 6746 | } |
| 6720 | | 6747 | |
| 6721 | IrBasicBlock *prev_block = irb->current_basic_block; | 6748 | IrBasicBlock *prev_block = irb->current_basic_block; |
| | 6749 | next_peer_block(&peer_result_locs, prong_block); |
| 6722 | ir_set_cursor_at_end_and_append_block(irb, prong_block); | 6750 | ir_set_cursor_at_end_and_append_block(irb, prong_block); |
| 6723 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6751 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6724 | is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, | 6752 | is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, |
| 6725 | &incoming_blocks, &incoming_values, nullptr)) | 6753 | &incoming_blocks, &incoming_values, nullptr, lval, &this_peer_result_loc->base)) |
| 6726 | { | 6754 | { |
| 6727 | return irb->codegen->invalid_instruction; | 6755 | return irb->codegen->invalid_instruction; |
| 6728 | } | 6756 | } |
| ... | @@ -6731,31 +6759,48 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6731,31 +6759,48 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6731 | | 6759 | |
| 6732 | } | 6760 | } |
| 6733 | | 6761 | |
| 6734 | IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length, | 6762 | IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, |
| 6735 | else_prong != nullptr); | 6763 | check_ranges.items, check_ranges.length, else_prong != nullptr); |
| 6736 | | 6764 | |
| | 6765 | IrInstruction *br_instruction; |
| 6737 | if (cases.length == 0) { | 6766 | if (cases.length == 0) { |
| 6738 | ir_build_br(irb, scope, node, else_block, is_comptime); | 6767 | br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); |
| 6739 | } else { | 6768 | } else { |
| 6740 | IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, scope, node, target_value, else_block, | 6769 | IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, scope, node, target_value, else_block, |
| 6741 | cases.length, cases.items, is_comptime, switch_prongs_void); | 6770 | cases.length, cases.items, is_comptime, switch_prongs_void); |
| 6742 | if (switch_else_var != nullptr) { | 6771 | if (switch_else_var != nullptr) { |
| 6743 | switch_else_var->switch_br = switch_br; | 6772 | switch_else_var->switch_br = switch_br; |
| 6744 | } | 6773 | } |
| | 6774 | br_instruction = &switch_br->base; |
| | 6775 | } |
| | 6776 | for (size_t i = 0; i < peer_result_locs.length; i += 1) { |
| | 6777 | peer_result_locs.at(i).base.source_instruction = br_instruction; |
| 6745 | } | 6778 | } |
| | 6779 | peer_parent->base.source_instruction = br_instruction; |
| | 6780 | peer_parent->peer_count = peer_result_locs.length; |
| | 6781 | peer_parent->peers = peer_result_locs.items; |
| 6746 | | 6782 | |
| 6747 | if (!else_prong) { | 6783 | if (!else_prong) { |
| | 6784 | if (peer_result_locs.length != 0) { |
| | 6785 | peer_result_locs.last().next_bb = else_block; |
| | 6786 | } |
| 6748 | ir_set_cursor_at_end_and_append_block(irb, else_block); | 6787 | ir_set_cursor_at_end_and_append_block(irb, else_block); |
| 6749 | ir_build_unreachable(irb, scope, node); | 6788 | ir_build_unreachable(irb, scope, node); |
| | 6789 | } else { |
| | 6790 | if (peer_result_locs.length != 0) { |
| | 6791 | peer_result_locs.last().next_bb = end_block; |
| | 6792 | } |
| 6750 | } | 6793 | } |
| 6751 | | 6794 | |
| 6752 | ir_set_cursor_at_end_and_append_block(irb, end_block); | 6795 | ir_set_cursor_at_end_and_append_block(irb, end_block); |
| 6753 | assert(incoming_blocks.length == incoming_values.length); | 6796 | assert(incoming_blocks.length == incoming_values.length); |
| | 6797 | IrInstruction *result_instruction; |
| 6754 | if (incoming_blocks.length == 0) { | 6798 | if (incoming_blocks.length == 0) { |
| 6755 | return ir_build_const_void(irb, scope, node); | 6799 | result_instruction = ir_build_const_void(irb, scope, node); |
| 6756 | } else { | 6800 | } else { |
| 6757 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); | 6801 | result_instruction = ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 6758 | } | 6802 | } |
| | 6803 | return ir_expr_wrap(irb, scope, result_instruction, result_loc); |
| 6759 | } | 6804 | } |
| 6760 | | 6805 | |
| 6761 | static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { | 6806 | static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { |
| ... | @@ -7828,7 +7873,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -7828,7 +7873,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 7828 | case NodeTypeIfOptional: | 7873 | case NodeTypeIfOptional: |
| 7829 | return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval, result_loc); | 7874 | return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval, result_loc); |
| 7830 | case NodeTypeSwitchExpr: | 7875 | case NodeTypeSwitchExpr: |
| 7831 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval, result_loc); | 7876 | return ir_gen_switch_expr(irb, scope, node, lval, result_loc); |
| 7832 | case NodeTypeCompTime: | 7877 | case NodeTypeCompTime: |
| 7833 | return ir_gen_comptime(irb, scope, node, lval); | 7878 | return ir_gen_comptime(irb, scope, node, lval); |
| 7834 | case NodeTypeErrorType: | 7879 | case NodeTypeErrorType: |