| author | |
| committer | |
| log | 9f4649b197b720dbc168ced25eee0805d3b678b1 |
| tree | edc09234b4d8385fce36a306bb36c55cfadd823c |
| parent | 4e9f5f25c8226144eff8d9c1df79cfcffbae5492 |
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(".{ "); |
| 89 | 89 | ||
| 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 | } |
| 103 | 104 | ||
| 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 | } |
| 584 | 584 | ||
| 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 | } | ||
| 587 | 599 | ||
| 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 | } |
| 605 | 614 | ||
| 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 already | 706 | .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 writeToMemory | 833 | .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 readFromMemory | 1143 | .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 | } |
| 1756 | 1761 | ||
| 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 | } |