authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-04 14:47:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-04 14:47:01-04:00
logb19b1c1298f755238e7b6a54e5482616d923f9a8
treec79430c313a914e231f0ff2d26fbb4c2e87311e5
parent057b96006b055ca480167ac4ca66c87c2be89354
signature Commit is signed but in an unrecognized format.

no-copy semantics for switch expressions

```zig export fn entry() void { var c: i32 = 1234; var x = switch (c) { 1 => u8(1), 2...4 => u16(2), else => u32(3), }; } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %c = alloca i32, align 4 %x = alloca i32, align 4 store i32 1234, i32* %c, align 4, !dbg !44 call void @llvm.dbg.declare(metadata i32* %c, metadata !39, metadata !DIExpression()), !dbg !44 %0 = load i32, i32* %c, align 4, !dbg !45 %1 = icmp sge i32 %0, 2, !dbg !46 %2 = icmp sle i32 %0, 4, !dbg !46 %3 = and i1 %1, %2, !dbg !46 br i1 %3, label %SwitchRangeYes, label %SwitchRangeNo, !dbg !46 SwitchRangeYes: ; preds = %Entry br label %SwitchEnd, !dbg !45 SwitchElse: ; preds = %SwitchRangeNo br label %SwitchEnd, !dbg !45 SwitchProng: ; preds = %SwitchRangeNo br label %SwitchEnd, !dbg !45 SwitchEnd: ; preds = %SwitchProng, %SwitchElse, %SwitchRangeYes %4 = phi i32 [ 2, %SwitchRangeYes ], [ 3, %SwitchElse ], [ 1, %SwitchProng ], !dbg !45 store i32 %4, i32* %x, align 4, !dbg !45 call void @llvm.dbg.declare(metadata i32* %x, metadata !42, metadata !DIExpression()), !dbg !47 ret void, !dbg !48 SwitchRangeNo: ; preds = %Entry switch i32 %0, label %SwitchElse [ i32 1, label %SwitchProng ], !dbg !45 } ```

2 files changed, 71 insertions(+), 23 deletions(-)

BRANCH_TODO+6-3
...@@ -1,14 +1,17 @@...@@ -1,14 +1,17 @@
1Scratch pad for stuff to do before merging master1Scratch pad for stuff to do before merging master
2=================================================2=================================================
33
4migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize4 * if bool - do we need to call lval wrap or just expr wrap?
55 * hook up peer result locs to if optional and if err
6 * switch expression6 * hook up peer result locs to while bool, while optional, and while err
7 * hook up peer result locs to for
8 * hook up peer result locs to catch
7 * struct initializations9 * struct initializations
8 * function call parameters10 * function call parameters
9 * bitCast11 * bitCast
1012
11look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated13look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated
14 return ir_gen_comptime(irb, scope, node, lval);
1215
13migrate all the alloca_list to alloca_gen_list16migrate all the alloca_list to alloca_gen_list
1417
src/ir.cpp+65-20
...@@ -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 ?
6544target_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 }
65506550
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}
65606560
6561static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) {6561static 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
6567static 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);
65636571
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 *
65896597
6590 IrInstructionSwitchElseVar *switch_else_var = nullptr;6598 IrInstructionSwitchElseVar *switch_else_var = nullptr;
65916599
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 ranges6606 // 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;
66086625
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));
66776699
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;
66986721
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);
67016728
...@@ -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 }
67206747
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 *
67316759
6732 }6760 }
67336761
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);
67366764
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;
67466782
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 }
67516794
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}
67606805
6761static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {6806static 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: