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 {...@@ -396,8 +396,8 @@ fn gen(self: *Self) !void {
396 // The address of where to store the return value is in396 // The address of where to store the return value is in
397 // r0. As this register might get overwritten along the397 // r0. As this register might get overwritten along the
398 // way, save the address to the stack.398 // way, save the address to the stack.
399 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4);399 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4;
400 self.next_stack_offset = stack_offset + 4;400 self.next_stack_offset = stack_offset;
401 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);401 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
402402
403 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });403 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 {...@@ -535,8 +535,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
535 .mod => try self.airMod(inst),535 .mod => try self.airMod(inst),
536 .shl, .shl_exact => try self.airBinOp(inst),536 .shl, .shl_exact => try self.airBinOp(inst),
537 .shl_sat => try self.airShlSat(inst),537 .shl_sat => try self.airShlSat(inst),
538 .min => try self.airMin(inst),538 .min => try self.airMinMax(inst),
539 .max => try self.airMax(inst),539 .max => try self.airMinMax(inst),
540 .slice => try self.airSlice(inst),540 .slice => try self.airSlice(inst),
541541
542 .sqrt,542 .sqrt,
...@@ -780,10 +780,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -780,10 +780,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
780 if (abi_align > self.stack_align)780 if (abi_align > self.stack_align)
781 self.stack_align = abi_align;781 self.stack_align = abi_align;
782 // TODO find a free slot instead of always appending782 // TODO find a free slot instead of always appending
783 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);783 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
784 self.next_stack_offset = offset + abi_size;784 self.next_stack_offset = offset;
785 if (self.next_stack_offset > self.max_end_stack)785 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
786 self.max_end_stack = self.next_stack_offset;
787 try self.stack.putNoClobber(self.gpa, offset, .{786 try self.stack.putNoClobber(self.gpa, offset, .{
788 .inst = inst,787 .inst = inst,
789 .size = abi_size,788 .size = abi_size,
...@@ -797,8 +796,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -797,8 +796,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
797796
798 if (!elem_ty.hasRuntimeBits()) {797 if (!elem_ty.hasRuntimeBits()) {
799 // As this stack item will never be dereferenced at runtime,798 // As this stack item will never be dereferenced at runtime,
800 // return the current stack offset799 // return the stack offset 0. Stack offset 0 will be where all
801 return self.next_stack_offset;800 // zero-sized stack allocations live as non-zero-sized
801 // allocations will always have an offset > 0.
802 return @as(u32, 0);
802 }803 }
803804
804 const target = self.target.*;805 const target = self.target.*;
...@@ -1139,15 +1140,119 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1139,15 +1140,119 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1139 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1140 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1140}1141}
11411142
1142fn airMin(self: *Self, inst: Air.Inst.Index) !void {1143fn minMax(
1143 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1144 self: *Self,
1144 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});1145 tag: Air.Inst.Tag,
1145 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });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 }
1146}1241}
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];
1149 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1245 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 };
1151 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1256 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1152}1257}
11531258
...@@ -1161,8 +1266,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1161,8 +1266,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1161 const len_ty = self.air.typeOf(bin_op.rhs);1266 const len_ty = self.air.typeOf(bin_op.rhs);
11621267
1163 const stack_offset = try self.allocMem(inst, 8, 8);1268 const stack_offset = try self.allocMem(inst, 8, 8);
1164 try self.genSetStack(ptr_ty, stack_offset + 4, ptr);1269 try self.genSetStack(ptr_ty, stack_offset, ptr);
1165 try self.genSetStack(len_ty, stack_offset, len);1270 try self.genSetStack(len_ty, stack_offset - 4, len);
1166 break :result MCValue{ .stack_offset = stack_offset };1271 break :result MCValue{ .stack_offset = stack_offset };
1167 };1272 };
1168 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1273 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 {...@@ -1180,36 +1285,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1180 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1285 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1181}1286}
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
1189fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {1288fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
1190 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1289 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1191 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});1290 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
1192 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1291 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1193}1292}
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
1201fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {1294fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1202 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1295 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1203 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});1296 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
1204 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1297 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1205}1298}
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
1213fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {1300fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1214 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1301 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1215 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});1302 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 {...@@ -1278,27 +1365,84 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1278 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1365 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1279}1366}
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
1281fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {1404fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1282 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1405 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1283 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1406 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1284 const error_union_ty = self.air.typeOf(ty_op.operand);1407 const error_union_ty = self.air.typeOf(ty_op.operand);
1285 const payload_ty = error_union_ty.errorUnionPayload();
1286 const mcv = try self.resolveInst(ty_op.operand);1408 const mcv = try self.resolveInst(ty_op.operand);
1287 if (!payload_ty.hasRuntimeBits()) break :result mcv;1409 break :result try self.errUnionErr(mcv, error_union_ty);
1288
1289 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1290 };1410 };
1291 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1411 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1292}1412}
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
1294fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {1440fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1295 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1441 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1296 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1442 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1297 const error_union_ty = self.air.typeOf(ty_op.operand);1443 const error_union_ty = self.air.typeOf(ty_op.operand);
1298 const payload_ty = error_union_ty.errorUnionPayload();1444 const mcv = try self.resolveInst(ty_op.operand);
1299 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;1445 break :result try self.errUnionPayload(mcv, error_union_ty);
1300
1301 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1302 };1446 };
1303 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1447 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1304}1448}
...@@ -1323,20 +1467,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -1323,20 +1467,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1323 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1467 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1324}1468}
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
1340/// T to E!T1470/// T to E!T
1341fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {1471fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
1342 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1472 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -1358,20 +1488,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1358,20 +1488,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1358 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1488 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1359}1489}
13601490
1361fn slicePtr(self: *Self, mcv: MCValue) !MCValue {1491/// Given a slice, returns the length
1492fn slicePtr(mcv: MCValue) MCValue {
1362 switch (mcv) {1493 switch (mcv) {
1363 .dead, .unreach => unreachable,
1364 .register => unreachable, // a slice doesn't fit in one register1494 .register => unreachable, // a slice doesn't fit in one register
1365 .stack_argument_offset => |off| {1495 .stack_argument_offset => |off| {
1366 return MCValue{ .stack_argument_offset = off + 4 };1496 return MCValue{ .stack_argument_offset = off };
1367 },1497 },
1368 .stack_offset => |off| {1498 .stack_offset => |off| {
1369 return MCValue{ .stack_offset = off + 4 };1499 return MCValue{ .stack_offset = off };
1370 },1500 },
1371 .memory => |addr| {1501 .memory => |addr| {
1372 return MCValue{ .memory = addr };1502 return MCValue{ .memory = addr };
1373 },1503 },
1374 else => return self.fail("TODO implement slice_ptr for {}", .{mcv}),1504 else => unreachable, // invalid MCValue for a slice
1375 }1505 }
1376}1506}
13771507
...@@ -1379,7 +1509,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1379,7 +1509,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1379 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1509 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1380 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1510 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1381 const mcv = try self.resolveInst(ty_op.operand);1511 const mcv = try self.resolveInst(ty_op.operand);
1382 break :result try self.slicePtr(mcv);1512 break :result slicePtr(mcv);
1383 };1513 };
1384 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1514 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1385}1515}
...@@ -1392,10 +1522,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1392,10 +1522,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1392 .dead, .unreach => unreachable,1522 .dead, .unreach => unreachable,
1393 .register => unreachable, // a slice doesn't fit in one register1523 .register => unreachable, // a slice doesn't fit in one register
1394 .stack_argument_offset => |off| {1524 .stack_argument_offset => |off| {
1395 break :result MCValue{ .stack_argument_offset = off };1525 break :result MCValue{ .stack_argument_offset = off - 4 };
1396 },1526 },
1397 .stack_offset => |off| {1527 .stack_offset => |off| {
1398 break :result MCValue{ .stack_offset = off };1528 break :result MCValue{ .stack_offset = off - 4 };
1399 },1529 },
1400 .memory => |addr| {1530 .memory => |addr| {
1401 break :result MCValue{ .memory = addr + 4 };1531 break :result MCValue{ .memory = addr + 4 };
...@@ -1413,7 +1543,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1413,7 +1543,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
1413 switch (mcv) {1543 switch (mcv) {
1414 .dead, .unreach => unreachable,1544 .dead, .unreach => unreachable,
1415 .ptr_stack_offset => |off| {1545 .ptr_stack_offset => |off| {
1416 break :result MCValue{ .ptr_stack_offset = off };1546 break :result MCValue{ .ptr_stack_offset = off - 4 };
1417 },1547 },
1418 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),1548 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),
1419 }1549 }
...@@ -1428,7 +1558,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1428,7 +1558,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
1428 switch (mcv) {1558 switch (mcv) {
1429 .dead, .unreach => unreachable,1559 .dead, .unreach => unreachable,
1430 .ptr_stack_offset => |off| {1560 .ptr_stack_offset => |off| {
1431 break :result MCValue{ .ptr_stack_offset = off + 4 };1561 break :result MCValue{ .ptr_stack_offset = off };
1432 },1562 },
1433 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}),1563 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}),
1434 }1564 }
...@@ -1459,7 +1589,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1459,7 +1589,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1459 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});1589 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
1460 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});1590 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
1464 switch (elem_size) {1594 switch (elem_size) {
1465 1, 4 => {1595 1, 4 => {
...@@ -1522,7 +1652,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1522,7 +1652,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1522 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1652 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1523 const slice_mcv = try self.resolveInst(extra.lhs);1653 const slice_mcv = try self.resolveInst(extra.lhs);
1524 const index_mcv = try self.resolveInst(extra.rhs);1654 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
1527 const slice_ty = self.air.typeOf(extra.lhs);1657 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...@@ -1797,14 +1927,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
1797 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });1927 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
1798 },1928 },
1799 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),1929 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
1800 .stack_argument_offset => |unadjusted_off| {1930 .stack_argument_offset => |off| {
1801 const adj_off = unadjusted_off + elem_size;
1802
1803 _ = try self.addInst(.{1931 _ = try self.addInst(.{
1804 .tag = .ldr_ptr_stack_argument,1932 .tag = .ldr_ptr_stack_argument,
1805 .data = .{ .r_stack_offset = .{1933 .data = .{ .r_stack_offset = .{
1806 .rt = src_reg,1934 .rt = src_reg,
1807 .stack_offset = adj_off,1935 .stack_offset = off,
1808 } },1936 } },
1809 });1937 });
1810 },1938 },
...@@ -1860,13 +1988,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -1860,13 +1988,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
1860 const mcv = try self.resolveInst(operand);1988 const mcv = try self.resolveInst(operand);
1861 const ptr_ty = self.air.typeOf(operand);1989 const ptr_ty = self.air.typeOf(operand);
1862 const struct_ty = ptr_ty.childType();1990 const struct_ty = ptr_ty.childType();
1863 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1864 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));1991 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.*));
1867 switch (mcv) {1992 switch (mcv) {
1868 .ptr_stack_offset => |off| {1993 .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 };
1870 },1995 },
1871 else => {1996 else => {
1872 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{1997 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
...@@ -1902,22 +2027,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1902,22 +2027,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1902 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2027 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1903 const mcv = try self.resolveInst(operand);2028 const mcv = try self.resolveInst(operand);
1904 const struct_ty = self.air.typeOf(operand);2029 const struct_ty = self.air.typeOf(operand);
1905 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1906 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));2030 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
1911 switch (mcv) {2032 switch (mcv) {
1912 .dead, .unreach => unreachable,2033 .dead, .unreach => unreachable,
1913 .stack_argument_offset => |off| {2034 .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 };
1915 },2036 },
1916 .stack_offset => |off| {2037 .stack_offset => |off| {
1917 break :result MCValue{ .stack_offset = off + adjusted_field_offset };2038 break :result MCValue{ .stack_offset = off - struct_field_offset };
1918 },2039 },
1919 .memory => |addr| {2040 .memory => |addr| {
1920 break :result MCValue{ .memory = addr + adjusted_field_offset };2041 break :result MCValue{ .memory = addr + struct_field_offset };
1921 },2042 },
1922 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),2043 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
1923 }2044 }
...@@ -2871,10 +2992,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2871,10 +2992,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
2871 if (abi_align > self.stack_align)2992 if (abi_align > self.stack_align)
2872 self.stack_align = abi_align;2993 self.stack_align = abi_align;
2873 // TODO find a free slot instead of always appending2994 // TODO find a free slot instead of always appending
2874 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);2995 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
2875 self.next_stack_offset = offset + abi_size;2996 self.next_stack_offset = offset;
2876 if (self.next_stack_offset > self.max_end_stack)2997 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
2877 self.max_end_stack = self.next_stack_offset;
28782998
2879 const tmp_mcv = MCValue{ .stack_offset = offset };2999 const tmp_mcv = MCValue{ .stack_offset = offset };
2880 try self.load(tmp_mcv, ptr, ptr_ty);3000 try self.load(tmp_mcv, ptr, ptr_ty);
...@@ -2897,36 +3017,41 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2897,36 +3017,41 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2897 const rhs = try self.resolveInst(bin_op.rhs);3017 const rhs = try self.resolveInst(bin_op.rhs);
2898 const lhs_ty = self.air.typeOf(bin_op.lhs);3018 const lhs_ty = self.air.typeOf(bin_op.lhs);
28993019
2900 switch (lhs_ty.zigTypeTag()) {3020 var int_buffer: Type.Payload.Bits = undefined;
2901 .Optional => return self.fail("TODO ARM cmp optionals", .{}),3021 const int_ty = switch (lhs_ty.zigTypeTag()) {
2902 .Float => return self.fail("TODO ARM cmp floats", .{}),3022 .Optional => blk: {
2903 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {3023 var opt_buffer: Type.Payload.ElemType = undefined;
2904 var int_buffer: Type.Payload.Bits = undefined;3024 const payload_ty = lhs_ty.optionalChild(&opt_buffer);
2905 const int_ty = switch (lhs_ty.zigTypeTag()) {3025 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2906 .Enum => lhs_ty.intTagType(&int_buffer),3026 break :blk Type.initTag(.u1);
2907 .Int => lhs_ty,3027 } else if (lhs_ty.isPtrLikeOptional()) {
2908 .Bool => Type.initTag(.u1),3028 break :blk Type.usize;
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 };
2925 } else {3029 } else {
2926 return self.fail("TODO ARM cmp for ints > 32 bits", .{});3030 return self.fail("TODO ARM cmp non-pointer optionals", .{});
2927 }3031 }
2928 },3032 },
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),
2929 else => unreachable,3039 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", .{});
2930 }3055 }
2931 };3056 };
2932 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });3057 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 {...@@ -3188,33 +3313,15 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
31883313
3189fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3314fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3190 const error_type = ty.errorUnionSet();3315 const error_type = ty.errorUnionSet();
3191 const payload_type = ty.errorUnionPayload();3316 const error_int_type = Type.initTag(.u16);
31923317
3193 if (!error_type.hasRuntimeBits()) {3318 if (!error_type.hasRuntimeBits()) {
3194 return MCValue{ .immediate = 0 }; // always false3319 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", .{});
3217 }3320 }
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 };
3218}3325}
32193326
3220fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3327fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
...@@ -3620,13 +3727,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3620,13 +3727,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3620 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3727 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3621 },3728 },
3622 .register => |reg| {3729 .register => |reg| {
3623 const adj_off = stack_offset + abi_size;
3624
3625 switch (abi_size) {3730 switch (abi_size) {
3626 1, 4 => {3731 1, 4 => {
3627 const offset = if (math.cast(u12, adj_off)) |imm| blk: {3732 const offset = if (math.cast(u12, stack_offset)) |imm| blk: {
3628 break :blk Instruction.Offset.imm(imm);3733 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
3631 const tag: Mir.Inst.Tag = switch (abi_size) {3736 const tag: Mir.Inst.Tag = switch (abi_size) {
3632 1 => .strb,3737 1 => .strb,
...@@ -3647,9 +3752,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3647,9 +3752,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3647 });3752 });
3648 },3753 },
3649 2 => {3754 2 => {
3650 const offset = if (adj_off <= math.maxInt(u8)) blk: {3755 const offset = if (stack_offset <= math.maxInt(u8)) blk: {
3651 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));3756 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset));
3652 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));3757 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }));
36533758
3654 _ = try self.addInst(.{3759 _ = try self.addInst(.{
3655 .tag = .strh,3760 .tag = .strh,
...@@ -3702,14 +3807,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3702,14 +3807,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3702 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });3807 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
3703 },3808 },
3704 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),3809 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
3705 .stack_argument_offset => |unadjusted_off| {3810 .stack_argument_offset => |off| {
3706 const adj_off = unadjusted_off + abi_size;
3707
3708 _ = try self.addInst(.{3811 _ = try self.addInst(.{
3709 .tag = .ldr_ptr_stack_argument,3812 .tag = .ldr_ptr_stack_argument,
3710 .data = .{ .r_stack_offset = .{3813 .data = .{ .r_stack_offset = .{
3711 .rt = src_reg,3814 .rt = src_reg,
3712 .stack_offset = adj_off,3815 .stack_offset = off,
3713 } },3816 } },
3714 });3817 });
3715 },3818 },
...@@ -3739,13 +3842,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3739,13 +3842,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3739 // Write the debug undefined value.3842 // Write the debug undefined value.
3740 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa });3843 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa });
3741 },3844 },
3742 .ptr_stack_offset => |unadjusted_off| {3845 .ptr_stack_offset => |off| {
3743 // TODO: maybe addressing from sp instead of fp3846 // TODO: maybe addressing from sp instead of fp
3744 const elem_ty = ty.childType();3847 const op = Instruction.Operand.fromU32(off) orelse
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
3749 return self.fail("TODO larger stack offsets", .{});3848 return self.fail("TODO larger stack offsets", .{});
37503849
3751 _ = try self.addInst(.{3850 _ = try self.addInst(.{
...@@ -3919,10 +4018,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3919,10 +4018,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3919 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });4018 try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });
3920 try self.genLdrRegister(reg, reg, ty);4019 try self.genLdrRegister(reg, reg, ty);
3921 },4020 },
3922 .stack_offset => |unadjusted_off| {4021 .stack_offset => |off| {
3923 // TODO: maybe addressing from sp instead of fp4022 // TODO: maybe addressing from sp instead of fp
3924 const abi_size = @intCast(u32, ty.abiSize(self.target.*));4023 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3925 const adj_off = unadjusted_off + abi_size;
39264024
3927 const tag: Mir.Inst.Tag = switch (abi_size) {4025 const tag: Mir.Inst.Tag = switch (abi_size) {
3928 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,4026 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...@@ -3939,9 +4037,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3939 };4037 };
39404038
3941 if (extra_offset) {4039 if (extra_offset) {
3942 const offset = if (adj_off <= math.maxInt(u8)) blk: {4040 const offset = if (off <= math.maxInt(u8)) blk: {
3943 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));4041 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, off));
3944 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));4042 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off }));
39454043
3946 _ = try self.addInst(.{4044 _ = try self.addInst(.{
3947 .tag = tag,4045 .tag = tag,
...@@ -3955,9 +4053,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3955,9 +4053,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3955 } },4053 } },
3956 });4054 });
3957 } else {4055 } else {
3958 const offset = if (adj_off <= math.maxInt(u12)) blk: {4056 const offset = if (off <= math.maxInt(u12)) blk: {
3959 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));4057 break :blk Instruction.Offset.imm(@intCast(u12, off));
3960 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);4058 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off }), .none);
39614059
3962 _ = try self.addInst(.{4060 _ = try self.addInst(.{
3963 .tag = tag,4061 .tag = tag,
...@@ -3972,9 +4070,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3972,9 +4070,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3972 });4070 });
3973 }4071 }
3974 },4072 },
3975 .stack_argument_offset => |unadjusted_off| {4073 .stack_argument_offset => |off| {
3976 const abi_size = ty.abiSize(self.target.*);4074 const abi_size = ty.abiSize(self.target.*);
3977 const adj_off = unadjusted_off + abi_size;
39784075
3979 const tag: Mir.Inst.Tag = switch (abi_size) {4076 const tag: Mir.Inst.Tag = switch (abi_size) {
3980 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,4077 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...@@ -3987,7 +4084,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3987 .tag = tag,4084 .tag = tag,
3988 .data = .{ .r_stack_offset = .{4085 .data = .{ .r_stack_offset = .{
3989 .rt = reg,4086 .rt = reg,
3990 .stack_offset = @intCast(u32, adj_off),4087 .stack_offset = off,
3991 } },4088 } },
3992 });4089 });
3993 },4090 },
...@@ -4003,7 +4100,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4003,7 +4100,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4003 if (!self.wantSafety())4100 if (!self.wantSafety())
4004 return; // The already existing value will do just fine.4101 return; // The already existing value will do just fine.
4005 // TODO Upgrade this to a memset call when we have that available.4102 // TODO Upgrade this to a memset call when we have that available.
4006 switch (ty.abiSize(self.target.*)) {4103 switch (abi_size) {
4007 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),4104 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
4008 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),4105 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
4009 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),4106 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...@@ -4011,13 +4108,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4011 }4108 }
4012 },4109 },
4013 .register => |reg| {4110 .register => |reg| {
4014 const adj_off = stack_offset - abi_size;
4015
4016 switch (abi_size) {4111 switch (abi_size) {
4017 1, 4 => {4112 1, 4 => {
4018 const offset = if (math.cast(u12, adj_off)) |imm| blk: {4113 const offset = if (math.cast(u12, stack_offset)) |imm| blk: {
4019 break :blk Instruction.Offset.imm(imm);4114 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
4022 const tag: Mir.Inst.Tag = switch (abi_size) {4117 const tag: Mir.Inst.Tag = switch (abi_size) {
4023 1 => .strb,4118 1 => .strb,
...@@ -4035,9 +4130,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4035,9 +4130,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4035 });4130 });
4036 },4131 },
4037 2 => {4132 2 => {
4038 const offset = if (adj_off <= math.maxInt(u8)) blk: {4133 const offset = if (stack_offset <= math.maxInt(u8)) blk: {
4039 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));4134 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset));
4040 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));4135 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }));
40414136
4042 _ = try self.addInst(.{4137 _ = try self.addInst(.{
4043 .tag = .strh,4138 .tag = .strh,
...@@ -4079,13 +4174,20 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4079,13 +4174,20 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4079 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });4174 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
4080 },4175 },
4081 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),4176 .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 },
4083 else => unreachable,4186 else => unreachable,
4084 }4187 }
40854188
4086 // add dst_reg, sp, #stack_offset4189 // add dst_reg, sp, #stack_offset
4087 const adj_dst_offset = stack_offset - abi_size;4190 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(stack_offset)) |x| x else {
4088 const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_dst_offset)) |x| x else {
4089 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});4191 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
4090 };4192 };
4091 _ = try self.addInst(.{4193 _ = try self.addInst(.{
...@@ -4136,8 +4238,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -4136,8 +4238,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4136 const array_len = @intCast(u32, array_ty.arrayLen());4238 const array_len = @intCast(u32, array_ty.arrayLen());
41374239
4138 const stack_offset = try self.allocMem(inst, 8, 8);4240 const stack_offset = try self.allocMem(inst, 8, 8);
4139 try self.genSetStack(ptr_ty, stack_offset + 4, ptr);4241 try self.genSetStack(ptr_ty, stack_offset, ptr);
4140 try self.genSetStack(Type.initTag(.usize), stack_offset, .{ .immediate = array_len });4242 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });
4141 break :result MCValue{ .stack_offset = stack_offset };4243 break :result MCValue{ .stack_offset = stack_offset };
4142 };4244 };
4143 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4245 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -4577,8 +4679,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4577,8 +4679,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4577 if (ty.abiAlignment(self.target.*) == 8)4679 if (ty.abiAlignment(self.target.*) == 8)
4578 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);4680 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
45794681
4580 result.args[i] = .{ .stack_argument_offset = nsaa };
4581 nsaa += param_size;4682 nsaa += param_size;
4683 result.args[i] = .{ .stack_argument_offset = nsaa };
4582 }4684 }
4583 }4685 }
45844686
...@@ -4607,9 +4709,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4607,9 +4709,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
46074709
4608 for (param_types) |ty, i| {4710 for (param_types) |ty, i| {
4609 if (ty.abiSize(self.target.*) > 0) {4711 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;
4611 result.args[i] = .{ .stack_argument_offset = stack_offset };4715 result.args[i] = .{ .stack_argument_offset = stack_offset };
4612 stack_offset += @intCast(u32, ty.abiSize(self.target.*));
4613 } else {4716 } else {
4614 result.args[i] = .{ .none = {} };4717 result.args[i] = .{ .none = {} };
4615 }4718 }
test/behavior/optional.zig-2
...@@ -33,8 +33,6 @@ test "optional pointer to size zero struct" {...@@ -33,8 +33,6 @@ test "optional pointer to size zero struct" {
33}33}
3434
35test "equality compare optional pointers" {35test "equality compare optional pointers" {
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
37
38 try testNullPtrsEql();36 try testNullPtrsEql();
39 comptime try testNullPtrsEql();37 comptime try testNullPtrsEql();
40}38}