| ... | @@ -589,6 +589,40 @@ pub const DeclGen = struct { | ... | @@ -589,6 +589,40 @@ pub const DeclGen = struct { |
| 589 | | 589 | |
| 590 | try writer.writeAll("}"); | 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 | .ComptimeInt => unreachable, | 627 | .ComptimeInt => unreachable, |
| 594 | .ComptimeFloat => unreachable, | 628 | .ComptimeFloat => unreachable, |
| ... | @@ -601,7 +635,6 @@ pub const DeclGen = struct { | ... | @@ -601,7 +635,6 @@ pub const DeclGen = struct { |
| 601 | .BoundFn => unreachable, | 635 | .BoundFn => unreachable, |
| 602 | .Opaque => unreachable, | 636 | .Opaque => unreachable, |
| 603 | | 637 | |
| 604 | .Union, | | |
| 605 | .Frame, | 638 | .Frame, |
| 606 | .AnyFrame, | 639 | .AnyFrame, |
| 607 | .Vector, | 640 | .Vector, |
| ... | @@ -781,6 +814,65 @@ pub const DeclGen = struct { | ... | @@ -781,6 +814,65 @@ pub const DeclGen = struct { |
| 781 | return name; | 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 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | 876 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 785 | const child_type = t.errorUnionPayload(); | 877 | const child_type = t.errorUnionPayload(); |
| 786 | const err_set_type = t.errorUnionSet(); | 878 | const err_set_type = t.errorUnionSet(); |
| ... | @@ -959,6 +1051,12 @@ pub const DeclGen = struct { | ... | @@ -959,6 +1051,12 @@ pub const DeclGen = struct { |
| 959 | | 1051 | |
| 960 | return w.writeAll(name); | 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 | .Enum => { | 1060 | .Enum => { |
| 963 | // For enums, we simply use the integer tag type. | 1061 | // For enums, we simply use the integer tag type. |
| 964 | var int_tag_ty_buffer: Type.Payload.Bits = undefined; | 1062 | var int_tag_ty_buffer: Type.Payload.Bits = undefined; |
| ... | @@ -967,7 +1065,6 @@ pub const DeclGen = struct { | ... | @@ -967,7 +1065,6 @@ pub const DeclGen = struct { |
| 967 | try dg.renderType(w, int_tag_ty); | 1065 | try dg.renderType(w, int_tag_ty); |
| 968 | }, | 1066 | }, |
| 969 | | 1067 | |
| 970 | .Union, | | |
| 971 | .Frame, | 1068 | .Frame, |
| 972 | .AnyFrame, | 1069 | .AnyFrame, |
| 973 | .Vector, | 1070 | .Vector, |
| ... | @@ -2671,21 +2768,36 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue | ... | @@ -2671,21 +2768,36 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue |
| 2671 | | 2768 | |
| 2672 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { | 2769 | fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { |
| 2673 | const writer = f.object.writer(); | 2770 | const writer = f.object.writer(); |
| 2674 | const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data; | 2771 | const struct_ty = struct_ptr_ty.elemType(); |
| 2675 | const field_name = struct_obj.fields.keys()[index]; | 2772 | var field_name: []const u8 = undefined; |
| 2676 | const field_val = struct_obj.fields.values()[index]; | 2773 | var field_val_ty: Type = undefined; |
| 2677 | const addrof = if (field_val.ty.zigTypeTag() == .Array) "" else "&"; | 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 | const inst_ty = f.air.typeOfIndex(inst); | 2791 | const inst_ty = f.air.typeOfIndex(inst); |
| 2680 | const local = try f.allocLocal(inst_ty, .Const); | 2792 | const local = try f.allocLocal(inst_ty, .Const); |
| 2681 | switch (struct_ptr) { | 2793 | switch (struct_ptr) { |
| 2682 | .local_ref => |i| { | 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 | else => { | 2797 | else => { |
| 2686 | try writer.print(" = {s}", .{addrof}); | 2798 | try writer.print(" = {s}", .{addrof}); |
| 2687 | try f.writeCValue(writer, struct_ptr); | 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 | return local; | 2803 | return local; |
| ... | @@ -2700,14 +2812,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2700,14 +2812,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2700 | const writer = f.object.writer(); | 2812 | const writer = f.object.writer(); |
| 2701 | const struct_byval = try f.resolveInst(extra.struct_operand); | 2813 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 2702 | const struct_ty = f.air.typeOf(extra.struct_operand); | 2814 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| 2703 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 2815 | const field_name = switch (struct_ty.tag()) { |
| 2704 | const field_name = struct_obj.fields.keys()[extra.field_index]; | 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 | const inst_ty = f.air.typeOfIndex(inst); | 2822 | const inst_ty = f.air.typeOfIndex(inst); |
| 2707 | const local = try f.allocLocal(inst_ty, .Const); | 2823 | const local = try f.allocLocal(inst_ty, .Const); |
| 2708 | try writer.writeAll(" = "); | 2824 | try writer.writeAll(" = "); |
| 2709 | try f.writeCValue(writer, struct_byval); | 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 | return local; | 2827 | return local; |
| 2712 | } | 2828 | } |
| 2713 | | 2829 | |
| ... | @@ -3048,9 +3164,13 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3048,9 +3164,13 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3048 | const new_tag = try f.resolveInst(bin_op.rhs); | 3164 | const new_tag = try f.resolveInst(bin_op.rhs); |
| 3049 | const writer = f.object.writer(); | 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 | try f.writeCValue(writer, union_ptr); | 3172 | try f.writeCValue(writer, union_ptr); |
| 3053 | try writer.writeAll(" = "); | 3173 | try writer.writeAll("->tag = "); |
| 3054 | try f.writeCValue(writer, new_tag); | 3174 | try f.writeCValue(writer, new_tag); |
| 3055 | try writer.writeAll(";\n"); | 3175 | try writer.writeAll(";\n"); |
| 3056 | | 3176 | |
| ... | @@ -3064,12 +3184,17 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3064,12 +3184,17 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3064 | const inst_ty = f.air.typeOfIndex(inst); | 3184 | const inst_ty = f.air.typeOfIndex(inst); |
| 3065 | const local = try f.allocLocal(inst_ty, .Const); | 3185 | const local = try f.allocLocal(inst_ty, .Const); |
| 3066 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3186 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| | 3187 | const un_ty = f.air.typeOf(ty_op.operand); |
| 3067 | const writer = f.object.writer(); | 3188 | const writer = f.object.writer(); |
| 3068 | const operand = try f.resolveInst(ty_op.operand); | 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 | try f.writeCValue(writer, operand); | 3196 | try f.writeCValue(writer, operand); |
| 3072 | try writer.writeAll(");\n"); | 3197 | try writer.writeAll(".tag;\n"); |
| 3073 | return local; | 3198 | return local; |
| 3074 | } | 3199 | } |
| 3075 | | 3200 | |