authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-02 16:33:58+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-02 16:33:58+01:00
logf95fcb2b1fadb34588f727f22b4d5ed07cd73d5e
tree04255c9c61f790c1bc67d770d7cd8299fd1cdc2d
parent23e981bbd1138bb7328d2cbb5a0480e26324088e
parentc157b1987865892fa1acfe88208e3567048fc892
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10762 from ziglang/stage2-x86_64-new-regalloc-api

stage2: handle more MCValue types in `struct_field_ptr` in x86_64 and pad out nonpacked struct fields when lowering to bytes (all targets incl wasm32)

7 files changed, 200 insertions(+), 74 deletions(-)

src/arch/wasm/CodeGen.zig+41-28
......@@ -619,7 +619,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
619619 .code = &value_bytes,
620620 .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),
621621 };
622 const result = decl_gen.genTypedValue(ty, val, value_bytes.writer()) catch |err| {
622 const result = decl_gen.genTypedValue(ty, val) catch |err| {
623623 // When a codegen error occured, take ownership of the error message
624624 if (err == error.CodegenFail) {
625625 self.err_msg = decl_gen.err_msg;
......@@ -907,14 +907,15 @@ pub const DeclGen = struct {
907907 break :init_val payload.data.init;
908908 } else decl.val;
909909 if (init_val.tag() != .unreachable_value) {
910 return self.genTypedValue(decl.ty, init_val, self.code.writer());
910 return self.genTypedValue(decl.ty, init_val);
911911 }
912912 return Result{ .appended = {} };
913913 }
914914 }
915915
916916 /// Generates the wasm bytecode for the declaration belonging to `Context`
917 fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result {
917 fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
918 const writer = self.code.writer();
918919 if (val.isUndef()) {
919920 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
920921 return Result{ .appended = {} };
......@@ -926,7 +927,7 @@ pub const DeclGen = struct {
926927 .function => val.castTag(.function).?.data.owner_decl,
927928 else => unreachable,
928929 };
929 return try self.lowerDeclRef(ty, val, fn_decl, writer);
930 return try self.lowerDeclRef(ty, val, fn_decl);
930931 },
931932 .Optional => {
932933 var opt_buf: Type.Payload.ElemType = undefined;
......@@ -942,9 +943,9 @@ pub const DeclGen = struct {
942943
943944 if (ty.isPtrLikeOptional()) {
944945 if (val.castTag(.opt_payload)) |payload| {
945 return self.genTypedValue(payload_type, payload.data, writer);
946 return self.genTypedValue(payload_type, payload.data);
946947 } else if (!val.isNull()) {
947 return self.genTypedValue(payload_type, val, writer);
948 return self.genTypedValue(payload_type, val);
948949 } else {
949950 try writer.writeByteNTimes(0, abi_size);
950951 return Result{ .appended = {} };
......@@ -956,7 +957,6 @@ pub const DeclGen = struct {
956957 switch (try self.genTypedValue(
957958 payload_type,
958959 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
959 writer,
960960 )) {
961961 .appended => {},
962962 .externally_managed => |payload| try writer.writeAll(payload),
......@@ -972,7 +972,7 @@ pub const DeclGen = struct {
972972 const elem_vals = val.castTag(.array).?.data;
973973 const elem_ty = ty.childType();
974974 for (elem_vals) |elem_val| {
975 switch (try self.genTypedValue(elem_ty, elem_val, writer)) {
975 switch (try self.genTypedValue(elem_ty, elem_val)) {
976976 .appended => {},
977977 .externally_managed => |data| try writer.writeAll(data),
978978 }
......@@ -987,20 +987,20 @@ pub const DeclGen = struct {
987987
988988 var index: u32 = 0;
989989 while (index < len) : (index += 1) {
990 switch (try self.genTypedValue(elem_ty, array, writer)) {
990 switch (try self.genTypedValue(elem_ty, array)) {
991991 .externally_managed => |data| try writer.writeAll(data),
992992 .appended => {},
993993 }
994994 }
995995 if (sentinel) |sentinel_value| {
996 return self.genTypedValue(elem_ty, sentinel_value, writer);
996 return self.genTypedValue(elem_ty, sentinel_value);
997997 }
998998 return Result{ .appended = {} };
999999 },
10001000 .empty_array_sentinel => {
10011001 const elem_ty = ty.childType();
10021002 const sent_val = ty.sentinel().?;
1003 return self.genTypedValue(elem_ty, sent_val, writer);
1003 return self.genTypedValue(elem_ty, sent_val);
10041004 },
10051005 else => unreachable,
10061006 },
......@@ -1037,25 +1037,37 @@ pub const DeclGen = struct {
10371037 const int_val = val.enumToInt(ty, &int_buffer);
10381038 var buf: Type.Payload.Bits = undefined;
10391039 const int_ty = ty.intTagType(&buf);
1040 return self.genTypedValue(int_ty, int_val, writer);
1040 return self.genTypedValue(int_ty, int_val);
10411041 },
10421042 .Bool => {
10431043 try writer.writeByte(@boolToInt(val.toBool()));
10441044 return Result{ .appended = {} };
10451045 },
10461046 .Struct => {
1047 const struct_ty = ty.castTag(.@"struct").?.data;
1048 if (struct_ty.layout == .Packed) {
1047 const struct_obj = ty.castTag(.@"struct").?.data;
1048 if (struct_obj.layout == .Packed) {
10491049 return self.fail("TODO: Packed structs for wasm", .{});
10501050 }
1051
1052 const struct_begin = self.code.items.len;
10511053 const field_vals = val.castTag(.@"struct").?.data;
10521054 for (field_vals) |field_val, index| {
10531055 const field_ty = ty.structFieldType(index);
10541056 if (!field_ty.hasRuntimeBits()) continue;
1055 switch (try self.genTypedValue(field_ty, field_val, writer)) {
1057
1058 switch (try self.genTypedValue(field_ty, field_val)) {
10561059 .appended => {},
10571060 .externally_managed => |payload| try writer.writeAll(payload),
10581061 }
1062 const unpadded_field_len = self.code.items.len - struct_begin;
1063
1064 // Pad struct members if required
1065 const padded_field_end = ty.structFieldOffset(index + 1, self.target());
1066 const padding = try std.math.cast(usize, padded_field_end - unpadded_field_len);
1067
1068 if (padding > 0) {
1069 try writer.writeByteNTimes(0, padding);
1070 }
10591071 }
10601072 return Result{ .appended = {} };
10611073 },
......@@ -1064,12 +1076,12 @@ pub const DeclGen = struct {
10641076 const layout = ty.unionGetLayout(self.target());
10651077
10661078 if (layout.payload_size == 0) {
1067 return self.genTypedValue(ty.unionTagType().?, union_val.tag, writer);
1079 return self.genTypedValue(ty.unionTagType().?, union_val.tag);
10681080 }
10691081
10701082 // Check if we should store the tag first, in which case, do so now:
10711083 if (layout.tag_align >= layout.payload_align) {
1072 switch (try self.genTypedValue(ty.unionTagType().?, union_val.tag, writer)) {
1084 switch (try self.genTypedValue(ty.unionTagType().?, union_val.tag)) {
10731085 .appended => {},
10741086 .externally_managed => |payload| try writer.writeAll(payload),
10751087 }
......@@ -1082,7 +1094,7 @@ pub const DeclGen = struct {
10821094 if (!field_ty.hasRuntimeBits()) {
10831095 try writer.writeByteNTimes(0xaa, @intCast(usize, layout.payload_size));
10841096 } else {
1085 switch (try self.genTypedValue(field_ty, union_val.val, writer)) {
1097 switch (try self.genTypedValue(field_ty, union_val.val)) {
10861098 .appended => {},
10871099 .externally_managed => |payload| try writer.writeAll(payload),
10881100 }
......@@ -1098,26 +1110,26 @@ pub const DeclGen = struct {
10981110 if (layout.tag_size == 0) {
10991111 return Result{ .appended = {} };
11001112 }
1101 return self.genTypedValue(union_ty.tag_ty, union_val.tag, writer);
1113 return self.genTypedValue(union_ty.tag_ty, union_val.tag);
11021114 },
11031115 .Pointer => switch (val.tag()) {
11041116 .variable => {
11051117 const decl = val.castTag(.variable).?.data.owner_decl;
1106 return self.lowerDeclRef(ty, val, decl, writer);
1118 return self.lowerDeclRef(ty, val, decl);
11071119 },
11081120 .decl_ref => {
11091121 const decl = val.castTag(.decl_ref).?.data;
1110 return self.lowerDeclRef(ty, val, decl, writer);
1122 return self.lowerDeclRef(ty, val, decl);
11111123 },
11121124 .slice => {
11131125 const slice = val.castTag(.slice).?.data;
11141126 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
11151127 const ptr_ty = ty.slicePtrFieldType(&buf);
1116 switch (try self.genTypedValue(ptr_ty, slice.ptr, writer)) {
1128 switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
11171129 .externally_managed => |data| try writer.writeAll(data),
11181130 .appended => {},
11191131 }
1120 switch (try self.genTypedValue(Type.usize, slice.len, writer)) {
1132 switch (try self.genTypedValue(Type.usize, slice.len)) {
11211133 .externally_managed => |data| try writer.writeAll(data),
11221134 .appended => {},
11231135 }
......@@ -1135,14 +1147,14 @@ pub const DeclGen = struct {
11351147 const is_pl = val.errorUnionIsPayload();
11361148
11371149 const err_val = if (!is_pl) val else Value.initTag(.zero);
1138 switch (try self.genTypedValue(error_ty, err_val, writer)) {
1150 switch (try self.genTypedValue(error_ty, err_val)) {
11391151 .externally_managed => |data| try writer.writeAll(data),
11401152 .appended => {},
11411153 }
11421154
11431155 if (payload_ty.hasRuntimeBits()) {
11441156 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1145 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
1157 switch (try self.genTypedValue(payload_ty, pl_val)) {
11461158 .externally_managed => |data| try writer.writeAll(data),
11471159 .appended => {},
11481160 }
......@@ -1167,11 +1179,12 @@ pub const DeclGen = struct {
11671179 }
11681180 }
11691181
1170 fn lowerDeclRef(self: *DeclGen, ty: Type, val: Value, decl: *Module.Decl, writer: anytype) InnerError!Result {
1182 fn lowerDeclRef(self: *DeclGen, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result {
1183 const writer = self.code.writer();
11711184 if (ty.isSlice()) {
11721185 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
11731186 const slice_ty = ty.slicePtrFieldType(&buf);
1174 switch (try self.genTypedValue(slice_ty, val, writer)) {
1187 switch (try self.genTypedValue(slice_ty, val)) {
11751188 .appended => {},
11761189 .externally_managed => |payload| try writer.writeAll(payload),
11771190 }
......@@ -1179,7 +1192,7 @@ pub const DeclGen = struct {
11791192 .base = .{ .tag = .int_u64 },
11801193 .data = val.sliceLen(),
11811194 };
1182 return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer);
1195 return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
11831196 }
11841197
11851198 decl.markAlive();
src/arch/x86_64/CodeGen.zig+76-40
......@@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
680680 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
681681 // zig fmt: on
682682 }
683
684 assert(!self.register_manager.frozenRegsExist());
685
683686 if (std.debug.runtime_safety) {
684687 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
685688 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
......@@ -809,7 +812,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
809812 const stack_mcv = try self.allocRegOrMem(inst, false);
810813 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
811814 const reg_mcv = self.getResolvedInstValue(inst);
812 assert(reg == reg_mcv.register.to64());
815 assert(reg.to64() == reg_mcv.register.to64());
813816 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
814817 try branch.inst_table.put(self.gpa, inst, stack_mcv);
815818 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);
......@@ -827,9 +830,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
827830/// Allocates a new register and copies `mcv` into it.
828831/// `reg_owner` is the instruction that gets associated with the register in the register table.
829832/// This can have a side effect of spilling instructions to the stack to free up a register.
830fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
833fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
831834 const reg = try self.register_manager.allocReg(reg_owner, &.{});
832 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
835 try self.genSetReg(ty, reg, mcv);
833836 return MCValue{ .register = reg };
834837}
835838
......@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
838841fn copyToNewRegisterWithExceptions(
839842 self: *Self,
840843 reg_owner: Air.Inst.Index,
844 ty: Type,
841845 mcv: MCValue,
842846 exceptions: []const Register,
843847) !MCValue {
844848 const reg = try self.register_manager.allocReg(reg_owner, exceptions);
845 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
849 try self.genSetReg(ty, reg, mcv);
846850 return MCValue{ .register = reg };
847851}
848852
......@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
892896 if (operand_abi_size > 8 or dest_abi_size > 8) {
893897 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
894898 }
895 const reg = switch (operand) {
896 .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),
897 else => try self.register_manager.allocReg(inst, &.{}),
898 };
899 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
900 try self.genSetReg(dest_ty, reg, operand);
901 break :blk .{ .register = registerAlias(reg, @intCast(u32, dest_abi_size)) };
899
900 if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
901 defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
902 break :blk try self.copyToNewRegister(inst, dest_ty, operand);
902903 };
903904
904905 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
......@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
12081209 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
12091210 break :result operand;
12101211 }
1211 break :result try self.copyToNewRegister(inst, operand);
1212 break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand);
12121213 };
12131214 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12141215}
......@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
14791480 const index_ty = self.air.typeOf(extra.rhs);
14801481 const index = try self.resolveInst(extra.rhs);
14811482 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
1482 const dst_mcv = blk: {
1483 switch (ptr) {
1484 .ptr_stack_offset => {
1485 const reg = try self.register_manager.allocReg(inst, &.{offset_reg});
1486 try self.genSetReg(ptr_ty, reg, ptr);
1487 break :blk .{ .register = reg };
1488 },
1489 else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
1490 }
1491 };
1483
1484 self.register_manager.freezeRegs(&.{offset_reg});
1485 defer self.register_manager.unfreezeRegs(&.{offset_reg});
1486
1487 const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr);
14921488 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
14931489 break :result dst_mcv;
14941490 };
......@@ -1795,22 +1791,62 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
17951791}
17961792
17971793fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
1798 return if (self.liveness.isUnused(inst)) .dead else result: {
1799 const mcv = try self.resolveInst(operand);
1800 const struct_ty = self.air.typeOf(operand).childType();
1801 const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));
1802 const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));
1803 const struct_field_ty = struct_ty.structFieldType(index);
1804 const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));
1805
1794 if (self.liveness.isUnused(inst)) {
1795 return MCValue.dead;
1796 }
1797 const mcv = try self.resolveInst(operand);
1798 const ptr_ty = self.air.typeOf(operand);
1799 const struct_ty = ptr_ty.childType();
1800 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1801 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1802 const struct_field_ty = struct_ty.structFieldType(index);
1803 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
1804
1805 const dst_mcv: MCValue = result: {
18061806 switch (mcv) {
1807 .stack_offset => {
1808 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
1809 .immediate = struct_field_offset,
1810 });
1811 self.register_manager.freezeRegs(&.{offset_reg});
1812 defer self.register_manager.unfreezeRegs(&.{offset_reg});
1813
1814 const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, mcv);
1815 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
1816 break :result dst_mcv;
1817 },
18071818 .ptr_stack_offset => |off| {
1808 const ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size;
1819 const offset_to_field = struct_size - struct_field_offset - struct_field_size;
1820 const ptr_stack_offset = off + @intCast(i32, offset_to_field);
18091821 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
18101822 },
1823 .register => |reg| {
1824 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
1825 .immediate = struct_field_offset,
1826 });
1827 self.register_manager.freezeRegs(&.{offset_reg});
1828 defer self.register_manager.unfreezeRegs(&.{offset_reg});
1829
1830 const can_reuse_operand = self.reuseOperand(inst, operand, 0, mcv);
1831 const result_reg = blk: {
1832 if (can_reuse_operand) {
1833 break :blk reg;
1834 } else {
1835 self.register_manager.freezeRegs(&.{reg});
1836 const result_reg = try self.register_manager.allocReg(inst, &.{});
1837 try self.genSetReg(ptr_ty, result_reg, mcv);
1838 break :blk result_reg;
1839 }
1840 };
1841 defer if (!can_reuse_operand) self.register_manager.unfreezeRegs(&.{reg});
1842
1843 try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
1844 break :result MCValue{ .register = result_reg };
1845 },
18111846 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
18121847 }
18131848 };
1849 return dst_mcv;
18141850}
18151851
18161852fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1859,13 +1895,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
18591895 // Source operand can be an immediate, 8 bits or 32 bits.
18601896 // So, if either one of the operands dies with this instruction, we can use it
18611897 // as the result MCValue.
1898 const dst_ty = self.air.typeOfIndex(inst);
18621899 var dst_mcv: MCValue = undefined;
18631900 var src_mcv: MCValue = undefined;
18641901 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
18651902 // LHS dies; use it as the destination.
18661903 // Both operands cannot be memory.
18671904 if (lhs.isMemory() and rhs.isMemory()) {
1868 dst_mcv = try self.copyToNewRegister(inst, lhs);
1905 dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
18691906 src_mcv = rhs;
18701907 } else {
18711908 dst_mcv = lhs;
......@@ -1875,7 +1912,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
18751912 // RHS dies; use it as the destination.
18761913 // Both operands cannot be memory.
18771914 if (lhs.isMemory() and rhs.isMemory()) {
1878 dst_mcv = try self.copyToNewRegister(inst, rhs);
1915 dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
18791916 src_mcv = lhs;
18801917 } else {
18811918 dst_mcv = rhs;
......@@ -1887,18 +1924,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
18871924 // If the allocated register is the same as the rhs register, don't allocate that one
18881925 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
18891926 // in the presence of several binary operations performed in a single block.
1890 try self.copyToNewRegisterWithExceptions(inst, lhs, &.{rhs.register})
1927 try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register})
18911928 else
1892 try self.copyToNewRegister(inst, lhs);
1929 try self.copyToNewRegister(inst, dst_ty, lhs);
18931930 src_mcv = rhs;
18941931 } else {
18951932 dst_mcv = if (lhs.isRegister())
18961933 // If the allocated register is the same as the rhs register, don't allocate that one
18971934 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
18981935 // in the presence of several binary operations performed in a single block.
1899 try self.copyToNewRegisterWithExceptions(inst, rhs, &.{lhs.register})
1936 try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register})
19001937 else
1901 try self.copyToNewRegister(inst, rhs);
1938 try self.copyToNewRegister(inst, dst_ty, rhs);
19021939 src_mcv = lhs;
19031940 }
19041941 }
......@@ -1917,7 +1954,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
19171954 }
19181955
19191956 // Now for step 2, we assing an MIR instruction
1920 const dst_ty = self.air.typeOfIndex(inst);
19211957 const air_tags = self.air.instructions.items(.tag);
19221958 switch (air_tags[inst]) {
19231959 .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
......@@ -2417,7 +2453,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
24172453 .register => |reg| {
24182454 if (Register.allocIndex(reg) == null) {
24192455 // Save function return value in a callee saved register
2420 break :result try self.copyToNewRegister(inst, info.return_value);
2456 break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), info.return_value);
24212457 }
24222458 },
24232459 else => {},
......@@ -2494,7 +2530,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24942530 // Either one, but not both, can be a memory operand.
24952531 // Source operand can be an immediate, 8 bits or 32 bits.
24962532 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))
2497 try self.copyToNewRegister(inst, lhs)
2533 try self.copyToNewRegister(inst, ty, lhs)
24982534 else
24992535 lhs;
25002536 // This instruction supports only signed 32-bit immediates at most.
src/codegen.zig+24-1
......@@ -373,11 +373,24 @@ pub fn generateSymbol(
373373 },
374374 .Struct => {
375375 // TODO debug info
376 // TODO padding of struct members
376 const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
377 if (struct_obj.layout == .Packed) {
378 return Result{
379 .fail = try ErrorMsg.create(
380 bin_file.allocator,
381 src_loc,
382 "TODO implement generateSymbol for packed struct",
383 .{},
384 ),
385 };
386 }
387
388 const struct_begin = code.items.len;
377389 const field_vals = typed_value.val.castTag(.@"struct").?.data;
378390 for (field_vals) |field_val, index| {
379391 const field_ty = typed_value.ty.structFieldType(index);
380392 if (!field_ty.hasRuntimeBits()) continue;
393
381394 switch (try generateSymbol(bin_file, src_loc, .{
382395 .ty = field_ty,
383396 .val = field_val,
......@@ -388,6 +401,16 @@ pub fn generateSymbol(
388401 },
389402 .fail => |em| return Result{ .fail = em },
390403 }
404 const unpadded_field_end = code.items.len - struct_begin;
405
406 // Pad struct members if required
407 const target = bin_file.options.target;
408 const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target);
409 const padding = try math.cast(usize, padded_field_end - unpadded_field_end);
410
411 if (padding > 0) {
412 try code.writer().writeByteNTimes(0, padding);
413 }
391414 }
392415
393416 return Result{ .appended = {} };
src/link/Elf.zig+1
......@@ -2367,6 +2367,7 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
23672367}
23682368
23692369fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2370 log.debug("updateDeclCode {s}{*}", .{ mem.sliceTo(decl.name, 0), decl });
23702371 const required_alignment = decl.ty.abiAlignment(self.base.options.target);
23712372
23722373 const block_list = self.getDeclBlockList(decl);
test/behavior.zig+1-1
......@@ -34,6 +34,7 @@ test {
3434 _ = @import("behavior/slice_sentinel_comptime.zig");
3535 _ = @import("behavior/type.zig");
3636 _ = @import("behavior/truncate.zig");
37 _ = @import("behavior/struct.zig");
3738
3839 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
3940 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
......@@ -69,7 +70,6 @@ test {
6970 _ = @import("behavior/ptrcast.zig");
7071 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
7172 _ = @import("behavior/src.zig");
72 _ = @import("behavior/struct.zig");
7373 _ = @import("behavior/this.zig");
7474 _ = @import("behavior/try.zig");
7575 _ = @import("behavior/type_info.zig");
test/behavior/cast.zig-4
......@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;
55const builtin = @import("builtin");
66
77test "int to ptr cast" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
9
108 const x = @as(usize, 13);
119 const y = @intToPtr(*u8, x);
1210 const z = @ptrToInt(y);
......@@ -14,8 +12,6 @@ test "int to ptr cast" {
1412}
1513
1614test "integer literal to pointer cast" {
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
18
1915 const vga_mem = @intToPtr(*u16, 0xB8000);
2016 try expect(@ptrToInt(vga_mem) == 0xB8000);
2117}
test/behavior/struct.zig+57
......@@ -9,6 +9,8 @@ const maxInt = std.math.maxInt;
99top_level_field: i32,
1010
1111test "top level fields" {
12 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13
1214 var instance = @This(){
1315 .top_level_field = 1234,
1416 };
......@@ -16,6 +18,39 @@ test "top level fields" {
1618 try expect(@as(i32, 1235) == instance.top_level_field);
1719}
1820
21const StructWithFields = struct {
22 a: u8,
23 b: u32,
24 c: u64,
25 d: u32,
26
27 fn first(self: *const StructWithFields) u8 {
28 return self.a;
29 }
30
31 fn second(self: *const StructWithFields) u32 {
32 return self.b;
33 }
34
35 fn third(self: *const StructWithFields) u64 {
36 return self.c;
37 }
38
39 fn fourth(self: *const StructWithFields) u32 {
40 return self.d;
41 }
42};
43
44test "non-packed struct has fields padded out to the required alignment" {
45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
46
47 const foo = StructWithFields{ .a = 5, .b = 1, .c = 10, .d = 2 };
48 try expect(foo.first() == 5);
49 try expect(foo.second() == 1);
50 try expect(foo.third() == 10);
51 try expect(foo.fourth() == 2);
52}
53
1954const StructWithNoFields = struct {
2055 fn add(a: i32, b: i32) i32 {
2156 return a + b;
......@@ -29,6 +64,8 @@ const StructFoo = struct {
2964};
3065
3166test "structs" {
67 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
68
3269 var foo: StructFoo = undefined;
3370 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
3471 foo.a += 1;
......@@ -45,6 +82,8 @@ fn testMutation(foo: *StructFoo) void {
4582}
4683
4784test "struct byval assign" {
85 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
86
4887 var foo1: StructFoo = undefined;
4988 var foo2: StructFoo = undefined;
5089
......@@ -56,6 +95,8 @@ test "struct byval assign" {
5695}
5796
5897test "call struct static method" {
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99
59100 const result = StructWithNoFields.add(3, 4);
60101 try expect(result == 7);
61102}
......@@ -85,6 +126,8 @@ const Val = struct {
85126};
86127
87128test "fn call of struct field" {
129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
130
88131 const Foo = struct {
89132 ptr: fn () i32,
90133 };
......@@ -114,12 +157,16 @@ const MemberFnTestFoo = struct {
114157};
115158
116159test "call member function directly" {
160 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161
117162 const instance = MemberFnTestFoo{ .x = 1234 };
118163 const result = MemberFnTestFoo.member(instance);
119164 try expect(result == 1234);
120165}
121166
122167test "store member function in variable" {
168 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
169
123170 const instance = MemberFnTestFoo{ .x = 1234 };
124171 const memberFn = MemberFnTestFoo.member;
125172 const result = memberFn(instance);
......@@ -127,6 +174,8 @@ test "store member function in variable" {
127174}
128175
129176test "member functions" {
177 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
178
130179 const r = MemberFnRand{ .seed = 1234 };
131180 try expect(r.getSeed() == 1234);
132181}
......@@ -138,6 +187,8 @@ const MemberFnRand = struct {
138187};
139188
140189test "return struct byval from function" {
190 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
191
141192 const bar = makeBar2(1234, 5678);
142193 try expect(bar.y == 5678);
143194}
......@@ -153,6 +204,8 @@ fn makeBar2(x: i32, y: i32) Bar {
153204}
154205
155206test "call method with mutable reference to struct with no fields" {
207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
208
156209 const S = struct {
157210 fn doC(s: *const @This()) bool {
158211 _ = s;
......@@ -172,6 +225,8 @@ test "call method with mutable reference to struct with no fields" {
172225}
173226
174227test "usingnamespace within struct scope" {
228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
229
175230 const S = struct {
176231 usingnamespace struct {
177232 pub fn inner() i32 {
......@@ -183,6 +238,8 @@ test "usingnamespace within struct scope" {
183238}
184239
185240test "struct field init with catch" {
241 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
242
186243 const S = struct {
187244 fn doTheTest() !void {
188245 var x: anyerror!isize = 1;