authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-11 21:10:18+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 16:14:50+02:00
log151e15e444cc691546bc30646967ef08dbcc073f
tree4ca72326c6f61fa346b123aa773881e1922c4854
parentb41b35f5789f39ef12d07997a74a7dc35224538c
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: merge floating-point registers into Register enum


3 files changed, 336 insertions(+), 210 deletions(-)

src/arch/aarch64/CodeGen.zig+82-67
...@@ -414,7 +414,7 @@ fn gen(self: *Self) !void {...@@ -414,7 +414,7 @@ fn gen(self: *Self) !void {
414 // to the stack.414 // to the stack.
415 const ptr_bits = self.target.cpu.arch.ptrBitWidth();415 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
416 const ptr_bytes = @divExact(ptr_bits, 8);416 const ptr_bytes = @divExact(ptr_bits, 8);
417 const ret_ptr_reg = registerAlias(.x0, ptr_bytes);417 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
418418
419 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;419 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
420 self.next_stack_offset = stack_offset;420 self.next_stack_offset = stack_offset;
...@@ -927,7 +927,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -927,7 +927,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
927 // Make sure the type can fit in a register before we try to allocate one.927 // Make sure the type can fit in a register before we try to allocate one.
928 if (abi_size <= 8) {928 if (abi_size <= 8) {
929 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {929 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
930 return MCValue{ .register = registerAlias(reg, abi_size) };930 return MCValue{ .register = self.registerAlias(reg, elem_ty) };
931 }931 }
932 }932 }
933 }933 }
...@@ -982,7 +982,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -982,7 +982,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
982/// This can have a side effect of spilling instructions to the stack to free up a register.982/// This can have a side effect of spilling instructions to the stack to free up a register.
983fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {983fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
984 const raw_reg = try self.register_manager.allocReg(null, gp);984 const raw_reg = try self.register_manager.allocReg(null, gp);
985 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));985 const reg = self.registerAlias(raw_reg, ty);
986 try self.genSetReg(ty, reg, mcv);986 try self.genSetReg(ty, reg, mcv);
987 return reg;987 return reg;
988}988}
...@@ -993,7 +993,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -993,7 +993,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
993fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {993fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
994 const raw_reg = try self.register_manager.allocReg(reg_owner, gp);994 const raw_reg = try self.register_manager.allocReg(reg_owner, gp);
995 const ty = self.air.typeOfIndex(reg_owner);995 const ty = self.air.typeOfIndex(reg_owner);
996 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));996 const reg = self.registerAlias(raw_reg, ty);
997 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);997 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
998 return MCValue{ .register = reg };998 return MCValue{ .register = reg };
999}999}
...@@ -1031,7 +1031,6 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1031,7 +1031,6 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1031 const operand_info = operand_ty.intInfo(self.target.*);1031 const operand_info = operand_ty.intInfo(self.target.*);
10321032
1033 const dest_ty = self.air.typeOfIndex(inst);1033 const dest_ty = self.air.typeOfIndex(inst);
1034 const dest_abi_size = dest_ty.abiSize(self.target.*);
1035 const dest_info = dest_ty.intInfo(self.target.*);1034 const dest_info = dest_ty.intInfo(self.target.*);
10361035
1037 const result: MCValue = result: {1036 const result: MCValue = result: {
...@@ -1042,7 +1041,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1042,7 +1041,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1042 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);1041 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10431042
1044 const truncated: MCValue = switch (operand_mcv) {1043 const truncated: MCValue = switch (operand_mcv) {
1045 .register => |r| MCValue{ .register = registerAlias(r, dest_abi_size) },1044 .register => |r| MCValue{ .register = self.registerAlias(r, dest_ty) },
1046 else => operand_mcv,1045 else => operand_mcv,
1047 };1046 };
10481047
...@@ -1117,7 +1116,7 @@ fn trunc(...@@ -1117,7 +1116,7 @@ fn trunc(
1117 else => operand_reg: {1116 else => operand_reg: {
1118 if (info_a.bits <= 64) {1117 if (info_a.bits <= 64) {
1119 const raw_reg = try self.copyToTmpRegister(operand_ty, operand);1118 const raw_reg = try self.copyToTmpRegister(operand_ty, operand);
1120 break :operand_reg registerAlias(raw_reg, operand_ty.abiSize(self.target.*));1119 break :operand_reg self.registerAlias(raw_reg, operand_ty);
1121 } else {1120 } else {
1122 return self.fail("TODO load least significant word into register", .{});1121 return self.fail("TODO load least significant word into register", .{});
1123 }1122 }
...@@ -1130,14 +1129,14 @@ fn trunc(...@@ -1130,14 +1129,14 @@ fn trunc(
1130 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1129 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11311130
1132 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1131 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1133 break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));1132 break :blk self.registerAlias(operand_reg, dest_ty);
1134 } else {1133 } else {
1135 const raw_reg = try self.register_manager.allocReg(inst, gp);1134 const raw_reg = try self.register_manager.allocReg(inst, gp);
1136 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));1135 break :blk self.registerAlias(raw_reg, dest_ty);
1137 }1136 }
1138 } else blk: {1137 } else blk: {
1139 const raw_reg = try self.register_manager.allocReg(null, gp);1138 const raw_reg = try self.register_manager.allocReg(null, gp);
1140 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));1139 break :blk self.registerAlias(raw_reg, dest_ty);
1141 };1140 };
11421141
1143 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);1142 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
...@@ -1194,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1194,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1194 }1193 }
11951194
1196 const raw_reg = try self.register_manager.allocReg(null, gp);1195 const raw_reg = try self.register_manager.allocReg(null, gp);
1197 break :blk raw_reg.to32();1196 break :blk self.registerAlias(raw_reg, operand_ty);
1198 };1197 };
11991198
1200 _ = try self.addInst(.{1199 _ = try self.addInst(.{
...@@ -1227,7 +1226,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1227,7 +1226,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1227 }1226 }
12281227
1229 const raw_reg = try self.register_manager.allocReg(null, gp);1228 const raw_reg = try self.register_manager.allocReg(null, gp);
1230 break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));1229 break :blk self.registerAlias(raw_reg, operand_ty);
1231 };1230 };
12321231
1233 _ = try self.addInst(.{1232 _ = try self.addInst(.{
...@@ -1307,8 +1306,8 @@ fn binOpRegister(...@@ -1307,8 +1306,8 @@ fn binOpRegister(
1307 const lhs_is_register = lhs == .register;1306 const lhs_is_register = lhs == .register;
1308 const rhs_is_register = rhs == .register;1307 const rhs_is_register = rhs == .register;
13091308
1310 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));1309 if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty));
1311 if (rhs_is_register) assert(rhs.register == registerAlias(rhs.register, rhs_ty.abiSize(self.target.*)));1310 if (rhs_is_register) assert(rhs.register == self.registerAlias(rhs.register, rhs_ty));
13121311
1313 const lhs_lock: ?RegisterLock = if (lhs_is_register)1312 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1314 self.register_manager.lockReg(lhs.register)1313 self.register_manager.lockReg(lhs.register)
...@@ -1330,7 +1329,7 @@ fn binOpRegister(...@@ -1330,7 +1329,7 @@ fn binOpRegister(
1330 } else null;1329 } else null;
13311330
1332 const raw_reg = try self.register_manager.allocReg(track_inst, gp);1331 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1333 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1332 const reg = self.registerAlias(raw_reg, lhs_ty);
13341333
1335 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1334 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13361335
...@@ -1344,7 +1343,7 @@ fn binOpRegister(...@@ -1344,7 +1343,7 @@ fn binOpRegister(
1344 // order to guarantee that registers will have equal sizes, we1343 // order to guarantee that registers will have equal sizes, we
1345 // use the register alias of rhs corresponding to the size of1344 // use the register alias of rhs corresponding to the size of
1346 // lhs.1345 // lhs.
1347 registerAlias(rhs.register, lhs_ty.abiSize(self.target.*))1346 self.registerAlias(rhs.register, lhs_ty)
1348 else blk: {1347 else blk: {
1349 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {1348 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1350 break :inst Air.refToIndex(md.rhs).?;1349 break :inst Air.refToIndex(md.rhs).?;
...@@ -1354,7 +1353,7 @@ fn binOpRegister(...@@ -1354,7 +1353,7 @@ fn binOpRegister(
13541353
1355 // Here, we deliberately use lhs as lhs and rhs may differ in1354 // Here, we deliberately use lhs as lhs and rhs may differ in
1356 // the case of shifts. See comment above.1355 // the case of shifts. See comment above.
1357 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1356 const reg = self.registerAlias(raw_reg, lhs_ty);
13581357
1359 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1358 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13601359
...@@ -1372,11 +1371,11 @@ fn binOpRegister(...@@ -1372,11 +1371,11 @@ fn binOpRegister(
1372 break :blk rhs_reg;1371 break :blk rhs_reg;
1373 } else {1372 } else {
1374 const raw_reg = try self.register_manager.allocReg(md.inst, gp);1373 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
1375 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1374 break :blk self.registerAlias(raw_reg, lhs_ty);
1376 }1375 }
1377 } else blk: {1376 } else blk: {
1378 const raw_reg = try self.register_manager.allocReg(null, gp);1377 const raw_reg = try self.register_manager.allocReg(null, gp);
1379 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1378 break :blk self.registerAlias(raw_reg, lhs_ty);
1380 },1379 },
1381 };1380 };
13821381
...@@ -1415,7 +1414,7 @@ fn binOpRegister(...@@ -1415,7 +1414,7 @@ fn binOpRegister(
1415 .smull,1414 .smull,
1416 .umull,1415 .umull,
1417 => .{ .rrr = .{1416 => .{ .rrr = .{
1418 .rd = dest_reg.to64(),1417 .rd = dest_reg.toX(),
1419 .rn = lhs_reg,1418 .rn = lhs_reg,
1420 .rm = rhs_reg,1419 .rm = rhs_reg,
1421 } },1420 } },
...@@ -1463,7 +1462,7 @@ fn binOpImmediate(...@@ -1463,7 +1462,7 @@ fn binOpImmediate(
1463) !MCValue {1462) !MCValue {
1464 const lhs_is_register = lhs == .register;1463 const lhs_is_register = lhs == .register;
14651464
1466 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));1465 if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty));
14671466
1468 const lhs_lock: ?RegisterLock = if (lhs_is_register)1467 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1469 self.register_manager.lockReg(lhs.register)1468 self.register_manager.lockReg(lhs.register)
...@@ -1481,7 +1480,7 @@ fn binOpImmediate(...@@ -1481,7 +1480,7 @@ fn binOpImmediate(
1481 } else null;1480 } else null;
14821481
1483 const raw_reg = try self.register_manager.allocReg(track_inst, gp);1482 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1484 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1483 const reg = self.registerAlias(raw_reg, lhs_ty);
14851484
1486 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1485 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
14871486
...@@ -1502,11 +1501,11 @@ fn binOpImmediate(...@@ -1502,11 +1501,11 @@ fn binOpImmediate(
1502 break :blk lhs_reg;1501 break :blk lhs_reg;
1503 } else {1502 } else {
1504 const raw_reg = try self.register_manager.allocReg(md.inst, gp);1503 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
1505 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1504 break :blk self.registerAlias(raw_reg, lhs_ty);
1506 }1505 }
1507 } else blk: {1506 } else blk: {
1508 const raw_reg = try self.register_manager.allocReg(null, gp);1507 const raw_reg = try self.register_manager.allocReg(null, gp);
1509 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1508 break :blk self.registerAlias(raw_reg, lhs_ty);
1510 },1509 },
1511 };1510 };
15121511
...@@ -1719,7 +1718,7 @@ fn binOp(...@@ -1719,7 +1718,7 @@ fn binOp(
1719 } else null;1718 } else null;
17201719
1721 const raw_reg = try self.register_manager.allocReg(track_inst, gp);1720 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1722 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1721 const reg = self.registerAlias(raw_reg, lhs_ty);
17231722
1724 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1723 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
17251724
...@@ -1734,7 +1733,7 @@ fn binOp(...@@ -1734,7 +1733,7 @@ fn binOp(
1734 } else null;1733 } else null;
17351734
1736 const raw_reg = try self.register_manager.allocReg(track_inst, gp);1735 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1737 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));1736 const reg = self.registerAlias(raw_reg, rhs_ty);
17381737
1739 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1738 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
17401739
...@@ -1745,10 +1744,9 @@ fn binOp(...@@ -1745,10 +1744,9 @@ fn binOp(
17451744
1746 const dest_regs: [2]Register = blk: {1745 const dest_regs: [2]Register = blk: {
1747 const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);1746 const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1748 const abi_size = lhs_ty.abiSize(self.target.*);
1749 break :blk .{1747 break :blk .{
1750 registerAlias(raw_regs[0], abi_size),1748 self.registerAlias(raw_regs[0], lhs_ty),
1751 registerAlias(raw_regs[1], abi_size),1749 self.registerAlias(raw_regs[1], lhs_ty),
1752 };1750 };
1753 };1751 };
1754 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);1752 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
...@@ -2067,7 +2065,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2067,7 +2065,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
2067 defer self.register_manager.unlockReg(dest_reg_lock);2065 defer self.register_manager.unlockReg(dest_reg_lock);
20682066
2069 const raw_truncated_reg = try self.register_manager.allocReg(null, gp);2067 const raw_truncated_reg = try self.register_manager.allocReg(null, gp);
2070 const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*));2068 const truncated_reg = self.registerAlias(raw_truncated_reg, lhs_ty);
2071 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);2069 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
2072 defer self.register_manager.unlockReg(truncated_reg_lock);2070 defer self.register_manager.unlockReg(truncated_reg_lock);
20732071
...@@ -2186,8 +2184,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2186,8 +2184,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2186 defer self.register_manager.unlockReg(truncated_reg_lock);2184 defer self.register_manager.unlockReg(truncated_reg_lock);
21872185
2188 try self.truncRegister(2186 try self.truncRegister(
2189 dest_reg.to32(),2187 dest_reg.toW(),
2190 truncated_reg.to32(),2188 truncated_reg.toW(),
2191 int_info.signedness,2189 int_info.signedness,
2192 int_info.bits,2190 int_info.bits,
2193 );2191 );
...@@ -2197,8 +2195,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2197,8 +2195,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2197 _ = try self.addInst(.{2195 _ = try self.addInst(.{
2198 .tag = .cmp_extended_register,2196 .tag = .cmp_extended_register,
2199 .data = .{ .rr_extend_shift = .{2197 .data = .{ .rr_extend_shift = .{
2200 .rn = dest_reg.to64(),2198 .rn = dest_reg.toX(),
2201 .rm = truncated_reg.to32(),2199 .rm = truncated_reg.toW(),
2202 .ext_type = .sxtw,2200 .ext_type = .sxtw,
2203 .imm3 = 0,2201 .imm3 = 0,
2204 } },2202 } },
...@@ -2208,8 +2206,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2208,8 +2206,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2208 _ = try self.addInst(.{2206 _ = try self.addInst(.{
2209 .tag = .cmp_extended_register,2207 .tag = .cmp_extended_register,
2210 .data = .{ .rr_extend_shift = .{2208 .data = .{ .rr_extend_shift = .{
2211 .rn = dest_reg.to64(),2209 .rn = dest_reg.toX(),
2212 .rm = truncated_reg.to32(),2210 .rm = truncated_reg.toW(),
2213 .ext_type = .uxtw,2211 .ext_type = .uxtw,
2214 .imm3 = 0,2212 .imm3 = 0,
2215 } },2213 } },
...@@ -2245,7 +2243,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2245,7 +2243,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22452243
2246 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2244 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2247 const raw_reg = try self.register_manager.allocReg(null, gp);2245 const raw_reg = try self.register_manager.allocReg(null, gp);
2248 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));2246 const reg = self.registerAlias(raw_reg, lhs_ty);
2249 break :blk reg;2247 break :blk reg;
2250 };2248 };
2251 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);2249 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
...@@ -2253,7 +2251,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2253,7 +2251,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22532251
2254 const rhs_reg = if (rhs_is_register) rhs.register else blk: {2252 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2255 const raw_reg = try self.register_manager.allocReg(null, gp);2253 const raw_reg = try self.register_manager.allocReg(null, gp);
2256 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));2254 const reg = self.registerAlias(raw_reg, rhs_ty);
2257 break :blk reg;2255 break :blk reg;
2258 };2256 };
2259 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);2257 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
...@@ -2264,7 +2262,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2264,7 +2262,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22642262
2265 const dest_reg = blk: {2263 const dest_reg = blk: {
2266 const raw_reg = try self.register_manager.allocReg(null, gp);2264 const raw_reg = try self.register_manager.allocReg(null, gp);
2267 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));2265 const reg = self.registerAlias(raw_reg, lhs_ty);
2268 break :blk reg;2266 break :blk reg;
2269 };2267 };
2270 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);2268 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
...@@ -2853,7 +2851,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {...@@ -2853,7 +2851,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
2853 return self.finishAir(inst, result, .{ un_op, .none, .none });2851 return self.finishAir(inst, result, .{ un_op, .none, .none });
2854}2852}
28552853
2856fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {2854fn reuseOperand(
2855 self: *Self,
2856 inst: Air.Inst.Index,
2857 operand: Air.Inst.Ref,
2858 op_index: Liveness.OperandInt,
2859 mcv: MCValue,
2860) bool {
2857 if (!self.liveness.operandDies(inst, op_index))2861 if (!self.liveness.operandDies(inst, op_index))
2858 return false;2862 return false;
28592863
...@@ -2912,7 +2916,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2912,7 +2916,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2912 .stack_offset => |off| {2916 .stack_offset => |off| {
2913 if (elem_size <= 8) {2917 if (elem_size <= 8) {
2914 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);2918 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
2915 const tmp_reg = registerAlias(raw_tmp_reg, elem_size);2919 const tmp_reg = self.registerAlias(raw_tmp_reg, elem_ty);
2916 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2920 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2917 defer self.register_manager.unlockReg(tmp_reg_lock);2921 defer self.register_manager.unlockReg(tmp_reg_lock);
29182922
...@@ -3050,7 +3054,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3050,7 +3054,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
3050 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {3054 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
3051 // The MCValue that holds the pointer can be re-used as the value.3055 // The MCValue that holds the pointer can be re-used as the value.
3052 break :blk switch (ptr) {3056 break :blk switch (ptr) {
3053 .register => |r| MCValue{ .register = registerAlias(r, elem_size) },3057 .register => |reg| MCValue{ .register = self.registerAlias(reg, elem_ty) },
3054 else => ptr,3058 else => ptr,
3055 };3059 };
3056 } else {3060 } else {
...@@ -3136,7 +3140,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3136,7 +3140,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3136 else => {3140 else => {
3137 if (abi_size <= 8) {3141 if (abi_size <= 8) {
3138 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);3142 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
3139 const tmp_reg = registerAlias(raw_tmp_reg, abi_size);3143 const tmp_reg = self.registerAlias(raw_tmp_reg, value_ty);
3140 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);3144 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
3141 defer self.register_manager.unlockReg(tmp_reg_lock);3145 defer self.register_manager.unlockReg(tmp_reg_lock);
31423146
...@@ -3295,7 +3299,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3295,7 +3299,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3295 } else {3299 } else {
3296 // Copy to new register3300 // Copy to new register
3297 const raw_dest_reg = try self.register_manager.allocReg(null, gp);3301 const raw_dest_reg = try self.register_manager.allocReg(null, gp);
3298 const dest_reg = registerAlias(raw_dest_reg, struct_field_ty.abiSize(self.target.*));3302 const dest_reg = self.registerAlias(raw_dest_reg, struct_field_ty);
3299 try self.genSetReg(struct_field_ty, dest_reg, field);3303 try self.genSetReg(struct_field_ty, dest_reg, field);
33003304
3301 break :result MCValue{ .register = dest_reg };3305 break :result MCValue{ .register = dest_reg };
...@@ -3410,9 +3414,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3410,9 +3414,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3410 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));3414 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3411 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);3415 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
34123416
3413 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3417 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
3414 const ptr_bytes = @divExact(ptr_bits, 8);
3415 const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
34163418
3417 var ptr_ty_payload: Type.Payload.ElemType = .{3419 var ptr_ty_payload: Type.Payload.ElemType = .{
3418 .base = .{ .tag = .single_mut_pointer },3420 .base = .{ .tag = .single_mut_pointer },
...@@ -4376,7 +4378,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4376,7 +4378,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4376 4, 8 => .str_stack,4378 4, 8 => .str_stack,
4377 else => unreachable, // unexpected abi size4379 else => unreachable, // unexpected abi size
4378 };4380 };
4379 const rt = registerAlias(reg, abi_size);4381 const rt = self.registerAlias(reg, ty);
43804382
4381 _ = try self.addInst(.{4383 _ = try self.addInst(.{
4382 .tag = tag,4384 .tag = tag,
...@@ -4399,10 +4401,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4399,10 +4401,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4399 const overflow_bit_ty = ty.structFieldType(1);4401 const overflow_bit_ty = ty.structFieldType(1);
4400 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));4402 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
4401 const raw_cond_reg = try self.register_manager.allocReg(null, gp);4403 const raw_cond_reg = try self.register_manager.allocReg(null, gp);
4402 const cond_reg = registerAlias(4404 const cond_reg = self.registerAlias(raw_cond_reg, overflow_bit_ty);
4403 raw_cond_reg,
4404 @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),
4405 );
44064405
4407 _ = try self.addInst(.{4406 _ = try self.addInst(.{
4408 .tag = .cset,4407 .tag = .cset,
...@@ -4599,8 +4598,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4599,8 +4598,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4599 .memory => |addr| {4598 .memory => |addr| {
4600 // The value is in memory at a hard-coded address.4599 // The value is in memory at a hard-coded address.
4601 // If the type is a pointer, it means the pointer address is at this memory location.4600 // If the type is a pointer, it means the pointer address is at this memory location.
4602 try self.genSetReg(ty, reg.to64(), .{ .immediate = addr });4601 try self.genSetReg(ty, reg.toX(), .{ .immediate = addr });
4603 try self.genLdrRegister(reg, reg.to64(), ty);4602 try self.genLdrRegister(reg, reg.toX(), ty);
4604 },4603 },
4605 .stack_offset => |off| {4604 .stack_offset => |off| {
4606 const abi_size = ty.abiSize(self.target.*);4605 const abi_size = ty.abiSize(self.target.*);
...@@ -4679,7 +4678,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4679,7 +4678,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4679 4, 8 => .str_immediate,4678 4, 8 => .str_immediate,
4680 else => unreachable, // unexpected abi size4679 else => unreachable, // unexpected abi size
4681 };4680 };
4682 const rt = registerAlias(reg, abi_size);4681 const rt = self.registerAlias(reg, ty);
4683 const offset = switch (abi_size) {4682 const offset = switch (abi_size) {
4684 1 => blk: {4683 1 => blk: {
4685 if (math.cast(u12, stack_offset)) |imm| {4684 if (math.cast(u12, stack_offset)) |imm| {
...@@ -5300,7 +5299,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5300,7 +5299,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5300 assert(ret_ty.isError());5299 assert(ret_ty.isError());
5301 result.return_value = .{ .immediate = 0 };5300 result.return_value = .{ .immediate = 0 };
5302 } else if (ret_ty_size <= 8) {5301 } else if (ret_ty_size <= 8) {
5303 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };5302 result.return_value = .{ .register = self.registerAlias(c_abi_int_return_regs[0], ret_ty) };
5304 } else {5303 } else {
5305 return self.fail("TODO support more return types for ARM backend", .{});5304 return self.fail("TODO support more return types for ARM backend", .{});
5306 }5305 }
...@@ -5322,7 +5321,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5322,7 +5321,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
53225321
5323 if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) {5322 if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) {
5324 if (param_size <= 8) {5323 if (param_size <= 8) {
5325 result.args[i] = .{ .register = registerAlias(c_abi_int_param_regs[ncrn], param_size) };5324 result.args[i] = .{ .register = self.registerAlias(c_abi_int_param_regs[ncrn], ty) };
5326 ncrn += 1;5325 ncrn += 1;
5327 } else {5326 } else {
5328 return self.fail("TODO MCValues with multiple registers", .{});5327 return self.fail("TODO MCValues with multiple registers", .{});
...@@ -5358,7 +5357,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5358,7 +5357,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5358 assert(ret_ty.isError());5357 assert(ret_ty.isError());
5359 result.return_value = .{ .immediate = 0 };5358 result.return_value = .{ .immediate = 0 };
5360 } else if (ret_ty_size <= 8) {5359 } else if (ret_ty_size <= 8) {
5361 result.return_value = .{ .register = registerAlias(.x0, ret_ty_size) };5360 result.return_value = .{ .register = self.registerAlias(.x0, ret_ty) };
5362 } else {5361 } else {
5363 // The result is returned by reference, not by5362 // The result is returned by reference, not by
5364 // value. This means that x0 (or w0 when pointer5363 // value. This means that x0 (or w0 when pointer
...@@ -5424,14 +5423,30 @@ fn parseRegName(name: []const u8) ?Register {...@@ -5424,14 +5423,30 @@ fn parseRegName(name: []const u8) ?Register {
5424 return std.meta.stringToEnum(Register, name);5423 return std.meta.stringToEnum(Register, name);
5425}5424}
54265425
5427fn registerAlias(reg: Register, size_bytes: u64) Register {5426fn registerAlias(self: *Self, reg: Register, ty: Type) Register {
5428 if (size_bytes == 0) {5427 const abi_size = ty.abiSize(self.target.*);
5429 unreachable; // should be comptime-known5428
5430 } else if (size_bytes <= 4) {5429 switch (reg.class()) {
5431 return reg.to32();5430 .general_purpose => {
5432 } else if (size_bytes <= 8) {5431 if (abi_size == 0) {
5433 return reg.to64();5432 unreachable; // should be comptime-known
5434 } else {5433 } else if (abi_size <= 4) {
5435 unreachable; // TODO handle floating-point registers5434 return reg.toW();
5435 } else if (abi_size <= 8) {
5436 return reg.toX();
5437 } else unreachable;
5438 },
5439 .stack_pointer => unreachable, // we can't store/load the sp
5440 .floating_point => {
5441 return switch (ty.floatBits(self.target.*)) {
5442 16 => reg.toH(),
5443 32 => reg.toS(),
5444 64 => reg.toD(),
5445 128 => reg.toQ(),
5446
5447 80 => unreachable, // f80 registers don't exist
5448 else => unreachable,
5449 };
5450 },
5436 }5451 }
5437}5452}
src/arch/aarch64/Emit.zig+4-4
...@@ -842,14 +842,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -842,14 +842,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
842 // PC-relative displacement to the entry in memory.842 // PC-relative displacement to the entry in memory.
843 // adrp843 // adrp
844 const offset = @intCast(u32, emit.code.items.len);844 const offset = @intCast(u32, emit.code.items.len);
845 try emit.writeInstruction(Instruction.adrp(reg.to64(), 0));845 try emit.writeInstruction(Instruction.adrp(reg.toX(), 0));
846846
847 switch (tag) {847 switch (tag) {
848 .load_memory_got => {848 .load_memory_got => {
849 // ldr reg, reg, offset849 // ldr reg, reg, offset
850 try emit.writeInstruction(Instruction.ldr(850 try emit.writeInstruction(Instruction.ldr(
851 reg,851 reg,
852 reg.to64(),852 reg.toX(),
853 Instruction.LoadStoreOffset.imm(0),853 Instruction.LoadStoreOffset.imm(0),
854 ));854 ));
855 },855 },
...@@ -863,11 +863,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -863,11 +863,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
863 // Note that this can potentially be optimised out by the codegen/linker if the863 // Note that this can potentially be optimised out by the codegen/linker if the
864 // target address is appropriately aligned.864 // target address is appropriately aligned.
865 // add reg, reg, offset865 // add reg, reg, offset
866 try emit.writeInstruction(Instruction.add(reg.to64(), reg.to64(), 0, false));866 try emit.writeInstruction(Instruction.add(reg.toX(), reg.toX(), 0, false));
867 // ldr reg, reg, offset867 // ldr reg, reg, offset
868 try emit.writeInstruction(Instruction.ldr(868 try emit.writeInstruction(Instruction.ldr(
869 reg,869 reg,
870 reg.to64(),870 reg.toX(),
871 Instruction.LoadStoreOffset.imm(0),871 Instruction.LoadStoreOffset.imm(0),
872 ));872 ));
873 },873 },
src/arch/aarch64/bits.zig+250-139
...@@ -4,17 +4,22 @@ const DW = std.dwarf;...@@ -4,17 +4,22 @@ const DW = std.dwarf;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const testing = std.testing;5const testing = std.testing;
66
7// zig fmt: off7pub const RegisterClass = enum {
8 general_purpose,
9 stack_pointer,
10 floating_point,
11};
812
9/// General purpose registers in the AArch64 instruction set13/// General purpose registers in the AArch64 instruction set
10pub const Register = enum(u7) {14pub const Register = enum(u8) {
11 // 64-bit registers15 // zig fmt: off
16 // 64-bit general-purpose registers
12 x0, x1, x2, x3, x4, x5, x6, x7,17 x0, x1, x2, x3, x4, x5, x6, x7,
13 x8, x9, x10, x11, x12, x13, x14, x15,18 x8, x9, x10, x11, x12, x13, x14, x15,
14 x16, x17, x18, x19, x20, x21, x22, x23,19 x16, x17, x18, x19, x20, x21, x22, x23,
15 x24, x25, x26, x27, x28, x29, x30, xzr,20 x24, x25, x26, x27, x28, x29, x30, xzr,
1621
17 // 32-bit registers22 // 32-bit general-purpose registers
18 w0, w1, w2, w3, w4, w5, w6, w7,23 w0, w1, w2, w3, w4, w5, w6, w7,
19 w8, w9, w10, w11, w12, w13, w14, w15,24 w8, w9, w10, w11, w12, w13, w14, w15,
20 w16, w17, w18, w19, w20, w21, w22, w23,25 w16, w17, w18, w19, w20, w21, w22, w23,
...@@ -23,192 +28,298 @@ pub const Register = enum(u7) {...@@ -23,192 +28,298 @@ pub const Register = enum(u7) {
23 // Stack pointer28 // Stack pointer
24 sp, wsp,29 sp, wsp,
2530
26 pub fn id(self: Register) u6 {31 // 128-bit floating-point registers
27 return switch (@enumToInt(self)) {
28 0...63 => return @as(u6, @truncate(u5, @enumToInt(self))),
29 64...65 => 32,
30 else => unreachable,
31 };
32 }
33
34 pub fn enc(self: Register) u5 {
35 return switch (@enumToInt(self)) {
36 0...63 => return @truncate(u5, @enumToInt(self)),
37 64...65 => 31,
38 else => unreachable,
39 };
40 }
41
42 /// Returns the bit-width of the register.
43 pub fn size(self: Register) u7 {
44 return switch (@enumToInt(self)) {
45 0...31 => 64,
46 32...63 => 32,
47 64 => 64,
48 65 => 32,
49 else => unreachable,
50 };
51 }
52
53 /// Convert from any register to its 64 bit alias.
54 pub fn to64(self: Register) Register {
55 return switch (@enumToInt(self)) {
56 0...31 => self,
57 32...63 => @intToEnum(Register, @enumToInt(self) - 32),
58 64 => .sp,
59 65 => .sp,
60 else => unreachable,
61 };
62 }
63
64 /// Convert from any register to its 32 bit alias.
65 pub fn to32(self: Register) Register {
66 return switch (@enumToInt(self)) {
67 0...31 => @intToEnum(Register, @enumToInt(self) + 32),
68 32...63 => self,
69 64 => .wsp,
70 65 => .wsp,
71 else => unreachable,
72 };
73 }
74
75 pub fn dwarfLocOp(self: Register) u8 {
76 return @as(u8, self.enc()) + DW.OP.reg0;
77 }
78};
79
80// zig fmt: on
81
82test "Register.enc" {
83 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
84 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
85
86 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
87 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
88
89 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
90 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
91}
92
93test "Register.size" {
94 try testing.expectEqual(@as(u7, 64), Register.x19.size());
95 try testing.expectEqual(@as(u7, 32), Register.w3.size());
96}
97
98test "Register.to64/to32" {
99 try testing.expectEqual(Register.x0, Register.w0.to64());
100 try testing.expectEqual(Register.x0, Register.x0.to64());
101
102 try testing.expectEqual(Register.w3, Register.w3.to32());
103 try testing.expectEqual(Register.w3, Register.x3.to32());
104}
105
106// zig fmt: off
107
108/// Scalar floating point registers in the aarch64 instruction set
109pub const FloatingPointRegister = enum(u8) {
110 // 128-bit registers
111 q0, q1, q2, q3, q4, q5, q6, q7,32 q0, q1, q2, q3, q4, q5, q6, q7,
112 q8, q9, q10, q11, q12, q13, q14, q15,33 q8, q9, q10, q11, q12, q13, q14, q15,
113 q16, q17, q18, q19, q20, q21, q22, q23,34 q16, q17, q18, q19, q20, q21, q22, q23,
114 q24, q25, q26, q27, q28, q29, q30, q31,35 q24, q25, q26, q27, q28, q29, q30, q31,
11536
116 // 64-bit registers37 // 64-bit floating-point registers
117 d0, d1, d2, d3, d4, d5, d6, d7,38 d0, d1, d2, d3, d4, d5, d6, d7,
118 d8, d9, d10, d11, d12, d13, d14, d15,39 d8, d9, d10, d11, d12, d13, d14, d15,
119 d16, d17, d18, d19, d20, d21, d22, d23,40 d16, d17, d18, d19, d20, d21, d22, d23,
120 d24, d25, d26, d27, d28, d29, d30, d31,41 d24, d25, d26, d27, d28, d29, d30, d31,
12142
122 // 32-bit registers43 // 32-bit floating-point registers
123 s0, s1, s2, s3, s4, s5, s6, s7,44 s0, s1, s2, s3, s4, s5, s6, s7,
124 s8, s9, s10, s11, s12, s13, s14, s15,45 s8, s9, s10, s11, s12, s13, s14, s15,
125 s16, s17, s18, s19, s20, s21, s22, s23,46 s16, s17, s18, s19, s20, s21, s22, s23,
126 s24, s25, s26, s27, s28, s29, s30, s31,47 s24, s25, s26, s27, s28, s29, s30, s31,
12748
128 // 16-bit registers49 // 16-bit floating-point registers
129 h0, h1, h2, h3, h4, h5, h6, h7,50 h0, h1, h2, h3, h4, h5, h6, h7,
130 h8, h9, h10, h11, h12, h13, h14, h15,51 h8, h9, h10, h11, h12, h13, h14, h15,
131 h16, h17, h18, h19, h20, h21, h22, h23,52 h16, h17, h18, h19, h20, h21, h22, h23,
132 h24, h25, h26, h27, h28, h29, h30, h31,53 h24, h25, h26, h27, h28, h29, h30, h31,
13354
134 // 8-bit registers55 // 8-bit floating-point registers
135 b0, b1, b2, b3, b4, b5, b6, b7,56 b0, b1, b2, b3, b4, b5, b6, b7,
136 b8, b9, b10, b11, b12, b13, b14, b15,57 b8, b9, b10, b11, b12, b13, b14, b15,
137 b16, b17, b18, b19, b20, b21, b22, b23,58 b16, b17, b18, b19, b20, b21, b22, b23,
138 b24, b25, b26, b27, b28, b29, b30, b31,59 b24, b25, b26, b27, b28, b29, b30, b31,
60 // zig fmt: on
13961
140 pub fn id(self: FloatingPointRegister) u5 {62 pub fn class(self: Register) RegisterClass {
141 return @truncate(u5, @enumToInt(self));63 return switch (@enumToInt(self)) {
64 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => .general_purpose,
65 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => .general_purpose,
66
67 @enumToInt(Register.sp) => .stack_pointer,
68 @enumToInt(Register.wsp) => .stack_pointer,
69
70 @enumToInt(Register.q0)...@enumToInt(Register.q31) => .floating_point,
71 @enumToInt(Register.d0)...@enumToInt(Register.d31) => .floating_point,
72 @enumToInt(Register.s0)...@enumToInt(Register.s31) => .floating_point,
73 @enumToInt(Register.h0)...@enumToInt(Register.h31) => .floating_point,
74 @enumToInt(Register.b0)...@enumToInt(Register.b31) => .floating_point,
75 else => unreachable,
76 };
77 }
78
79 pub fn id(self: Register) u6 {
80 return switch (@enumToInt(self)) {
81 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.x0)),
82 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.w0)),
83
84 @enumToInt(Register.sp) => 32,
85 @enumToInt(Register.wsp) => 32,
86
87 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.q0) + 33),
88 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.d0) + 33),
89 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.s0) + 33),
90 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.h0) + 33),
91 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intCast(u6, @enumToInt(self) - @enumToInt(Register.b0) + 33),
92 else => unreachable,
93 };
94 }
95
96 pub fn enc(self: Register) u5 {
97 return switch (@enumToInt(self)) {
98 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.x0)),
99 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.w0)),
100
101 @enumToInt(Register.sp) => 31,
102 @enumToInt(Register.wsp) => 31,
103
104 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.q0)),
105 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.d0)),
106 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.s0)),
107 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.h0)),
108 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intCast(u5, @enumToInt(self) - @enumToInt(Register.b0)),
109 else => unreachable,
110 };
142 }111 }
143112
144 /// Returns the bit-width of the register.113 /// Returns the bit-width of the register.
145 pub fn size(self: FloatingPointRegister) u8 {114 pub fn size(self: Register) u8 {
115 return switch (@enumToInt(self)) {
116 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => 64,
117 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => 32,
118
119 @enumToInt(Register.sp) => 64,
120 @enumToInt(Register.wsp) => 32,
121
122 @enumToInt(Register.q0)...@enumToInt(Register.q31) => 128,
123 @enumToInt(Register.d0)...@enumToInt(Register.d31) => 64,
124 @enumToInt(Register.s0)...@enumToInt(Register.s31) => 32,
125 @enumToInt(Register.h0)...@enumToInt(Register.h31) => 16,
126 @enumToInt(Register.b0)...@enumToInt(Register.b31) => 8,
127 else => unreachable,
128 };
129 }
130
131 /// Convert from a general-purpose register to its 64 bit alias.
132 pub fn toX(self: Register) Register {
133 return switch (@enumToInt(self)) {
134 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intToEnum(
135 Register,
136 @enumToInt(self) - @enumToInt(Register.x0) + @enumToInt(Register.x0),
137 ),
138 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intToEnum(
139 Register,
140 @enumToInt(self) - @enumToInt(Register.w0) + @enumToInt(Register.x0),
141 ),
142 else => unreachable,
143 };
144 }
145
146 /// Convert from a general-purpose register to its 32 bit alias.
147 pub fn toW(self: Register) Register {
146 return switch (@enumToInt(self)) {148 return switch (@enumToInt(self)) {
147 0...31 => 128,149 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intToEnum(
148 32...63 => 64,150 Register,
149 64...95 => 32,151 @enumToInt(self) - @enumToInt(Register.x0) + @enumToInt(Register.w0),
150 96...127 => 16,152 ),
151 128...159 => 8,153 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intToEnum(
154 Register,
155 @enumToInt(self) - @enumToInt(Register.w0) + @enumToInt(Register.w0),
156 ),
152 else => unreachable,157 else => unreachable,
153 };158 };
154 }159 }
155160
156 /// Convert from any register to its 128 bit alias.161 /// Convert from a floating-point register to its 128 bit alias.
157 pub fn to128(self: FloatingPointRegister) FloatingPointRegister {162 pub fn toQ(self: Register) Register {
158 return @intToEnum(FloatingPointRegister, self.id());163 return switch (@enumToInt(self)) {
164 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
165 Register,
166 @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.q0),
167 ),
168 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
169 Register,
170 @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.q0),
171 ),
172 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
173 Register,
174 @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.q0),
175 ),
176 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
177 Register,
178 @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.q0),
179 ),
180 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
181 Register,
182 @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.q0),
183 ),
184 else => unreachable,
185 };
186 }
187
188 /// Convert from a floating-point register to its 64 bit alias.
189 pub fn toD(self: Register) Register {
190 return switch (@enumToInt(self)) {
191 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
192 Register,
193 @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.d0),
194 ),
195 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
196 Register,
197 @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.d0),
198 ),
199 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
200 Register,
201 @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.d0),
202 ),
203 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
204 Register,
205 @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.d0),
206 ),
207 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
208 Register,
209 @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.d0),
210 ),
211 else => unreachable,
212 };
159 }213 }
160214
161 /// Convert from any register to its 64 bit alias.215 /// Convert from a floating-point register to its 32 bit alias.
162 pub fn to64(self: FloatingPointRegister) FloatingPointRegister {216 pub fn toS(self: Register) Register {
163 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 32);217 return switch (@enumToInt(self)) {
218 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
219 Register,
220 @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.s0),
221 ),
222 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
223 Register,
224 @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.s0),
225 ),
226 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
227 Register,
228 @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.s0),
229 ),
230 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
231 Register,
232 @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.s0),
233 ),
234 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
235 Register,
236 @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.s0),
237 ),
238 else => unreachable,
239 };
164 }240 }
165241
166 /// Convert from any register to its 32 bit alias.242 /// Convert from a floating-point register to its 16 bit alias.
167 pub fn to32(self: FloatingPointRegister) FloatingPointRegister {243 pub fn toH(self: Register) Register {
168 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 64);244 return switch (@enumToInt(self)) {
245 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
246 Register,
247 @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.h0),
248 ),
249 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
250 Register,
251 @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.h0),
252 ),
253 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
254 Register,
255 @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.h0),
256 ),
257 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
258 Register,
259 @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.h0),
260 ),
261 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
262 Register,
263 @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.h0),
264 ),
265 else => unreachable,
266 };
169 }267 }
170268
171 /// Convert from any register to its 16 bit alias.269 /// Convert from a floating-point register to its 8 bit alias.
172 pub fn to16(self: FloatingPointRegister) FloatingPointRegister {270 pub fn toB(self: Register) Register {
173 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 96);271 return switch (@enumToInt(self)) {
272 @enumToInt(Register.q0)...@enumToInt(Register.q31) => @intToEnum(
273 Register,
274 @enumToInt(self) - @enumToInt(Register.q0) + @enumToInt(Register.b0),
275 ),
276 @enumToInt(Register.d0)...@enumToInt(Register.d31) => @intToEnum(
277 Register,
278 @enumToInt(self) - @enumToInt(Register.d0) + @enumToInt(Register.b0),
279 ),
280 @enumToInt(Register.s0)...@enumToInt(Register.s31) => @intToEnum(
281 Register,
282 @enumToInt(self) - @enumToInt(Register.s0) + @enumToInt(Register.b0),
283 ),
284 @enumToInt(Register.h0)...@enumToInt(Register.h31) => @intToEnum(
285 Register,
286 @enumToInt(self) - @enumToInt(Register.h0) + @enumToInt(Register.b0),
287 ),
288 @enumToInt(Register.b0)...@enumToInt(Register.b31) => @intToEnum(
289 Register,
290 @enumToInt(self) - @enumToInt(Register.b0) + @enumToInt(Register.b0),
291 ),
292 else => unreachable,
293 };
174 }294 }
175295
176 /// Convert from any register to its 8 bit alias.296 pub fn dwarfLocOp(self: Register) u8 {
177 pub fn to8(self: FloatingPointRegister) FloatingPointRegister {297 return @as(u8, self.enc()) + DW.OP.reg0;
178 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 128);
179 }298 }
180};299};
181300
182// zig fmt: on301test "Register.enc" {
302 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
303 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
183304
184test "FloatingPointRegister.id" {305 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
185 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.b0.id());306 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
186 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.h0.id());
187 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.s0.id());
188 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.id());
189 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.id());
190307
191 try testing.expectEqual(@as(u5, 2), FloatingPointRegister.q2.id());308 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
192 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d31.id());309 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
193}310}
194311
195test "FloatingPointRegister.size" {312test "Register.size" {
196 try testing.expectEqual(@as(u8, 128), FloatingPointRegister.q1.size());313 try testing.expectEqual(@as(u8, 64), Register.x19.size());
197 try testing.expectEqual(@as(u8, 64), FloatingPointRegister.d2.size());314 try testing.expectEqual(@as(u8, 32), Register.w3.size());
198 try testing.expectEqual(@as(u8, 32), FloatingPointRegister.s3.size());
199 try testing.expectEqual(@as(u8, 16), FloatingPointRegister.h4.size());
200 try testing.expectEqual(@as(u8, 8), FloatingPointRegister.b5.size());
201}315}
202316
203test "FloatingPointRegister.toX" {317test "Register.toX/toW" {
204 try testing.expectEqual(FloatingPointRegister.q1, FloatingPointRegister.q1.to128());318 try testing.expectEqual(Register.x0, Register.w0.toX());
205 try testing.expectEqual(FloatingPointRegister.q2, FloatingPointRegister.b2.to128());319 try testing.expectEqual(Register.x0, Register.x0.toX());
206 try testing.expectEqual(FloatingPointRegister.q3, FloatingPointRegister.h3.to128());
207320
208 try testing.expectEqual(FloatingPointRegister.d0, FloatingPointRegister.q0.to64());321 try testing.expectEqual(Register.w3, Register.w3.toW());
209 try testing.expectEqual(FloatingPointRegister.s1, FloatingPointRegister.d1.to32());322 try testing.expectEqual(Register.w3, Register.x3.toW());
210 try testing.expectEqual(FloatingPointRegister.h2, FloatingPointRegister.s2.to16());
211 try testing.expectEqual(FloatingPointRegister.b3, FloatingPointRegister.h3.to8());
212}323}
213324
214/// Represents an instruction in the AArch64 instruction set325/// Represents an instruction in the AArch64 instruction set