authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-22 23:31:41-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 00:29:23-05:00
logbdb1e014a085fdd872886dddc66cfe1081887e5c
tree78a17c0c3280910a26fc8758c9be75d837930c89
parentc9e02d3e69f909a6eb215286c6109f2b3f1e68a2

CBE: cleanup field access

* Implement @fieldParentPtr on a union * Refactor field access to ensure that it is handled consistently * Remove `renderTypecast` as it is now behaves the same as `renderType`

3 files changed, 314 insertions(+), 299 deletions(-)

src/codegen/c.zig+314-295
......@@ -39,7 +39,7 @@ pub const CValue = union(enum) {
3939 constant: Air.Inst.Ref,
4040 /// Index into the parameters
4141 arg: usize,
42 /// The payload field of a parameter
42 /// The array field of a parameter
4343 arg_array: usize,
4444 /// Index into a tuple's fields
4545 field: usize,
......@@ -50,6 +50,8 @@ pub const CValue = union(enum) {
5050 undef: Type,
5151 /// Render the slice as an identifier (using fmtIdent)
5252 identifier: []const u8,
53 /// Render the slice as an payload.identifier (using fmtIdent)
54 payload_identifier: []const u8,
5355 /// Render these bytes literally.
5456 /// TODO make this a [*:0]const u8 to save memory
5557 bytes: []const u8,
......@@ -416,12 +418,20 @@ pub const Function = struct {
416418 return f.object.dg.fail(format, args);
417419 }
418420
419 fn renderType(f: *Function, w: anytype, t: Type) !void {
420 return f.object.dg.renderType(w, t, .Complete);
421 fn indexToCType(f: *Function, idx: CType.Index) CType {
422 return f.object.dg.indexToCType(idx);
423 }
424
425 fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
426 return f.object.dg.typeToIndex(ty, kind);
427 }
428
429 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
430 return f.object.dg.typeToCType(ty, kind);
421431 }
422432
423 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {
424 return f.object.dg.renderTypecast(w, t);
433 fn renderType(f: *Function, w: anytype, t: Type) !void {
434 return f.object.dg.renderType(w, t);
425435 }
426436
427437 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
......@@ -532,7 +542,7 @@ pub const DeclGen = struct {
532542 try writer.writeByte('{');
533543 } else {
534544 try writer.writeByte('(');
535 try dg.renderTypecast(writer, ty);
545 try dg.renderType(writer, ty);
536546 try writer.writeAll("){ .ptr = ");
537547 }
538548
......@@ -559,7 +569,7 @@ pub const DeclGen = struct {
559569 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);
560570 if (need_typecast) {
561571 try writer.writeAll("((");
562 try dg.renderTypecast(writer, ty);
572 try dg.renderType(writer, ty);
563573 try writer.writeByte(')');
564574 }
565575 try writer.writeByte('&');
......@@ -574,7 +584,7 @@ pub const DeclGen = struct {
574584 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
575585 if (!ptr_ty.isSlice()) {
576586 try writer.writeByte('(');
577 try dg.renderTypecast(writer, ptr_ty);
587 try dg.renderType(writer, ptr_ty);
578588 try writer.writeByte(')');
579589 }
580590 switch (ptr_val.tag()) {
......@@ -589,90 +599,71 @@ pub const DeclGen = struct {
589599 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
590600 },
591601 .field_ptr => {
592 const ptr_info = ptr_ty.ptrInfo();
602 const target = dg.module.getTarget();
593603 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
594 const container_ty = field_ptr.container_ty;
595 const index = field_ptr.field_index;
596
597 var container_ptr_ty_pl: Type.Payload.ElemType = .{
598 .base = .{ .tag = .c_mut_pointer },
599 .data = field_ptr.container_ty,
600 };
601 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
602
603 const FieldInfo = struct { name: []const u8, ty: Type };
604 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
605 .Struct => switch (container_ty.containerLayout()) {
606 .Auto, .Extern => FieldInfo{
607 .name = container_ty.structFields().keys()[index],
608 .ty = container_ty.structFields().values()[index].ty,
609 },
610 .Packed => if (ptr_info.data.host_size == 0) {
611 const target = dg.module.getTarget();
612
613 const byte_offset = container_ty.packedStructFieldByteOffset(index, target);
614 var byte_offset_pl = Value.Payload.U64{
615 .base = .{ .tag = .int_u64 },
616 .data = byte_offset,
617 };
618 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
619
620 var u8_ptr_pl = ptr_info;
621 u8_ptr_pl.data.pointee_type = Type.u8;
622 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
623
624 try writer.writeAll("&((");
625 try dg.renderTypecast(writer, u8_ptr_ty);
626 try writer.writeByte(')');
627 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
628 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
629 } else {
630 var host_pl = Type.Payload.Bits{
631 .base = .{ .tag = .int_unsigned },
632 .data = ptr_info.data.host_size * 8,
633 };
634 const host_ty = Type.initPayload(&host_pl.base);
635604
636 try writer.writeByte('(');
637 try dg.renderTypecast(writer, ptr_ty);
638 try writer.writeByte(')');
639 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);
640 },
641 },
642 .Union => switch (container_ty.containerLayout()) {
643 .Auto, .Extern => FieldInfo{
644 .name = container_ty.unionFields().keys()[index],
645 .ty = container_ty.unionFields().values()[index].ty,
646 },
647 .Packed => {
648 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);
649 },
605 // Ensure complete type definition is visible before accessing fields.
606 _ = try dg.typeToIndex(field_ptr.container_ty, .complete);
607
608 var container_ptr_pl = ptr_ty.ptrInfo();
609 container_ptr_pl.data.pointee_type = field_ptr.container_ty;
610 const container_ptr_ty = Type.initPayload(&container_ptr_pl.base);
611
612 switch (fieldLocation(
613 field_ptr.container_ty,
614 ptr_ty,
615 @intCast(u32, field_ptr.field_index),
616 target,
617 )) {
618 .begin => try dg.renderParentPtr(
619 writer,
620 field_ptr.container_ptr,
621 container_ptr_ty,
622 location,
623 ),
624 .field => |field| {
625 try writer.writeAll("&(");
626 try dg.renderParentPtr(
627 writer,
628 field_ptr.container_ptr,
629 container_ptr_ty,
630 location,
631 );
632 try writer.writeAll(")->");
633 try dg.writeCValue(writer, field);
650634 },
651 .Pointer => field_info: {
652 assert(container_ty.isSlice());
653 break :field_info switch (index) {
654 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },
655 1 => FieldInfo{ .name = "len", .ty = Type.usize },
656 else => unreachable,
635 .byte_offset => |byte_offset| {
636 var u8_ptr_pl = ptr_ty.ptrInfo();
637 u8_ptr_pl.data.pointee_type = Type.u8;
638 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
639
640 var byte_offset_pl = Value.Payload.U64{
641 .base = .{ .tag = .int_u64 },
642 .data = byte_offset,
657643 };
658 },
659 else => unreachable,
660 };
661
662 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
663 // Ensure complete type definition is visible before accessing fields.
664 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);
644 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
665645
666 try writer.writeAll("&(");
667 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
668 try writer.writeAll(")->");
669 switch (field_ptr.container_ty.tag()) {
670 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
671 else => {},
672 }
673 try writer.print("{ }", .{fmtIdent(field_info.name)});
674 } else {
675 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
646 try writer.writeAll("((");
647 try dg.renderType(writer, u8_ptr_ty);
648 try writer.writeByte(')');
649 try dg.renderParentPtr(
650 writer,
651 field_ptr.container_ptr,
652 container_ptr_ty,
653 location,
654 );
655 try writer.print(" + {})", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
656 },
657 .end => {
658 try writer.writeAll("((");
659 try dg.renderParentPtr(
660 writer,
661 field_ptr.container_ptr,
662 container_ptr_ty,
663 location,
664 );
665 try writer.print(") + {})", .{try dg.fmtIntLiteral(Type.usize, Value.one)});
666 },
676667 }
677668 },
678669 .elem_ptr => {
......@@ -696,7 +687,7 @@ pub const DeclGen = struct {
696687 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
697688
698689 // Ensure complete type definition is visible before accessing fields.
699 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);
690 _ = try dg.typeToIndex(payload_ptr.container_ty, .complete);
700691
701692 try writer.writeAll("&(");
702693 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
......@@ -763,18 +754,18 @@ pub const DeclGen = struct {
763754 .Pointer => if (ty.isSlice()) {
764755 if (!location.isInitializer()) {
765756 try writer.writeByte('(');
766 try dg.renderTypecast(writer, ty);
757 try dg.renderType(writer, ty);
767758 try writer.writeByte(')');
768759 }
769760
770761 try writer.writeAll("{(");
771762 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
772763 const ptr_ty = ty.slicePtrFieldType(&buf);
773 try dg.renderTypecast(writer, ptr_ty);
764 try dg.renderType(writer, ptr_ty);
774765 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});
775766 } else {
776767 try writer.writeAll("((");
777 try dg.renderTypecast(writer, ty);
768 try dg.renderType(writer, ty);
778769 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
779770 },
780771 .Optional => {
......@@ -791,7 +782,7 @@ pub const DeclGen = struct {
791782
792783 if (!location.isInitializer()) {
793784 try writer.writeByte('(');
794 try dg.renderTypecast(writer, ty);
785 try dg.renderType(writer, ty);
795786 try writer.writeByte(')');
796787 }
797788
......@@ -805,7 +796,7 @@ pub const DeclGen = struct {
805796 .Auto, .Extern => {
806797 if (!location.isInitializer()) {
807798 try writer.writeByte('(');
808 try dg.renderTypecast(writer, ty);
799 try dg.renderType(writer, ty);
809800 try writer.writeByte(')');
810801 }
811802
......@@ -827,7 +818,7 @@ pub const DeclGen = struct {
827818 .Union => {
828819 if (!location.isInitializer()) {
829820 try writer.writeByte('(');
830 try dg.renderTypecast(writer, ty);
821 try dg.renderType(writer, ty);
831822 try writer.writeByte(')');
832823 }
833824
......@@ -852,7 +843,7 @@ pub const DeclGen = struct {
852843 .ErrorUnion => {
853844 if (!location.isInitializer()) {
854845 try writer.writeByte('(');
855 try dg.renderTypecast(writer, ty);
846 try dg.renderType(writer, ty);
856847 try writer.writeByte(')');
857848 }
858849
......@@ -865,7 +856,7 @@ pub const DeclGen = struct {
865856 .Array, .Vector => {
866857 if (!location.isInitializer()) {
867858 try writer.writeByte('(');
868 try dg.renderTypecast(writer, ty);
859 try dg.renderType(writer, ty);
869860 try writer.writeByte(')');
870861 }
871862
......@@ -1026,7 +1017,7 @@ pub const DeclGen = struct {
10261017 return dg.renderValue(writer, ty, slice_val, location);
10271018 } else {
10281019 try writer.writeAll("((");
1029 try dg.renderTypecast(writer, ty);
1020 try dg.renderType(writer, ty);
10301021 try writer.writeAll(")NULL)");
10311022 },
10321023 .variable => {
......@@ -1036,7 +1027,7 @@ pub const DeclGen = struct {
10361027 .slice => {
10371028 if (!location.isInitializer()) {
10381029 try writer.writeByte('(');
1039 try dg.renderTypecast(writer, ty);
1030 try dg.renderType(writer, ty);
10401031 try writer.writeByte(')');
10411032 }
10421033
......@@ -1059,7 +1050,7 @@ pub const DeclGen = struct {
10591050 },
10601051 .int_u64, .one => {
10611052 try writer.writeAll("((");
1062 try dg.renderTypecast(writer, ty);
1053 try dg.renderType(writer, ty);
10631054 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
10641055 },
10651056 .field_ptr,
......@@ -1074,7 +1065,7 @@ pub const DeclGen = struct {
10741065 .Array, .Vector => {
10751066 if (location == .FunctionArgument) {
10761067 try writer.writeByte('(');
1077 try dg.renderTypecast(writer, ty);
1068 try dg.renderType(writer, ty);
10781069 try writer.writeByte(')');
10791070 }
10801071
......@@ -1177,7 +1168,7 @@ pub const DeclGen = struct {
11771168
11781169 if (!location.isInitializer()) {
11791170 try writer.writeByte('(');
1180 try dg.renderTypecast(writer, ty);
1171 try dg.renderType(writer, ty);
11811172 try writer.writeByte(')');
11821173 }
11831174
......@@ -1211,7 +1202,7 @@ pub const DeclGen = struct {
12111202
12121203 if (!location.isInitializer()) {
12131204 try writer.writeByte('(');
1214 try dg.renderTypecast(writer, ty);
1205 try dg.renderType(writer, ty);
12151206 try writer.writeByte(')');
12161207 }
12171208
......@@ -1275,7 +1266,7 @@ pub const DeclGen = struct {
12751266
12761267 if (!location.isInitializer()) {
12771268 try writer.writeByte('(');
1278 try dg.renderTypecast(writer, ty);
1269 try dg.renderType(writer, ty);
12791270 try writer.writeByte(')');
12801271 }
12811272
......@@ -1362,7 +1353,7 @@ pub const DeclGen = struct {
13621353
13631354 if (!empty) try writer.writeAll(" | ");
13641355 try writer.writeByte('(');
1365 try dg.renderTypecast(writer, ty);
1356 try dg.renderType(writer, ty);
13661357 try writer.writeByte(')');
13671358
13681359 if (bit_offset_val_pl.data != 0) {
......@@ -1385,7 +1376,7 @@ pub const DeclGen = struct {
13851376
13861377 if (!location.isInitializer()) {
13871378 try writer.writeByte('(');
1388 try dg.renderTypecast(writer, ty);
1379 try dg.renderType(writer, ty);
13891380 try writer.writeByte(')');
13901381 }
13911382
......@@ -1396,11 +1387,11 @@ pub const DeclGen = struct {
13961387 if (field_ty.hasRuntimeBits()) {
13971388 if (field_ty.isPtrAtRuntime()) {
13981389 try writer.writeByte('(');
1399 try dg.renderTypecast(writer, ty);
1390 try dg.renderType(writer, ty);
14001391 try writer.writeByte(')');
14011392 } else if (field_ty.zigTypeTag() == .Float) {
14021393 try writer.writeByte('(');
1403 try dg.renderTypecast(writer, ty);
1394 try dg.renderType(writer, ty);
14041395 try writer.writeByte(')');
14051396 }
14061397 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
......@@ -1509,9 +1500,11 @@ pub const DeclGen = struct {
15091500 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
15101501 return dg.ctypes.indexToCType(idx);
15111502 }
1503
15121504 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
15131505 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
15141506 }
1507
15151508 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
15161509 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
15171510 }
......@@ -1524,16 +1517,10 @@ pub const DeclGen = struct {
15241517 /// There are three type formats in total that we support rendering:
15251518 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
15261519 /// |---------------------|-----------------|---------------------|
1527 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
15281520 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
15291521 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
15301522 ///
1531 fn renderType(
1532 dg: *DeclGen,
1533 w: anytype,
1534 t: Type,
1535 _: TypedefKind,
1536 ) error{ OutOfMemory, AnalysisFail }!void {
1523 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
15371524 const store = &dg.ctypes.set;
15381525 const module = dg.module;
15391526 const idx = try dg.typeToIndex(t, .complete);
......@@ -1603,12 +1590,12 @@ pub const DeclGen = struct {
16031590
16041591 if (needs_cast) {
16051592 try w.writeByte('(');
1606 try dg.renderTypecast(w, dest_ty);
1593 try dg.renderType(w, dest_ty);
16071594 try w.writeByte(')');
16081595 }
16091596 if (src_is_ptr) {
16101597 try w.writeByte('(');
1611 try dg.renderTypecast(w, src_eff_ty);
1598 try dg.renderType(w, src_eff_ty);
16121599 try w.writeByte(')');
16131600 }
16141601 try context.writeValue(dg, w, src_ty, location);
......@@ -1625,7 +1612,7 @@ pub const DeclGen = struct {
16251612 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
16261613 if (src_is_ptr) {
16271614 try w.writeByte('(');
1628 try dg.renderTypecast(w, src_eff_ty);
1615 try dg.renderType(w, src_eff_ty);
16291616 try w.writeByte(')');
16301617 }
16311618 try context.writeValue(dg, w, src_ty, .FunctionArgument);
......@@ -1646,28 +1633,11 @@ pub const DeclGen = struct {
16461633 }
16471634 }
16481635
1649 /// Renders a type in C typecast format.
1650 ///
1651 /// This is guaranteed to be valid in a typecast expression, but not
1652 /// necessarily in a variable/field declaration.
1653 ///
1654 /// There are three type formats in total that we support rendering:
1655 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1656 /// |---------------------|-----------------|---------------------|
1657 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1658 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1659 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1660 ///
1661 fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void {
1662 try dg.renderType(w, ty, undefined);
1663 }
1664
16651636 /// Renders a type and name in field declaration/definition format.
16661637 ///
16671638 /// There are three type formats in total that we support rendering:
16681639 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
16691640 /// |---------------------|-----------------|---------------------|
1670 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
16711641 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
16721642 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
16731643 ///
......@@ -1708,7 +1678,7 @@ pub const DeclGen = struct {
17081678 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
17091679
17101680 try w.writeAll("static ");
1711 try dg.renderType(w, name_slice_ty, .Complete);
1681 try dg.renderType(w, name_slice_ty);
17121682 try w.writeByte(' ');
17131683 try w.writeAll(fn_name);
17141684 try w.writeByte('(');
......@@ -1742,7 +1712,7 @@ pub const DeclGen = struct {
17421712 try w.writeAll(" = ");
17431713 try dg.renderValue(w, name_ty, name_val, .Initializer);
17441714 try w.writeAll(";\n return (");
1745 try dg.renderTypecast(w, name_slice_ty);
1715 try dg.renderType(w, name_slice_ty);
17461716 try w.print("){{{}, {}}};\n", .{
17471717 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
17481718 });
......@@ -1787,6 +1757,10 @@ pub const DeclGen = struct {
17871757 },
17881758 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),
17891759 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1760 .payload_identifier => |ident| return w.print("{ }.{ }", .{
1761 fmtIdent("payload"),
1762 fmtIdent(ident),
1763 }),
17901764 .bytes => |bytes| return w.writeAll(bytes),
17911765 }
17921766 }
......@@ -1812,6 +1786,10 @@ pub const DeclGen = struct {
18121786 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),
18131787 .undef => unreachable,
18141788 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),
1789 .payload_identifier => |ident| return w.print("(*{ }.{ })", .{
1790 fmtIdent("payload"),
1791 fmtIdent(ident),
1792 }),
18151793 .bytes => |bytes| {
18161794 try w.writeAll("(*");
18171795 try w.writeAll(bytes);
......@@ -1829,7 +1807,7 @@ pub const DeclGen = struct {
18291807 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
18301808 switch (c_value) {
18311809 .none, .constant, .field, .undef => unreachable,
1832 .new_local, .local, .arg, .arg_array, .decl, .identifier, .bytes => {
1810 .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => {
18331811 try dg.writeCValue(writer, c_value);
18341812 try writer.writeAll("->");
18351813 },
......@@ -3048,7 +3026,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
30483026 try writer.writeByte(']');
30493027 if (is_array) {
30503028 try writer.writeAll(", sizeof(");
3051 try f.renderTypecast(writer, inst_ty);
3029 try f.renderType(writer, inst_ty);
30523030 try writer.writeAll("))");
30533031 }
30543032 try writer.writeAll(";\n");
......@@ -3080,7 +3058,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30803058 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
30813059 try f.writeCValue(writer, local, .Other);
30823060 try writer.writeAll(" = (");
3083 try f.renderTypecast(writer, inst_ty);
3061 try f.renderType(writer, inst_ty);
30843062 try writer.writeAll(")&(");
30853063 if (ptr_ty.ptrSize() == .One) {
30863064 // It's a pointer to an array, so we need to de-reference.
......@@ -3128,7 +3106,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31283106 try writer.writeByte(']');
31293107 if (is_array) {
31303108 try writer.writeAll(", sizeof(");
3131 try f.renderTypecast(writer, inst_ty);
3109 try f.renderType(writer, inst_ty);
31323110 try writer.writeAll("))");
31333111 }
31343112 try writer.writeAll(";\n");
......@@ -3197,7 +3175,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31973175 try writer.writeByte(']');
31983176 if (is_array) {
31993177 try writer.writeAll(", sizeof(");
3200 try f.renderTypecast(writer, inst_ty);
3178 try f.renderType(writer, inst_ty);
32013179 try writer.writeAll("))");
32023180 }
32033181 try writer.writeAll(";\n");
......@@ -3240,11 +3218,11 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
32403218
32413219fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
32423220 const inst_ty = f.air.typeOfIndex(inst);
3243 const inst_cty = try f.object.dg.typeToIndex(inst_ty, .parameter);
3221 const inst_cty = try f.typeToIndex(inst_ty, .parameter);
32443222
32453223 const i = f.next_arg_index;
32463224 f.next_arg_index += 1;
3247 return if (inst_cty != try f.object.dg.typeToIndex(inst_ty, .complete))
3225 return if (inst_cty != try f.typeToIndex(inst_ty, .complete))
32483226 .{ .arg_array = i }
32493227 else
32503228 .{ .arg = i };
......@@ -3281,7 +3259,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
32813259 try writer.writeAll(", (const char *)");
32823260 try f.writeCValue(writer, operand, .Other);
32833261 try writer.writeAll(", sizeof(");
3284 try f.renderTypecast(writer, src_ty);
3262 try f.renderType(writer, src_ty);
32853263 try writer.writeAll("))");
32863264 } else if (ptr_info.host_size != 0) {
32873265 var host_pl = Type.Payload.Bits{
......@@ -3310,11 +3288,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
33103288
33113289 try f.writeCValue(writer, local, .Other);
33123290 try writer.writeAll(" = (");
3313 try f.renderTypecast(writer, src_ty);
3291 try f.renderType(writer, src_ty);
33143292 try writer.writeAll(")zig_wrap_");
33153293 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
33163294 try writer.writeAll("((");
3317 try f.renderTypecast(writer, field_ty);
3295 try f.renderType(writer, field_ty);
33183296 try writer.writeByte(')');
33193297 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
33203298 if (cant_cast) {
......@@ -3365,7 +3343,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
33653343 try f.writeCValue(writer, operand, .FunctionArgument);
33663344 deref = false;
33673345 try writer.writeAll(", sizeof(");
3368 try f.renderTypecast(writer, ret_ty);
3346 try f.renderType(writer, ret_ty);
33693347 try writer.writeAll("));\n");
33703348 break :ret_val array_local;
33713349 } else operand;
......@@ -3440,7 +3418,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
34403418 try writer.writeByte('(');
34413419 } else if (dest_c_bits <= 64) {
34423420 try writer.writeByte('(');
3443 try f.renderTypecast(writer, inst_ty);
3421 try f.renderType(writer, inst_ty);
34443422 try writer.writeByte(')');
34453423 }
34463424
......@@ -3521,7 +3499,7 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
35213499 try writer.writeAll("memset(");
35223500 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
35233501 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});
3524 try f.renderTypecast(writer, lhs_child_ty);
3502 try f.renderType(writer, lhs_child_ty);
35253503 try writer.writeAll("));\n");
35263504 }
35273505 return CValue.none;
......@@ -3582,7 +3560,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
35823560 if (!is_array) try writer.writeByte('&');
35833561 try f.writeCValue(writer, array_src, .FunctionArgument);
35843562 try writer.writeAll(", sizeof(");
3585 try f.renderTypecast(writer, src_ty);
3563 try f.renderType(writer, src_ty);
35863564 try writer.writeAll("))");
35873565 if (src_val == .constant) {
35883566 try freeLocal(f, inst, array_src.new_local, 0);
......@@ -3641,13 +3619,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
36413619 try writer.writeAll("(0, ");
36423620 } else {
36433621 try writer.writeByte('(');
3644 try f.renderTypecast(writer, host_ty);
3622 try f.renderType(writer, host_ty);
36453623 try writer.writeByte(')');
36463624 }
36473625
36483626 if (src_ty.isPtrAtRuntime()) {
36493627 try writer.writeByte('(');
3650 try f.renderTypecast(writer, Type.usize);
3628 try f.renderType(writer, Type.usize);
36513629 try writer.writeByte(')');
36523630 }
36533631 try f.writeCValue(writer, src_val, .Other);
......@@ -3919,7 +3897,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
39193897 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
39203898 // if the result is NULL and then dereferenced.
39213899 try writer.writeByte('(');
3922 try f.renderTypecast(writer, inst_ty);
3900 try f.renderType(writer, inst_ty);
39233901 try writer.writeAll(")(((uintptr_t)");
39243902 try f.writeCValue(writer, lhs, .Other);
39253903 try writer.writeAll(") ");
......@@ -3927,7 +3905,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
39273905 try writer.writeAll(" (");
39283906 try f.writeCValue(writer, rhs, .Other);
39293907 try writer.writeAll("*sizeof(");
3930 try f.renderTypecast(writer, elem_ty);
3908 try f.renderType(writer, elem_ty);
39313909 try writer.writeAll(")))");
39323910 } else try f.writeCValue(writer, lhs, .Initializer);
39333911
......@@ -3992,7 +3970,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
39923970 try f.writeCValue(writer, local, .Other);
39933971 try writer.writeAll(".ptr = (");
39943972 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3995 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));
3973 try f.renderType(writer, inst_ty.slicePtrFieldType(&buf));
39963974 try writer.writeByte(')');
39973975 try f.writeCValue(writer, ptr, .Other);
39983976 try writer.writeAll("; ");
......@@ -4032,13 +4010,13 @@ fn airCall(
40324010 defer gpa.free(resolved_args);
40334011 for (resolved_args, args) |*resolved_arg, arg| {
40344012 const arg_ty = f.air.typeOf(arg);
4035 const arg_cty = try f.object.dg.typeToIndex(arg_ty, .parameter);
4036 if (f.object.dg.indexToCType(arg_cty).tag() == .void) {
4013 const arg_cty = try f.typeToIndex(arg_ty, .parameter);
4014 if (f.indexToCType(arg_cty).tag() == .void) {
40374015 resolved_arg.* = .none;
40384016 continue;
40394017 }
40404018 resolved_arg.* = try f.resolveInst(arg);
4041 if (arg_cty != try f.object.dg.typeToIndex(arg_ty, .complete)) {
4019 if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {
40424020 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
40434021 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
40444022
......@@ -4048,7 +4026,7 @@ fn airCall(
40484026 try writer.writeAll(", ");
40494027 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
40504028 try writer.writeAll(", sizeof(");
4051 try f.renderTypecast(writer, lowered_arg_ty);
4029 try f.renderType(writer, lowered_arg_ty);
40524030 try writer.writeAll("));\n");
40534031 resolved_arg.* = array_local;
40544032 }
......@@ -4077,7 +4055,7 @@ fn airCall(
40774055 .none
40784056 else if (f.liveness.isUnused(inst)) r: {
40794057 try writer.writeByte('(');
4080 try f.renderTypecast(writer, Type.void);
4058 try f.renderType(writer, Type.void);
40814059 try writer.writeByte(')');
40824060 break :r .none;
40834061 } else r: {
......@@ -4132,7 +4110,7 @@ fn airCall(
41324110 try writer.writeAll(", ");
41334111 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
41344112 try writer.writeAll(", sizeof(");
4135 try f.renderTypecast(writer, ret_ty);
4113 try f.renderType(writer, ret_ty);
41364114 try writer.writeAll("));\n");
41374115 try freeLocal(f, inst, result_local.new_local, 0);
41384116 break :r array_local;
......@@ -4280,7 +4258,7 @@ fn lowerTry(
42804258 try writer.writeAll(", ");
42814259 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });
42824260 try writer.writeAll(", sizeof(");
4283 try f.renderTypecast(writer, payload_ty);
4261 try f.renderType(writer, payload_ty);
42844262 try writer.writeAll("));\n");
42854263 } else {
42864264 try f.writeCValue(writer, local, .Other);
......@@ -4313,7 +4291,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
43134291 try writer.writeAll(", ");
43144292 try f.writeCValue(writer, operand, .FunctionArgument);
43154293 try writer.writeAll(", sizeof(");
4316 try f.renderTypecast(writer, operand_ty);
4294 try f.renderType(writer, operand_ty);
43174295 try writer.writeAll("))");
43184296 } else {
43194297 try f.writeCValue(writer, result, .Other);
......@@ -4362,7 +4340,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
43624340 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
43634341 try f.writeCValue(writer, local, .Other);
43644342 try writer.writeAll(" = (");
4365 try f.renderTypecast(writer, dest_ty);
4343 try f.renderType(writer, dest_ty);
43664344 try writer.writeByte(')');
43674345 try f.writeCValue(writer, operand, .Other);
43684346 try writer.writeAll(";\n");
......@@ -4383,7 +4361,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
43834361 try writer.writeAll(", &");
43844362 try f.writeCValue(writer, operand_lval, .Other);
43854363 try writer.writeAll(", sizeof(");
4386 try f.renderTypecast(writer, dest_ty);
4364 try f.renderType(writer, dest_ty);
43874365 try writer.writeAll("));\n");
43884366
43894367 // Ensure padding bits have the expected value.
......@@ -4415,7 +4393,7 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
44154393 const local = try f.allocLocal(inst, Type.usize);
44164394 try f.writeCValue(writer, local, .Other);
44174395 try writer.writeAll(" = (");
4418 try f.renderTypecast(writer, Type.usize);
4396 try f.renderType(writer, Type.usize);
44194397 try writer.writeAll(")zig_return_address();\n");
44204398 return local;
44214399}
......@@ -4426,7 +4404,7 @@ fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
44264404 const local = try f.allocLocal(inst, Type.usize);
44274405 try f.writeCValue(writer, local, .Other);
44284406 try writer.writeAll(" = (");
4429 try f.renderTypecast(writer, Type.usize);
4407 try f.renderType(writer, Type.usize);
44304408 try writer.writeAll(")zig_frame_address();\n");
44314409 return local;
44324410}
......@@ -4558,11 +4536,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
45584536 try writer.writeAll("switch (");
45594537 if (condition_ty.zigTypeTag() == .Bool) {
45604538 try writer.writeByte('(');
4561 try f.renderTypecast(writer, Type.u1);
4539 try f.renderType(writer, Type.u1);
45624540 try writer.writeByte(')');
45634541 } else if (condition_ty.isPtrAtRuntime()) {
45644542 try writer.writeByte('(');
4565 try f.renderTypecast(writer, Type.usize);
4543 try f.renderType(writer, Type.usize);
45664544 try writer.writeByte(')');
45674545 }
45684546 try f.writeCValue(writer, condition, .Other);
......@@ -4591,7 +4569,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
45914569 try writer.writeAll("case ");
45924570 if (condition_ty.isPtrAtRuntime()) {
45934571 try writer.writeByte('(');
4594 try f.renderTypecast(writer, Type.usize);
4572 try f.renderType(writer, Type.usize);
45954573 try writer.writeByte(')');
45964574 }
45974575 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
......@@ -5043,7 +5021,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
50435021 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
50445022 if (is_array) {
50455023 try writer.writeAll(", sizeof(");
5046 try f.renderTypecast(writer, inst_ty);
5024 try f.renderType(writer, inst_ty);
50475025 try writer.writeAll("))");
50485026 }
50495027 try writer.writeAll(";\n");
......@@ -5127,6 +5105,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
51275105 }
51285106}
51295107
5108fn fieldLocation(
5109 container_ty: Type,
5110 field_ptr_ty: Type,
5111 field_index: u32,
5112 target: std.Target,
5113) union(enum) {
5114 begin: void,
5115 field: CValue,
5116 byte_offset: u32,
5117 end: void,
5118} {
5119 return switch (container_ty.zigTypeTag()) {
5120 .Struct => switch (container_ty.containerLayout()) {
5121 .Auto, .Extern => for (field_index..container_ty.structFieldCount()) |next_field_index| {
5122 if (container_ty.structFieldIsComptime(next_field_index)) continue;
5123 const field_ty = container_ty.structFieldType(next_field_index);
5124 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
5125 break .{ .field = if (container_ty.isSimpleTuple())
5126 .{ .field = next_field_index }
5127 else
5128 .{ .identifier = container_ty.structFieldName(next_field_index) } };
5129 } else if (container_ty.hasRuntimeBitsIgnoreComptime()) .end else .begin,
5130 .Packed => if (field_ptr_ty.ptrInfo().data.host_size == 0)
5131 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, target) }
5132 else
5133 .begin,
5134 },
5135 .Union => switch (container_ty.containerLayout()) {
5136 .Auto, .Extern => {
5137 const field_ty = container_ty.structFieldType(field_index);
5138 if (!field_ty.hasRuntimeBitsIgnoreComptime())
5139 return if (container_ty.unionTagTypeSafety() != null and
5140 !container_ty.unionHasAllZeroBitFieldTypes())
5141 .{ .field = .{ .identifier = "payload" } }
5142 else
5143 .begin;
5144 const field_name = container_ty.unionFields().keys()[field_index];
5145 return .{ .field = if (container_ty.unionTagTypeSafety()) |_|
5146 .{ .payload_identifier = field_name }
5147 else
5148 .{ .identifier = field_name } };
5149 },
5150 .Packed => .begin,
5151 },
5152 .Pointer => switch (container_ty.ptrSize()) {
5153 .Slice => switch (field_index) {
5154 0 => .{ .field = .{ .identifier = "ptr" } },
5155 1 => .{ .field = .{ .identifier = "len" } },
5156 else => unreachable,
5157 },
5158 .One, .Many, .C => unreachable,
5159 },
5160 else => unreachable,
5161 };
5162}
5163
51305164fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51315165 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
51325166 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -5136,10 +5170,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51365170 return .none;
51375171 }
51385172
5139 const struct_ptr = try f.resolveInst(extra.struct_operand);
5173 const container_ptr_val = try f.resolveInst(extra.struct_operand);
51405174 try reap(f, inst, &.{extra.struct_operand});
5141 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
5142 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
5175 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
5176 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index);
51435177}
51445178
51455179fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
......@@ -5150,10 +5184,10 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
51505184 return .none;
51515185 }
51525186
5153 const struct_ptr = try f.resolveInst(ty_op.operand);
5187 const container_ptr_val = try f.resolveInst(ty_op.operand);
51545188 try reap(f, inst, &.{ty_op.operand});
5155 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
5156 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
5189 const container_ptr_ty = f.air.typeOf(ty_op.operand);
5190 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index);
51575191}
51585192
51595193fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -5165,130 +5199,115 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51655199 return CValue.none;
51665200 }
51675201
5168 const struct_ptr_ty = f.air.typeOfIndex(inst);
5202 const target = f.object.dg.module.getTarget();
5203 const container_ptr_ty = f.air.typeOfIndex(inst);
5204 const container_ty = container_ptr_ty.childType();
51695205
51705206 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
51715207 const field_ptr_val = try f.resolveInst(extra.field_ptr);
51725208 try reap(f, inst, &.{extra.field_ptr});
51735209
5174 const target = f.object.dg.module.getTarget();
5175 const struct_ty = struct_ptr_ty.childType();
5210 const writer = f.object.writer();
5211 const local = try f.allocLocal(inst, container_ptr_ty);
5212 try f.writeCValue(writer, local, .Other);
5213 try writer.writeAll(" = (");
5214 try f.renderType(writer, container_ptr_ty);
5215 try writer.writeByte(')');
51765216
5177 if (struct_ty.zigTypeTag() == .Union) {
5178 return f.fail("TODO: CBE: @fieldParentPtr for unions", .{});
5179 }
5217 switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, target)) {
5218 .begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
5219 .field => |field| {
5220 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5221 u8_ptr_pl.data.pointee_type = Type.u8;
5222 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
51805223
5181 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
5224 try writer.writeAll("((");
5225 try f.renderType(writer, u8_ptr_ty);
5226 try writer.writeByte(')');
5227 try f.writeCValue(writer, field_ptr_val, .Other);
5228 try writer.writeAll(" - offsetof(");
5229 try f.renderType(writer, container_ty);
5230 try writer.writeAll(", ");
5231 try f.writeCValue(writer, field, .Other);
5232 try writer.writeAll("))");
5233 },
5234 .byte_offset => |byte_offset| {
5235 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5236 u8_ptr_pl.data.pointee_type = Type.u8;
5237 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
51825238
5183 var field_offset_pl = Value.Payload.I64{
5184 .base = .{ .tag = .int_i64 },
5185 .data = -@intCast(i64, field_offset),
5186 };
5187 const field_offset_val = Value.initPayload(&field_offset_pl.base);
5239 var byte_offset_pl = Value.Payload.U64{
5240 .base = .{ .tag = .int_u64 },
5241 .data = byte_offset,
5242 };
5243 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
51885244
5189 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5190 u8_ptr_pl.data.pointee_type = Type.u8;
5191 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5245 try writer.writeAll("((");
5246 try f.renderType(writer, u8_ptr_ty);
5247 try writer.writeByte(')');
5248 try f.writeCValue(writer, field_ptr_val, .Other);
5249 try writer.print(" - {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5250 },
5251 .end => {
5252 try f.writeCValue(writer, field_ptr_val, .Other);
5253 try writer.print(" - {}", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5254 },
5255 }
51925256
5193 const writer = f.object.writer();
5194 const local = try f.allocLocal(inst, struct_ptr_ty);
5195 try f.writeCValue(writer, local, .Other);
5196 try writer.writeAll(" = (");
5197 try f.renderTypecast(writer, struct_ptr_ty);
5198 try writer.writeAll(")&((");
5199 try f.renderTypecast(writer, u8_ptr_ty);
5200 try writer.writeByte(')');
5201 try f.writeCValue(writer, field_ptr_val, .Other);
5202 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.isize, field_offset_val)});
5257 try writer.writeAll(";\n");
52035258 return local;
52045259}
52055260
5206fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
5207 const writer = f.object.writer();
5261fn fieldPtr(
5262 f: *Function,
5263 inst: Air.Inst.Index,
5264 container_ptr_ty: Type,
5265 container_ptr_val: CValue,
5266 field_index: u32,
5267) !CValue {
5268 const target = f.object.dg.module.getTarget();
5269 const container_ty = container_ptr_ty.elemType();
52085270 const field_ptr_ty = f.air.typeOfIndex(inst);
5209 const field_ptr_info = field_ptr_ty.ptrInfo();
5210 const struct_ty = struct_ptr_ty.elemType();
5211 const field_ty = struct_ty.structFieldType(index);
52125271
52135272 // Ensure complete type definition is visible before accessing fields.
5214 try f.renderType(std.io.null_writer, struct_ty);
5273 _ = try f.typeToIndex(container_ty, .complete);
52155274
5275 const writer = f.object.writer();
52165276 const local = try f.allocLocal(inst, field_ptr_ty);
52175277 try f.writeCValue(writer, local, .Other);
52185278 try writer.writeAll(" = (");
5219 try f.renderTypecast(writer, field_ptr_ty);
5279 try f.renderType(writer, field_ptr_ty);
52205280 try writer.writeByte(')');
52215281
5222 const extra_name: CValue = switch (struct_ty.tag()) {
5223 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
5224 else => .none,
5225 };
5226
5227 const field_loc: union(enum) {
5228 begin: void,
5229 field: CValue,
5230 end: void,
5231 } = switch (struct_ty.tag()) {
5232 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5233 .Auto, .Extern => for (index..struct_ty.structFieldCount()) |field_i| {
5234 if (!struct_ty.structFieldIsComptime(field_i) and
5235 struct_ty.structFieldType(field_i).hasRuntimeBitsIgnoreComptime())
5236 break .{ .field = if (struct_ty.isSimpleTuple())
5237 .{ .field = field_i }
5238 else
5239 .{ .identifier = struct_ty.structFieldName(field_i) } };
5240 } else .end,
5241 .Packed => if (field_ptr_info.data.host_size == 0) {
5242 const target = f.object.dg.module.getTarget();
5243
5244 const byte_offset = struct_ty.packedStructFieldByteOffset(index, target);
5245 var byte_offset_pl = Value.Payload.U64{
5246 .base = .{ .tag = .int_u64 },
5247 .data = byte_offset,
5248 };
5249 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
5250
5251 var u8_ptr_pl = field_ptr_info;
5252 u8_ptr_pl.data.pointee_type = Type.u8;
5253 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5282 switch (fieldLocation(container_ty, field_ptr_ty, field_index, target)) {
5283 .begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
5284 .field => |field| {
5285 try writer.writeByte('&');
5286 try f.writeCValueDerefMember(writer, container_ptr_val, field);
5287 },
5288 .byte_offset => |byte_offset| {
5289 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5290 u8_ptr_pl.data.pointee_type = Type.u8;
5291 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
52545292
5255 if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) {
5256 return f.fail("TODO: CBE: unaligned packed struct field pointer", .{});
5257 }
5293 var byte_offset_pl = Value.Payload.U64{
5294 .base = .{ .tag = .int_u64 },
5295 .data = byte_offset,
5296 };
5297 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
52585298
5259 try writer.writeAll("&((");
5260 try f.renderTypecast(writer, u8_ptr_ty);
5261 try writer.writeByte(')');
5262 try f.writeCValue(writer, struct_ptr, .Other);
5263 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5264 return local;
5265 } else .begin,
5299 try writer.writeAll("((");
5300 try f.renderType(writer, u8_ptr_ty);
5301 try writer.writeByte(')');
5302 try f.writeCValue(writer, container_ptr_val, .Other);
5303 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
52665304 },
5267 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
5268 try f.writeCValue(writer, struct_ptr, .Other);
5269 try writer.writeAll(";\n");
5270 return local;
5271 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) .{ .field = .{
5272 .identifier = struct_ty.unionFields().keys()[index],
5273 } } else .end,
5274 else => unreachable,
5275 };
5305 .end => {
5306 try f.writeCValue(writer, container_ptr_val, .Other);
5307 try writer.print(" + {}", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5308 },
5309 }
52765310
5277 if (struct_ty.hasRuntimeBitsIgnoreComptime()) {
5278 try writer.writeByte('&');
5279 switch (field_loc) {
5280 .begin, .end => {
5281 try writer.writeByte('(');
5282 try f.writeCValue(writer, struct_ptr, .Other);
5283 try writer.print(")[{}]", .{@boolToInt(field_loc == .end)});
5284 },
5285 .field => |field| if (extra_name != .none) {
5286 try f.writeCValueDerefMember(writer, struct_ptr, extra_name);
5287 try writer.writeByte('.');
5288 try f.writeCValue(writer, field, .Other);
5289 } else try f.writeCValueDerefMember(writer, struct_ptr, field),
5290 }
5291 } else try f.writeCValue(writer, struct_ptr, .Other);
52925311 try writer.writeAll(";\n");
52935312 return local;
52945313}
......@@ -5315,7 +5334,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53155334 const writer = f.object.writer();
53165335
53175336 // Ensure complete type definition is visible before accessing fields.
5318 try f.renderType(std.io.null_writer, struct_ty);
5337 _ = try f.typeToIndex(struct_ty, .complete);
53195338
53205339 const extra_name: CValue = switch (struct_ty.tag()) {
53215340 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
......@@ -5362,7 +5381,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53625381 try writer.writeAll(" = zig_wrap_");
53635382 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
53645383 try writer.writeAll("((");
5365 try f.renderTypecast(writer, field_int_ty);
5384 try f.renderType(writer, field_int_ty);
53665385 try writer.writeByte(')');
53675386 const cant_cast = int_info.bits > 64;
53685387 if (cant_cast) {
......@@ -5389,7 +5408,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53895408 try writer.writeAll(", ");
53905409 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
53915410 try writer.writeAll(", sizeof(");
5392 try f.renderTypecast(writer, inst_ty);
5411 try f.renderType(writer, inst_ty);
53935412 try writer.writeAll("));\n");
53945413 try freeLocal(f, inst, temp_local.new_local, 0);
53955414 return local;
......@@ -5411,7 +5430,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54115430 try writer.writeAll(", &");
54125431 try f.writeCValue(writer, operand_lval, .FunctionArgument);
54135432 try writer.writeAll(", sizeof(");
5414 try f.renderTypecast(writer, inst_ty);
5433 try f.renderType(writer, inst_ty);
54155434 try writer.writeAll("));\n");
54165435
54175436 if (struct_byval == .constant) {
......@@ -5442,7 +5461,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54425461 } else try f.writeCValueMember(writer, struct_byval, field_name);
54435462 if (is_array) {
54445463 try writer.writeAll(", sizeof(");
5445 try f.renderTypecast(writer, inst_ty);
5464 try f.renderType(writer, inst_ty);
54465465 try writer.writeAll("))");
54475466 }
54485467 try writer.writeAll(";\n");
......@@ -5510,7 +5529,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
55105529 const local = try f.allocLocal(inst, inst_ty);
55115530 try f.writeCValue(w, local, .Other);
55125531 try w.writeAll(" = (");
5513 try f.renderTypecast(w, inst_ty);
5532 try f.renderType(w, inst_ty);
55145533 try w.writeByte(')');
55155534 try f.writeCValue(w, operand, .Initializer);
55165535 try w.writeAll(";\n");
......@@ -5571,7 +5590,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
55715590 try writer.writeAll(", ");
55725591 try f.writeCValue(writer, payload, .FunctionArgument);
55735592 try writer.writeAll(", sizeof(");
5574 try f.renderTypecast(writer, payload_ty);
5593 try f.renderType(writer, payload_ty);
55755594 try writer.writeAll("));\n");
55765595 }
55775596 return local;
......@@ -5691,7 +5710,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
56915710 try writer.writeAll(", ");
56925711 try f.writeCValue(writer, payload, .FunctionArgument);
56935712 try writer.writeAll(", sizeof(");
5694 try f.renderTypecast(writer, payload_ty);
5713 try f.renderType(writer, payload_ty);
56955714 try writer.writeAll("));\n");
56965715 }
56975716 return local;
......@@ -5837,7 +5856,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
58375856 try f.writeCValue(writer, local, .Other);
58385857
58395858 try writer.writeAll(" = (");
5840 try f.renderTypecast(writer, inst_ty);
5859 try f.renderType(writer, inst_ty);
58415860 try writer.writeByte(')');
58425861 try f.writeCValue(writer, operand, .Other);
58435862 try writer.writeAll(";\n");
......@@ -5959,7 +5978,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
59595978 try writer.writeAll(";\n");
59605979 try writer.writeAll("if (");
59615980 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
5962 try f.renderTypecast(writer, ptr_ty.childType());
5981 try f.renderType(writer, ptr_ty.childType());
59635982 try writer.writeByte(')');
59645983 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
59655984 try writer.writeAll(" *)");
......@@ -5988,7 +6007,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
59886007 try writer.writeAll(";\n");
59896008 try f.writeCValue(writer, local, .Other);
59906009 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});
5991 try f.renderTypecast(writer, ptr_ty.childType());
6010 try f.renderType(writer, ptr_ty.childType());
59926011 try writer.writeByte(')');
59936012 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
59946013 try writer.writeAll(" *)");
......@@ -6031,12 +6050,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
60316050 switch (extra.op()) {
60326051 else => {
60336052 try writer.writeAll("zig_atomic(");
6034 try f.renderTypecast(writer, ptr_ty.elemType());
6053 try f.renderType(writer, ptr_ty.elemType());
60356054 try writer.writeByte(')');
60366055 },
60376056 .Nand, .Min, .Max => {
60386057 // These are missing from stdatomic.h, so no atomic types for now.
6039 try f.renderTypecast(writer, ptr_ty.elemType());
6058 try f.renderType(writer, ptr_ty.elemType());
60406059 },
60416060 }
60426061 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
......@@ -6073,7 +6092,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
60736092 try f.writeCValue(writer, local, .Other);
60746093
60756094 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
6076 try f.renderTypecast(writer, ptr_ty.elemType());
6095 try f.renderType(writer, ptr_ty.elemType());
60776096 try writer.writeByte(')');
60786097 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
60796098 try writer.writeAll(" *)");
......@@ -6096,7 +6115,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
60966115 const writer = f.object.writer();
60976116
60986117 try writer.writeAll("zig_atomic_store((zig_atomic(");
6099 try f.renderTypecast(writer, ptr_ty.elemType());
6118 try f.renderType(writer, ptr_ty.elemType());
61006119 try writer.writeByte(')');
61016120 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
61026121 try writer.writeAll(" *)");
......@@ -6138,7 +6157,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
61386157 try writer.writeAll(" += ");
61396158 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
61406159 try writer.writeAll(") ((");
6141 try f.renderTypecast(writer, u8_ptr_ty);
6160 try f.renderType(writer, u8_ptr_ty);
61426161 try writer.writeByte(')');
61436162 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
61446163 try writer.writeAll(")[");
......@@ -6514,7 +6533,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65146533 .Auto, .Extern => {
65156534 try f.writeCValue(writer, local, .Other);
65166535 try writer.writeAll(" = (");
6517 try f.renderTypecast(writer, inst_ty);
6536 try f.renderType(writer, inst_ty);
65186537 try writer.writeAll(")");
65196538 try writer.writeByte('{');
65206539 var empty = true;
......@@ -6557,7 +6576,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65576576 try writer.writeAll(", ");
65586577 try f.writeCValue(writer, resolved_element, .FunctionArgument);
65596578 try writer.writeAll(", sizeof(");
6560 try f.renderTypecast(writer, element_ty);
6579 try f.renderType(writer, element_ty);
65616580 try writer.writeAll("));\n");
65626581 }
65636582 },
......@@ -6602,11 +6621,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
66026621 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
66036622 } else {
66046623 try writer.writeByte('(');
6605 try f.renderTypecast(writer, inst_ty);
6624 try f.renderType(writer, inst_ty);
66066625 try writer.writeByte(')');
66076626 if (field_ty.isPtrAtRuntime()) {
66086627 try writer.writeByte('(');
6609 try f.renderTypecast(writer, switch (int_info.signedness) {
6628 try f.renderType(writer, switch (int_info.signedness) {
66106629 .unsigned => Type.usize,
66116630 .signed => Type.isize,
66126631 });
test/behavior/field_parent_ptr.zig-3
......@@ -48,7 +48,6 @@ fn testParentFieldPtrFirst(a: *const bool) !void {
4848test "@fieldParentPtr untagged union" {
4949 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
5050 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5352
5453 try testFieldParentPtrUnion(&bar.c);
......@@ -75,7 +74,6 @@ fn testFieldParentPtrUnion(c: *const i32) !void {
7574test "@fieldParentPtr tagged union" {
7675 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
7776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8078
8179 try testFieldParentPtrTaggedUnion(&bar_tagged.c);
......@@ -102,7 +100,6 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void {
102100test "@fieldParentPtr extern union" {
103101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
104102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
106103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
107104
108105 try testFieldParentPtrExternUnion(&bar_extern.c);
test/behavior/packed-struct.zig-1
......@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {
603603test "pointer to container level packed struct field" {
604604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
605605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
607606 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
608607 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
609608