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(...@@ -32879,7 +32879,7 @@ fn unionToTag(
32879 return Air.internedToRef(opv.toIntern());32879 return Air.internedToRef(opv.toIntern());
32880 }32880 }
32881 if (try sema.resolveMaybeUndefVal(un)) |un_val| {32881 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());
32883 }32883 }
32884 try sema.requireRuntimeBlock(block, un_src, null);32884 try sema.requireRuntimeBlock(block, un_src, null);
32885 return block.addTyOp(.get_union_tag, enum_ty, un);32885 return block.addTyOp(.get_union_tag, enum_ty, un);
src/TypedValue.zig+16-14
...@@ -87,18 +87,19 @@ pub fn print(...@@ -87,18 +87,19 @@ pub fn print(
87 const union_val = val.castTag(.@"union").?.data;87 const union_val = val.castTag(.@"union").?.data;
88 try writer.writeAll(".{ ");88 try writer.writeAll(".{ ");
8989
90 try print(.{90 if (union_val.tag.toIntern() != .none) {
91 .ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),91 try print(.{
92 .val = union_val.tag,92 .ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
93 }, writer, level - 1, mod);93 .val = union_val.tag,
94 try writer.writeAll(" = ");94 }, writer, level - 1, mod);
95 if (ty.unionFieldType(union_val.tag, mod)) |field_ty| {95 try writer.writeAll(" = ");
96 const field_ty = ty.unionFieldType(union_val.tag, mod).?;
96 try print(.{97 try print(.{
97 .ty = field_ty,98 .ty = field_ty,
98 .val = union_val.val,99 .val = union_val.val,
99 }, writer, level - 1, mod);100 }, writer, level - 1, mod);
100 } else {101 } else {
101 return writer.writeAll("(no tag)");102 return writer.writeAll("(unknown tag)");
102 }103 }
103104
104 return writer.writeAll(" }");105 return writer.writeAll(" }");
...@@ -408,18 +409,19 @@ pub fn print(...@@ -408,18 +409,19 @@ pub fn print(
408 .un => |un| {409 .un => |un| {
409 try writer.writeAll(".{ ");410 try writer.writeAll(".{ ");
410 if (level > 0) {411 if (level > 0) {
411 try print(.{412 if (un.tag != .none) {
412 .ty = ty.unionTagTypeHypothetical(mod),413 try print(.{
413 .val = un.tag.toValue(),414 .ty = ty.unionTagTypeHypothetical(mod),
414 }, writer, level - 1, mod);415 .val = un.tag.toValue(),
415 try writer.writeAll(" = ");416 }, writer, level - 1, mod);
416 if (ty.unionFieldType(un.tag.toValue(), mod)) |field_ty| {417 try writer.writeAll(" = ");
418 const field_ty = ty.unionFieldType(un.tag.toValue(), mod).?;
417 try print(.{419 try print(.{
418 .ty = field_ty,420 .ty = field_ty,
419 .val = un.val.toValue(),421 .val = un.val.toValue(),
420 }, writer, level - 1, mod);422 }, writer, level - 1, mod);
421 } else {423 } else {
422 try writer.writeAll("(no tag)");424 try writer.writeAll("(unknown tag)");
423 }425 }
424 } else try writer.writeAll("...");426 } else try writer.writeAll("...");
425 return writer.writeAll(" }");427 return writer.writeAll(" }");
src/codegen.zig+19-10
...@@ -583,24 +583,33 @@ pub fn generateSymbol(...@@ -583,24 +583,33 @@ pub fn generateSymbol(
583 }583 }
584584
585 const union_obj = mod.typeToUnion(typed_value.ty).?;585 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();600 const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow;
589 if (!field_ty.hasRuntimeBits(mod)) {601 if (padding > 0) {
590 try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);602 try code.appendNTimes(0, padding);
603 }
604 }
591 } else {605 } else {
592 switch (try generateSymbol(bin_file, src_loc, .{606 switch (try generateSymbol(bin_file, src_loc, .{
593 .ty = field_ty,607 .ty = ip.typeOf(un.val).toType(),
594 .val = un.val.toValue(),608 .val = un.val.toValue(),
595 }, code, debug_output, reloc_info)) {609 }, code, debug_output, reloc_info)) {
596 .ok => {},610 .ok => {},
597 .fail => |em| return Result{ .fail = em },611 .fail => |em| return Result{ .fail = em },
598 }612 }
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 }
604 }613 }
605614
606 if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {615 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 {...@@ -706,8 +706,8 @@ pub const Value = struct {
706 .Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already706 .Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
707 .Extern => {707 .Extern => {
708 const union_obj = mod.typeToUnion(ty).?;708 const union_obj = mod.typeToUnion(ty).?;
709 const union_tag = val.unionTag(mod);709 if (val.unionTag(mod)) |union_tag| {
710 if (mod.unionTagFieldIndex(union_obj, union_tag)) |field_index| {710 const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
711 const field_type = union_obj.field_types.get(&mod.intern_pool)[field_index].toType();711 const field_type = union_obj.field_types.get(&mod.intern_pool)[field_index].toType();
712 const field_val = try val.fieldValue(mod, field_index);712 const field_val = try val.fieldValue(mod, field_index);
713 const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));713 const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));
...@@ -715,7 +715,7 @@ pub const Value = struct {...@@ -715,7 +715,7 @@ pub const Value = struct {
715 } else {715 } else {
716 const union_size = ty.abiSize(mod);716 const union_size = ty.abiSize(mod);
717 const array_type = try mod.arrayType(.{ .len = union_size, .child = .u8_type });717 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))]);
719 }719 }
720 },720 },
721 .Packed => {721 .Packed => {
...@@ -832,10 +832,16 @@ pub const Value = struct {...@@ -832,10 +832,16 @@ pub const Value = struct {
832 switch (union_obj.getLayout(ip)) {832 switch (union_obj.getLayout(ip)) {
833 .Auto, .Extern => unreachable, // Handled in non-packed writeToMemory833 .Auto, .Extern => unreachable, // Handled in non-packed writeToMemory
834 .Packed => {834 .Packed => {
835 const field_index = mod.unionTagFieldIndex(union_obj, val.unionTag(mod)).?;835 if (val.unionTag(mod)) |union_tag| {
836 const field_type = union_obj.field_types.get(ip)[field_index].toType();836 const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
837 const field_val = try val.fieldValue(mod, field_index);837 const field_type = union_obj.field_types.get(ip)[field_index].toType();
838 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);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 }
839 },845 },
840 }846 }
841 },847 },
...@@ -1137,7 +1143,6 @@ pub const Value = struct {...@@ -1137,7 +1143,6 @@ pub const Value = struct {
1137 .Auto, .Extern => unreachable, // Handled by non-packed readFromMemory1143 .Auto, .Extern => unreachable, // Handled by non-packed readFromMemory
1138 .Packed => {1144 .Packed => {
1139 const union_bits: u16 = @intCast(ty.bitSize(mod));1145 const union_bits: u16 = @intCast(ty.bitSize(mod));
1140 // TODO: Remove after tests pass
1141 assert(union_bits != 0);1146 assert(union_bits != 0);
1142 const int_ty = try mod.intType(.unsigned, union_bits);1147 const int_ty = try mod.intType(.unsigned, union_bits);
1143 const val = (try readFromPackedMemory(int_ty, mod, buffer, bit_offset, arena)).toIntern();1148 const val = (try readFromPackedMemory(int_ty, mod, buffer, bit_offset, arena)).toIntern();
...@@ -1754,11 +1759,11 @@ pub const Value = struct {...@@ -1754,11 +1759,11 @@ pub const Value = struct {
1754 };1759 };
1755 }1760 }
17561761
1757 pub fn unionTag(val: Value, mod: *Module) Value {1762 pub fn unionTag(val: Value, mod: *Module) ?Value {
1758 if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;1763 if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;
1759 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1764 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1760 .undef, .enum_tag => val,1765 .undef, .enum_tag => val,
1761 .un => |un| un.tag.toValue(),1766 .un => |un| if (un.tag != .none) un.tag.toValue() else return null,
1762 else => unreachable,1767 else => unreachable,
1763 };1768 };
1764 }1769 }