authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-20 09:44:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-20 09:44:43+02:00
log1a1b5ee264d8b2219c34d53cc9602692e6d2ba24
tree6ccf27612a093414ed1e50933a27bde1bc6920f7
parente3cbea934ee196b3833f4c4269bc3b2796c11928
parentfa85a739d9a85084fbb6d934c2c8803042fa7d48
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11462 from joachimschmidt557/stage2-aarch64

stage2 AArch64: truncation support

7 files changed, 611 insertions(+), 364 deletions(-)

src/arch/aarch64/CodeGen.zig+336-247
......@@ -376,7 +376,7 @@ fn gen(self: *Self) !void {
376376 // mov fp, sp
377377 _ = try self.addInst(.{
378378 .tag = .mov_to_from_sp,
379 .data = .{ .rr = .{ .rd = .x29, .rn = .xzr } },
379 .data = .{ .rr = .{ .rd = .x29, .rn = .sp } },
380380 });
381381
382382 // sub sp, sp, #reloc
......@@ -421,7 +421,7 @@ fn gen(self: *Self) !void {
421421 if (math.cast(u12, stack_size)) |size| {
422422 self.mir_instructions.set(backpatch_reloc, .{
423423 .tag = .sub_immediate,
424 .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = size } },
424 .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = size } },
425425 });
426426 } else |_| {
427427 return self.failSymbol("TODO AArch64: allow larger stacks", .{});
......@@ -453,7 +453,7 @@ fn gen(self: *Self) !void {
453453 // add sp, sp, #stack_size
454454 _ = try self.addInst(.{
455455 .tag = .add_immediate,
456 .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = @intCast(u12, stack_size) } },
456 .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = @intCast(u12, stack_size) } },
457457 });
458458
459459 // <load other registers>
......@@ -512,13 +512,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
512512 switch (air_tags[inst]) {
513513 // zig fmt: off
514514 .add, .ptr_add => try self.airBinOp(inst),
515 .addwrap => try self.airAddWrap(inst),
515 .addwrap => try self.airBinOp(inst),
516516 .add_sat => try self.airAddSat(inst),
517517 .sub, .ptr_sub => try self.airBinOp(inst),
518 .subwrap => try self.airSubWrap(inst),
518 .subwrap => try self.airBinOp(inst),
519519 .sub_sat => try self.airSubSat(inst),
520520 .mul => try self.airBinOp(inst),
521 .mulwrap => try self.airMulWrap(inst),
521 .mulwrap => try self.airBinOp(inst),
522522 .mul_sat => try self.airMulSat(inst),
523523 .rem => try self.airRem(inst),
524524 .mod => try self.airMod(inst),
......@@ -882,7 +882,8 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
882882/// allocated. A second call to `copyToTmpRegister` may return the same register.
883883/// This can have a side effect of spilling instructions to the stack to free up a register.
884884fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
885 const reg = try self.register_manager.allocReg(null);
885 const raw_reg = try self.register_manager.allocReg(null);
886 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
886887 try self.genSetReg(ty, reg, mcv);
887888 return reg;
888889}
......@@ -891,7 +892,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
891892/// `reg_owner` is the instruction that gets associated with the register in the register table.
892893/// This can have a side effect of spilling instructions to the stack to free up a register.
893894fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
894 const reg = try self.register_manager.allocReg(reg_owner);
895 const raw_reg = try self.register_manager.allocReg(reg_owner);
896 const ty = self.air.typeOfIndex(reg_owner);
897 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
895898 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
896899 return MCValue{ .register = reg };
897900}
......@@ -936,14 +939,99 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
936939 return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch});
937940}
938941
942fn truncRegister(
943 self: *Self,
944 operand_reg: Register,
945 dest_reg: Register,
946 int_signedness: std.builtin.Signedness,
947 int_bits: u16,
948) !void {
949 switch (int_bits) {
950 1...31, 33...63 => {
951 _ = try self.addInst(.{
952 .tag = switch (int_signedness) {
953 .signed => .sbfx,
954 .unsigned => .ubfx,
955 },
956 .data = .{ .rr_lsb_width = .{
957 .rd = dest_reg,
958 .rn = operand_reg,
959 .lsb = 0,
960 .width = @intCast(u6, int_bits),
961 } },
962 });
963 },
964 32, 64 => {
965 _ = try self.addInst(.{
966 .tag = .mov_register,
967 .data = .{ .rr = .{
968 .rd = dest_reg,
969 .rn = operand_reg,
970 } },
971 });
972 },
973 else => unreachable,
974 }
975}
976
977fn trunc(
978 self: *Self,
979 maybe_inst: ?Air.Inst.Index,
980 operand: MCValue,
981 operand_ty: Type,
982 dest_ty: Type,
983) !MCValue {
984 const info_a = operand_ty.intInfo(self.target.*);
985 const info_b = dest_ty.intInfo(self.target.*);
986
987 if (info_b.bits <= 64) {
988 const operand_reg = switch (operand) {
989 .register => |r| r,
990 else => operand_reg: {
991 if (info_a.bits <= 64) {
992 const raw_reg = try self.copyToTmpRegister(operand_ty, operand);
993 break :operand_reg registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
994 } else {
995 return self.fail("TODO load least significant word into register", .{});
996 }
997 },
998 };
999 self.register_manager.freezeRegs(&.{operand_reg});
1000 defer self.register_manager.unfreezeRegs(&.{operand_reg});
1001
1002 const dest_reg = if (maybe_inst) |inst| blk: {
1003 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1004
1005 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1006 break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));
1007 } else {
1008 const raw_reg = try self.register_manager.allocReg(inst);
1009 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
1010 }
1011 } else blk: {
1012 const raw_reg = try self.register_manager.allocReg(null);
1013 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
1014 };
1015
1016 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
1017
1018 return MCValue{ .register = dest_reg };
1019 } else {
1020 return self.fail("TODO: truncate to ints > 32 bits", .{});
1021 }
1022}
1023
9391024fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
9401025 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
941 if (self.liveness.isUnused(inst))
942 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
943
9441026 const operand = try self.resolveInst(ty_op.operand);
945 _ = operand;
946 return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch});
1027 const operand_ty = self.air.typeOf(ty_op.operand);
1028 const dest_ty = self.air.typeOfIndex(inst);
1029
1030 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
1031 break :blk try self.trunc(inst, operand, operand_ty, dest_ty);
1032 };
1033
1034 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
9471035}
9481036
9491037fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1003,7 +1091,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
10031091 break :blk op_reg;
10041092 }
10051093
1006 break :blk try self.register_manager.allocReg(null);
1094 const raw_reg = try self.register_manager.allocReg(null);
1095 break :blk raw_reg.to32();
10071096 };
10081097
10091098 _ = try self.addInst(.{
......@@ -1013,7 +1102,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
10131102 .rn = op_reg,
10141103 .imms = 0b000000,
10151104 .immr = 0b000000,
1016 .n = 0b1,
1105 .n = 0b0,
10171106 } },
10181107 });
10191108
......@@ -1035,7 +1124,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
10351124 break :blk op_reg;
10361125 }
10371126
1038 break :blk try self.register_manager.allocReg(null);
1127 const raw_reg = try self.register_manager.allocReg(null);
1128 break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
10391129 };
10401130
10411131 _ = try self.addInst(.{
......@@ -1048,6 +1138,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
10481138 } },
10491139 });
10501140
1141 try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
1142
10511143 break :result MCValue{ .register = dest_reg };
10521144 } else {
10531145 return self.fail("TODO AArch64 not on integers > u64/i64", .{});
......@@ -1103,7 +1195,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
11031195/// Asserts that generating an instruction of that form is possible.
11041196fn binOpRegister(
11051197 self: *Self,
1106 tag: Air.Inst.Tag,
1198 mir_tag: Mir.Inst.Tag,
11071199 maybe_inst: ?Air.Inst.Index,
11081200 lhs: MCValue,
11091201 rhs: MCValue,
......@@ -1124,7 +1216,8 @@ fn binOpRegister(
11241216 break :inst Air.refToIndex(bin_op.lhs).?;
11251217 } else null;
11261218
1127 const reg = try self.register_manager.allocReg(track_inst);
1219 const raw_reg = try self.register_manager.allocReg(track_inst);
1220 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
11281221 self.register_manager.freezeRegs(&.{reg});
11291222
11301223 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1139,7 +1232,8 @@ fn binOpRegister(
11391232 break :inst Air.refToIndex(bin_op.rhs).?;
11401233 } else null;
11411234
1142 const reg = try self.register_manager.allocReg(track_inst);
1235 const raw_reg = try self.register_manager.allocReg(track_inst);
1236 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
11431237 self.register_manager.freezeRegs(&.{reg});
11441238
11451239 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1156,45 +1250,17 @@ fn binOpRegister(
11561250 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
11571251 break :blk rhs_reg;
11581252 } else {
1159 break :blk try self.register_manager.allocReg(inst);
1253 const raw_reg = try self.register_manager.allocReg(inst);
1254 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
11601255 }
11611256 } else try self.register_manager.allocReg(null);
11621257
11631258 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
11641259 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
11651260
1166 const mir_tag: Mir.Inst.Tag = switch (tag) {
1167 .add,
1168 .ptr_add,
1169 => .add_shifted_register,
1170 .sub,
1171 .ptr_sub,
1172 => .sub_shifted_register,
1173 .cmp_eq => .cmp_shifted_register,
1174 .mul => .mul,
1175 .bit_and,
1176 .bool_and,
1177 => .and_shifted_register,
1178 .bit_or,
1179 .bool_or,
1180 => .orr_shifted_register,
1181 .shl,
1182 .shl_exact,
1183 => .lsl_register,
1184 .shr,
1185 .shr_exact,
1186 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1187 .signed => Mir.Inst.Tag.asr_register,
1188 .unsigned => Mir.Inst.Tag.lsr_register,
1189 },
1190 .xor => .eor_shifted_register,
1191 else => unreachable,
1192 };
1193 const mir_data: Mir.Inst.Data = switch (tag) {
1194 .add,
1195 .sub,
1196 .ptr_add,
1197 .ptr_sub,
1261 const mir_data: Mir.Inst.Data = switch (mir_tag) {
1262 .add_shifted_register,
1263 .sub_shifted_register,
11981264 => .{ .rrr_imm6_shift = .{
11991265 .rd = dest_reg,
12001266 .rn = lhs_reg,
......@@ -1202,27 +1268,24 @@ fn binOpRegister(
12021268 .imm6 = 0,
12031269 .shift = .lsl,
12041270 } },
1205 .cmp_eq => .{ .rr_imm6_shift = .{
1271 .cmp_shifted_register => .{ .rr_imm6_shift = .{
12061272 .rn = lhs_reg,
12071273 .rm = rhs_reg,
12081274 .imm6 = 0,
12091275 .shift = .lsl,
12101276 } },
12111277 .mul,
1212 .shl,
1213 .shl_exact,
1214 .shr,
1215 .shr_exact,
1278 .lsl_register,
1279 .asr_register,
1280 .lsr_register,
12161281 => .{ .rrr = .{
12171282 .rd = dest_reg,
12181283 .rn = lhs_reg,
12191284 .rm = rhs_reg,
12201285 } },
1221 .bit_and,
1222 .bool_and,
1223 .bit_or,
1224 .bool_or,
1225 .xor,
1286 .and_shifted_register,
1287 .orr_shifted_register,
1288 .eor_shifted_register,
12261289 => .{ .rrr_imm6_logical_shift = .{
12271290 .rd = dest_reg,
12281291 .rn = lhs_reg,
......@@ -1255,7 +1318,7 @@ fn binOpRegister(
12551318/// Asserts that generating an instruction of that form is possible.
12561319fn binOpImmediate(
12571320 self: *Self,
1258 tag: Air.Inst.Tag,
1321 mir_tag: Mir.Inst.Tag,
12591322 maybe_inst: ?Air.Inst.Index,
12601323 lhs: MCValue,
12611324 rhs: MCValue,
......@@ -1276,7 +1339,8 @@ fn binOpImmediate(
12761339 ).?;
12771340 } else null;
12781341
1279 const reg = try self.register_manager.allocReg(track_inst);
1342 const raw_reg = try self.register_manager.allocReg(track_inst);
1343 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
12801344 self.register_manager.freezeRegs(&.{reg});
12811345
12821346 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1285,8 +1349,8 @@ fn binOpImmediate(
12851349 };
12861350 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
12871351
1288 const dest_reg = switch (tag) {
1289 .cmp_eq => undefined, // cmp has no destination register
1352 const dest_reg = switch (mir_tag) {
1353 .cmp_immediate => undefined, // cmp has no destination register
12901354 else => if (maybe_inst) |inst| blk: {
12911355 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12921356
......@@ -1298,46 +1362,31 @@ fn binOpImmediate(
12981362 )) {
12991363 break :blk lhs_reg;
13001364 } else {
1301 break :blk try self.register_manager.allocReg(inst);
1365 const raw_reg = try self.register_manager.allocReg(inst);
1366 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
13021367 }
13031368 } else try self.register_manager.allocReg(null),
13041369 };
13051370
13061371 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
13071372
1308 const mir_tag: Mir.Inst.Tag = switch (tag) {
1309 .add => .add_immediate,
1310 .sub => .sub_immediate,
1311 .shl,
1312 .shl_exact,
1313 => .lsl_immediate,
1314 .shr,
1315 .shr_exact,
1316 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1317 .signed => Mir.Inst.Tag.asr_immediate,
1318 .unsigned => Mir.Inst.Tag.lsr_immediate,
1319 },
1320 .cmp_eq => .cmp_immediate,
1321 else => unreachable,
1322 };
1323 const mir_data: Mir.Inst.Data = switch (tag) {
1324 .add,
1325 .sub,
1373 const mir_data: Mir.Inst.Data = switch (mir_tag) {
1374 .add_immediate,
1375 .sub_immediate,
13261376 => .{ .rr_imm12_sh = .{
13271377 .rd = dest_reg,
13281378 .rn = lhs_reg,
13291379 .imm12 = @intCast(u12, rhs.immediate),
13301380 } },
1331 .shl,
1332 .shl_exact,
1333 .shr,
1334 .shr_exact,
1381 .lsl_immediate,
1382 .asr_immediate,
1383 .lsr_immediate,
13351384 => .{ .rr_shift = .{
13361385 .rd = dest_reg,
13371386 .rn = lhs_reg,
13381387 .shift = @intCast(u6, rhs.immediate),
13391388 } },
1340 .cmp_eq => .{ .r_imm12_sh = .{
1389 .cmp_immediate => .{ .r_imm12_sh = .{
13411390 .rn = lhs_reg,
13421391 .imm12 = @intCast(u12, rhs.immediate),
13431392 } },
......@@ -1375,7 +1424,6 @@ fn binOp(
13751424) InnerError!MCValue {
13761425 const target = self.target.*;
13771426 switch (tag) {
1378 // Arithmetic operations on integers and floats
13791427 .add,
13801428 .sub,
13811429 .cmp_eq,
......@@ -1403,13 +1451,26 @@ fn binOp(
14031451 else => unreachable,
14041452 };
14051453
1454 const mir_tag_register: Mir.Inst.Tag = switch (tag) {
1455 .add => .add_shifted_register,
1456 .sub => .sub_shifted_register,
1457 .cmp_eq => .cmp_shifted_register,
1458 else => unreachable,
1459 };
1460 const mir_tag_immediate: Mir.Inst.Tag = switch (tag) {
1461 .add => .add_immediate,
1462 .sub => .sub_immediate,
1463 .cmp_eq => .cmp_immediate,
1464 else => unreachable,
1465 };
1466
14061467 if (rhs_immediate_ok) {
1407 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1468 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);
14081469 } else if (lhs_immediate_ok) {
14091470 // swap lhs and rhs
1410 return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true);
1471 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, rhs, lhs, rhs_ty, true);
14111472 } else {
1412 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1473 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
14131474 }
14141475 } else {
14151476 return self.fail("TODO binary operations on int with bits > 64", .{});
......@@ -1428,7 +1489,7 @@ fn binOp(
14281489 // TODO add optimisations for multiplication
14291490 // with immediates, for example a * 2 can be
14301491 // lowered to a << 1
1431 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1492 return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
14321493 } else {
14331494 return self.fail("TODO binary operations on int with bits > 64", .{});
14341495 }
......@@ -1436,7 +1497,36 @@ fn binOp(
14361497 else => unreachable,
14371498 }
14381499 },
1439 // Bitwise operations on integers
1500 .addwrap,
1501 .subwrap,
1502 .mulwrap,
1503 => {
1504 const base_tag: Air.Inst.Tag = switch (tag) {
1505 .addwrap => .add,
1506 .subwrap => .sub,
1507 .mulwrap => .mul,
1508 else => unreachable,
1509 };
1510
1511 // Generate an add/sub/mul
1512 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1513
1514 // Truncate if necessary
1515 switch (lhs_ty.zigTypeTag()) {
1516 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1517 .Int => {
1518 const int_info = lhs_ty.intInfo(self.target.*);
1519 if (int_info.bits <= 64) {
1520 const result_reg = result.register;
1521 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
1522 return result;
1523 } else {
1524 return self.fail("TODO binary operations on integers > u64/i64", .{});
1525 }
1526 },
1527 else => unreachable,
1528 }
1529 },
14401530 .bit_and,
14411531 .bit_or,
14421532 .xor,
......@@ -1448,7 +1538,14 @@ fn binOp(
14481538 const int_info = lhs_ty.intInfo(self.target.*);
14491539 if (int_info.bits <= 64) {
14501540 // TODO implement bitwise operations with immediates
1451 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1541 const mir_tag: Mir.Inst.Tag = switch (tag) {
1542 .bit_and => .and_shifted_register,
1543 .bit_or => .orr_shifted_register,
1544 .xor => .eor_shifted_register,
1545 else => unreachable,
1546 };
1547
1548 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
14521549 } else {
14531550 return self.fail("TODO binary operations on int with bits > 64", .{});
14541551 }
......@@ -1456,8 +1553,8 @@ fn binOp(
14561553 else => unreachable,
14571554 }
14581555 },
1459 .shl,
1460 .shr,
1556 .shl_exact,
1557 .shr_exact,
14611558 => {
14621559 switch (lhs_ty.zigTypeTag()) {
14631560 .Vector => return self.fail("TODO binary operations on vectors", .{}),
......@@ -1466,10 +1563,27 @@ fn binOp(
14661563 if (int_info.bits <= 64) {
14671564 const rhs_immediate_ok = rhs == .immediate;
14681565
1566 const mir_tag_register: Mir.Inst.Tag = switch (tag) {
1567 .shl_exact => .lsl_register,
1568 .shr_exact => switch (int_info.signedness) {
1569 .signed => Mir.Inst.Tag.asr_register,
1570 .unsigned => Mir.Inst.Tag.lsr_register,
1571 },
1572 else => unreachable,
1573 };
1574 const mir_tag_immediate: Mir.Inst.Tag = switch (tag) {
1575 .shl_exact => .lsl_immediate,
1576 .shr_exact => switch (int_info.signedness) {
1577 .signed => Mir.Inst.Tag.asr_immediate,
1578 .unsigned => Mir.Inst.Tag.lsr_immediate,
1579 },
1580 else => unreachable,
1581 };
1582
14691583 if (rhs_immediate_ok) {
1470 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1584 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);
14711585 } else {
1472 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1586 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
14731587 }
14741588 } else {
14751589 return self.fail("TODO binary operations on int with bits > 64", .{});
......@@ -1478,6 +1592,38 @@ fn binOp(
14781592 else => unreachable,
14791593 }
14801594 },
1595 .shl,
1596 .shr,
1597 => {
1598 const base_tag: Air.Inst.Tag = switch (tag) {
1599 .shl => .shl_exact,
1600 .shr => .shr_exact,
1601 else => unreachable,
1602 };
1603
1604 // Generate a shl_exact/shr_exact
1605 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1606
1607 // Truncate if necessary
1608 switch (tag) {
1609 .shr => return result,
1610 .shl => switch (lhs_ty.zigTypeTag()) {
1611 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1612 .Int => {
1613 const int_info = lhs_ty.intInfo(self.target.*);
1614 if (int_info.bits <= 64) {
1615 const result_reg = result.register;
1616 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
1617 return result;
1618 } else {
1619 return self.fail("TODO binary operations on integers > u64/i64", .{});
1620 }
1621 },
1622 else => unreachable,
1623 },
1624 else => unreachable,
1625 }
1626 },
14811627 .bool_and,
14821628 .bool_or,
14831629 => {
......@@ -1486,7 +1632,13 @@ fn binOp(
14861632 assert(lhs != .immediate); // should have been handled by Sema
14871633 assert(rhs != .immediate); // should have been handled by Sema
14881634
1489 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1635 const mir_tag_register: Mir.Inst.Tag = switch (tag) {
1636 .bool_and => .and_shifted_register,
1637 .bool_or => .orr_shifted_register,
1638 else => unreachable,
1639 };
1640
1641 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
14901642 },
14911643 else => unreachable,
14921644 }
......@@ -1504,9 +1656,9 @@ fn binOp(
15041656 const elem_size = elem_ty.abiSize(self.target.*);
15051657
15061658 if (elem_size == 1) {
1507 const base_tag: Air.Inst.Tag = switch (tag) {
1508 .ptr_add => .add,
1509 .ptr_sub => .sub,
1659 const base_tag: Mir.Inst.Tag = switch (tag) {
1660 .ptr_add => .add_shifted_register,
1661 .ptr_sub => .sub_shifted_register,
15101662 else => unreachable,
15111663 };
15121664
......@@ -1538,36 +1690,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
15381690 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15391691}
15401692
1541fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
1542 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1543 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});
1544 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1545}
1546
15471693fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
15481694 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
15491695 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
15501696 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15511697}
15521698
1553fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
1554 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1555 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
1556 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1557}
1558
15591699fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
15601700 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
15611701 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
15621702 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15631703}
15641704
1565fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void {
1566 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1567 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch});
1568 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1569}
1570
15711705fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
15721706 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
15731707 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});
......@@ -1961,11 +2095,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
19612095 .undef => unreachable,
19622096 .compare_flags_signed, .compare_flags_unsigned => unreachable,
19632097 .register => |dst_reg| {
1964 try self.genLdrRegister(dst_reg, addr_reg, elem_size);
2098 try self.genLdrRegister(dst_reg, addr_reg, elem_ty);
19652099 },
19662100 .stack_offset => |off| {
19672101 if (elem_size <= 8) {
1968 const tmp_reg = try self.register_manager.allocReg(null);
2102 const raw_tmp_reg = try self.register_manager.allocReg(null);
2103 const tmp_reg = registerAlias(raw_tmp_reg, elem_size);
19692104 self.register_manager.freezeRegs(&.{tmp_reg});
19702105 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
19712106
......@@ -2001,12 +2136,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
20012136 .got_load,
20022137 .direct_load,
20032138 => {
2004 const reg = try self.register_manager.allocReg(null);
2005 self.register_manager.freezeRegs(&.{reg});
2006 defer self.register_manager.unfreezeRegs(&.{reg});
2007
2008 try self.genSetReg(ptr_ty, reg, ptr);
2009 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
2139 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
2140 try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty);
20102141 },
20112142 }
20122143}
......@@ -2091,6 +2222,7 @@ fn genInlineMemcpy(
20912222fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
20922223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
20932224 const elem_ty = self.air.typeOfIndex(inst);
2225 const elem_size = elem_ty.abiSize(self.target.*);
20942226 const result: MCValue = result: {
20952227 if (!elem_ty.hasRuntimeBits())
20962228 break :result MCValue.none;
......@@ -2101,9 +2233,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
21012233 break :result MCValue.dead;
21022234
21032235 const dst_mcv: MCValue = blk: {
2104 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
2236 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
21052237 // The MCValue that holds the pointer can be re-used as the value.
2106 break :blk ptr;
2238 break :blk switch (ptr) {
2239 .register => |r| MCValue{ .register = registerAlias(r, elem_size) },
2240 else => ptr,
2241 };
21072242 } else {
21082243 break :blk try self.allocRegOrMem(inst, true);
21092244 }
......@@ -2114,101 +2249,52 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
21142249 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
21152250}
21162251
2117fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
2118 switch (abi_size) {
2119 1 => {
2120 _ = try self.addInst(.{
2121 .tag = .ldrb_immediate,
2122 .data = .{ .load_store_register_immediate = .{
2123 .rt = value_reg.to32(),
2124 .rn = addr_reg,
2125 .offset = Instruction.LoadStoreOffset.none.immediate,
2126 } },
2127 });
2128 },
2129 2 => {
2130 _ = try self.addInst(.{
2131 .tag = .ldrh_immediate,
2132 .data = .{ .load_store_register_immediate = .{
2133 .rt = value_reg.to32(),
2134 .rn = addr_reg,
2135 .offset = Instruction.LoadStoreOffset.none.immediate,
2136 } },
2137 });
2138 },
2139 4 => {
2140 _ = try self.addInst(.{
2141 .tag = .ldr_immediate,
2142 .data = .{ .load_store_register_immediate = .{
2143 .rt = value_reg.to32(),
2144 .rn = addr_reg,
2145 .offset = Instruction.LoadStoreOffset.none.immediate,
2146 } },
2147 });
2148 },
2149 8 => {
2150 _ = try self.addInst(.{
2151 .tag = .ldr_immediate,
2152 .data = .{ .load_store_register_immediate = .{
2153 .rt = value_reg.to64(),
2154 .rn = addr_reg,
2155 .offset = Instruction.LoadStoreOffset.none.immediate,
2156 } },
2157 });
2158 },
2252fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
2253 const abi_size = ty.abiSize(self.target.*);
2254
2255 const tag: Mir.Inst.Tag = switch (abi_size) {
2256 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate,
2257 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate,
2258 4 => .ldr_immediate,
2259 8 => .ldr_immediate,
21592260 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}),
21602261 else => unreachable,
2161 }
2262 };
2263
2264 _ = try self.addInst(.{
2265 .tag = tag,
2266 .data = .{ .load_store_register_immediate = .{
2267 .rt = value_reg,
2268 .rn = addr_reg,
2269 .offset = Instruction.LoadStoreOffset.none.immediate,
2270 } },
2271 });
21622272}
21632273
2164fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
2165 switch (abi_size) {
2166 1 => {
2167 _ = try self.addInst(.{
2168 .tag = .strb_immediate,
2169 .data = .{ .load_store_register_immediate = .{
2170 .rt = value_reg.to32(),
2171 .rn = addr_reg,
2172 .offset = Instruction.LoadStoreOffset.none.immediate,
2173 } },
2174 });
2175 },
2176 2 => {
2177 _ = try self.addInst(.{
2178 .tag = .strh_immediate,
2179 .data = .{ .load_store_register_immediate = .{
2180 .rt = value_reg.to32(),
2181 .rn = addr_reg,
2182 .offset = Instruction.LoadStoreOffset.none.immediate,
2183 } },
2184 });
2185 },
2186 4 => {
2187 _ = try self.addInst(.{
2188 .tag = .str_immediate,
2189 .data = .{ .load_store_register_immediate = .{
2190 .rt = value_reg.to32(),
2191 .rn = addr_reg,
2192 .offset = Instruction.LoadStoreOffset.none.immediate,
2193 } },
2194 });
2195 },
2196 8 => {
2197 _ = try self.addInst(.{
2198 .tag = .str_immediate,
2199 .data = .{ .load_store_register_immediate = .{
2200 .rt = value_reg.to64(),
2201 .rn = addr_reg,
2202 .offset = Instruction.LoadStoreOffset.none.immediate,
2203 } },
2204 });
2205 },
2274fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
2275 const abi_size = ty.abiSize(self.target.*);
2276
2277 const tag: Mir.Inst.Tag = switch (abi_size) {
2278 1 => .strb_immediate,
2279 2 => .strh_immediate,
2280 4, 8 => .str_immediate,
22062281 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}),
22072282 else => unreachable,
2208 }
2283 };
2284
2285 _ = try self.addInst(.{
2286 .tag = tag,
2287 .data = .{ .load_store_register_immediate = .{
2288 .rt = value_reg,
2289 .rn = addr_reg,
2290 .offset = Instruction.LoadStoreOffset.none.immediate,
2291 } },
2292 });
22092293}
22102294
22112295fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
2296 const abi_size = value_ty.abiSize(self.target.*);
2297
22122298 switch (ptr) {
22132299 .none => unreachable,
22142300 .undef => unreachable,
......@@ -2226,14 +2312,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
22262312 self.register_manager.freezeRegs(&.{addr_reg});
22272313 defer self.register_manager.unfreezeRegs(&.{addr_reg});
22282314
2229 const abi_size = value_ty.abiSize(self.target.*);
22302315 switch (value) {
22312316 .register => |value_reg| {
2232 try self.genStrRegister(value_reg, addr_reg, abi_size);
2317 try self.genStrRegister(value_reg, addr_reg, value_ty);
22332318 },
22342319 else => {
22352320 if (abi_size <= 8) {
2236 const tmp_reg = try self.register_manager.allocReg(null);
2321 const raw_tmp_reg = try self.register_manager.allocReg(null);
2322 const tmp_reg = registerAlias(raw_tmp_reg, abi_size);
22372323 self.register_manager.freezeRegs(&.{tmp_reg});
22382324 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
22392325
......@@ -3470,23 +3556,26 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
34703556 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x) } },
34713557 });
34723558
3473 if (x > math.maxInt(u16)) {
3559 if (x & 0x0000_0000_ffff_0000 != 0) {
34743560 _ = try self.addInst(.{
34753561 .tag = .movk,
34763562 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 16), .hw = 1 } },
34773563 });
34783564 }
3479 if (x > math.maxInt(u32)) {
3480 _ = try self.addInst(.{
3481 .tag = .movk,
3482 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } },
3483 });
3484 }
3485 if (x > math.maxInt(u48)) {
3486 _ = try self.addInst(.{
3487 .tag = .movk,
3488 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } },
3489 });
3565
3566 if (reg.size() == 64) {
3567 if (x & 0x0000_ffff_0000_0000 != 0) {
3568 _ = try self.addInst(.{
3569 .tag = .movk,
3570 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } },
3571 });
3572 }
3573 if (x & 0xffff_0000_0000_0000 != 0) {
3574 _ = try self.addInst(.{
3575 .tag = .movk,
3576 .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } },
3577 });
3578 }
34903579 }
34913580 },
34923581 .register => |src_reg| {
......@@ -3522,8 +3611,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
35223611 .memory => |addr| {
35233612 // The value is in memory at a hard-coded address.
35243613 // If the type is a pointer, it means the pointer address is at this memory location.
3525 try self.genSetReg(ty, reg, .{ .immediate = addr });
3526 try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*));
3614 try self.genSetReg(ty, reg.to64(), .{ .immediate = addr });
3615 try self.genLdrRegister(reg, reg.to64(), ty);
35273616 },
35283617 .stack_offset => |off| {
35293618 const abi_size = ty.abiSize(self.target.*);
......@@ -3531,21 +3620,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
35313620 switch (abi_size) {
35323621 1, 2, 4, 8 => {
35333622 const tag: Mir.Inst.Tag = switch (abi_size) {
3534 1 => .ldrb_stack,
3535 2 => .ldrh_stack,
3623 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack,
3624 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack,
35363625 4, 8 => .ldr_stack,
35373626 else => unreachable, // unexpected abi size
35383627 };
3539 const rt: Register = switch (abi_size) {
3540 1, 2, 4 => reg.to32(),
3541 8 => reg.to64(),
3542 else => unreachable, // unexpected abi size
3543 };
35443628
35453629 _ = try self.addInst(.{
35463630 .tag = tag,
35473631 .data = .{ .load_store_stack = .{
3548 .rt = rt,
3632 .rt = reg,
35493633 .offset = @intCast(u32, off),
35503634 } },
35513635 });
......@@ -3998,6 +4082,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
39984082 var nsaa: u32 = 0; // Next stacked argument address
39994083
40004084 for (param_types) |ty, i| {
4085 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4086 if (param_size == 0) {
4087 result.args[i] = .{ .none = {} };
4088 continue;
4089 }
4090
40014091 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned
40024092 // values to spread across odd-numbered registers.
40034093 if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) {
......@@ -4005,10 +4095,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
40054095 ncrn += ncrn % 2;
40064096 }
40074097
4008 const param_size = @intCast(u32, ty.abiSize(self.target.*));
40094098 if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) {
40104099 if (param_size <= 8) {
4011 result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] };
4100 result.args[i] = .{ .register = registerAlias(c_abi_int_param_regs[ncrn], param_size) };
40124101 ncrn += 1;
40134102 } else {
40144103 return self.fail("TODO MCValues with multiple registers", .{});
......@@ -4045,7 +4134,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
40454134 .Unspecified, .C => {
40464135 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
40474136 if (ret_ty_size <= 8) {
4048 result.return_value = .{ .register = c_abi_int_return_regs[0] };
4137 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
40494138 } else {
40504139 return self.fail("TODO support more return types for ARM backend", .{});
40514140 }
src/arch/aarch64/Emit.zig+87-11
......@@ -131,6 +131,8 @@ pub fn emitMir(
131131 .ldr_stack => try emit.mirLoadStoreStack(inst),
132132 .ldrb_stack => try emit.mirLoadStoreStack(inst),
133133 .ldrh_stack => try emit.mirLoadStoreStack(inst),
134 .ldrsb_stack => try emit.mirLoadStoreStack(inst),
135 .ldrsh_stack => try emit.mirLoadStoreStack(inst),
134136 .str_stack => try emit.mirLoadStoreStack(inst),
135137 .strb_stack => try emit.mirLoadStoreStack(inst),
136138 .strh_stack => try emit.mirLoadStoreStack(inst),
......@@ -145,6 +147,9 @@ pub fn emitMir(
145147 .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
146148 .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
147149 .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150 .ldrsb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
151 .ldrsh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
152 .ldrsw_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
148153 .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
149154 .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150155 .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
......@@ -162,6 +167,17 @@ pub fn emitMir(
162167
163168 .push_regs => try emit.mirPushPopRegs(inst),
164169 .pop_regs => try emit.mirPushPopRegs(inst),
170
171 .sbfx,
172 .ubfx,
173 => try emit.mirBitfieldExtract(inst),
174
175 .sxtb,
176 .sxth,
177 .sxtw,
178 .uxtb,
179 .uxth,
180 => try emit.mirExtend(inst),
165181 }
166182 }
167183}
......@@ -457,8 +473,13 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
457473 const rn = r_imm12_sh.rn;
458474 const imm12 = r_imm12_sh.imm12;
459475 const sh = r_imm12_sh.sh == 1;
476 const zr: Register = switch (rn.size()) {
477 32 => .wzr,
478 64 => .xzr,
479 else => unreachable,
480 };
460481
461 try emit.writeInstruction(Instruction.subs(.xzr, rn, imm12, sh));
482 try emit.writeInstruction(Instruction.subs(zr, rn, imm12, sh));
462483 },
463484 else => unreachable,
464485 }
......@@ -674,8 +695,13 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
674695 const rm = rr_imm6_shift.rm;
675696 const shift = rr_imm6_shift.shift;
676697 const imm6 = rr_imm6_shift.imm6;
698 const zr: Register = switch (rn.size()) {
699 32 => .wzr,
700 64 => .xzr,
701 else => unreachable,
702 };
677703
678 try emit.writeInstruction(Instruction.subsShiftedRegister(.xzr, rn, rm, shift, imm6));
704 try emit.writeInstruction(Instruction.subsShiftedRegister(zr, rn, rm, shift, imm6));
679705 },
680706 else => unreachable,
681707 }
......@@ -686,7 +712,12 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
686712 switch (tag) {
687713 .cset => {
688714 const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
689 try emit.writeInstruction(Instruction.csinc(r_cond.rd, .xzr, .xzr, r_cond.cond));
715 const zr: Register = switch (r_cond.rd.size()) {
716 32 => .wzr,
717 64 => .xzr,
718 else => unreachable,
719 };
720 try emit.writeInstruction(Instruction.csinc(r_cond.rd, zr, zr, r_cond.cond));
690721 },
691722 else => unreachable,
692723 }
......@@ -718,14 +749,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
718749 // PC-relative displacement to the entry in memory.
719750 // adrp
720751 const offset = @intCast(u32, emit.code.items.len);
721 try emit.writeInstruction(Instruction.adrp(reg, 0));
752 try emit.writeInstruction(Instruction.adrp(reg.to64(), 0));
722753
723754 switch (tag) {
724755 .load_memory_got => {
725756 // ldr reg, reg, offset
726757 try emit.writeInstruction(Instruction.ldr(
727758 reg,
728 reg,
759 reg.to64(),
729760 Instruction.LoadStoreOffset.imm(0),
730761 ));
731762 },
......@@ -739,11 +770,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
739770 // Note that this can potentially be optimised out by the codegen/linker if the
740771 // target address is appropriately aligned.
741772 // add reg, reg, offset
742 try emit.writeInstruction(Instruction.add(reg, reg, 0, false));
773 try emit.writeInstruction(Instruction.add(reg.to64(), reg.to64(), 0, false));
743774 // ldr reg, reg, offset
744775 try emit.writeInstruction(Instruction.ldr(
745776 reg,
746 reg,
777 reg.to64(),
747778 Instruction.LoadStoreOffset.imm(0),
748779 ));
749780 },
......@@ -821,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
821852
822853 const raw_offset = emit.stack_size - load_store_stack.offset;
823854 const offset = switch (tag) {
824 .ldrb_stack, .strb_stack => blk: {
855 .ldrb_stack, .ldrsb_stack, .strb_stack => blk: {
825856 if (math.cast(u12, raw_offset)) |imm| {
826857 break :blk Instruction.LoadStoreOffset.imm(imm);
827858 } else |_| {
828859 return emit.fail("TODO load/store stack byte with larger offset", .{});
829860 }
830861 },
831 .ldrh_stack, .strh_stack => blk: {
862 .ldrh_stack, .ldrsh_stack, .strh_stack => blk: {
832863 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
833864 if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {
834865 break :blk Instruction.LoadStoreOffset.imm(imm);
......@@ -857,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
857888 .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
858889 .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
859890 .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
891 .ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
892 .ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
860893 .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),
861894 .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),
862895 .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),
......@@ -875,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
875908 .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),
876909 .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),
877910 .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),
911 .ldrsb_immediate => try emit.writeInstruction(Instruction.ldrsb(rt, rn, offset)),
912 .ldrsh_immediate => try emit.writeInstruction(Instruction.ldrsh(rt, rn, offset)),
913 .ldrsw_immediate => try emit.writeInstruction(Instruction.ldrsw(rt, rn, offset)),
878914 .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)),
879915 .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),
880916 .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),
......@@ -905,7 +941,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
905941 switch (tag) {
906942 .mov_register => {
907943 const rr = emit.mir.instructions.items(.data)[inst].rr;
908 try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, .xzr, rr.rn, .lsl, 0));
944 const zr: Register = switch (rr.rd.size()) {
945 32 => .wzr,
946 64 => .xzr,
947 else => unreachable,
948 };
949
950 try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, zr, rr.rn, .lsl, 0));
909951 },
910952 .mov_to_from_sp => {
911953 const rr = emit.mir.instructions.items(.data)[inst].rr;
......@@ -917,8 +959,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
917959 const rm = rr_imm6_logical_shift.rm;
918960 const shift = rr_imm6_logical_shift.shift;
919961 const imm6 = rr_imm6_logical_shift.imm6;
962 const zr: Register = switch (rd.size()) {
963 32 => .wzr,
964 64 => .xzr,
965 else => unreachable,
966 };
920967
921 try emit.writeInstruction(Instruction.ornShiftedRegister(rd, .xzr, rm, shift, imm6));
968 try emit.writeInstruction(Instruction.ornShiftedRegister(rd, zr, rm, shift, imm6));
922969 },
923970 else => unreachable,
924971 }
......@@ -1024,3 +1071,32 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
10241071 else => unreachable,
10251072 }
10261073}
1074
1075fn mirBitfieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void {
1076 const tag = emit.mir.instructions.items(.tag)[inst];
1077 const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width;
1078 const rd = rr_lsb_width.rd;
1079 const rn = rr_lsb_width.rn;
1080 const lsb = rr_lsb_width.lsb;
1081 const width = rr_lsb_width.width;
1082
1083 switch (tag) {
1084 .sbfx => try emit.writeInstruction(Instruction.sbfx(rd, rn, lsb, width)),
1085 .ubfx => try emit.writeInstruction(Instruction.ubfx(rd, rn, lsb, width)),
1086 else => unreachable,
1087 }
1088}
1089
1090fn mirExtend(emit: *Emit, inst: Mir.Inst.Index) !void {
1091 const tag = emit.mir.instructions.items(.tag)[inst];
1092 const rr = emit.mir.instructions.items(.data)[inst].rr;
1093
1094 switch (tag) {
1095 .sxtb => try emit.writeInstruction(Instruction.sxtb(rr.rd, rr.rn)),
1096 .sxth => try emit.writeInstruction(Instruction.sxth(rr.rd, rr.rn)),
1097 .sxtw => try emit.writeInstruction(Instruction.sxtw(rr.rd, rr.rn)),
1098 .uxtb => try emit.writeInstruction(Instruction.uxtb(rr.rd, rr.rn)),
1099 .uxth => try emit.writeInstruction(Instruction.uxth(rr.rd, rr.rn)),
1100 else => unreachable,
1101 }
1102}
src/arch/aarch64/Mir.zig+41-7
......@@ -100,6 +100,16 @@ pub const Inst = struct {
100100 ldrh_immediate,
101101 /// Load Register Halfword (register)
102102 ldrh_register,
103 /// Load Register Signed Byte (immediate)
104 ldrsb_immediate,
105 /// Pseudo-instruction: Load signed byte from stack
106 ldrsb_stack,
107 /// Load Register Signed Halfword (immediate)
108 ldrsh_immediate,
109 /// Pseudo-instruction: Load signed halfword from stack
110 ldrsh_stack,
111 /// Load Register Signed Word (immediate)
112 ldrsw_immediate,
103113 /// Logical Shift Left (immediate)
104114 lsl_immediate,
105115 /// Logical Shift Left (register)
......@@ -130,6 +140,14 @@ pub const Inst = struct {
130140 push_regs,
131141 /// Return from subroutine
132142 ret,
143 /// Signed bitfield extract
144 sbfx,
145 /// Signed extend byte
146 sxtb,
147 /// Signed extend halfword
148 sxth,
149 /// Signed extend word
150 sxtw,
133151 /// Store Pair of Registers
134152 stp,
135153 /// Pseudo-instruction: Store to stack
......@@ -156,6 +174,12 @@ pub const Inst = struct {
156174 sub_shifted_register,
157175 /// Supervisor Call
158176 svc,
177 /// Unsigned bitfield extract
178 ubfx,
179 /// Unsigned extend byte
180 uxtb,
181 /// Unsigned extend halfword
182 uxth,
159183 };
160184
161185 /// The position of an MIR instruction within the `Mir` instructions array.
......@@ -225,13 +249,6 @@ pub const Inst = struct {
225249 rt: Register,
226250 inst: Index,
227251 },
228 /// Two registers
229 ///
230 /// Used by e.g. mov_register
231 rr: struct {
232 rd: Register,
233 rn: Register,
234 },
235252 /// A register, an unsigned 12-bit immediate, and an optional shift
236253 ///
237254 /// Used by e.g. cmp_immediate
......@@ -240,6 +257,13 @@ pub const Inst = struct {
240257 imm12: u12,
241258 sh: u1 = 0,
242259 },
260 /// Two registers
261 ///
262 /// Used by e.g. mov_register
263 rr: struct {
264 rd: Register,
265 rn: Register,
266 },
243267 /// Two registers, an unsigned 12-bit immediate, and an optional shift
244268 ///
245269 /// Used by e.g. sub_immediate
......@@ -268,6 +292,16 @@ pub const Inst = struct {
268292 imm6: u6,
269293 shift: bits.Instruction.LogicalShiftedRegisterShift,
270294 },
295 /// Two registers and a lsb (range 0-63) and a width (range
296 /// 1-64)
297 ///
298 /// Used by e.g. ubfx
299 rr_lsb_width: struct {
300 rd: Register,
301 rn: Register,
302 lsb: u6,
303 width: u7,
304 },
271305 /// Two registers and a bitmask immediate
272306 ///
273307 /// Used by e.g. eor_immediate
src/arch/aarch64/bits.zig+147-79
......@@ -510,33 +510,23 @@ pub const Instruction = union(enum) {
510510 imm16: u16,
511511 shift: u6,
512512 ) Instruction {
513 switch (rd.size()) {
514 32 => {
515 assert(shift % 16 == 0 and shift <= 16);
516 return Instruction{
517 .move_wide_immediate = .{
518 .rd = rd.enc(),
519 .imm16 = imm16,
520 .hw = @intCast(u2, shift / 16),
521 .opc = opc,
522 .sf = 0,
523 },
524 };
525 },
526 64 => {
527 assert(shift % 16 == 0 and shift <= 48);
528 return Instruction{
529 .move_wide_immediate = .{
530 .rd = rd.enc(),
531 .imm16 = imm16,
532 .hw = @intCast(u2, shift / 16),
533 .opc = opc,
534 .sf = 1,
535 },
536 };
513 assert(shift % 16 == 0);
514 assert(!(rd.size() == 32 and shift > 16));
515 assert(!(rd.size() == 64 and shift > 48));
516
517 return Instruction{
518 .move_wide_immediate = .{
519 .rd = rd.enc(),
520 .imm16 = imm16,
521 .hw = @intCast(u2, shift / 16),
522 .opc = opc,
523 .sf = switch (rd.size()) {
524 32 => 0,
525 64 => 1,
526 else => unreachable, // unexpected register size
527 },
537528 },
538 else => unreachable, // unexpected register size
539 }
529 };
540530 }
541531
542532 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {
......@@ -675,18 +665,24 @@ pub const Instruction = union(enum) {
675665
676666 /// Which kind of load/store to perform
677667 const LoadStoreVariant = enum {
678 /// 32-bit or 64-bit
668 /// 32 bits or 64 bits
679669 str,
680 /// 16-bit, zero-extended
681 strh,
682 /// 8-bit, zero-extended
670 /// 8 bits, zero-extended
683671 strb,
684 /// 32-bit or 64-bit
672 /// 16 bits, zero-extended
673 strh,
674 /// 32 bits or 64 bits
685675 ldr,
686 /// 16-bit, zero-extended
687 ldrh,
688 /// 8-bit, zero-extended
676 /// 8 bits, zero-extended
689677 ldrb,
678 /// 16 bits, zero-extended
679 ldrh,
680 /// 8 bits, sign extended
681 ldrsb,
682 /// 16 bits, sign extended
683 ldrsh,
684 /// 32 bits, sign extended
685 ldrsw,
690686 };
691687
692688 fn loadStoreRegister(
......@@ -695,7 +691,11 @@ pub const Instruction = union(enum) {
695691 offset: LoadStoreOffset,
696692 variant: LoadStoreVariant,
697693 ) Instruction {
694 assert(rn.size() == 64);
695 assert(rn.id() != Register.xzr.id());
696
698697 const off = offset.toU12();
698
699699 const op1: u2 = blk: {
700700 switch (offset) {
701701 .immediate => |imm| switch (imm) {
......@@ -706,10 +706,35 @@ pub const Instruction = union(enum) {
706706 }
707707 break :blk 0b00;
708708 };
709 const opc: u2 = switch (variant) {
710 .ldr, .ldrh, .ldrb => 0b01,
711 .str, .strh, .strb => 0b00,
709
710 const opc: u2 = blk: {
711 switch (variant) {
712 .ldr, .ldrh, .ldrb => break :blk 0b01,
713 .str, .strh, .strb => break :blk 0b00,
714 .ldrsb,
715 .ldrsh,
716 => switch (rt.size()) {
717 32 => break :blk 0b11,
718 64 => break :blk 0b10,
719 else => unreachable, // unexpected register size
720 },
721 .ldrsw => break :blk 0b10,
722 }
723 };
724
725 const size: u2 = blk: {
726 switch (variant) {
727 .ldr, .str => switch (rt.size()) {
728 32 => break :blk 0b10,
729 64 => break :blk 0b11,
730 else => unreachable, // unexpected register size
731 },
732 .ldrsw => break :blk 0b10,
733 .ldrh, .ldrsh, .strh => break :blk 0b01,
734 .ldrb, .ldrsb, .strb => break :blk 0b00,
735 }
712736 };
737
713738 return Instruction{
714739 .load_store_register = .{
715740 .rt = rt.enc(),
......@@ -718,17 +743,7 @@ pub const Instruction = union(enum) {
718743 .opc = opc,
719744 .op1 = op1,
720745 .v = 0,
721 .size = blk: {
722 switch (variant) {
723 .ldr, .str => switch (rt.size()) {
724 32 => break :blk 0b10,
725 64 => break :blk 0b11,
726 else => unreachable, // unexpected register size
727 },
728 .ldrh, .strh => break :blk 0b01,
729 .ldrb, .strb => break :blk 0b00,
730 }
731 },
746 .size = size,
732747 },
733748 };
734749 }
......@@ -741,6 +756,9 @@ pub const Instruction = union(enum) {
741756 encoding: u2,
742757 load: bool,
743758 ) Instruction {
759 assert(rn.size() == 64);
760 assert(rn.id() != Register.xzr.id());
761
744762 switch (rt1.size()) {
745763 32 => {
746764 assert(-256 <= offset and offset <= 252);
......@@ -849,38 +867,26 @@ pub const Instruction = union(enum) {
849867 shift: LogicalShiftedRegisterShift,
850868 amount: u6,
851869 ) Instruction {
852 switch (rd.size()) {
853 32 => {
854 assert(amount < 32);
855 return Instruction{
856 .logical_shifted_register = .{
857 .rd = rd.enc(),
858 .rn = rn.enc(),
859 .imm6 = amount,
860 .rm = rm.enc(),
861 .n = n,
862 .shift = @enumToInt(shift),
863 .opc = opc,
864 .sf = 0b0,
865 },
866 };
867 },
868 64 => {
869 return Instruction{
870 .logical_shifted_register = .{
871 .rd = rd.enc(),
872 .rn = rn.enc(),
873 .imm6 = amount,
874 .rm = rm.enc(),
875 .n = n,
876 .shift = @enumToInt(shift),
877 .opc = opc,
878 .sf = 0b1,
879 },
880 };
870 assert(rd.size() == rn.size());
871 assert(rd.size() == rm.size());
872 if (rd.size() == 32) assert(amount < 32);
873
874 return Instruction{
875 .logical_shifted_register = .{
876 .rd = rd.enc(),
877 .rn = rn.enc(),
878 .imm6 = amount,
879 .rm = rm.enc(),
880 .n = n,
881 .shift = @enumToInt(shift),
882 .opc = opc,
883 .sf = switch (rd.size()) {
884 32 => 0b0,
885 64 => 0b1,
886 else => unreachable,
887 },
881888 },
882 else => unreachable, // unexpected register size
883 }
889 };
884890 }
885891
886892 fn addSubtractImmediate(
......@@ -891,6 +897,9 @@ pub const Instruction = union(enum) {
891897 imm12: u12,
892898 shift: bool,
893899 ) Instruction {
900 assert(rd.size() == rn.size());
901 assert(rn.id() != Register.xzr.id());
902
894903 return Instruction{
895904 .add_subtract_immediate = .{
896905 .rd = rd.enc(),
......@@ -916,6 +925,9 @@ pub const Instruction = union(enum) {
916925 immr: u6,
917926 n: u1,
918927 ) Instruction {
928 assert(rd.size() == rn.size());
929 assert(!(rd.size() == 32 and n != 0));
930
919931 return Instruction{
920932 .logical_immediate = .{
921933 .rd = rd.enc(),
......@@ -941,6 +953,10 @@ pub const Instruction = union(enum) {
941953 immr: u6,
942954 imms: u6,
943955 ) Instruction {
956 assert(rd.size() == rn.size());
957 assert(!(rd.size() == 64 and n != 1));
958 assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0)));
959
944960 return Instruction{
945961 .bitfield = .{
946962 .rd = rd.enc(),
......@@ -969,6 +985,9 @@ pub const Instruction = union(enum) {
969985 rm: Register,
970986 imm6: u6,
971987 ) Instruction {
988 assert(rd.size() == rn.size());
989 assert(rd.size() == rm.size());
990
972991 return Instruction{
973992 .add_subtract_shifted_register = .{
974993 .rd = rd.enc(),
......@@ -994,6 +1013,7 @@ pub const Instruction = union(enum) {
9941013 offset: i21,
9951014 ) Instruction {
9961015 assert(offset & 0b11 == 0b00);
1016
9971017 return Instruction{
9981018 .conditional_branch = .{
9991019 .cond = @enumToInt(cond),
......@@ -1010,6 +1030,7 @@ pub const Instruction = union(enum) {
10101030 offset: i21,
10111031 ) Instruction {
10121032 assert(offset & 0b11 == 0b00);
1033
10131034 return Instruction{
10141035 .compare_and_branch = .{
10151036 .rt = rt.enc(),
......@@ -1033,6 +1054,9 @@ pub const Instruction = union(enum) {
10331054 rm: Register,
10341055 cond: Condition,
10351056 ) Instruction {
1057 assert(rd.size() == rn.size());
1058 assert(rd.size() == rm.size());
1059
10361060 return Instruction{
10371061 .conditional_select = .{
10381062 .rd = rd.enc(),
......@@ -1085,6 +1109,9 @@ pub const Instruction = union(enum) {
10851109 rn: Register,
10861110 rm: Register,
10871111 ) Instruction {
1112 assert(rd.size() == rn.size());
1113 assert(rd.size() == rm.size());
1114
10881115 return Instruction{
10891116 .data_processing_2_source = .{
10901117 .rd = rd.enc(),
......@@ -1145,6 +1172,18 @@ pub const Instruction = union(enum) {
11451172 return loadStoreRegister(rt, rn, offset, .ldrb);
11461173 }
11471174
1175 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1176 return loadStoreRegister(rt, rn, offset, .ldrsb);
1177 }
1178
1179 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1180 return loadStoreRegister(rt, rn, offset, .ldrsh);
1181 }
1182
1183 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1184 return loadStoreRegister(rt, rn, offset, .ldrsw);
1185 }
1186
11481187 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
11491188 return loadStoreRegister(rt, rn, offset, .str);
11501189 }
......@@ -1404,6 +1443,23 @@ pub const Instruction = union(enum) {
14041443 return sbfm(rd, rn, shift, imms);
14051444 }
14061445
1446 pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1447 return sbfm(rd, rn, lsb, @intCast(u6, lsb + width - 1));
1448 }
1449
1450 pub fn sxtb(rd: Register, rn: Register) Instruction {
1451 return sbfm(rd, rn, 0, 7);
1452 }
1453
1454 pub fn sxth(rd: Register, rn: Register) Instruction {
1455 return sbfm(rd, rn, 0, 15);
1456 }
1457
1458 pub fn sxtw(rd: Register, rn: Register) Instruction {
1459 assert(rd.size() == 64);
1460 return sbfm(rd, rn, 0, 31);
1461 }
1462
14071463 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
14081464 const size = @intCast(u6, rd.size() - 1);
14091465 return ubfm(rd, rn, size - shift + 1, size - shift);
......@@ -1414,6 +1470,18 @@ pub const Instruction = union(enum) {
14141470 return ubfm(rd, rn, shift, imms);
14151471 }
14161472
1473 pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1474 return ubfm(rd, rn, lsb, @intCast(u6, lsb + width - 1));
1475 }
1476
1477 pub fn uxtb(rd: Register, rn: Register) Instruction {
1478 return ubfm(rd, rn, 0, 7);
1479 }
1480
1481 pub fn uxth(rd: Register, rn: Register) Instruction {
1482 return ubfm(rd, rn, 0, 15);
1483 }
1484
14171485 // Add/subtract (shifted register)
14181486
14191487 pub fn addShiftedRegister(
test/behavior/basic.zig-4
......@@ -15,8 +15,6 @@ test "empty function with comments" {
1515}
1616
1717test "truncate" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19
2018 try expect(testTruncate(0x10fd) == 0xfd);
2119 comptime try expect(testTruncate(0x10fd) == 0xfd);
2220}
......@@ -25,8 +23,6 @@ fn testTruncate(x: u32) u8 {
2523}
2624
2725test "truncate to non-power-of-two integers" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29
3026 try testTrunc(u32, u1, 0b10101, 0b1);
3127 try testTrunc(u32, u1, 0b10110, 0b0);
3228 try testTrunc(u32, u2, 0b10101, 0b01);
test/behavior/math.zig-14
......@@ -363,7 +363,6 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int
363363test "binary not" {
364364 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
365365 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
367366
368367 try expect(comptime x: {
369368 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
......@@ -499,8 +498,6 @@ fn mod(comptime T: type, a: T, b: T) T {
499498}
500499
501500test "unsigned wrapping" {
502 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
503
504501 try testUnsignedWrappingEval(maxInt(u32));
505502 comptime try testUnsignedWrappingEval(maxInt(u32));
506503}
......@@ -512,8 +509,6 @@ fn testUnsignedWrappingEval(x: u32) !void {
512509}
513510
514511test "signed wrapping" {
515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
516
517512 try testSignedWrappingEval(maxInt(i32));
518513 comptime try testSignedWrappingEval(maxInt(i32));
519514}
......@@ -525,8 +520,6 @@ fn testSignedWrappingEval(x: i32) !void {
525520}
526521
527522test "signed negation wrapping" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529
530523 try testSignedNegationWrappingEval(minInt(i16));
531524 comptime try testSignedNegationWrappingEval(minInt(i16));
532525}
......@@ -537,8 +530,6 @@ fn testSignedNegationWrappingEval(x: i16) !void {
537530}
538531
539532test "unsigned negation wrapping" {
540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
541
542533 try testUnsignedNegationWrappingEval(1);
543534 comptime try testUnsignedNegationWrappingEval(1);
544535}
......@@ -859,8 +850,6 @@ test "quad hex float literal parsing accurate" {
859850}
860851
861852test "truncating shift left" {
862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
863
864853 try testShlTrunc(maxInt(u16));
865854 comptime try testShlTrunc(maxInt(u16));
866855}
......@@ -871,7 +860,6 @@ fn testShlTrunc(x: u16) !void {
871860
872861test "exact shift left" {
873862 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875863
876864 try testShlExact(0b00110101);
877865 comptime try testShlExact(0b00110101);
......@@ -883,7 +871,6 @@ fn testShlExact(x: u8) !void {
883871
884872test "exact shift right" {
885873 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
887874
888875 try testShrExact(0b10110100);
889876 comptime try testShrExact(0b10110100);
......@@ -895,7 +882,6 @@ fn testShrExact(x: u8) !void {
895882
896883test "shift left/right on u0 operand" {
897884 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
899885
900886 const S = struct {
901887 fn doTheTest() !void {
test/behavior/truncate.zig-2
......@@ -49,8 +49,6 @@ test "truncate.i0.var" {
4949}
5050
5151test "truncate on comptime integer" {
52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
53
5452 var x = @truncate(u16, 9999);
5553 try expect(x == 9999);
5654 var y = @truncate(u16, -21555);