authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-22 23:18:26-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-22 23:18:26-04:00
log4a837dddd0e2d2a8490f2391e2c4e4fac12bfbc4
tree2fb4a5bd2c56bec09c5c38a127d4dfc654a154d7
parente8813b296bc55a13b534bd9b2a03e1f6af366915
parent98b932cfabb6d33f184f1cb9c3d4a39c41c5c4f7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11266 from joachimschmidt557/stage2-arm

stage2 ARM: move closer to test runner output working

2 files changed, 285 insertions(+), 184 deletions(-)

src/arch/arm/CodeGen.zig+285-182
......@@ -396,8 +396,8 @@ fn gen(self: *Self) !void {
396396 // The address of where to store the return value is in
397397 // r0. As this register might get overwritten along the
398398 // way, save the address to the stack.
399 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4);
400 self.next_stack_offset = stack_offset + 4;
399 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4;
400 self.next_stack_offset = stack_offset;
401401 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
402402
403403 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
......@@ -535,8 +535,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
535535 .mod => try self.airMod(inst),
536536 .shl, .shl_exact => try self.airBinOp(inst),
537537 .shl_sat => try self.airShlSat(inst),
538 .min => try self.airMin(inst),
539 .max => try self.airMax(inst),
538 .min => try self.airMinMax(inst),
539 .max => try self.airMinMax(inst),
540540 .slice => try self.airSlice(inst),
541541
542542 .sqrt,
......@@ -780,10 +780,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
780780 if (abi_align > self.stack_align)
781781 self.stack_align = abi_align;
782782 // TODO find a free slot instead of always appending
783 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
784 self.next_stack_offset = offset + abi_size;
785 if (self.next_stack_offset > self.max_end_stack)
786 self.max_end_stack = self.next_stack_offset;
783 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
784 self.next_stack_offset = offset;
785 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
787786 try self.stack.putNoClobber(self.gpa, offset, .{
788787 .inst = inst,
789788 .size = abi_size,
......@@ -797,8 +796,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
797796
798797 if (!elem_ty.hasRuntimeBits()) {
799798 // As this stack item will never be dereferenced at runtime,
800 // return the current stack offset
801 return self.next_stack_offset;
799 // return the stack offset 0. Stack offset 0 will be where all
800 // zero-sized stack allocations live as non-zero-sized
801 // allocations will always have an offset > 0.
802 return @as(u32, 0);
802803 }
803804
804805 const target = self.target.*;
......@@ -1139,15 +1140,119 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11391140 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11401141}
11411142
1142fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1143 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1144 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});
1145 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1143fn minMax(
1144 self: *Self,
1145 tag: Air.Inst.Tag,
1146 maybe_inst: ?Air.Inst.Index,
1147 lhs: MCValue,
1148 rhs: MCValue,
1149 lhs_ty: Type,
1150 rhs_ty: Type,
1151) !MCValue {
1152 switch (lhs_ty.zigTypeTag()) {
1153 .Float => return self.fail("TODO ARM min/max on floats", .{}),
1154 .Vector => return self.fail("TODO ARM min/max on vectors", .{}),
1155 .Int => {
1156 assert(lhs_ty.eql(rhs_ty, self.target.*));
1157 const int_info = lhs_ty.intInfo(self.target.*);
1158 if (int_info.bits <= 32) {
1159 const lhs_is_register = lhs == .register;
1160 const rhs_is_register = rhs == .register;
1161
1162 const lhs_reg = switch (lhs) {
1163 .register => |r| r,
1164 else => try self.copyToTmpRegister(lhs_ty, lhs),
1165 };
1166 self.register_manager.freezeRegs(&.{lhs_reg});
1167 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1168
1169 const rhs_reg = switch (rhs) {
1170 .register => |r| r,
1171 else => try self.copyToTmpRegister(rhs_ty, rhs),
1172 };
1173 self.register_manager.freezeRegs(&.{rhs_reg});
1174 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
1175
1176 const dest_reg = if (maybe_inst) |inst| blk: {
1177 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1178
1179 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1180 break :blk lhs_reg;
1181 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1182 break :blk rhs_reg;
1183 } else {
1184 break :blk try self.register_manager.allocReg(inst);
1185 }
1186 } else try self.register_manager.allocReg(null);
1187
1188 // lhs == reg should have been checked by airMinMax
1189 //
1190 // By guaranteeing lhs != rhs, we guarantee (dst !=
1191 // lhs) or (dst != rhs), which is a property we use to
1192 // omit generating one instruction when we reuse a
1193 // register.
1194 assert(lhs_reg != rhs_reg); // see note above
1195
1196 _ = try self.binOpRegister(.cmp_eq, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty);
1197
1198 const cond_choose_lhs: Condition = switch (tag) {
1199 .max => switch (int_info.signedness) {
1200 .signed => Condition.gt,
1201 .unsigned => Condition.hi,
1202 },
1203 .min => switch (int_info.signedness) {
1204 .signed => Condition.lt,
1205 .unsigned => Condition.cc,
1206 },
1207 else => unreachable,
1208 };
1209 const cond_choose_rhs = cond_choose_lhs.negate();
1210
1211 if (dest_reg != lhs_reg) {
1212 _ = try self.addInst(.{
1213 .tag = .mov,
1214 .cond = cond_choose_lhs,
1215 .data = .{ .rr_op = .{
1216 .rd = dest_reg,
1217 .rn = .r0,
1218 .op = Instruction.Operand.reg(lhs_reg, Instruction.Operand.Shift.none),
1219 } },
1220 });
1221 }
1222 if (dest_reg != rhs_reg) {
1223 _ = try self.addInst(.{
1224 .tag = .mov,
1225 .cond = cond_choose_rhs,
1226 .data = .{ .rr_op = .{
1227 .rd = dest_reg,
1228 .rn = .r0,
1229 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
1230 } },
1231 });
1232 }
1233
1234 return MCValue{ .register = dest_reg };
1235 } else {
1236 return self.fail("TODO ARM min/max on integers > u32/i32", .{});
1237 }
1238 },
1239 else => unreachable,
1240 }
11461241}
11471242
1148fn airMax(self: *Self, inst: Air.Inst.Index) !void {
1243fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
1244 const tag = self.air.instructions.items(.tag)[inst];
11491245 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1150 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch});
1246 const lhs = try self.resolveInst(bin_op.lhs);
1247 const rhs = try self.resolveInst(bin_op.rhs);
1248 const lhs_ty = self.air.typeOf(bin_op.lhs);
1249 const rhs_ty = self.air.typeOf(bin_op.rhs);
1250
1251 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1252 if (bin_op.lhs == bin_op.rhs) break :result lhs;
1253
1254 break :result try self.minMax(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1255 };
11511256 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11521257}
11531258
......@@ -1161,8 +1266,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
11611266 const len_ty = self.air.typeOf(bin_op.rhs);
11621267
11631268 const stack_offset = try self.allocMem(inst, 8, 8);
1164 try self.genSetStack(ptr_ty, stack_offset + 4, ptr);
1165 try self.genSetStack(len_ty, stack_offset, len);
1269 try self.genSetStack(ptr_ty, stack_offset, ptr);
1270 try self.genSetStack(len_ty, stack_offset - 4, len);
11661271 break :result MCValue{ .stack_offset = stack_offset };
11671272 };
11681273 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -1180,36 +1285,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
11801285 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11811286}
11821287
1183fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
1184 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1185 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});
1186 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1187}
1188
11891288fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
11901289 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11911290 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
11921291 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11931292}
11941293
1195fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
1196 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1197 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
1198 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1199}
1200
12011294fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
12021295 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12031296 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
12041297 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12051298}
12061299
1207fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void {
1208 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1209 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch});
1210 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1211}
1212
12131300fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
12141301 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12151302 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});
......@@ -1278,27 +1365,84 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
12781365 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12791366}
12801367
1368fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1369 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1370 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1371 const optional_ty = self.air.typeOfIndex(inst);
1372 const abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
1373
1374 // Optional with a zero-bit payload type is just a boolean true
1375 if (abi_size == 1) {
1376 break :result MCValue{ .immediate = 1 };
1377 } else {
1378 return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch});
1379 }
1380 };
1381 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1382}
1383
1384/// Given an error union, returns the error
1385fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1386 const payload_ty = error_union_ty.errorUnionPayload();
1387 if (!payload_ty.hasRuntimeBits()) return error_union_mcv;
1388
1389 switch (error_union_mcv) {
1390 .register => return self.fail("TODO errUnionErr for registers", .{}),
1391 .stack_argument_offset => |off| {
1392 return MCValue{ .stack_argument_offset = off };
1393 },
1394 .stack_offset => |off| {
1395 return MCValue{ .stack_offset = off };
1396 },
1397 .memory => |addr| {
1398 return MCValue{ .memory = addr };
1399 },
1400 else => unreachable, // invalid MCValue for an error union
1401 }
1402}
1403
12811404fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
12821405 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12831406 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12841407 const error_union_ty = self.air.typeOf(ty_op.operand);
1285 const payload_ty = error_union_ty.errorUnionPayload();
12861408 const mcv = try self.resolveInst(ty_op.operand);
1287 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1288
1289 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1409 break :result try self.errUnionErr(mcv, error_union_ty);
12901410 };
12911411 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12921412}
12931413
1414/// Given an error union, returns the payload
1415fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1416 const payload_ty = error_union_ty.errorUnionPayload();
1417 if (!payload_ty.hasRuntimeBits()) return MCValue.none;
1418
1419 const error_ty = error_union_ty.errorUnionSet();
1420 const error_size = @intCast(u32, error_ty.abiSize(self.target.*));
1421 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));
1422 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);
1423
1424 // TODO optimization for small error unions: put into register
1425 switch (error_union_mcv) {
1426 .register => return self.fail("TODO errUnionPayload for registers", .{}),
1427 .stack_argument_offset => |off| {
1428 return MCValue{ .stack_argument_offset = off - offset };
1429 },
1430 .stack_offset => |off| {
1431 return MCValue{ .stack_offset = off - offset };
1432 },
1433 .memory => |addr| {
1434 return MCValue{ .memory = addr - offset };
1435 },
1436 else => unreachable, // invalid MCValue for an error union
1437 }
1438}
1439
12941440fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
12951441 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12961442 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12971443 const error_union_ty = self.air.typeOf(ty_op.operand);
1298 const payload_ty = error_union_ty.errorUnionPayload();
1299 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1300
1301 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1444 const mcv = try self.resolveInst(ty_op.operand);
1445 break :result try self.errUnionPayload(mcv, error_union_ty);
13021446 };
13031447 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13041448}
......@@ -1323,20 +1467,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
13231467 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13241468}
13251469
1326fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1327 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1328 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1329 const optional_ty = self.air.typeOfIndex(inst);
1330
1331 // Optional with a zero-bit payload type is just a boolean true
1332 if (optional_ty.abiSize(self.target.*) == 1)
1333 break :result MCValue{ .immediate = 1 };
1334
1335 return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch});
1336 };
1337 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1338}
1339
13401470/// T to E!T
13411471fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
13421472 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -1358,20 +1488,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
13581488 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13591489}
13601490
1361fn slicePtr(self: *Self, mcv: MCValue) !MCValue {
1491/// Given a slice, returns the length
1492fn slicePtr(mcv: MCValue) MCValue {
13621493 switch (mcv) {
1363 .dead, .unreach => unreachable,
13641494 .register => unreachable, // a slice doesn't fit in one register
13651495 .stack_argument_offset => |off| {
1366 return MCValue{ .stack_argument_offset = off + 4 };
1496 return MCValue{ .stack_argument_offset = off };
13671497 },
13681498 .stack_offset => |off| {
1369 return MCValue{ .stack_offset = off + 4 };
1499 return MCValue{ .stack_offset = off };
13701500 },
13711501 .memory => |addr| {
13721502 return MCValue{ .memory = addr };
13731503 },
1374 else => return self.fail("TODO implement slice_ptr for {}", .{mcv}),
1504 else => unreachable, // invalid MCValue for a slice
13751505 }
13761506}
13771507
......@@ -1379,7 +1509,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
13791509 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13801510 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
13811511 const mcv = try self.resolveInst(ty_op.operand);
1382 break :result try self.slicePtr(mcv);
1512 break :result slicePtr(mcv);
13831513 };
13841514 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13851515}
......@@ -1392,10 +1522,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
13921522 .dead, .unreach => unreachable,
13931523 .register => unreachable, // a slice doesn't fit in one register
13941524 .stack_argument_offset => |off| {
1395 break :result MCValue{ .stack_argument_offset = off };
1525 break :result MCValue{ .stack_argument_offset = off - 4 };
13961526 },
13971527 .stack_offset => |off| {
1398 break :result MCValue{ .stack_offset = off };
1528 break :result MCValue{ .stack_offset = off - 4 };
13991529 },
14001530 .memory => |addr| {
14011531 break :result MCValue{ .memory = addr + 4 };
......@@ -1413,7 +1543,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
14131543 switch (mcv) {
14141544 .dead, .unreach => unreachable,
14151545 .ptr_stack_offset => |off| {
1416 break :result MCValue{ .ptr_stack_offset = off };
1546 break :result MCValue{ .ptr_stack_offset = off - 4 };
14171547 },
14181548 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),
14191549 }
......@@ -1428,7 +1558,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
14281558 switch (mcv) {
14291559 .dead, .unreach => unreachable,
14301560 .ptr_stack_offset => |off| {
1431 break :result MCValue{ .ptr_stack_offset = off + 4 };
1561 break :result MCValue{ .ptr_stack_offset = off };
14321562 },
14331563 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}),
14341564 }
......@@ -1459,7 +1589,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
14591589 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
14601590 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
14611591
1462 const base_mcv = try self.slicePtr(slice_mcv);
1592 const base_mcv = slicePtr(slice_mcv);
14631593
14641594 switch (elem_size) {
14651595 1, 4 => {
......@@ -1522,7 +1652,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
15221652 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
15231653 const slice_mcv = try self.resolveInst(extra.lhs);
15241654 const index_mcv = try self.resolveInst(extra.rhs);
1525 const base_mcv = try self.slicePtr(slice_mcv);
1655 const base_mcv = slicePtr(slice_mcv);
15261656
15271657 const slice_ty = self.air.typeOf(extra.lhs);
15281658
......@@ -1797,14 +1927,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
17971927 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
17981928 },
17991929 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
1800 .stack_argument_offset => |unadjusted_off| {
1801 const adj_off = unadjusted_off + elem_size;
1802
1930 .stack_argument_offset => |off| {
18031931 _ = try self.addInst(.{
18041932 .tag = .ldr_ptr_stack_argument,
18051933 .data = .{ .r_stack_offset = .{
18061934 .rt = src_reg,
1807 .stack_offset = adj_off,
1935 .stack_offset = off,
18081936 } },
18091937 });
18101938 },
......@@ -1860,13 +1988,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
18601988 const mcv = try self.resolveInst(operand);
18611989 const ptr_ty = self.air.typeOf(operand);
18621990 const struct_ty = ptr_ty.childType();
1863 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
18641991 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1865 const struct_field_ty = struct_ty.structFieldType(index);
1866 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
18671992 switch (mcv) {
18681993 .ptr_stack_offset => |off| {
1869 break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size };
1994 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };
18701995 },
18711996 else => {
18721997 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
......@@ -1902,22 +2027,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
19022027 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
19032028 const mcv = try self.resolveInst(operand);
19042029 const struct_ty = self.air.typeOf(operand);
1905 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
19062030 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1907 const struct_field_ty = struct_ty.structFieldType(index);
1908 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
1909 const adjusted_field_offset = struct_size - struct_field_offset - struct_field_size;
19102031
19112032 switch (mcv) {
19122033 .dead, .unreach => unreachable,
19132034 .stack_argument_offset => |off| {
1914 break :result MCValue{ .stack_argument_offset = off + adjusted_field_offset };
2035 break :result MCValue{ .stack_argument_offset = off - struct_field_offset };
19152036 },
19162037 .stack_offset => |off| {
1917 break :result MCValue{ .stack_offset = off + adjusted_field_offset };
2038 break :result MCValue{ .stack_offset = off - struct_field_offset };
19182039 },
19192040 .memory => |addr| {
1920 break :result MCValue{ .memory = addr + adjusted_field_offset };
2041 break :result MCValue{ .memory = addr + struct_field_offset };
19212042 },
19222043 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
19232044 }
......@@ -2871,10 +2992,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
28712992 if (abi_align > self.stack_align)
28722993 self.stack_align = abi_align;
28732994 // TODO find a free slot instead of always appending
2874 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
2875 self.next_stack_offset = offset + abi_size;
2876 if (self.next_stack_offset > self.max_end_stack)
2877 self.max_end_stack = self.next_stack_offset;
2995 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
2996 self.next_stack_offset = offset;
2997 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
28782998
28792999 const tmp_mcv = MCValue{ .stack_offset = offset };
28803000 try self.load(tmp_mcv, ptr, ptr_ty);
......@@ -2897,36 +3017,41 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
28973017 const rhs = try self.resolveInst(bin_op.rhs);
28983018 const lhs_ty = self.air.typeOf(bin_op.lhs);
28993019
2900 switch (lhs_ty.zigTypeTag()) {
2901 .Optional => return self.fail("TODO ARM cmp optionals", .{}),
2902 .Float => return self.fail("TODO ARM cmp floats", .{}),
2903 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {
2904 var int_buffer: Type.Payload.Bits = undefined;
2905 const int_ty = switch (lhs_ty.zigTypeTag()) {
2906 .Enum => lhs_ty.intTagType(&int_buffer),
2907 .Int => lhs_ty,
2908 .Bool => Type.initTag(.u1),
2909 .Pointer => Type.usize,
2910 .ErrorSet => Type.initTag(.u16),
2911 else => unreachable,
2912 };
2913
2914 const int_info = int_ty.intInfo(self.target.*);
2915 if (int_info.bits <= 32) {
2916 try self.spillCompareFlagsIfOccupied();
2917 self.compare_flags_inst = inst;
2918
2919 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);
2920
2921 break :result switch (int_info.signedness) {
2922 .signed => MCValue{ .compare_flags_signed = op },
2923 .unsigned => MCValue{ .compare_flags_unsigned = op },
2924 };
3020 var int_buffer: Type.Payload.Bits = undefined;
3021 const int_ty = switch (lhs_ty.zigTypeTag()) {
3022 .Optional => blk: {
3023 var opt_buffer: Type.Payload.ElemType = undefined;
3024 const payload_ty = lhs_ty.optionalChild(&opt_buffer);
3025 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3026 break :blk Type.initTag(.u1);
3027 } else if (lhs_ty.isPtrLikeOptional()) {
3028 break :blk Type.usize;
29253029 } else {
2926 return self.fail("TODO ARM cmp for ints > 32 bits", .{});
3030 return self.fail("TODO ARM cmp non-pointer optionals", .{});
29273031 }
29283032 },
3033 .Float => return self.fail("TODO ARM cmp floats", .{}),
3034 .Enum => lhs_ty.intTagType(&int_buffer),
3035 .Int => lhs_ty,
3036 .Bool => Type.initTag(.u1),
3037 .Pointer => Type.usize,
3038 .ErrorSet => Type.initTag(.u16),
29293039 else => unreachable,
3040 };
3041
3042 const int_info = int_ty.intInfo(self.target.*);
3043 if (int_info.bits <= 32) {
3044 try self.spillCompareFlagsIfOccupied();
3045 self.compare_flags_inst = inst;
3046
3047 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);
3048
3049 break :result switch (int_info.signedness) {
3050 .signed => MCValue{ .compare_flags_signed = op },
3051 .unsigned => MCValue{ .compare_flags_unsigned = op },
3052 };
3053 } else {
3054 return self.fail("TODO ARM cmp for ints > 32 bits", .{});
29303055 }
29313056 };
29323057 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -3188,33 +3313,15 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
31883313
31893314fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
31903315 const error_type = ty.errorUnionSet();
3191 const payload_type = ty.errorUnionPayload();
3316 const error_int_type = Type.initTag(.u16);
31923317
31933318 if (!error_type.hasRuntimeBits()) {
31943319 return MCValue{ .immediate = 0 }; // always false
3195 } else if (!payload_type.hasRuntimeBits()) {
3196 if (error_type.abiSize(self.target.*) <= 4) {
3197 const reg_mcv: MCValue = switch (operand) {
3198 .register => operand,
3199 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
3200 };
3201
3202 _ = try self.addInst(.{
3203 .tag = .cmp,
3204 .data = .{ .rr_op = .{
3205 .rd = undefined,
3206 .rn = reg_mcv.register,
3207 .op = Instruction.Operand.fromU32(0).?,
3208 } },
3209 });
3210
3211 return MCValue{ .compare_flags_unsigned = .gt };
3212 } else {
3213 return self.fail("TODO isErr for errors with size > 4", .{});
3214 }
3215 } else {
3216 return self.fail("TODO isErr for non-empty payloads", .{});
32173320 }
3321
3322 const error_mcv = try self.errUnionErr(operand, ty);
3323 _ = try self.binOp(.cmp_eq, null, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type);
3324 return MCValue{ .compare_flags_unsigned = .gt };
32183325}
32193326
32203327fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
......@@ -3620,13 +3727,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
36203727 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
36213728 },
36223729 .register => |reg| {
3623 const adj_off = stack_offset + abi_size;
3624
36253730 switch (abi_size) {
36263731 1, 4 => {
3627 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
3732 const offset = if (math.cast(u12, stack_offset)) |imm| blk: {
36283733 break :blk Instruction.Offset.imm(imm);
3629 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
3734 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }), .none);
36303735
36313736 const tag: Mir.Inst.Tag = switch (abi_size) {
36323737 1 => .strb,
......@@ -3647,9 +3752,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
36473752 });
36483753 },
36493754 2 => {
3650 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3651 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3652 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
3755 const offset = if (stack_offset <= math.maxInt(u8)) blk: {
3756 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset));
3757 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }));
36533758
36543759 _ = try self.addInst(.{
36553760 .tag = .strh,
......@@ -3702,14 +3807,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
37023807 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
37033808 },
37043809 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
3705 .stack_argument_offset => |unadjusted_off| {
3706 const adj_off = unadjusted_off + abi_size;
3707
3810 .stack_argument_offset => |off| {
37083811 _ = try self.addInst(.{
37093812 .tag = .ldr_ptr_stack_argument,
37103813 .data = .{ .r_stack_offset = .{
37113814 .rt = src_reg,
3712 .stack_offset = adj_off,
3815 .stack_offset = off,
37133816 } },
37143817 });
37153818 },
......@@ -3739,13 +3842,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
37393842 // Write the debug undefined value.
37403843 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa });
37413844 },
3742 .ptr_stack_offset => |unadjusted_off| {
3845 .ptr_stack_offset => |off| {
37433846 // TODO: maybe addressing from sp instead of fp
3744 const elem_ty = ty.childType();
3745 const abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3746 const adj_off = unadjusted_off + abi_size;
3747
3748 const op = Instruction.Operand.fromU32(adj_off) orelse
3847 const op = Instruction.Operand.fromU32(off) orelse
37493848 return self.fail("TODO larger stack offsets", .{});
37503849
37513850 _ = try self.addInst(.{
......@@ -3919,10 +4018,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39194018 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });
39204019 try self.genLdrRegister(reg, reg, ty);
39214020 },
3922 .stack_offset => |unadjusted_off| {
4021 .stack_offset => |off| {
39234022 // TODO: maybe addressing from sp instead of fp
39244023 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3925 const adj_off = unadjusted_off + abi_size;
39264024
39274025 const tag: Mir.Inst.Tag = switch (abi_size) {
39284026 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
......@@ -3939,9 +4037,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39394037 };
39404038
39414039 if (extra_offset) {
3942 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3943 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3944 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
4040 const offset = if (off <= math.maxInt(u8)) blk: {
4041 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, off));
4042 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off }));
39454043
39464044 _ = try self.addInst(.{
39474045 .tag = tag,
......@@ -3955,9 +4053,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39554053 } },
39564054 });
39574055 } else {
3958 const offset = if (adj_off <= math.maxInt(u12)) blk: {
3959 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3960 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
4056 const offset = if (off <= math.maxInt(u12)) blk: {
4057 break :blk Instruction.Offset.imm(@intCast(u12, off));
4058 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off }), .none);
39614059
39624060 _ = try self.addInst(.{
39634061 .tag = tag,
......@@ -3972,9 +4070,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39724070 });
39734071 }
39744072 },
3975 .stack_argument_offset => |unadjusted_off| {
4073 .stack_argument_offset => |off| {
39764074 const abi_size = ty.abiSize(self.target.*);
3977 const adj_off = unadjusted_off + abi_size;
39784075
39794076 const tag: Mir.Inst.Tag = switch (abi_size) {
39804077 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
......@@ -3987,7 +4084,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39874084 .tag = tag,
39884085 .data = .{ .r_stack_offset = .{
39894086 .rt = reg,
3990 .stack_offset = @intCast(u32, adj_off),
4087 .stack_offset = off,
39914088 } },
39924089 });
39934090 },
......@@ -4003,7 +4100,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
40034100 if (!self.wantSafety())
40044101 return; // The already existing value will do just fine.
40054102 // TODO Upgrade this to a memset call when we have that available.
4006 switch (ty.abiSize(self.target.*)) {
4103 switch (abi_size) {
40074104 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
40084105 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
40094106 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
......@@ -4011,13 +4108,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
40114108 }
40124109 },
40134110 .register => |reg| {
4014 const adj_off = stack_offset - abi_size;
4015
40164111 switch (abi_size) {
40174112 1, 4 => {
4018 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
4113 const offset = if (math.cast(u12, stack_offset)) |imm| blk: {
40194114 break :blk Instruction.Offset.imm(imm);
4020 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
4115 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }), .none);
40214116
40224117 const tag: Mir.Inst.Tag = switch (abi_size) {
40234118 1 => .strb,
......@@ -4035,9 +4130,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
40354130 });
40364131 },
40374132 2 => {
4038 const offset = if (adj_off <= math.maxInt(u8)) blk: {
4039 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
4040 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
4133 const offset = if (stack_offset <= math.maxInt(u8)) blk: {
4134 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset));
4135 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }));
40414136
40424137 _ = try self.addInst(.{
40434138 .tag = .strh,
......@@ -4079,13 +4174,20 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
40794174 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
40804175 },
40814176 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4082 .stack_argument_offset => return self.fail("TODO genSetStackArgument src={}", .{mcv}),
4177 .stack_argument_offset => |off| {
4178 _ = try self.addInst(.{
4179 .tag = .ldr_ptr_stack_argument,
4180 .data = .{ .r_stack_offset = .{
4181 .rt = src_reg,
4182 .stack_offset = off,
4183 } },
4184 });
4185 },
40834186 else => unreachable,
40844187 }
40854188
40864189 // add dst_reg, sp, #stack_offset
4087 const adj_dst_offset = stack_offset - abi_size;
4088 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_dst_offset)) |x| x else {
4190 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(stack_offset)) |x| x else {
40894191 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
40904192 };
40914193 _ = try self.addInst(.{
......@@ -4136,8 +4238,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
41364238 const array_len = @intCast(u32, array_ty.arrayLen());
41374239
41384240 const stack_offset = try self.allocMem(inst, 8, 8);
4139 try self.genSetStack(ptr_ty, stack_offset + 4, ptr);
4140 try self.genSetStack(Type.initTag(.usize), stack_offset, .{ .immediate = array_len });
4241 try self.genSetStack(ptr_ty, stack_offset, ptr);
4242 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });
41414243 break :result MCValue{ .stack_offset = stack_offset };
41424244 };
41434245 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -4577,8 +4679,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
45774679 if (ty.abiAlignment(self.target.*) == 8)
45784680 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
45794681
4580 result.args[i] = .{ .stack_argument_offset = nsaa };
45814682 nsaa += param_size;
4683 result.args[i] = .{ .stack_argument_offset = nsaa };
45824684 }
45834685 }
45844686
......@@ -4607,9 +4709,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
46074709
46084710 for (param_types) |ty, i| {
46094711 if (ty.abiSize(self.target.*) > 0) {
4610 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*));
4712 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4713
4714 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*)) + param_size;
46114715 result.args[i] = .{ .stack_argument_offset = stack_offset };
4612 stack_offset += @intCast(u32, ty.abiSize(self.target.*));
46134716 } else {
46144717 result.args[i] = .{ .none = {} };
46154718 }
test/behavior/optional.zig-2
......@@ -33,8 +33,6 @@ test "optional pointer to size zero struct" {
3333}
3434
3535test "equality compare optional pointers" {
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
37
3836 try testNullPtrsEql();
3937 comptime try testNullPtrsEql();
4038}