| ... | ... | @@ -6510,7 +6510,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 6510 | 6510 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, |
| 6511 | 6511 | IrInstruction *target_value_ptr, IrInstruction **prong_values, size_t prong_values_len, |
| 6512 | 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 | 6515 | assert(switch_node->type == NodeTypeSwitchExpr); |
| 6516 | 6516 | assert(prong_node->type == NodeTypeSwitchProng); |
| ... | ... | @@ -6528,27 +6528,27 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 6528 | 6528 | ZigVar *var = ir_create_var(irb, var_symbol_node, scope, |
| 6529 | 6529 | var_name, is_const, is_const, is_shadowable, var_is_comptime); |
| 6530 | 6530 | child_scope = var->child_scope; |
| 6531 | | IrInstruction *var_value; |
| 6531 | IrInstruction *var_ptr; |
| 6532 | 6532 | if (out_switch_else_var != nullptr) { |
| 6533 | 6533 | IrInstructionSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, |
| 6534 | 6534 | target_value_ptr); |
| 6535 | 6535 | *out_switch_else_var = switch_else_var; |
| 6536 | | IrInstruction *var_ptr_value = &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); |
| 6536 | IrInstruction *payload_ptr = &switch_else_var->base; |
| 6537 | var_ptr = var_is_ptr ? ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; |
| 6538 | 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 | 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 | 6542 | } else { |
| 6543 | | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, |
| 6544 | | target_value_ptr); |
| 6543 | var_ptr = var_is_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 | 6547 | } else { |
| 6548 | 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 | 6552 | if (expr_result == irb->codegen->invalid_instruction) |
| 6553 | 6553 | return false; |
| 6554 | 6554 | if (!instr_is_unreachable(expr_result)) |
| ... | ... | @@ -6558,7 +6558,15 @@ target_value_ptr); |
| 6558 | 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 | 6570 | assert(node->type == NodeTypeSwitchExpr); |
| 6563 | 6571 | |
| 6564 | 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 | 6597 | |
| 6590 | 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 | 6606 | // First do the else and the ranges |
| 6593 | 6607 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); |
| 6594 | 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 | 6611 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 6598 | 6612 | size_t prong_item_count = prong_node->data.switch_prong.items.length; |
| 6599 | 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 | 6617 | if (else_prong) { |
| 6601 | 6618 | ErrorMsg *msg = add_node_error(irb->codegen, prong_node, |
| 6602 | 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 | 6624 | else_prong = prong_node; |
| 6608 | 6625 | |
| 6609 | 6626 | IrBasicBlock *prev_block = irb->current_basic_block; |
| 6627 | next_peer_block(&peer_result_locs, else_block); |
| 6610 | 6628 | ir_set_cursor_at_end_and_append_block(irb, else_block); |
| 6611 | 6629 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6612 | 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 | 6633 | return irb->codegen->invalid_instruction; |
| 6616 | 6634 | } |
| 6617 | 6635 | ir_set_cursor_at_end(irb, prev_block); |
| 6618 | 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 | 6641 | IrInstruction *ok_bit = nullptr; |
| 6620 | 6642 | AstNode *last_item_node = nullptr; |
| 6621 | 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 | 6697 | ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes, |
| 6676 | 6698 | range_block_no, is_comptime)); |
| 6677 | 6699 | |
| 6700 | next_peer_block(&peer_result_locs, range_block_yes); |
| 6678 | 6701 | ir_set_cursor_at_end_and_append_block(irb, range_block_yes); |
| 6679 | 6702 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6680 | 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 | 6706 | return irb->codegen->invalid_instruction; |
| 6684 | 6707 | } |
| ... | ... | @@ -6696,6 +6719,10 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6696 | 6719 | if (prong_node->data.switch_prong.any_items_are_range) |
| 6697 | 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 | 6726 | IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); |
| 6700 | 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 | 6746 | } |
| 6720 | 6747 | |
| 6721 | 6748 | IrBasicBlock *prev_block = irb->current_basic_block; |
| 6749 | next_peer_block(&peer_result_locs, prong_block); |
| 6722 | 6750 | ir_set_cursor_at_end_and_append_block(irb, prong_block); |
| 6723 | 6751 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6724 | 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 | 6755 | return irb->codegen->invalid_instruction; |
| 6728 | 6756 | } |
| ... | ... | @@ -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, |
| 6735 | | else_prong != nullptr); |
| 6762 | IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, |
| 6763 | check_ranges.items, check_ranges.length, else_prong != nullptr); |
| 6736 | 6764 | |
| 6765 | IrInstruction *br_instruction; |
| 6737 | 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 | 6768 | } else { |
| 6740 | 6769 | IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, scope, node, target_value, else_block, |
| 6741 | 6770 | cases.length, cases.items, is_comptime, switch_prongs_void); |
| 6742 | 6771 | if (switch_else_var != nullptr) { |
| 6743 | 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 | 6783 | if (!else_prong) { |
| 6784 | if (peer_result_locs.length != 0) { |
| 6785 | peer_result_locs.last().next_bb = else_block; |
| 6786 | } |
| 6748 | 6787 | ir_set_cursor_at_end_and_append_block(irb, else_block); |
| 6749 | 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 | 6795 | ir_set_cursor_at_end_and_append_block(irb, end_block); |
| 6753 | 6796 | assert(incoming_blocks.length == incoming_values.length); |
| 6797 | IrInstruction *result_instruction; |
| 6754 | 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 | 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 | 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 | 7873 | case NodeTypeIfOptional: |
| 7829 | 7874 | return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval, result_loc); |
| 7830 | 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 | 7877 | case NodeTypeCompTime: |
| 7833 | 7878 | return ir_gen_comptime(irb, scope, node, lval); |
| 7834 | 7879 | case NodeTypeErrorType: |