authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-27 20:22:54+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-09 19:17:17+02:00
log261fec8036e1e5518951d91c5fc27b53c1a511d8
tree03e2856039842234617a97d32233551c447e9795
parente2b029e2c8ad761c32886d27aa0227655a60eb9e
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: amend implementation of various AIR instructions

- unwrap_errunion_err for registers - unwrap_errunion_payload for registers - ptr_slice_len_ptr for all MCValues - ptr_slice_ptr_ptr for all MCValues

15 files changed, 208 insertions(+), 119 deletions(-)

src/arch/arm/CodeGen.zig+208-89
......@@ -451,9 +451,7 @@ fn gen(self: *Self) !void {
451451 // The address of where to store the return value is in
452452 // r0. As this register might get overwritten along the
453453 // way, save the address to the stack.
454 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4;
455 self.next_stack_offset = stack_offset;
456 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
454 const stack_offset = try self.allocMem(4, 4, null);
457455
458456 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
459457 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
......@@ -893,17 +891,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
893891 try table.ensureUnusedCapacity(self.gpa, additional_count);
894892}
895893
896fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
894fn allocMem(
895 self: *Self,
896 abi_size: u32,
897 abi_align: u32,
898 maybe_inst: ?Air.Inst.Index,
899) !u32 {
900 assert(abi_size > 0);
901 assert(abi_align > 0);
902
897903 if (abi_align > self.stack_align)
898904 self.stack_align = abi_align;
905
899906 // TODO find a free slot instead of always appending
900907 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
901908 self.next_stack_offset = offset;
902909 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
903 try self.stack.putNoClobber(self.gpa, offset, .{
904 .inst = inst,
905 .size = abi_size,
906 });
910
911 if (maybe_inst) |inst| {
912 try self.stack.putNoClobber(self.gpa, offset, .{
913 .inst = inst,
914 .size = abi_size,
915 });
916 }
917
907918 return offset;
908919}
909920
......@@ -925,7 +936,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
925936 };
926937 // TODO swap this for inst.ty.ptrAlign
927938 const abi_align = elem_ty.abiAlignment(self.target.*);
928 return self.allocMem(inst, abi_size, abi_align);
939 return self.allocMem(abi_size, abi_align, inst);
929940}
930941
931942fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
......@@ -948,7 +959,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
948959 }
949960 }
950961 }
951 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
962 const stack_offset = try self.allocMem(abi_size, abi_align, inst);
952963 return MCValue{ .stack_offset = stack_offset };
953964}
954965
......@@ -1182,29 +1193,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
11821193fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11831194 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11841195 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1185 const operand = try self.resolveInst(ty_op.operand);
1196 const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
11861197 const operand_ty = self.air.typeOf(ty_op.operand);
1187 switch (operand) {
1198 switch (try operand_bind.resolveToMcv(self)) {
11881199 .dead => unreachable,
11891200 .unreach => unreachable,
11901201 .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() },
11911202 else => {
11921203 switch (operand_ty.zigTypeTag()) {
11931204 .Bool => {
1194 const op_reg = switch (operand) {
1195 .register => |r| r,
1196 else => try self.copyToTmpRegister(operand_ty, operand),
1197 };
1198 const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
1199 defer self.register_manager.unlockReg(op_reg_lock);
1200
1201 const dest_reg = blk: {
1202 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1203 break :blk op_reg;
1204 }
1205 var op_reg: Register = undefined;
1206 var dest_reg: Register = undefined;
12051207
1206 break :blk try self.register_manager.allocReg(null, gp);
1208 const read_args = [_]ReadArg{
1209 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg },
1210 };
1211 const write_args = [_]WriteArg{
1212 .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg },
12071213 };
1214 try self.allocRegs(
1215 &read_args,
1216 &write_args,
1217 ReuseMetadata{
1218 .corresponding_inst = inst,
1219 .operand_mapping = &.{0},
1220 },
1221 );
12081222
12091223 _ = try self.addInst(.{
12101224 .tag = .eor,
......@@ -1221,20 +1235,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
12211235 .Int => {
12221236 const int_info = operand_ty.intInfo(self.target.*);
12231237 if (int_info.bits <= 32) {
1224 const op_reg = switch (operand) {
1225 .register => |r| r,
1226 else => try self.copyToTmpRegister(operand_ty, operand),
1227 };
1228 const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
1229 defer self.register_manager.unlockReg(op_reg_lock);
1230
1231 const dest_reg = blk: {
1232 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1233 break :blk op_reg;
1234 }
1238 var op_reg: Register = undefined;
1239 var dest_reg: Register = undefined;
12351240
1236 break :blk try self.register_manager.allocReg(null, gp);
1241 const read_args = [_]ReadArg{
1242 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg },
1243 };
1244 const write_args = [_]WriteArg{
1245 .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg },
12371246 };
1247 try self.allocRegs(
1248 &read_args,
1249 &write_args,
1250 ReuseMetadata{
1251 .corresponding_inst = inst,
1252 .operand_mapping = &.{0},
1253 },
1254 );
12381255
12391256 _ = try self.addInst(.{
12401257 .tag = .mvn,
......@@ -1384,7 +1401,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
13841401 const len = try self.resolveInst(bin_op.rhs);
13851402 const len_ty = self.air.typeOf(bin_op.rhs);
13861403
1387 const stack_offset = try self.allocMem(inst, 8, 4);
1404 const stack_offset = try self.allocMem(8, 4, inst);
13881405 try self.genSetStack(ptr_ty, stack_offset, ptr);
13891406 try self.genSetStack(len_ty, stack_offset - 4, len);
13901407 break :result MCValue{ .stack_offset = stack_offset };
......@@ -1496,7 +1513,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14961513 assert(lhs_ty.eql(rhs_ty, mod));
14971514 const int_info = lhs_ty.intInfo(self.target.*);
14981515 if (int_info.bits < 32) {
1499 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1516 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
15001517
15011518 try self.spillCompareFlagsIfOccupied();
15021519
......@@ -1609,7 +1626,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16091626 assert(lhs_ty.eql(rhs_ty, mod));
16101627 const int_info = lhs_ty.intInfo(self.target.*);
16111628 if (int_info.bits <= 16) {
1612 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1629 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
16131630
16141631 try self.spillCompareFlagsIfOccupied();
16151632
......@@ -1644,7 +1661,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16441661
16451662 break :result MCValue{ .stack_offset = stack_offset };
16461663 } else if (int_info.bits <= 32) {
1647 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1664 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
16481665
16491666 try self.spillCompareFlagsIfOccupied();
16501667
......@@ -1769,7 +1786,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
17691786 .Int => {
17701787 const int_info = lhs_ty.intInfo(self.target.*);
17711788 if (int_info.bits <= 32) {
1772 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1789 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
17731790
17741791 try self.spillCompareFlagsIfOccupied();
17751792
......@@ -1926,19 +1943,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
19261943}
19271944
19281945/// Given an error union, returns the error
1929fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1946fn errUnionErr(
1947 self: *Self,
1948 error_union_bind: ReadArg.Bind,
1949 error_union_ty: Type,
1950 maybe_inst: ?Air.Inst.Index,
1951) !MCValue {
19301952 const err_ty = error_union_ty.errorUnionSet();
19311953 const payload_ty = error_union_ty.errorUnionPayload();
19321954 if (err_ty.errorSetIsEmpty()) {
19331955 return MCValue{ .immediate = 0 };
19341956 }
19351957 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1936 return error_union_mcv;
1958 return try error_union_bind.resolveToMcv(self);
19371959 }
19381960
19391961 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
1940 switch (error_union_mcv) {
1941 .register => return self.fail("TODO errUnionErr for registers", .{}),
1962 switch (try error_union_bind.resolveToMcv(self)) {
1963 .register => {
1964 var operand_reg: Register = undefined;
1965 var dest_reg: Register = undefined;
1966
1967 const read_args = [_]ReadArg{
1968 .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg },
1969 };
1970 const write_args = [_]WriteArg{
1971 .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1972 };
1973 try self.allocRegs(
1974 &read_args,
1975 &write_args,
1976 if (maybe_inst) |inst| .{
1977 .corresponding_inst = inst,
1978 .operand_mapping = &.{0},
1979 } else null,
1980 );
1981
1982 const err_bit_offset = err_offset * 8;
1983 const err_bit_size = @intCast(u32, err_ty.abiSize(self.target.*)) * 8;
1984
1985 _ = try self.addInst(.{
1986 .tag = .ubfx, // errors are unsigned integers
1987 .data = .{ .rr_lsb_width = .{
1988 .rd = dest_reg,
1989 .rn = operand_reg,
1990 .lsb = @intCast(u5, err_bit_offset),
1991 .width = @intCast(u6, err_bit_size),
1992 } },
1993 });
1994
1995 return MCValue{ .register = dest_reg };
1996 },
19421997 .stack_argument_offset => |off| {
19431998 return MCValue{ .stack_argument_offset = off + err_offset };
19441999 },
......@@ -1955,27 +2010,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
19552010fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
19562011 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
19572012 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2013 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
19582014 const error_union_ty = self.air.typeOf(ty_op.operand);
1959 const mcv = try self.resolveInst(ty_op.operand);
1960 break :result try self.errUnionErr(mcv, error_union_ty);
2015
2016 break :result try self.errUnionErr(error_union_bind, error_union_ty, inst);
19612017 };
19622018 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
19632019}
19642020
19652021/// Given an error union, returns the payload
1966fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
2022fn errUnionPayload(
2023 self: *Self,
2024 error_union_bind: ReadArg.Bind,
2025 error_union_ty: Type,
2026 maybe_inst: ?Air.Inst.Index,
2027) !MCValue {
19672028 const err_ty = error_union_ty.errorUnionSet();
19682029 const payload_ty = error_union_ty.errorUnionPayload();
19692030 if (err_ty.errorSetIsEmpty()) {
1970 return error_union_mcv;
2031 return try error_union_bind.resolveToMcv(self);
19712032 }
19722033 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
19732034 return MCValue.none;
19742035 }
19752036
19762037 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
1977 switch (error_union_mcv) {
1978 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2038 switch (try error_union_bind.resolveToMcv(self)) {
2039 .register => {
2040 var operand_reg: Register = undefined;
2041 var dest_reg: Register = undefined;
2042
2043 const read_args = [_]ReadArg{
2044 .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg },
2045 };
2046 const write_args = [_]WriteArg{
2047 .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg },
2048 };
2049 try self.allocRegs(
2050 &read_args,
2051 &write_args,
2052 if (maybe_inst) |inst| .{
2053 .corresponding_inst = inst,
2054 .operand_mapping = &.{0},
2055 } else null,
2056 );
2057
2058 const payload_bit_offset = payload_offset * 8;
2059 const payload_bit_size = @intCast(u32, payload_ty.abiSize(self.target.*)) * 8;
2060
2061 _ = try self.addInst(.{
2062 .tag = if (payload_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx,
2063 .data = .{ .rr_lsb_width = .{
2064 .rd = dest_reg,
2065 .rn = operand_reg,
2066 .lsb = @intCast(u5, payload_bit_offset),
2067 .width = @intCast(u6, payload_bit_size),
2068 } },
2069 });
2070
2071 return MCValue{ .register = dest_reg };
2072 },
19792073 .stack_argument_offset => |off| {
19802074 return MCValue{ .stack_argument_offset = off + payload_offset };
19812075 },
......@@ -1992,9 +2086,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
19922086fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
19932087 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
19942088 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2089 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
19952090 const error_union_ty = self.air.typeOf(ty_op.operand);
1996 const error_union = try self.resolveInst(ty_op.operand);
1997 break :result try self.errUnionPayload(error_union, error_union_ty);
2091
2092 break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst);
19982093 };
19992094 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
20002095}
......@@ -2038,17 +2133,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
20382133 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
20392134 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20402135 const error_union_ty = self.air.getRefType(ty_op.ty);
2136 const error_ty = error_union_ty.errorUnionSet();
20412137 const payload_ty = error_union_ty.errorUnionPayload();
20422138 const operand = try self.resolveInst(ty_op.operand);
20432139 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
20442140
20452141 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
20462142 const abi_align = error_union_ty.abiAlignment(self.target.*);
2047 const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
2143 const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst));
20482144 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
20492145 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
20502146 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand);
2051 try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 });
2147 try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 });
20522148
20532149 break :result MCValue{ .stack_offset = stack_offset };
20542150 };
......@@ -2060,16 +2156,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
20602156 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
20612157 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20622158 const error_union_ty = self.air.getRefType(ty_op.ty);
2159 const error_ty = error_union_ty.errorUnionSet();
20632160 const payload_ty = error_union_ty.errorUnionPayload();
20642161 const operand = try self.resolveInst(ty_op.operand);
20652162 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
20662163
20672164 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
20682165 const abi_align = error_union_ty.abiAlignment(self.target.*);
2069 const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
2166 const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst));
20702167 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
20712168 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
2072 try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), operand);
2169 try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand);
20732170 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef);
20742171
20752172 break :result MCValue{ .stack_offset = stack_offset };
......@@ -2108,7 +2205,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
21082205 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
21092206 const mcv = try self.resolveInst(ty_op.operand);
21102207 switch (mcv) {
2111 .dead, .unreach => unreachable,
21122208 .register => unreachable, // a slice doesn't fit in one register
21132209 .stack_argument_offset => |off| {
21142210 break :result MCValue{ .stack_argument_offset = off + 4 };
......@@ -2119,7 +2215,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
21192215 .memory => |addr| {
21202216 break :result MCValue{ .memory = addr + 4 };
21212217 },
2122 else => return self.fail("TODO implement slice_len for {}", .{mcv}),
2218 else => unreachable, // invalid MCValue for a slice
21232219 }
21242220 };
21252221 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -2134,7 +2230,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
21342230 .ptr_stack_offset => |off| {
21352231 break :result MCValue{ .ptr_stack_offset = off - 4 };
21362232 },
2137 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),
2233 else => {
2234 const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
2235 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 4 } };
2236
2237 break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
2238 },
21382239 }
21392240 };
21402241 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -2149,7 +2250,13 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
21492250 .ptr_stack_offset => |off| {
21502251 break :result MCValue{ .ptr_stack_offset = off };
21512252 },
2152 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}),
2253 else => {
2254 if (self.reuseOperand(inst, ty_op.operand, 0, mcv)) {
2255 break :result mcv;
2256 } else {
2257 break :result MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) };
2258 }
2259 },
21532260 }
21542261 };
21552262 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -3891,7 +3998,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
38913998 .register => |reg| blk: {
38923999 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
38934000 const abi_align = ty.abiAlignment(self.target.*);
3894 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
4001 const stack_offset = try self.allocMem(abi_size, abi_align, inst);
38954002 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
38964003
38974004 break :blk MCValue{ .stack_offset = stack_offset };
......@@ -3978,7 +4085,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
39784085 const ret_ty = fn_ty.fnReturnType();
39794086 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
39804087 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3981 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
4088 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
39824089
39834090 var ptr_ty_payload: Type.Payload.ElemType = .{
39844091 .base = .{ .tag = .single_mut_pointer },
......@@ -4166,14 +4273,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
41664273 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
41674274 const abi_align = ret_ty.abiAlignment(self.target.*);
41684275
4169 // This is essentially allocMem without the
4170 // instruction tracking
4171 if (abi_align > self.stack_align)
4172 self.stack_align = abi_align;
4173 // TODO find a free slot instead of always appending
4174 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
4175 self.next_stack_offset = offset;
4176 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
4276 const offset = try self.allocMem(abi_size, abi_align, null);
41774277
41784278 const tmp_mcv = MCValue{ .stack_offset = offset };
41794279 try self.load(tmp_mcv, ptr, ptr_ty);
......@@ -4545,20 +4645,28 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
45454645 return MCValue{ .cpsr_flags = .ne };
45464646}
45474647
4548fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
4549 const error_type = ty.errorUnionSet();
4648fn isErr(
4649 self: *Self,
4650 error_union_bind: ReadArg.Bind,
4651 error_union_ty: Type,
4652) !MCValue {
4653 const error_type = error_union_ty.errorUnionSet();
45504654
45514655 if (error_type.errorSetIsEmpty()) {
45524656 return MCValue{ .immediate = 0 }; // always false
45534657 }
45544658
4555 const error_mcv = try self.errUnionErr(operand, ty);
4659 const error_mcv = try self.errUnionErr(error_union_bind, error_union_ty, null);
45564660 _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq);
45574661 return MCValue{ .cpsr_flags = .hi };
45584662}
45594663
4560fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
4561 const is_err_result = try self.isErr(ty, operand);
4664fn isNonErr(
4665 self: *Self,
4666 error_union_bind: ReadArg.Bind,
4667 error_union_ty: Type,
4668) !MCValue {
4669 const is_err_result = try self.isErr(error_union_bind, error_union_ty);
45624670 switch (is_err_result) {
45634671 .cpsr_flags => |cond| {
45644672 assert(cond == .hi);
......@@ -4637,9 +4745,10 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
46374745fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
46384746 const un_op = self.air.instructions.items(.data)[inst].un_op;
46394747 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4640 const operand = try self.resolveInst(un_op);
4641 const ty = self.air.typeOf(un_op);
4642 break :result try self.isErr(ty, operand);
4748 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4749 const error_union_ty = self.air.typeOf(un_op);
4750
4751 break :result try self.isErr(error_union_bind, error_union_ty);
46434752 };
46444753 return self.finishAir(inst, result, .{ un_op, .none, .none });
46454754}
......@@ -4658,7 +4767,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
46584767 }
46594768 };
46604769 try self.load(operand, operand_ptr, ptr_ty);
4661 break :result try self.isErr(ptr_ty.elemType(), operand);
4770 break :result try self.isErr(.{ .mcv = operand }, ptr_ty.elemType());
46624771 };
46634772 return self.finishAir(inst, result, .{ un_op, .none, .none });
46644773}
......@@ -4666,9 +4775,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
46664775fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
46674776 const un_op = self.air.instructions.items(.data)[inst].un_op;
46684777 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4669 const operand = try self.resolveInst(un_op);
4670 const ty = self.air.typeOf(un_op);
4671 break :result try self.isNonErr(ty, operand);
4778 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4779 const error_union_ty = self.air.typeOf(un_op);
4780
4781 break :result try self.isNonErr(error_union_bind, error_union_ty);
46724782 };
46734783 return self.finishAir(inst, result, .{ un_op, .none, .none });
46744784}
......@@ -4687,7 +4797,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
46874797 }
46884798 };
46894799 try self.load(operand, operand_ptr, ptr_ty);
4690 break :result try self.isNonErr(ptr_ty.elemType(), operand);
4800 break :result try self.isNonErr(.{ .mcv = operand }, ptr_ty.elemType());
46914801 };
46924802 return self.finishAir(inst, result, .{ un_op, .none, .none });
46934803}
......@@ -5620,7 +5730,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
56205730 const array_ty = ptr_ty.childType();
56215731 const array_len = @intCast(u32, array_ty.arrayLen());
56225732
5623 const stack_offset = try self.allocMem(inst, 8, 8);
5733 const stack_offset = try self.allocMem(8, 8, inst);
56245734 try self.genSetStack(ptr_ty, stack_offset, ptr);
56255735 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });
56265736 break :result MCValue{ .stack_offset = stack_offset };
......@@ -5774,15 +5884,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {
57745884 const extra = self.air.extraData(Air.Try, pl_op.payload);
57755885 const body = self.air.extra[extra.end..][0..extra.data.body_len];
57765886 const result: MCValue = result: {
5887 const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand };
57775888 const error_union_ty = self.air.typeOf(pl_op.operand);
5778 const error_union = try self.resolveInst(pl_op.operand);
5779 const is_err_result = try self.isErr(error_union_ty, error_union);
5889 const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
5890 const error_union_align = error_union_ty.abiAlignment(self.target.*);
5891
5892 // The error union will die in the body. However, we need the
5893 // error union after the body in order to extract the payload
5894 // of the error union, so we create a copy of it
5895 const error_union_copy = try self.allocMem(error_union_size, error_union_align, null);
5896 try self.genSetStack(error_union_ty, error_union_copy, try error_union_bind.resolveToMcv(self));
5897
5898 const is_err_result = try self.isErr(error_union_bind, error_union_ty);
57805899 const reloc = try self.condBr(is_err_result);
57815900
57825901 try self.genBody(body);
5783
57845902 try self.performReloc(reloc);
5785 break :result try self.errUnionPayload(error_union, error_union_ty);
5903
5904 break :result try self.errUnionPayload(.{ .mcv = .{ .stack_offset = error_union_copy } }, error_union_ty, null);
57865905 };
57875906 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
57885907}
test/behavior/alignof.zig-1
......@@ -13,7 +13,6 @@ const Foo = struct {
1313test "@alignOf(T) before referencing T" {
1414 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1716 comptime try expect(@alignOf(Foo) != maxInt(usize));
1817 if (native_arch == .x86_64) {
1918 comptime try expect(@alignOf(Foo) == 4);
test/behavior/basic.zig-1
......@@ -1060,7 +1060,6 @@ comptime {
10601060
10611061test "switch inside @as gets correct type" {
10621062 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10641063
10651064 var a: u32 = 0;
10661065 var b: [2]u32 = undefined;
test/behavior/cast.zig-7
......@@ -523,7 +523,6 @@ fn testCastConstArrayRefToConstSlice() !void {
523523
524524test "peer type resolution: error and [N]T" {
525525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
527526
528527 try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
529528 comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
......@@ -548,7 +547,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
548547test "single-item pointer of array to slice to unknown length pointer" {
549548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
550549 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
552550
553551 try testCastPtrOfArrayToSliceAndPtr();
554552 comptime try testCastPtrOfArrayToSliceAndPtr();
......@@ -649,7 +647,6 @@ test "@floatCast cast down" {
649647test "peer type resolution: unreachable, error set, unreachable" {
650648 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
651649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
653650
654651 const Error = error{
655652 FileDescriptorAlreadyPresentInSet,
......@@ -964,7 +961,6 @@ test "peer cast [:x]T to [*:x]T" {
964961
965962test "peer type resolution implicit cast to return type" {
966963 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968964
969965 const S = struct {
970966 fn doTheTest() !void {
......@@ -984,7 +980,6 @@ test "peer type resolution implicit cast to return type" {
984980
985981test "peer type resolution implicit cast to variable type" {
986982 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
988983 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
989984
990985 const S = struct {
......@@ -1026,7 +1021,6 @@ test "cast between C pointer with different but compatible types" {
10261021
10271022test "peer type resolve string lit with sentinel-terminated mutable slice" {
10281023 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10301024 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10311025
10321026 var array: [4:0]u8 = undefined;
......@@ -1079,7 +1073,6 @@ test "comptime float casts" {
10791073test "pointer reinterpret const float to int" {
10801074 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10811075 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831076
10841077 // The hex representation is 0x3fe3333333333303.
10851078 const float: f64 = 5.99999999999994648725e-01;
test/behavior/comptime_memory.zig-2
......@@ -87,7 +87,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
8787test "type pun endianness" {
8888 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8989 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9190
9291 comptime {
9392 const StructOfBytes = extern struct { x: [4]u8 };
......@@ -398,7 +397,6 @@ test "offset field ptr by enclosing array element size" {
398397test "accessing reinterpreted memory of parent object" {
399398 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
400399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
402400 const S = extern struct {
403401 a: f32,
404402 b: [4]u8,
test/behavior/enum.zig-5
......@@ -606,7 +606,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
606606}
607607
608608test "enum with specified tag values" {
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
611610
612611 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
......@@ -614,7 +613,6 @@ test "enum with specified tag values" {
614613}
615614
616615test "non-exhaustive enum" {
617 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
618616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
619617
620618 const S = struct {
......@@ -677,7 +675,6 @@ test "empty non-exhaustive enum" {
677675}
678676
679677test "single field non-exhaustive enum" {
680 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
681678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
682679
683680 const S = struct {
......@@ -741,7 +738,6 @@ test "cast integer literal to enum" {
741738}
742739
743740test "enum with specified and unspecified tag values" {
744 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
745741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
746742
747743 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
......@@ -925,7 +921,6 @@ test "enum literal casting to tagged union" {
925921const Bar = enum { A, B, C, D };
926922
927923test "enum literal casting to error union with payload enum" {
928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
929924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930925
931926 var bar: error{B}!Bar = undefined;
test/behavior/error.zig-4
......@@ -222,7 +222,6 @@ fn testErrorSetType() !void {
222222
223223test "explicit error set cast" {
224224 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
226225 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
227226
228227 try testExplicitErrorSetCast(Set1.A);
......@@ -282,7 +281,6 @@ test "inferred empty error set comptime catch" {
282281}
283282
284283test "error union peer type resolution" {
285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
286284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
287285
288286 try testErrorUnionPeerTypeResolution(1);
......@@ -327,7 +325,6 @@ fn foo3(b: usize) Error!usize {
327325
328326test "error: Infer error set from literals" {
329327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331328
332329 _ = nullLiteral("n") catch |err| handleErrors(err);
333330 _ = floatLiteral("n") catch |err| handleErrors(err);
......@@ -700,7 +697,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {
700697
701698test "simple else prong allowed even when all errors handled" {
702699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704700 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
705701
706702 const S = struct {
test/behavior/eval.zig-2
......@@ -69,7 +69,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
6969}
7070
7171test "constant expressions" {
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7473
7574 var array: [array_size]u8 = undefined;
......@@ -565,7 +564,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
565564}
566565
567566test "ptr to local array argument at comptime" {
568 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
569567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
570568
571569 comptime {
test/behavior/merge_error_sets.zig-1
......@@ -12,7 +12,6 @@ fn foo() C!void {
1212}
1313
1414test "merge error sets" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1716 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1817 if (foo()) {
test/behavior/slice.zig-2
......@@ -28,7 +28,6 @@ comptime {
2828
2929test "slicing" {
3030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3231
3332 var array: [20]i32 = undefined;
3433
......@@ -283,7 +282,6 @@ test "slice type with custom alignment" {
283282
284283test "obtaining a null terminated slice" {
285284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
287285
288286 // here we have a normal array
289287 var buf: [50]u8 = undefined;
test/behavior/struct.zig-1
......@@ -104,7 +104,6 @@ fn testMutation(foo: *StructFoo) void {
104104
105105test "struct byval assign" {
106106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
108107
109108 var foo1: StructFoo = undefined;
110109 var foo2: StructFoo = undefined;
test/behavior/switch.zig-1
......@@ -490,7 +490,6 @@ test "switch prongs with error set cases make a new error set type for capture v
490490}
491491
492492test "return result loc and then switch with range implicit casted to error union" {
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494493 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
495494
496495 const S = struct {
test/behavior/this.zig-1
......@@ -25,7 +25,6 @@ test "this refer to module call private fn" {
2525}
2626
2727test "this refer to container" {
28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2928 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029
3130 var pt: Point(i32) = undefined;
test/behavior/try.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "try on error union" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
98 try tryOnErrorUnionImpl();
test/behavior/while.zig-1
......@@ -175,7 +175,6 @@ test "while with optional as condition with else" {
175175
176176test "while with error union condition" {
177177 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180179
181180 numbers_left = 10;