| ... | ... | @@ -10789,23 +10789,24 @@ const SwitchProngAnalysis = struct { |
| 10789 | 10789 | const first_field_index: u32 = mod.unionTagFieldIndex(union_obj, first_item_val).?; |
| 10790 | 10790 | const first_field_ty = union_obj.field_types.get(ip)[first_field_index].toType(); |
| 10791 | 10791 | |
| 10792 | | const field_tys = try sema.arena.alloc(Type, case_vals.len); |
| 10793 | | for (case_vals, field_tys) |item, *field_ty| { |
| 10792 | const field_indices = try sema.arena.alloc(u32, case_vals.len); |
| 10793 | for (case_vals, field_indices) |item, *field_idx| { |
| 10794 | 10794 | const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable; |
| 10795 | | const field_idx = mod.unionTagFieldIndex(union_obj, item_val).?; |
| 10796 | | field_ty.* = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10795 | field_idx.* = mod.unionTagFieldIndex(union_obj, item_val).?; |
| 10797 | 10796 | } |
| 10798 | 10797 | |
| 10799 | 10798 | // Fast path: if all the operands are the same type already, we don't need to hit |
| 10800 | 10799 | // PTR! This will also allow us to emit simpler code. |
| 10801 | | const same_types = for (field_tys[1..]) |field_ty| { |
| 10802 | | if (!field_ty.eql(field_tys[0], sema.mod)) break false; |
| 10800 | const same_types = for (field_indices[1..]) |field_idx| { |
| 10801 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10802 | if (!field_ty.eql(first_field_ty, sema.mod)) break false; |
| 10803 | 10803 | } else true; |
| 10804 | 10804 | |
| 10805 | | const capture_ty = if (same_types) field_tys[0] else capture_ty: { |
| 10805 | const capture_ty = if (same_types) first_field_ty else capture_ty: { |
| 10806 | 10806 | // We need values to run PTR on, so make a bunch of undef constants. |
| 10807 | 10807 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 10808 | | for (dummy_captures, field_tys) |*dummy, field_ty| { |
| 10808 | for (dummy_captures, field_indices) |*dummy, field_idx| { |
| 10809 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10809 | 10810 | dummy.* = try mod.undefRef(field_ty); |
| 10810 | 10811 | } |
| 10811 | 10812 | |
| ... | ... | @@ -10852,7 +10853,8 @@ const SwitchProngAnalysis = struct { |
| 10852 | 10853 | // By-ref captures of hetereogeneous types are only allowed if each field |
| 10853 | 10854 | // pointer type is in-memory coercible to the capture pointer type. |
| 10854 | 10855 | if (!same_types) { |
| 10855 | | for (field_tys, 0..) |field_ty, i| { |
| 10856 | for (field_indices, 0..) |field_idx, i| { |
| 10857 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10856 | 10858 | const field_ptr_ty = try sema.ptrType(.{ |
| 10857 | 10859 | .child = field_ty.toIntern(), |
| 10858 | 10860 | .flags = .{ |
| ... | ... | @@ -10915,7 +10917,8 @@ const SwitchProngAnalysis = struct { |
| 10915 | 10917 | // We may have to emit a switch block which coerces the operand to the capture type. |
| 10916 | 10918 | // If we can, try to avoid that using in-memory coercions. |
| 10917 | 10919 | const first_non_imc = in_mem: { |
| 10918 | | for (field_tys, 0..) |field_ty, i| { |
| 10920 | for (field_indices, 0..) |field_idx, i| { |
| 10921 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10919 | 10922 | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 10920 | 10923 | break :in_mem i; |
| 10921 | 10924 | } |
| ... | ... | @@ -10933,11 +10936,12 @@ const SwitchProngAnalysis = struct { |
| 10933 | 10936 | // be several, and we can squash all of these cases into the same switch prong using |
| 10934 | 10937 | // a simple bitcast. We'll make this the 'else' prong. |
| 10935 | 10938 | |
| 10936 | | var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len); |
| 10939 | var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_indices.len); |
| 10937 | 10940 | in_mem_coercible.unset(first_non_imc); |
| 10938 | 10941 | { |
| 10939 | 10942 | const next = first_non_imc + 1; |
| 10940 | | for (field_tys[next..], next..) |field_ty, i| { |
| 10943 | for (field_indices[next..], next..) |field_idx, i| { |
| 10944 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10941 | 10945 | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 10942 | 10946 | in_mem_coercible.unset(i); |
| 10943 | 10947 | } |
| ... | ... | @@ -10954,7 +10958,7 @@ const SwitchProngAnalysis = struct { |
| 10954 | 10958 | }, |
| 10955 | 10959 | }); |
| 10956 | 10960 | |
| 10957 | | const prong_count = field_tys.len - in_mem_coercible.count(); |
| 10961 | const prong_count = field_indices.len - in_mem_coercible.count(); |
| 10958 | 10962 | |
| 10959 | 10963 | const estimated_extra = prong_count * 6; // 2 for Case, 1 item, probably 3 insts |
| 10960 | 10964 | var cases_extra = try std.ArrayList(u32).initCapacity(sema.gpa, estimated_extra); |
| ... | ... | @@ -10967,7 +10971,9 @@ const SwitchProngAnalysis = struct { |
| 10967 | 10971 | var coerce_block = block.makeSubBlock(); |
| 10968 | 10972 | defer coerce_block.instructions.deinit(sema.gpa); |
| 10969 | 10973 | |
| 10970 | | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(idx), field_tys[idx]); |
| 10974 | const field_idx = field_indices[idx]; |
| 10975 | const field_ty = union_obj.field_types.get(ip)[field_idx].toType(); |
| 10976 | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, field_idx, field_ty); |
| 10971 | 10977 | const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) { |
| 10972 | 10978 | error.NeededSourceLocation => { |
| 10973 | 10979 | const multi_idx = raw_capture_src.multi_capture; |
| ... | ... | @@ -10993,8 +10999,10 @@ const SwitchProngAnalysis = struct { |
| 10993 | 10999 | var coerce_block = block.makeSubBlock(); |
| 10994 | 11000 | defer coerce_block.instructions.deinit(sema.gpa); |
| 10995 | 11001 | |
| 10996 | | const first_imc = in_mem_coercible.findFirstSet().?; |
| 10997 | | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(first_imc), field_tys[first_imc]); |
| 11002 | const first_imc_item_idx = in_mem_coercible.findFirstSet().?; |
| 11003 | const first_imc_field_idx = field_indices[first_imc_item_idx]; |
| 11004 | const first_imc_field_ty = union_obj.field_types.get(ip)[first_imc_field_idx].toType(); |
| 11005 | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, first_imc_field_idx, first_imc_field_ty); |
| 10998 | 11006 | const coerced = try coerce_block.addBitCast(capture_ty, uncoerced); |
| 10999 | 11007 | _ = try coerce_block.addBr(capture_block_inst, coerced); |
| 11000 | 11008 | |