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 {...@@ -619,7 +619,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
619 .code = &value_bytes,619 .code = &value_bytes,
620 .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),620 .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),
621 };621 };
622 const result = decl_gen.genTypedValue(ty, val, value_bytes.writer()) catch |err| {622 const result = decl_gen.genTypedValue(ty, val) catch |err| {
623 // When a codegen error occured, take ownership of the error message623 // When a codegen error occured, take ownership of the error message
624 if (err == error.CodegenFail) {624 if (err == error.CodegenFail) {
625 self.err_msg = decl_gen.err_msg;625 self.err_msg = decl_gen.err_msg;
...@@ -907,14 +907,15 @@ pub const DeclGen = struct {...@@ -907,14 +907,15 @@ pub const DeclGen = struct {
907 break :init_val payload.data.init;907 break :init_val payload.data.init;
908 } else decl.val;908 } else decl.val;
909 if (init_val.tag() != .unreachable_value) {909 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);
911 }911 }
912 return Result{ .appended = {} };912 return Result{ .appended = {} };
913 }913 }
914 }914 }
915915
916 /// Generates the wasm bytecode for the declaration belonging to `Context`916 /// 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();
918 if (val.isUndef()) {919 if (val.isUndef()) {
919 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));920 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
920 return Result{ .appended = {} };921 return Result{ .appended = {} };
...@@ -926,7 +927,7 @@ pub const DeclGen = struct {...@@ -926,7 +927,7 @@ pub const DeclGen = struct {
926 .function => val.castTag(.function).?.data.owner_decl,927 .function => val.castTag(.function).?.data.owner_decl,
927 else => unreachable,928 else => unreachable,
928 };929 };
929 return try self.lowerDeclRef(ty, val, fn_decl, writer);930 return try self.lowerDeclRef(ty, val, fn_decl);
930 },931 },
931 .Optional => {932 .Optional => {
932 var opt_buf: Type.Payload.ElemType = undefined;933 var opt_buf: Type.Payload.ElemType = undefined;
...@@ -942,9 +943,9 @@ pub const DeclGen = struct {...@@ -942,9 +943,9 @@ pub const DeclGen = struct {
942943
943 if (ty.isPtrLikeOptional()) {944 if (ty.isPtrLikeOptional()) {
944 if (val.castTag(.opt_payload)) |payload| {945 if (val.castTag(.opt_payload)) |payload| {
945 return self.genTypedValue(payload_type, payload.data, writer);946 return self.genTypedValue(payload_type, payload.data);
946 } else if (!val.isNull()) {947 } else if (!val.isNull()) {
947 return self.genTypedValue(payload_type, val, writer);948 return self.genTypedValue(payload_type, val);
948 } else {949 } else {
949 try writer.writeByteNTimes(0, abi_size);950 try writer.writeByteNTimes(0, abi_size);
950 return Result{ .appended = {} };951 return Result{ .appended = {} };
...@@ -956,7 +957,6 @@ pub const DeclGen = struct {...@@ -956,7 +957,6 @@ pub const DeclGen = struct {
956 switch (try self.genTypedValue(957 switch (try self.genTypedValue(
957 payload_type,958 payload_type,
958 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),959 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
959 writer,
960 )) {960 )) {
961 .appended => {},961 .appended => {},
962 .externally_managed => |payload| try writer.writeAll(payload),962 .externally_managed => |payload| try writer.writeAll(payload),
...@@ -972,7 +972,7 @@ pub const DeclGen = struct {...@@ -972,7 +972,7 @@ pub const DeclGen = struct {
972 const elem_vals = val.castTag(.array).?.data;972 const elem_vals = val.castTag(.array).?.data;
973 const elem_ty = ty.childType();973 const elem_ty = ty.childType();
974 for (elem_vals) |elem_val| {974 for (elem_vals) |elem_val| {
975 switch (try self.genTypedValue(elem_ty, elem_val, writer)) {975 switch (try self.genTypedValue(elem_ty, elem_val)) {
976 .appended => {},976 .appended => {},
977 .externally_managed => |data| try writer.writeAll(data),977 .externally_managed => |data| try writer.writeAll(data),
978 }978 }
...@@ -987,20 +987,20 @@ pub const DeclGen = struct {...@@ -987,20 +987,20 @@ pub const DeclGen = struct {
987987
988 var index: u32 = 0;988 var index: u32 = 0;
989 while (index < len) : (index += 1) {989 while (index < len) : (index += 1) {
990 switch (try self.genTypedValue(elem_ty, array, writer)) {990 switch (try self.genTypedValue(elem_ty, array)) {
991 .externally_managed => |data| try writer.writeAll(data),991 .externally_managed => |data| try writer.writeAll(data),
992 .appended => {},992 .appended => {},
993 }993 }
994 }994 }
995 if (sentinel) |sentinel_value| {995 if (sentinel) |sentinel_value| {
996 return self.genTypedValue(elem_ty, sentinel_value, writer);996 return self.genTypedValue(elem_ty, sentinel_value);
997 }997 }
998 return Result{ .appended = {} };998 return Result{ .appended = {} };
999 },999 },
1000 .empty_array_sentinel => {1000 .empty_array_sentinel => {
1001 const elem_ty = ty.childType();1001 const elem_ty = ty.childType();
1002 const sent_val = ty.sentinel().?;1002 const sent_val = ty.sentinel().?;
1003 return self.genTypedValue(elem_ty, sent_val, writer);1003 return self.genTypedValue(elem_ty, sent_val);
1004 },1004 },
1005 else => unreachable,1005 else => unreachable,
1006 },1006 },
...@@ -1037,25 +1037,37 @@ pub const DeclGen = struct {...@@ -1037,25 +1037,37 @@ pub const DeclGen = struct {
1037 const int_val = val.enumToInt(ty, &int_buffer);1037 const int_val = val.enumToInt(ty, &int_buffer);
1038 var buf: Type.Payload.Bits = undefined;1038 var buf: Type.Payload.Bits = undefined;
1039 const int_ty = ty.intTagType(&buf);1039 const int_ty = ty.intTagType(&buf);
1040 return self.genTypedValue(int_ty, int_val, writer);1040 return self.genTypedValue(int_ty, int_val);
1041 },1041 },
1042 .Bool => {1042 .Bool => {
1043 try writer.writeByte(@boolToInt(val.toBool()));1043 try writer.writeByte(@boolToInt(val.toBool()));
1044 return Result{ .appended = {} };1044 return Result{ .appended = {} };
1045 },1045 },
1046 .Struct => {1046 .Struct => {
1047 const struct_ty = ty.castTag(.@"struct").?.data;1047 const struct_obj = ty.castTag(.@"struct").?.data;
1048 if (struct_ty.layout == .Packed) {1048 if (struct_obj.layout == .Packed) {
1049 return self.fail("TODO: Packed structs for wasm", .{});1049 return self.fail("TODO: Packed structs for wasm", .{});
1050 }1050 }
1051
1052 const struct_begin = self.code.items.len;
1051 const field_vals = val.castTag(.@"struct").?.data;1053 const field_vals = val.castTag(.@"struct").?.data;
1052 for (field_vals) |field_val, index| {1054 for (field_vals) |field_val, index| {
1053 const field_ty = ty.structFieldType(index);1055 const field_ty = ty.structFieldType(index);
1054 if (!field_ty.hasRuntimeBits()) continue;1056 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)) {
1056 .appended => {},1059 .appended => {},
1057 .externally_managed => |payload| try writer.writeAll(payload),1060 .externally_managed => |payload| try writer.writeAll(payload),
1058 }1061 }
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 }
1059 }1071 }
1060 return Result{ .appended = {} };1072 return Result{ .appended = {} };
1061 },1073 },
...@@ -1064,12 +1076,12 @@ pub const DeclGen = struct {...@@ -1064,12 +1076,12 @@ pub const DeclGen = struct {
1064 const layout = ty.unionGetLayout(self.target());1076 const layout = ty.unionGetLayout(self.target());
10651077
1066 if (layout.payload_size == 0) {1078 if (layout.payload_size == 0) {
1067 return self.genTypedValue(ty.unionTagType().?, union_val.tag, writer);1079 return self.genTypedValue(ty.unionTagType().?, union_val.tag);
1068 }1080 }
10691081
1070 // Check if we should store the tag first, in which case, do so now:1082 // Check if we should store the tag first, in which case, do so now:
1071 if (layout.tag_align >= layout.payload_align) {1083 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)) {
1073 .appended => {},1085 .appended => {},
1074 .externally_managed => |payload| try writer.writeAll(payload),1086 .externally_managed => |payload| try writer.writeAll(payload),
1075 }1087 }
...@@ -1082,7 +1094,7 @@ pub const DeclGen = struct {...@@ -1082,7 +1094,7 @@ pub const DeclGen = struct {
1082 if (!field_ty.hasRuntimeBits()) {1094 if (!field_ty.hasRuntimeBits()) {
1083 try writer.writeByteNTimes(0xaa, @intCast(usize, layout.payload_size));1095 try writer.writeByteNTimes(0xaa, @intCast(usize, layout.payload_size));
1084 } else {1096 } else {
1085 switch (try self.genTypedValue(field_ty, union_val.val, writer)) {1097 switch (try self.genTypedValue(field_ty, union_val.val)) {
1086 .appended => {},1098 .appended => {},
1087 .externally_managed => |payload| try writer.writeAll(payload),1099 .externally_managed => |payload| try writer.writeAll(payload),
1088 }1100 }
...@@ -1098,26 +1110,26 @@ pub const DeclGen = struct {...@@ -1098,26 +1110,26 @@ pub const DeclGen = struct {
1098 if (layout.tag_size == 0) {1110 if (layout.tag_size == 0) {
1099 return Result{ .appended = {} };1111 return Result{ .appended = {} };
1100 }1112 }
1101 return self.genTypedValue(union_ty.tag_ty, union_val.tag, writer);1113 return self.genTypedValue(union_ty.tag_ty, union_val.tag);
1102 },1114 },
1103 .Pointer => switch (val.tag()) {1115 .Pointer => switch (val.tag()) {
1104 .variable => {1116 .variable => {
1105 const decl = val.castTag(.variable).?.data.owner_decl;1117 const decl = val.castTag(.variable).?.data.owner_decl;
1106 return self.lowerDeclRef(ty, val, decl, writer);1118 return self.lowerDeclRef(ty, val, decl);
1107 },1119 },
1108 .decl_ref => {1120 .decl_ref => {
1109 const decl = val.castTag(.decl_ref).?.data;1121 const decl = val.castTag(.decl_ref).?.data;
1110 return self.lowerDeclRef(ty, val, decl, writer);1122 return self.lowerDeclRef(ty, val, decl);
1111 },1123 },
1112 .slice => {1124 .slice => {
1113 const slice = val.castTag(.slice).?.data;1125 const slice = val.castTag(.slice).?.data;
1114 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1126 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1115 const ptr_ty = ty.slicePtrFieldType(&buf);1127 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)) {
1117 .externally_managed => |data| try writer.writeAll(data),1129 .externally_managed => |data| try writer.writeAll(data),
1118 .appended => {},1130 .appended => {},
1119 }1131 }
1120 switch (try self.genTypedValue(Type.usize, slice.len, writer)) {1132 switch (try self.genTypedValue(Type.usize, slice.len)) {
1121 .externally_managed => |data| try writer.writeAll(data),1133 .externally_managed => |data| try writer.writeAll(data),
1122 .appended => {},1134 .appended => {},
1123 }1135 }
...@@ -1135,14 +1147,14 @@ pub const DeclGen = struct {...@@ -1135,14 +1147,14 @@ pub const DeclGen = struct {
1135 const is_pl = val.errorUnionIsPayload();1147 const is_pl = val.errorUnionIsPayload();
11361148
1137 const err_val = if (!is_pl) val else Value.initTag(.zero);1149 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)) {
1139 .externally_managed => |data| try writer.writeAll(data),1151 .externally_managed => |data| try writer.writeAll(data),
1140 .appended => {},1152 .appended => {},
1141 }1153 }
11421154
1143 if (payload_ty.hasRuntimeBits()) {1155 if (payload_ty.hasRuntimeBits()) {
1144 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);1156 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)) {
1146 .externally_managed => |data| try writer.writeAll(data),1158 .externally_managed => |data| try writer.writeAll(data),
1147 .appended => {},1159 .appended => {},
1148 }1160 }
...@@ -1167,11 +1179,12 @@ pub const DeclGen = struct {...@@ -1167,11 +1179,12 @@ pub const DeclGen = struct {
1167 }1179 }
1168 }1180 }
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();
1171 if (ty.isSlice()) {1184 if (ty.isSlice()) {
1172 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1185 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1173 const slice_ty = ty.slicePtrFieldType(&buf);1186 const slice_ty = ty.slicePtrFieldType(&buf);
1174 switch (try self.genTypedValue(slice_ty, val, writer)) {1187 switch (try self.genTypedValue(slice_ty, val)) {
1175 .appended => {},1188 .appended => {},
1176 .externally_managed => |payload| try writer.writeAll(payload),1189 .externally_managed => |payload| try writer.writeAll(payload),
1177 }1190 }
...@@ -1179,7 +1192,7 @@ pub const DeclGen = struct {...@@ -1179,7 +1192,7 @@ pub const DeclGen = struct {
1179 .base = .{ .tag = .int_u64 },1192 .base = .{ .tag = .int_u64 },
1180 .data = val.sliceLen(),1193 .data = val.sliceLen(),
1181 };1194 };
1182 return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer);1195 return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
1183 }1196 }
11841197
1185 decl.markAlive();1198 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 {...@@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
680 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),680 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
681 // zig fmt: on681 // zig fmt: on
682 }682 }
683
684 assert(!self.register_manager.frozenRegsExist());
685
683 if (std.debug.runtime_safety) {686 if (std.debug.runtime_safety) {
684 if (self.air_bookkeeping < old_air_bookkeeping + 1) {687 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
685 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] });688 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...@@ -809,7 +812,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
809 const stack_mcv = try self.allocRegOrMem(inst, false);812 const stack_mcv = try self.allocRegOrMem(inst, false);
810 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });813 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
811 const reg_mcv = self.getResolvedInstValue(inst);814 const reg_mcv = self.getResolvedInstValue(inst);
812 assert(reg == reg_mcv.register.to64());815 assert(reg.to64() == reg_mcv.register.to64());
813 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];816 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
814 try branch.inst_table.put(self.gpa, inst, stack_mcv);817 try branch.inst_table.put(self.gpa, inst, stack_mcv);
815 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);818 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 {...@@ -827,9 +830,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
827/// Allocates a new register and copies `mcv` into it.830/// Allocates a new register and copies `mcv` into it.
828/// `reg_owner` is the instruction that gets associated with the register in the register table.831/// `reg_owner` is the instruction that gets associated with the register in the register table.
829/// This can have a side effect of spilling instructions to the stack to free up a register.832/// 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 {
831 const reg = try self.register_manager.allocReg(reg_owner, &.{});834 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);
833 return MCValue{ .register = reg };836 return MCValue{ .register = reg };
834}837}
835838
...@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa...@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
838fn copyToNewRegisterWithExceptions(841fn copyToNewRegisterWithExceptions(
839 self: *Self,842 self: *Self,
840 reg_owner: Air.Inst.Index,843 reg_owner: Air.Inst.Index,
844 ty: Type,
841 mcv: MCValue,845 mcv: MCValue,
842 exceptions: []const Register,846 exceptions: []const Register,
843) !MCValue {847) !MCValue {
844 const reg = try self.register_manager.allocReg(reg_owner, exceptions);848 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);
846 return MCValue{ .register = reg };850 return MCValue{ .register = reg };
847}851}
848852
...@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
892 if (operand_abi_size > 8 or dest_abi_size > 8) {896 if (operand_abi_size > 8 or dest_abi_size > 8) {
893 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});897 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
894 }898 }
895 const reg = switch (operand) {899
896 .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),900 if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
897 else => try self.register_manager.allocReg(inst, &.{}),901 defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
898 };902 break :blk try self.copyToNewRegister(inst, dest_ty, operand);
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)) };
902 };903 };
903904
904 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });905 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
...@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1208 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {1209 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1209 break :result operand;1210 break :result operand;
1210 }1211 }
1211 break :result try self.copyToNewRegister(inst, operand);1212 break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand);
1212 };1213 };
1213 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1214 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1214}1215}
...@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1479 const index_ty = self.air.typeOf(extra.rhs);1480 const index_ty = self.air.typeOf(extra.rhs);
1480 const index = try self.resolveInst(extra.rhs);1481 const index = try self.resolveInst(extra.rhs);
1481 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);1482 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
1482 const dst_mcv = blk: {1483
1483 switch (ptr) {1484 self.register_manager.freezeRegs(&.{offset_reg});
1484 .ptr_stack_offset => {1485 defer self.register_manager.unfreezeRegs(&.{offset_reg});
1485 const reg = try self.register_manager.allocReg(inst, &.{offset_reg});1486
1486 try self.genSetReg(ptr_ty, reg, ptr);1487 const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr);
1487 break :blk .{ .register = reg };
1488 },
1489 else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
1490 }
1491 };
1492 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });1488 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
1493 break :result dst_mcv;1489 break :result dst_mcv;
1494 };1490 };
...@@ -1795,22 +1791,62 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {...@@ -1795,22 +1791,62 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
1795}1791}
17961792
1797fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {1793fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
1798 return if (self.liveness.isUnused(inst)) .dead else result: {1794 if (self.liveness.isUnused(inst)) {
1799 const mcv = try self.resolveInst(operand);1795 return MCValue.dead;
1800 const struct_ty = self.air.typeOf(operand).childType();1796 }
1801 const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));1797 const mcv = try self.resolveInst(operand);
1802 const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));1798 const ptr_ty = self.air.typeOf(operand);
1803 const struct_field_ty = struct_ty.structFieldType(index);1799 const struct_ty = ptr_ty.childType();
1804 const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));1800 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
18051801 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: {
1806 switch (mcv) {1806 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 },
1807 .ptr_stack_offset => |off| {1818 .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);
1809 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };1821 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
1810 },1822 },
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 },
1811 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),1846 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
1812 }1847 }
1813 };1848 };
1849 return dst_mcv;
1814}1850}
18151851
1816fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {1852fn 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:...@@ -1859,13 +1895,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1859 // Source operand can be an immediate, 8 bits or 32 bits.1895 // Source operand can be an immediate, 8 bits or 32 bits.
1860 // So, if either one of the operands dies with this instruction, we can use it1896 // So, if either one of the operands dies with this instruction, we can use it
1861 // as the result MCValue.1897 // as the result MCValue.
1898 const dst_ty = self.air.typeOfIndex(inst);
1862 var dst_mcv: MCValue = undefined;1899 var dst_mcv: MCValue = undefined;
1863 var src_mcv: MCValue = undefined;1900 var src_mcv: MCValue = undefined;
1864 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {1901 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
1865 // LHS dies; use it as the destination.1902 // LHS dies; use it as the destination.
1866 // Both operands cannot be memory.1903 // Both operands cannot be memory.
1867 if (lhs.isMemory() and rhs.isMemory()) {1904 if (lhs.isMemory() and rhs.isMemory()) {
1868 dst_mcv = try self.copyToNewRegister(inst, lhs);1905 dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
1869 src_mcv = rhs;1906 src_mcv = rhs;
1870 } else {1907 } else {
1871 dst_mcv = lhs;1908 dst_mcv = lhs;
...@@ -1875,7 +1912,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1875,7 +1912,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1875 // RHS dies; use it as the destination.1912 // RHS dies; use it as the destination.
1876 // Both operands cannot be memory.1913 // Both operands cannot be memory.
1877 if (lhs.isMemory() and rhs.isMemory()) {1914 if (lhs.isMemory() and rhs.isMemory()) {
1878 dst_mcv = try self.copyToNewRegister(inst, rhs);1915 dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
1879 src_mcv = lhs;1916 src_mcv = lhs;
1880 } else {1917 } else {
1881 dst_mcv = rhs;1918 dst_mcv = rhs;
...@@ -1887,18 +1924,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1887,18 +1924,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1887 // If the allocated register is the same as the rhs register, don't allocate that one1924 // If the allocated register is the same as the rhs register, don't allocate that one
1888 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation1925 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
1889 // in the presence of several binary operations performed in a single block.1926 // 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})
1891 else1928 else
1892 try self.copyToNewRegister(inst, lhs);1929 try self.copyToNewRegister(inst, dst_ty, lhs);
1893 src_mcv = rhs;1930 src_mcv = rhs;
1894 } else {1931 } else {
1895 dst_mcv = if (lhs.isRegister())1932 dst_mcv = if (lhs.isRegister())
1896 // If the allocated register is the same as the rhs register, don't allocate that one1933 // If the allocated register is the same as the rhs register, don't allocate that one
1897 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation1934 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
1898 // in the presence of several binary operations performed in a single block.1935 // 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})
1900 else1937 else
1901 try self.copyToNewRegister(inst, rhs);1938 try self.copyToNewRegister(inst, dst_ty, rhs);
1902 src_mcv = lhs;1939 src_mcv = lhs;
1903 }1940 }
1904 }1941 }
...@@ -1917,7 +1954,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1917,7 +1954,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1917 }1954 }
19181955
1919 // Now for step 2, we assing an MIR instruction1956 // Now for step 2, we assing an MIR instruction
1920 const dst_ty = self.air.typeOfIndex(inst);
1921 const air_tags = self.air.instructions.items(.tag);1957 const air_tags = self.air.instructions.items(.tag);
1922 switch (air_tags[inst]) {1958 switch (air_tags[inst]) {
1923 .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),1959 .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 {...@@ -2417,7 +2453,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2417 .register => |reg| {2453 .register => |reg| {
2418 if (Register.allocIndex(reg) == null) {2454 if (Register.allocIndex(reg) == null) {
2419 // Save function return value in a callee saved register2455 // 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);
2421 }2457 }
2422 },2458 },
2423 else => {},2459 else => {},
...@@ -2494,7 +2530,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2494,7 +2530,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2494 // Either one, but not both, can be a memory operand.2530 // Either one, but not both, can be a memory operand.
2495 // Source operand can be an immediate, 8 bits or 32 bits.2531 // Source operand can be an immediate, 8 bits or 32 bits.
2496 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))2532 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)
2498 else2534 else
2499 lhs;2535 lhs;
2500 // This instruction supports only signed 32-bit immediates at most.2536 // This instruction supports only signed 32-bit immediates at most.
src/codegen.zig+24-1
...@@ -373,11 +373,24 @@ pub fn generateSymbol(...@@ -373,11 +373,24 @@ pub fn generateSymbol(
373 },373 },
374 .Struct => {374 .Struct => {
375 // TODO debug info375 // TODO debug info
376 // TODO padding of struct members376 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;
377 const field_vals = typed_value.val.castTag(.@"struct").?.data;389 const field_vals = typed_value.val.castTag(.@"struct").?.data;
378 for (field_vals) |field_val, index| {390 for (field_vals) |field_val, index| {
379 const field_ty = typed_value.ty.structFieldType(index);391 const field_ty = typed_value.ty.structFieldType(index);
380 if (!field_ty.hasRuntimeBits()) continue;392 if (!field_ty.hasRuntimeBits()) continue;
393
381 switch (try generateSymbol(bin_file, src_loc, .{394 switch (try generateSymbol(bin_file, src_loc, .{
382 .ty = field_ty,395 .ty = field_ty,
383 .val = field_val,396 .val = field_val,
...@@ -388,6 +401,16 @@ pub fn generateSymbol(...@@ -388,6 +401,16 @@ pub fn generateSymbol(
388 },401 },
389 .fail => |em| return Result{ .fail = em },402 .fail => |em| return Result{ .fail = em },
390 }403 }
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 }
391 }414 }
392415
393 return Result{ .appended = {} };416 return Result{ .appended = {} };
src/link/Elf.zig+1
...@@ -2367,6 +2367,7 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {...@@ -2367,6 +2367,7 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2367}2367}
23682368
2369fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {2369fn 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 });
2370 const required_alignment = decl.ty.abiAlignment(self.base.options.target);2371 const required_alignment = decl.ty.abiAlignment(self.base.options.target);
23712372
2372 const block_list = self.getDeclBlockList(decl);2373 const block_list = self.getDeclBlockList(decl);
test/behavior.zig+1-1
...@@ -34,6 +34,7 @@ test {...@@ -34,6 +34,7 @@ test {
34 _ = @import("behavior/slice_sentinel_comptime.zig");34 _ = @import("behavior/slice_sentinel_comptime.zig");
35 _ = @import("behavior/type.zig");35 _ = @import("behavior/type.zig");
36 _ = @import("behavior/truncate.zig");36 _ = @import("behavior/truncate.zig");
37 _ = @import("behavior/struct.zig");
3738
38 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {39 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
39 // Tests that pass for stage1, llvm backend, C backend, wasm backend.40 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
...@@ -69,7 +70,6 @@ test {...@@ -69,7 +70,6 @@ test {
69 _ = @import("behavior/ptrcast.zig");70 _ = @import("behavior/ptrcast.zig");
70 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");71 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
71 _ = @import("behavior/src.zig");72 _ = @import("behavior/src.zig");
72 _ = @import("behavior/struct.zig");
73 _ = @import("behavior/this.zig");73 _ = @import("behavior/this.zig");
74 _ = @import("behavior/try.zig");74 _ = @import("behavior/try.zig");
75 _ = @import("behavior/type_info.zig");75 _ = @import("behavior/type_info.zig");
test/behavior/cast.zig-4
...@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;...@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7test "int to ptr cast" {7test "int to ptr cast" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
9
10 const x = @as(usize, 13);8 const x = @as(usize, 13);
11 const y = @intToPtr(*u8, x);9 const y = @intToPtr(*u8, x);
12 const z = @ptrToInt(y);10 const z = @ptrToInt(y);
...@@ -14,8 +12,6 @@ test "int to ptr cast" {...@@ -14,8 +12,6 @@ test "int to ptr cast" {
14}12}
1513
16test "integer literal to pointer cast" {14test "integer literal to pointer cast" {
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
18
19 const vga_mem = @intToPtr(*u16, 0xB8000);15 const vga_mem = @intToPtr(*u16, 0xB8000);
20 try expect(@ptrToInt(vga_mem) == 0xB8000);16 try expect(@ptrToInt(vga_mem) == 0xB8000);
21}17}
test/behavior/struct.zig+57
...@@ -9,6 +9,8 @@ const maxInt = std.math.maxInt;...@@ -9,6 +9,8 @@ const maxInt = std.math.maxInt;
9top_level_field: i32,9top_level_field: i32,
1010
11test "top level fields" {11test "top level fields" {
12 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13
12 var instance = @This(){14 var instance = @This(){
13 .top_level_field = 1234,15 .top_level_field = 1234,
14 };16 };
...@@ -16,6 +18,39 @@ test "top level fields" {...@@ -16,6 +18,39 @@ test "top level fields" {
16 try expect(@as(i32, 1235) == instance.top_level_field);18 try expect(@as(i32, 1235) == instance.top_level_field);
17}19}
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
19const StructWithNoFields = struct {54const StructWithNoFields = struct {
20 fn add(a: i32, b: i32) i32 {55 fn add(a: i32, b: i32) i32 {
21 return a + b;56 return a + b;
...@@ -29,6 +64,8 @@ const StructFoo = struct {...@@ -29,6 +64,8 @@ const StructFoo = struct {
29};64};
3065
31test "structs" {66test "structs" {
67 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
68
32 var foo: StructFoo = undefined;69 var foo: StructFoo = undefined;
33 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));70 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
34 foo.a += 1;71 foo.a += 1;
...@@ -45,6 +82,8 @@ fn testMutation(foo: *StructFoo) void {...@@ -45,6 +82,8 @@ fn testMutation(foo: *StructFoo) void {
45}82}
4683
47test "struct byval assign" {84test "struct byval assign" {
85 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
86
48 var foo1: StructFoo = undefined;87 var foo1: StructFoo = undefined;
49 var foo2: StructFoo = undefined;88 var foo2: StructFoo = undefined;
5089
...@@ -56,6 +95,8 @@ test "struct byval assign" {...@@ -56,6 +95,8 @@ test "struct byval assign" {
56}95}
5796
58test "call struct static method" {97test "call struct static method" {
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99
59 const result = StructWithNoFields.add(3, 4);100 const result = StructWithNoFields.add(3, 4);
60 try expect(result == 7);101 try expect(result == 7);
61}102}
...@@ -85,6 +126,8 @@ const Val = struct {...@@ -85,6 +126,8 @@ const Val = struct {
85};126};
86127
87test "fn call of struct field" {128test "fn call of struct field" {
129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
130
88 const Foo = struct {131 const Foo = struct {
89 ptr: fn () i32,132 ptr: fn () i32,
90 };133 };
...@@ -114,12 +157,16 @@ const MemberFnTestFoo = struct {...@@ -114,12 +157,16 @@ const MemberFnTestFoo = struct {
114};157};
115158
116test "call member function directly" {159test "call member function directly" {
160 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161
117 const instance = MemberFnTestFoo{ .x = 1234 };162 const instance = MemberFnTestFoo{ .x = 1234 };
118 const result = MemberFnTestFoo.member(instance);163 const result = MemberFnTestFoo.member(instance);
119 try expect(result == 1234);164 try expect(result == 1234);
120}165}
121166
122test "store member function in variable" {167test "store member function in variable" {
168 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
169
123 const instance = MemberFnTestFoo{ .x = 1234 };170 const instance = MemberFnTestFoo{ .x = 1234 };
124 const memberFn = MemberFnTestFoo.member;171 const memberFn = MemberFnTestFoo.member;
125 const result = memberFn(instance);172 const result = memberFn(instance);
...@@ -127,6 +174,8 @@ test "store member function in variable" {...@@ -127,6 +174,8 @@ test "store member function in variable" {
127}174}
128175
129test "member functions" {176test "member functions" {
177 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
178
130 const r = MemberFnRand{ .seed = 1234 };179 const r = MemberFnRand{ .seed = 1234 };
131 try expect(r.getSeed() == 1234);180 try expect(r.getSeed() == 1234);
132}181}
...@@ -138,6 +187,8 @@ const MemberFnRand = struct {...@@ -138,6 +187,8 @@ const MemberFnRand = struct {
138};187};
139188
140test "return struct byval from function" {189test "return struct byval from function" {
190 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
191
141 const bar = makeBar2(1234, 5678);192 const bar = makeBar2(1234, 5678);
142 try expect(bar.y == 5678);193 try expect(bar.y == 5678);
143}194}
...@@ -153,6 +204,8 @@ fn makeBar2(x: i32, y: i32) Bar {...@@ -153,6 +204,8 @@ fn makeBar2(x: i32, y: i32) Bar {
153}204}
154205
155test "call method with mutable reference to struct with no fields" {206test "call method with mutable reference to struct with no fields" {
207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
208
156 const S = struct {209 const S = struct {
157 fn doC(s: *const @This()) bool {210 fn doC(s: *const @This()) bool {
158 _ = s;211 _ = s;
...@@ -172,6 +225,8 @@ test "call method with mutable reference to struct with no fields" {...@@ -172,6 +225,8 @@ test "call method with mutable reference to struct with no fields" {
172}225}
173226
174test "usingnamespace within struct scope" {227test "usingnamespace within struct scope" {
228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
229
175 const S = struct {230 const S = struct {
176 usingnamespace struct {231 usingnamespace struct {
177 pub fn inner() i32 {232 pub fn inner() i32 {
...@@ -183,6 +238,8 @@ test "usingnamespace within struct scope" {...@@ -183,6 +238,8 @@ test "usingnamespace within struct scope" {
183}238}
184239
185test "struct field init with catch" {240test "struct field init with catch" {
241 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
242
186 const S = struct {243 const S = struct {
187 fn doTheTest() !void {244 fn doTheTest() !void {
188 var x: anyerror!isize = 1;245 var x: anyerror!isize = 1;