authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-09-23 14:33:31-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-09-23 14:34:01-04:00
log9f4649b197b720dbc168ced25eee0805d3b678b1
treeedc09234b4d8385fce36a306bb36c55cfadd823c
parent4e9f5f25c8226144eff8d9c1df79cfcffbae5492

codegen/sema: handle unions with unknown tags in more places


4 files changed, 51 insertions(+), 35 deletions(-)

src/Sema.zig+1-1
......@@ -32879,7 +32879,7 @@ fn unionToTag(
3287932879 return Air.internedToRef(opv.toIntern());
3288032880 }
3288132881 if (try sema.resolveMaybeUndefVal(un)) |un_val| {
32882 return Air.internedToRef(un_val.unionTag(mod).toIntern());
32882 return Air.internedToRef(un_val.unionTag(mod).?.toIntern());
3288332883 }
3288432884 try sema.requireRuntimeBlock(block, un_src, null);
3288532885 return block.addTyOp(.get_union_tag, enum_ty, un);
src/TypedValue.zig+16-14
......@@ -87,18 +87,19 @@ pub fn print(
8787 const union_val = val.castTag(.@"union").?.data;
8888 try writer.writeAll(".{ ");
8989
90 try print(.{
91 .ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
92 .val = union_val.tag,
93 }, writer, level - 1, mod);
94 try writer.writeAll(" = ");
95 if (ty.unionFieldType(union_val.tag, mod)) |field_ty| {
90 if (union_val.tag.toIntern() != .none) {
91 try print(.{
92 .ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
93 .val = union_val.tag,
94 }, writer, level - 1, mod);
95 try writer.writeAll(" = ");
96 const field_ty = ty.unionFieldType(union_val.tag, mod).?;
9697 try print(.{
9798 .ty = field_ty,
9899 .val = union_val.val,
99100 }, writer, level - 1, mod);
100101 } else {
101 return writer.writeAll("(no tag)");
102 return writer.writeAll("(unknown tag)");
102103 }
103104
104105 return writer.writeAll(" }");
......@@ -408,18 +409,19 @@ pub fn print(
408409 .un => |un| {
409410 try writer.writeAll(".{ ");
410411 if (level > 0) {
411 try print(.{
412 .ty = ty.unionTagTypeHypothetical(mod),
413 .val = un.tag.toValue(),
414 }, writer, level - 1, mod);
415 try writer.writeAll(" = ");
416 if (ty.unionFieldType(un.tag.toValue(), mod)) |field_ty| {
412 if (un.tag != .none) {
413 try print(.{
414 .ty = ty.unionTagTypeHypothetical(mod),
415 .val = un.tag.toValue(),
416 }, writer, level - 1, mod);
417 try writer.writeAll(" = ");
418 const field_ty = ty.unionFieldType(un.tag.toValue(), mod).?;
417419 try print(.{
418420 .ty = field_ty,
419421 .val = un.val.toValue(),
420422 }, writer, level - 1, mod);
421423 } else {
422 try writer.writeAll("(no tag)");
424 try writer.writeAll("(unknown tag)");
423425 }
424426 } else try writer.writeAll("...");
425427 return writer.writeAll(" }");
src/codegen.zig+19-10
......@@ -583,24 +583,33 @@ pub fn generateSymbol(
583583 }
584584
585585 const union_obj = mod.typeToUnion(typed_value.ty).?;
586 const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
586 if (un.tag != .none) {
587 const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
588 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
589 if (!field_ty.hasRuntimeBits(mod)) {
590 try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
591 } else {
592 switch (try generateSymbol(bin_file, src_loc, .{
593 .ty = field_ty,
594 .val = un.val.toValue(),
595 }, code, debug_output, reloc_info)) {
596 .ok => {},
597 .fail => |em| return Result{ .fail = em },
598 }
587599
588 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
589 if (!field_ty.hasRuntimeBits(mod)) {
590 try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
600 const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow;
601 if (padding > 0) {
602 try code.appendNTimes(0, padding);
603 }
604 }
591605 } else {
592606 switch (try generateSymbol(bin_file, src_loc, .{
593 .ty = field_ty,
607 .ty = ip.typeOf(un.val).toType(),
594608 .val = un.val.toValue(),
595609 }, code, debug_output, reloc_info)) {
596610 .ok => {},
597611 .fail => |em| return Result{ .fail = em },
598612 }
599
600 const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow;
601 if (padding > 0) {
602 try code.appendNTimes(0, padding);
603 }
604613 }
605614
606615 if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
src/value.zig+15-10
......@@ -706,8 +706,8 @@ pub const Value = struct {
706706 .Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
707707 .Extern => {
708708 const union_obj = mod.typeToUnion(ty).?;
709 const union_tag = val.unionTag(mod);
710 if (mod.unionTagFieldIndex(union_obj, union_tag)) |field_index| {
709 if (val.unionTag(mod)) |union_tag| {
710 const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
711711 const field_type = union_obj.field_types.get(&mod.intern_pool)[field_index].toType();
712712 const field_val = try val.fieldValue(mod, field_index);
713713 const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));
......@@ -715,7 +715,7 @@ pub const Value = struct {
715715 } else {
716716 const union_size = ty.abiSize(mod);
717717 const array_type = try mod.arrayType(.{ .len = union_size, .child = .u8_type });
718 return writeToMemory(val.unionValue(mod), array_type, mod, buffer[0..union_size]);
718 return writeToMemory(val.unionValue(mod), array_type, mod, buffer[0..@as(usize, @intCast(union_size))]);
719719 }
720720 },
721721 .Packed => {
......@@ -832,10 +832,16 @@ pub const Value = struct {
832832 switch (union_obj.getLayout(ip)) {
833833 .Auto, .Extern => unreachable, // Handled in non-packed writeToMemory
834834 .Packed => {
835 const field_index = mod.unionTagFieldIndex(union_obj, val.unionTag(mod)).?;
836 const field_type = union_obj.field_types.get(ip)[field_index].toType();
837 const field_val = try val.fieldValue(mod, field_index);
838 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
835 if (val.unionTag(mod)) |union_tag| {
836 const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
837 const field_type = union_obj.field_types.get(ip)[field_index].toType();
838 const field_val = try val.fieldValue(mod, field_index);
839 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
840 } else {
841 const union_bits: u16 = @intCast(ty.bitSize(mod));
842 const int_ty = try mod.intType(.unsigned, union_bits);
843 return val.unionValue(mod).writeToPackedMemory(int_ty, mod, buffer, bit_offset);
844 }
839845 },
840846 }
841847 },
......@@ -1137,7 +1143,6 @@ pub const Value = struct {
11371143 .Auto, .Extern => unreachable, // Handled by non-packed readFromMemory
11381144 .Packed => {
11391145 const union_bits: u16 = @intCast(ty.bitSize(mod));
1140 // TODO: Remove after tests pass
11411146 assert(union_bits != 0);
11421147 const int_ty = try mod.intType(.unsigned, union_bits);
11431148 const val = (try readFromPackedMemory(int_ty, mod, buffer, bit_offset, arena)).toIntern();
......@@ -1754,11 +1759,11 @@ pub const Value = struct {
17541759 };
17551760 }
17561761
1757 pub fn unionTag(val: Value, mod: *Module) Value {
1762 pub fn unionTag(val: Value, mod: *Module) ?Value {
17581763 if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;
17591764 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
17601765 .undef, .enum_tag => val,
1761 .un => |un| un.tag.toValue(),
1766 .un => |un| if (un.tag != .none) un.tag.toValue() else return null,
17621767 else => unreachable,
17631768 };
17641769 }