| ... | ... | @@ -589,6 +589,40 @@ pub const DeclGen = struct { |
| 589 | 589 | |
| 590 | 590 | try writer.writeAll("}"); |
| 591 | 591 | }, |
| 592 | .Union => { |
| 593 | const union_obj = val.castTag(.@"union").?.data; |
| 594 | const target = dg.module.getTarget(); |
| 595 | const layout = ty.unionGetLayout(target); |
| 596 | |
| 597 | try writer.writeAll("("); |
| 598 | try dg.renderType(writer, ty); |
| 599 | try writer.writeAll("){"); |
| 600 | |
| 601 | if (ty.unionTagType()) |tag_ty| { |
| 602 | if (layout.tag_size != 0) { |
| 603 | try writer.writeAll(".tag = "); |
| 604 | try dg.renderValue(writer, tag_ty, union_obj.tag); |
| 605 | try writer.writeAll(", "); |
| 606 | } |
| 607 | try writer.writeAll(".payload = {"); |
| 608 | } |
| 609 | |
| 610 | const index = switch (ty.tag()) { |
| 611 | .union_tagged => ty.castTag(.union_tagged).?.data.tag_ty.enumTagFieldIndex(union_obj.tag).?, |
| 612 | .@"union" => ty.castTag(.@"union").?.data.tag_ty.enumTagFieldIndex(union_obj.tag).?, |
| 613 | else => unreachable, |
| 614 | }; |
| 615 | const field_ty = ty.unionFields().values()[index].ty; |
| 616 | const field_name = ty.unionFields().keys()[index]; |
| 617 | if (field_ty.hasCodeGenBits()) { |
| 618 | try writer.print(".{} = ", .{fmtIdent(field_name)}); |
| 619 | try dg.renderValue(writer, field_ty, union_obj.val); |
| 620 | } |
| 621 | if (ty.unionTagType()) |_| { |
| 622 | try writer.writeAll("}"); |
| 623 | } |
| 624 | try writer.writeAll("}"); |
| 625 | }, |
| 592 | 626 | |
| 593 | 627 | .ComptimeInt => unreachable, |
| 594 | 628 | .ComptimeFloat => unreachable, |
| ... | ... | @@ -601,7 +635,6 @@ pub const DeclGen = struct { |
| 601 | 635 | .BoundFn => unreachable, |
| 602 | 636 | .Opaque => unreachable, |
| 603 | 637 | |
| 604 | | .Union, |
| 605 | 638 | .Frame, |
| 606 | 639 | .AnyFrame, |
| 607 | 640 | .Vector, |
| ... | ... | @@ -781,6 +814,65 @@ pub const DeclGen = struct { |
| 781 | 814 | return name; |
| 782 | 815 | } |
| 783 | 816 | |
| 817 | fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 818 | const fqn = switch (t.tag()) { |
| 819 | .@"union" => try t.castTag(.@"union").?.data.getFullyQualifiedName(dg.typedefs.allocator), |
| 820 | .union_tagged => try t.castTag(.union_tagged).?.data.getFullyQualifiedName(dg.typedefs.allocator), |
| 821 | else => unreachable, |
| 822 | }; |
| 823 | defer dg.typedefs.allocator.free(fqn); |
| 824 | |
| 825 | const target = dg.module.getTarget(); |
| 826 | const layout = t.unionGetLayout(target); |
| 827 | |
| 828 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 829 | defer buffer.deinit(); |
| 830 | |
| 831 | try buffer.appendSlice("typedef "); |
| 832 | if (t.unionTagType()) |tag_ty| { |
| 833 | const name: CValue = .{ .bytes = "tag" }; |
| 834 | try buffer.appendSlice("struct {\n "); |
| 835 | if (layout.tag_size != 0) { |
| 836 | try dg.renderTypeAndName(buffer.writer(), tag_ty, name, .Mut, Value.initTag(.abi_align_default)); |
| 837 | try buffer.appendSlice(";\n"); |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | try buffer.appendSlice("union {\n"); |
| 842 | { |
| 843 | var it = t.unionFields().iterator(); |
| 844 | while (it.next()) |entry| { |
| 845 | const field_ty = entry.value_ptr.ty; |
| 846 | if (!field_ty.hasCodeGenBits()) continue; |
| 847 | const alignment = entry.value_ptr.abi_align; |
| 848 | const name: CValue = .{ .identifier = entry.key_ptr.* }; |
| 849 | try buffer.append(' '); |
| 850 | try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment); |
| 851 | try buffer.appendSlice(";\n"); |
| 852 | } |
| 853 | } |
| 854 | try buffer.appendSlice("} "); |
| 855 | |
| 856 | if (t.unionTagType()) |_| { |
| 857 | try buffer.appendSlice("payload;\n} "); |
| 858 | } |
| 859 | |
| 860 | const name_start = buffer.items.len; |
| 861 | try buffer.writer().print("zig_U_{s};\n", .{fmtIdent(fqn)}); |
| 862 | |
| 863 | const rendered = buffer.toOwnedSlice(); |
| 864 | errdefer dg.typedefs.allocator.free(rendered); |
| 865 | const name = rendered[name_start .. rendered.len - 2]; |
| 866 | |
| 867 | try dg.typedefs.ensureUnusedCapacity(1); |
| 868 | dg.typedefs.putAssumeCapacityNoClobber( |
| 869 | try t.copy(dg.typedefs_arena), |
| 870 | .{ .name = name, .rendered = rendered }, |
| 871 | ); |
| 872 | |
| 873 | return name; |
| 874 | } |
| 875 | |
| 784 | 876 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 785 | 877 | const child_type = t.errorUnionPayload(); |
| 786 | 878 | const err_set_type = t.errorUnionSet(); |
| ... | ... | @@ -959,6 +1051,12 @@ pub const DeclGen = struct { |
| 959 | 1051 | |
| 960 | 1052 | return w.writeAll(name); |
| 961 | 1053 | }, |
| 1054 | .Union => { |
| 1055 | const name = dg.getTypedefName(t) orelse |
| 1056 | try dg.renderUnionTypedef(t); |
| 1057 | |
| 1058 | return w.writeAll(name); |
| 1059 | }, |
| 962 | 1060 | .Enum => { |
| 963 | 1061 | // For enums, we simply use the integer tag type. |
| 964 | 1062 | var int_tag_ty_buffer: Type.Payload.Bits = undefined; |
| ... | ... | @@ -967,7 +1065,6 @@ pub const DeclGen = struct { |
| 967 | 1065 | try dg.renderType(w, int_tag_ty); |
| 968 | 1066 | }, |
| 969 | 1067 | |
| 970 | | .Union, |
| 971 | 1068 | .Frame, |
| 972 | 1069 | .AnyFrame, |
| 973 | 1070 | .Vector, |
| ... | ... | @@ -2671,21 +2768,36 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue |
| 2671 | 2768 | |
| 2672 | 2769 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { |
| 2673 | 2770 | const writer = f.object.writer(); |
| 2674 | | const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data; |
| 2675 | | const field_name = struct_obj.fields.keys()[index]; |
| 2676 | | const field_val = struct_obj.fields.values()[index]; |
| 2677 | | const addrof = if (field_val.ty.zigTypeTag() == .Array) "" else "&"; |
| 2771 | const struct_ty = struct_ptr_ty.elemType(); |
| 2772 | var field_name: []const u8 = undefined; |
| 2773 | var field_val_ty: Type = undefined; |
| 2774 | |
| 2775 | switch (struct_ty.tag()) { |
| 2776 | .@"struct" => { |
| 2777 | const fields = struct_ty.structFields(); |
| 2778 | field_name = fields.keys()[index]; |
| 2779 | field_val_ty = fields.values()[index].ty; |
| 2780 | }, |
| 2781 | .@"union", .union_tagged => { |
| 2782 | const fields = struct_ty.unionFields(); |
| 2783 | field_name = fields.keys()[index]; |
| 2784 | field_val_ty = fields.values()[index].ty; |
| 2785 | }, |
| 2786 | else => unreachable, |
| 2787 | } |
| 2788 | const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&"; |
| 2789 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2678 | 2790 | |
| 2679 | 2791 | const inst_ty = f.air.typeOfIndex(inst); |
| 2680 | 2792 | const local = try f.allocLocal(inst_ty, .Const); |
| 2681 | 2793 | switch (struct_ptr) { |
| 2682 | 2794 | .local_ref => |i| { |
| 2683 | | try writer.print(" = {s}t{d}.{};\n", .{ addrof, i, fmtIdent(field_name) }); |
| 2795 | try writer.print(" = {s}t{d}.{s}{};\n", .{ addrof, i, payload, fmtIdent(field_name) }); |
| 2684 | 2796 | }, |
| 2685 | 2797 | else => { |
| 2686 | 2798 | try writer.print(" = {s}", .{addrof}); |
| 2687 | 2799 | try f.writeCValue(writer, struct_ptr); |
| 2688 | | try writer.print("->{};\n", .{fmtIdent(field_name)}); |
| 2800 | try writer.print("->{s}{};\n", .{ payload, fmtIdent(field_name) }); |
| 2689 | 2801 | }, |
| 2690 | 2802 | } |
| 2691 | 2803 | return local; |
| ... | ... | @@ -2700,14 +2812,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2700 | 2812 | const writer = f.object.writer(); |
| 2701 | 2813 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 2702 | 2814 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| 2703 | | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 2704 | | const field_name = struct_obj.fields.keys()[extra.field_index]; |
| 2815 | const field_name = switch (struct_ty.tag()) { |
| 2816 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], |
| 2817 | .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index], |
| 2818 | else => unreachable, |
| 2819 | }; |
| 2820 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2705 | 2821 | |
| 2706 | 2822 | const inst_ty = f.air.typeOfIndex(inst); |
| 2707 | 2823 | const local = try f.allocLocal(inst_ty, .Const); |
| 2708 | 2824 | try writer.writeAll(" = "); |
| 2709 | 2825 | try f.writeCValue(writer, struct_byval); |
| 2710 | | try writer.print(".{};\n", .{fmtIdent(field_name)}); |
| 2826 | try writer.print(".{s}{};\n", .{ payload, fmtIdent(field_name) }); |
| 2711 | 2827 | return local; |
| 2712 | 2828 | } |
| 2713 | 2829 | |
| ... | ... | @@ -3048,9 +3164,13 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3048 | 3164 | const new_tag = try f.resolveInst(bin_op.rhs); |
| 3049 | 3165 | const writer = f.object.writer(); |
| 3050 | 3166 | |
| 3051 | | try writer.writeAll("*"); |
| 3167 | const union_ty = f.air.typeOf(bin_op.lhs).childType(); |
| 3168 | const target = f.object.dg.module.getTarget(); |
| 3169 | const layout = union_ty.unionGetLayout(target); |
| 3170 | if (layout.tag_size == 0) return CValue.none; |
| 3171 | |
| 3052 | 3172 | try f.writeCValue(writer, union_ptr); |
| 3053 | | try writer.writeAll(" = "); |
| 3173 | try writer.writeAll("->tag = "); |
| 3054 | 3174 | try f.writeCValue(writer, new_tag); |
| 3055 | 3175 | try writer.writeAll(";\n"); |
| 3056 | 3176 | |
| ... | ... | @@ -3064,12 +3184,17 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3064 | 3184 | const inst_ty = f.air.typeOfIndex(inst); |
| 3065 | 3185 | const local = try f.allocLocal(inst_ty, .Const); |
| 3066 | 3186 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3187 | const un_ty = f.air.typeOf(ty_op.operand); |
| 3067 | 3188 | const writer = f.object.writer(); |
| 3068 | 3189 | const operand = try f.resolveInst(ty_op.operand); |
| 3069 | 3190 | |
| 3070 | | try writer.writeAll("get_union_tag("); |
| 3191 | const target = f.object.dg.module.getTarget(); |
| 3192 | const layout = un_ty.unionGetLayout(target); |
| 3193 | if (layout.tag_size == 0) return CValue.none; |
| 3194 | |
| 3195 | try writer.writeAll(" = "); |
| 3071 | 3196 | try f.writeCValue(writer, operand); |
| 3072 | | try writer.writeAll(");\n"); |
| 3197 | try writer.writeAll(".tag;\n"); |
| 3073 | 3198 | return local; |
| 3074 | 3199 | } |
| 3075 | 3200 | |