| ... | @@ -2679,7 +2679,7 @@ fn switchExpr( | ... | @@ -2679,7 +2679,7 @@ fn switchExpr( |
| 2679 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); | 2679 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); |
| 2680 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; | 2680 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; |
| 2681 | | 2681 | |
| 2682 | // Contains the data that goes into the `extra` array for the SwitchBr/SwitchBrMulti. | 2682 | // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. |
| 2683 | // This is the header as well as the optional else prong body, as well as all the | 2683 | // This is the header as well as the optional else prong body, as well as all the |
| 2684 | // scalar cases. | 2684 | // scalar cases. |
| 2685 | // At the end we will memcpy this into place. | 2685 | // At the end we will memcpy this into place. |
| ... | @@ -2757,7 +2757,7 @@ fn switchExpr( | ... | @@ -2757,7 +2757,7 @@ fn switchExpr( |
| 2757 | if (!astgen.refIsNoReturn(case_result)) { | 2757 | if (!astgen.refIsNoReturn(case_result)) { |
| 2758 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 2758 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 2759 | } | 2759 | } |
| 2760 | // Documentation for this: `zir.Inst.SwitchBr` and `zir.Inst.SwitchBrMulti`. | 2760 | // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`. |
| 2761 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | 2761 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + |
| 2762 | 3 + // operand, scalar_cases_len, else body len | 2762 | 3 + // operand, scalar_cases_len, else body len |
| 2763 | @boolToInt(multi_cases_len != 0) + | 2763 | @boolToInt(multi_cases_len != 0) + |
| ... | @@ -2770,7 +2770,7 @@ fn switchExpr( | ... | @@ -2770,7 +2770,7 @@ fn switchExpr( |
| 2770 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | 2770 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); |
| 2771 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | 2771 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); |
| 2772 | } else { | 2772 | } else { |
| 2773 | // Documentation for this: `zir.Inst.SwitchBr` and `zir.Inst.SwitchBrMulti`. | 2773 | // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`. |
| 2774 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | 2774 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + |
| 2775 | 2 + // operand, scalar_cases_len | 2775 | 2 + // operand, scalar_cases_len |
| 2776 | @boolToInt(multi_cases_len != 0)); | 2776 | @boolToInt(multi_cases_len != 0)); |
| ... | @@ -2782,6 +2782,8 @@ fn switchExpr( | ... | @@ -2782,6 +2782,8 @@ fn switchExpr( |
| 2782 | } | 2782 | } |
| 2783 | | 2783 | |
| 2784 | // In this pass we generate all the item and prong expressions except the special case. | 2784 | // In this pass we generate all the item and prong expressions except the special case. |
| | 2785 | var multi_case_index: u32 = 0; |
| | 2786 | var scalar_case_index: u32 = 0; |
| 2785 | for (case_nodes) |case_node| { | 2787 | for (case_nodes) |case_node| { |
| 2786 | if (case_node == special_node) | 2788 | if (case_node == special_node) |
| 2787 | continue; | 2789 | continue; |
| ... | @@ -2818,7 +2820,13 @@ fn switchExpr( | ... | @@ -2818,7 +2820,13 @@ fn switchExpr( |
| 2818 | 0b10 => .switch_capture_multi, | 2820 | 0b10 => .switch_capture_multi, |
| 2819 | 0b11 => .switch_capture_multi_ref, | 2821 | 0b11 => .switch_capture_multi_ref, |
| 2820 | }; | 2822 | }; |
| 2821 | const capture_index = if (is_multi_case) multi_cases_len else scalar_cases_len; | 2823 | const capture_index = if (is_multi_case) ci: { |
| | 2824 | multi_case_index += 1; |
| | 2825 | break :ci multi_case_index - 1; |
| | 2826 | } else ci: { |
| | 2827 | scalar_case_index += 1; |
| | 2828 | break :ci scalar_case_index - 1; |
| | 2829 | }; |
| 2822 | const capture = try case_scope.add(.{ | 2830 | const capture = try case_scope.add(.{ |
| 2823 | .tag = capture_tag, | 2831 | .tag = capture_tag, |
| 2824 | .data = .{ .switch_capture = .{ | 2832 | .data = .{ .switch_capture = .{ |
| ... | @@ -2918,17 +2926,121 @@ fn switchExpr( | ... | @@ -2918,17 +2926,121 @@ fn switchExpr( |
| 2918 | else => unreachable, | 2926 | else => unreachable, |
| 2919 | }; | 2927 | }; |
| 2920 | const zir_datas = astgen.instructions.items(.data); | 2928 | const zir_datas = astgen.instructions.items(.data); |
| 2921 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, astgen.extra.items.len); | 2929 | const payload_index = astgen.extra.items.len; |
| | 2930 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); |
| 2922 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | 2931 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + |
| 2923 | scalar_cases_payload.items.len + multi_cases_payload.items.len); | 2932 | scalar_cases_payload.items.len + multi_cases_payload.items.len); |
| 2924 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | 2933 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); |
| 2925 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | 2934 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); |
| 2926 | const strat = rl.strategy(&block_scope); | 2935 | const strat = rl.strategy(&block_scope); |
| 2927 | assert(strat.tag == .break_operand); // TODO | 2936 | switch (strat.tag) { |
| 2928 | assert(!strat.elide_store_to_block_ptr_instructions); // TODO | 2937 | .break_operand => { |
| 2929 | assert(rl != .ref); // TODO | 2938 | // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus |
| 2930 | const switch_block_ref = astgen.indexToRef(switch_block); | 2939 | // this is always true. |
| 2931 | return rvalue(parent_gz, scope, rl, switch_block_ref, switch_node); | 2940 | assert(strat.elide_store_to_block_ptr_instructions); |
| | 2941 | |
| | 2942 | // Elide all the `store_to_block_ptr` instructions. |
| | 2943 | var extra_index: usize = payload_index; |
| | 2944 | extra_index += 2; |
| | 2945 | extra_index += @boolToInt(multi_cases_len != 0); |
| | 2946 | if (special_prong != .none) { |
| | 2947 | const body_len = astgen.extra.items[extra_index]; |
| | 2948 | extra_index += 1; |
| | 2949 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 2950 | extra_index += body_len; |
| | 2951 | const store_inst = body[body.len - 2]; |
| | 2952 | assert(zir_tags[store_inst] == .store_to_block_ptr); |
| | 2953 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| | 2954 | zir_tags[store_inst] = .elided; |
| | 2955 | zir_datas[store_inst] = undefined; |
| | 2956 | } |
| | 2957 | var scalar_i: u32 = 0; |
| | 2958 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| | 2959 | extra_index += 1; |
| | 2960 | const body_len = astgen.extra.items[extra_index]; |
| | 2961 | extra_index += 1; |
| | 2962 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 2963 | extra_index += body_len; |
| | 2964 | const store_inst = body[body.len - 2]; |
| | 2965 | assert(zir_tags[store_inst] == .store_to_block_ptr); |
| | 2966 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| | 2967 | zir_tags[store_inst] = .elided; |
| | 2968 | zir_datas[store_inst] = undefined; |
| | 2969 | } |
| | 2970 | var multi_i: u32 = 0; |
| | 2971 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| | 2972 | const items_len = astgen.extra.items[extra_index]; |
| | 2973 | extra_index += 1; |
| | 2974 | const ranges_len = astgen.extra.items[extra_index]; |
| | 2975 | extra_index += 1; |
| | 2976 | const body_len = astgen.extra.items[extra_index]; |
| | 2977 | extra_index += 1; |
| | 2978 | extra_index += items_len; |
| | 2979 | extra_index += 2 * ranges_len; |
| | 2980 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 2981 | extra_index += body_len; |
| | 2982 | const store_inst = body[body.len - 2]; |
| | 2983 | assert(zir_tags[store_inst] == .store_to_block_ptr); |
| | 2984 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| | 2985 | zir_tags[store_inst] = .elided; |
| | 2986 | zir_datas[store_inst] = undefined; |
| | 2987 | } |
| | 2988 | |
| | 2989 | const block_ref = astgen.indexToRef(switch_block); |
| | 2990 | switch (rl) { |
| | 2991 | .ref => return block_ref, |
| | 2992 | else => return rvalue(parent_gz, scope, rl, block_ref, switch_node), |
| | 2993 | } |
| | 2994 | }, |
| | 2995 | .break_void => { |
| | 2996 | assert(!strat.elide_store_to_block_ptr_instructions); |
| | 2997 | // Modify all the terminating instruction tags to become `break` variants. |
| | 2998 | var extra_index: usize = payload_index; |
| | 2999 | extra_index += 2; |
| | 3000 | extra_index += @boolToInt(multi_cases_len != 0); |
| | 3001 | if (special_prong != .none) { |
| | 3002 | const body_len = astgen.extra.items[extra_index]; |
| | 3003 | extra_index += 1; |
| | 3004 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 3005 | extra_index += body_len; |
| | 3006 | const last = body[body.len - 1]; |
| | 3007 | assert(zir_tags[last] == .@"break"); |
| | 3008 | assert(zir_datas[last].@"break".block_inst == switch_block); |
| | 3009 | zir_datas[last].@"break".operand = .void_value; |
| | 3010 | } |
| | 3011 | var scalar_i: u32 = 0; |
| | 3012 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| | 3013 | extra_index += 1; |
| | 3014 | const body_len = astgen.extra.items[extra_index]; |
| | 3015 | extra_index += 1; |
| | 3016 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 3017 | extra_index += body_len; |
| | 3018 | const last = body[body.len - 1]; |
| | 3019 | assert(zir_tags[last] == .@"break"); |
| | 3020 | assert(zir_datas[last].@"break".block_inst == switch_block); |
| | 3021 | zir_datas[last].@"break".operand = .void_value; |
| | 3022 | } |
| | 3023 | var multi_i: u32 = 0; |
| | 3024 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| | 3025 | const items_len = astgen.extra.items[extra_index]; |
| | 3026 | extra_index += 1; |
| | 3027 | const ranges_len = astgen.extra.items[extra_index]; |
| | 3028 | extra_index += 1; |
| | 3029 | const body_len = astgen.extra.items[extra_index]; |
| | 3030 | extra_index += 1; |
| | 3031 | extra_index += items_len; |
| | 3032 | extra_index += 2 * ranges_len; |
| | 3033 | const body = astgen.extra.items[extra_index..][0..body_len]; |
| | 3034 | extra_index += body_len; |
| | 3035 | const last = body[body.len - 1]; |
| | 3036 | assert(zir_tags[last] == .@"break"); |
| | 3037 | assert(zir_datas[last].@"break".block_inst == switch_block); |
| | 3038 | zir_datas[last].@"break".operand = .void_value; |
| | 3039 | } |
| | 3040 | |
| | 3041 | return astgen.indexToRef(switch_block); |
| | 3042 | }, |
| | 3043 | } |
| 2932 | } | 3044 | } |
| 2933 | | 3045 | |
| 2934 | fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 3046 | fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { |