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 {
414414 // to the stack.
415415 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
416416 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
419419 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
420420 self.next_stack_offset = stack_offset;
......@@ -927,7 +927,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
927927 // Make sure the type can fit in a register before we try to allocate one.
928928 if (abi_size <= 8) {
929929 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) };
931931 }
932932 }
933933 }
......@@ -982,7 +982,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
982982/// This can have a side effect of spilling instructions to the stack to free up a register.
983983fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
984984 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);
986986 try self.genSetReg(ty, reg, mcv);
987987 return reg;
988988}
......@@ -993,7 +993,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
993993fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
994994 const raw_reg = try self.register_manager.allocReg(reg_owner, gp);
995995 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);
997997 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
998998 return MCValue{ .register = reg };
999999}
......@@ -1031,7 +1031,6 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10311031 const operand_info = operand_ty.intInfo(self.target.*);
10321032
10331033 const dest_ty = self.air.typeOfIndex(inst);
1034 const dest_abi_size = dest_ty.abiSize(self.target.*);
10351034 const dest_info = dest_ty.intInfo(self.target.*);
10361035
10371036 const result: MCValue = result: {
......@@ -1042,7 +1041,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10421041 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10431042
10441043 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) },
10461045 else => operand_mcv,
10471046 };
10481047
......@@ -1117,7 +1116,7 @@ fn trunc(
11171116 else => operand_reg: {
11181117 if (info_a.bits <= 64) {
11191118 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);
11211120 } else {
11221121 return self.fail("TODO load least significant word into register", .{});
11231122 }
......@@ -1130,14 +1129,14 @@ fn trunc(
11301129 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11311130
11321131 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);
11341133 } else {
11351134 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);
11371136 }
11381137 } else blk: {
11391138 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);
11411140 };
11421141
11431142 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 {
11941193 }
11951194
11961195 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);
11981197 };
11991198
12001199 _ = try self.addInst(.{
......@@ -1227,7 +1226,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
12271226 }
12281227
12291228 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);
12311230 };
12321231
12331232 _ = try self.addInst(.{
......@@ -1307,8 +1306,8 @@ fn binOpRegister(
13071306 const lhs_is_register = lhs == .register;
13081307 const rhs_is_register = rhs == .register;
13091308
1310 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
1311 if (rhs_is_register) assert(rhs.register == registerAlias(rhs.register, rhs_ty.abiSize(self.target.*)));
1309 if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty));
1310 if (rhs_is_register) assert(rhs.register == self.registerAlias(rhs.register, rhs_ty));
13121311
13131312 const lhs_lock: ?RegisterLock = if (lhs_is_register)
13141313 self.register_manager.lockReg(lhs.register)
......@@ -1330,7 +1329,7 @@ fn binOpRegister(
13301329 } else null;
13311330
13321331 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
13351334 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13361335
......@@ -1344,7 +1343,7 @@ fn binOpRegister(
13441343 // order to guarantee that registers will have equal sizes, we
13451344 // use the register alias of rhs corresponding to the size of
13461345 // lhs.
1347 registerAlias(rhs.register, lhs_ty.abiSize(self.target.*))
1346 self.registerAlias(rhs.register, lhs_ty)
13481347 else blk: {
13491348 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
13501349 break :inst Air.refToIndex(md.rhs).?;
......@@ -1354,7 +1353,7 @@ fn binOpRegister(
13541353
13551354 // Here, we deliberately use lhs as lhs and rhs may differ in
13561355 // 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
13591358 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13601359
......@@ -1372,11 +1371,11 @@ fn binOpRegister(
13721371 break :blk rhs_reg;
13731372 } else {
13741373 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);
13761375 }
13771376 } else blk: {
13781377 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);
13801379 },
13811380 };
13821381
......@@ -1415,7 +1414,7 @@ fn binOpRegister(
14151414 .smull,
14161415 .umull,
14171416 => .{ .rrr = .{
1418 .rd = dest_reg.to64(),
1417 .rd = dest_reg.toX(),
14191418 .rn = lhs_reg,
14201419 .rm = rhs_reg,
14211420 } },
......@@ -1463,7 +1462,7 @@ fn binOpImmediate(
14631462) !MCValue {
14641463 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
14681467 const lhs_lock: ?RegisterLock = if (lhs_is_register)
14691468 self.register_manager.lockReg(lhs.register)
......@@ -1481,7 +1480,7 @@ fn binOpImmediate(
14811480 } else null;
14821481
14831482 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
14861485 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
14871486
......@@ -1502,11 +1501,11 @@ fn binOpImmediate(
15021501 break :blk lhs_reg;
15031502 } else {
15041503 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);
15061505 }
15071506 } else blk: {
15081507 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);
15101509 },
15111510 };
15121511
......@@ -1719,7 +1718,7 @@ fn binOp(
17191718 } else null;
17201719
17211720 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
17241723 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
17251724
......@@ -1734,7 +1733,7 @@ fn binOp(
17341733 } else null;
17351734
17361735 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
17391738 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
17401739
......@@ -1745,10 +1744,9 @@ fn binOp(
17451744
17461745 const dest_regs: [2]Register = blk: {
17471746 const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1748 const abi_size = lhs_ty.abiSize(self.target.*);
17491747 break :blk .{
1750 registerAlias(raw_regs[0], abi_size),
1751 registerAlias(raw_regs[1], abi_size),
1748 self.registerAlias(raw_regs[0], lhs_ty),
1749 self.registerAlias(raw_regs[1], lhs_ty),
17521750 };
17531751 };
17541752 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
......@@ -2067,7 +2065,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
20672065 defer self.register_manager.unlockReg(dest_reg_lock);
20682066
20692067 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);
20712069 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
20722070 defer self.register_manager.unlockReg(truncated_reg_lock);
20732071
......@@ -2186,8 +2184,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21862184 defer self.register_manager.unlockReg(truncated_reg_lock);
21872185
21882186 try self.truncRegister(
2189 dest_reg.to32(),
2190 truncated_reg.to32(),
2187 dest_reg.toW(),
2188 truncated_reg.toW(),
21912189 int_info.signedness,
21922190 int_info.bits,
21932191 );
......@@ -2197,8 +2195,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21972195 _ = try self.addInst(.{
21982196 .tag = .cmp_extended_register,
21992197 .data = .{ .rr_extend_shift = .{
2200 .rn = dest_reg.to64(),
2201 .rm = truncated_reg.to32(),
2198 .rn = dest_reg.toX(),
2199 .rm = truncated_reg.toW(),
22022200 .ext_type = .sxtw,
22032201 .imm3 = 0,
22042202 } },
......@@ -2208,8 +2206,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22082206 _ = try self.addInst(.{
22092207 .tag = .cmp_extended_register,
22102208 .data = .{ .rr_extend_shift = .{
2211 .rn = dest_reg.to64(),
2212 .rm = truncated_reg.to32(),
2209 .rn = dest_reg.toX(),
2210 .rm = truncated_reg.toW(),
22132211 .ext_type = .uxtw,
22142212 .imm3 = 0,
22152213 } },
......@@ -2245,7 +2243,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22452243
22462244 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
22472245 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);
22492247 break :blk reg;
22502248 };
22512249 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
......@@ -2253,7 +2251,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22532251
22542252 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
22552253 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);
22572255 break :blk reg;
22582256 };
22592257 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
......@@ -2264,7 +2262,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22642262
22652263 const dest_reg = blk: {
22662264 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);
22682266 break :blk reg;
22692267 };
22702268 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
......@@ -2853,7 +2851,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
28532851 return self.finishAir(inst, result, .{ un_op, .none, .none });
28542852}
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 {
28572861 if (!self.liveness.operandDies(inst, op_index))
28582862 return false;
28592863
......@@ -2912,7 +2916,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
29122916 .stack_offset => |off| {
29132917 if (elem_size <= 8) {
29142918 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);
29162920 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
29172921 defer self.register_manager.unlockReg(tmp_reg_lock);
29182922
......@@ -3050,7 +3054,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
30503054 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
30513055 // The MCValue that holds the pointer can be re-used as the value.
30523056 break :blk switch (ptr) {
3053 .register => |r| MCValue{ .register = registerAlias(r, elem_size) },
3057 .register => |reg| MCValue{ .register = self.registerAlias(reg, elem_ty) },
30543058 else => ptr,
30553059 };
30563060 } else {
......@@ -3136,7 +3140,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
31363140 else => {
31373141 if (abi_size <= 8) {
31383142 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);
31403144 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
31413145 defer self.register_manager.unlockReg(tmp_reg_lock);
31423146
......@@ -3295,7 +3299,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
32953299 } else {
32963300 // Copy to new register
32973301 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);
32993303 try self.genSetReg(struct_field_ty, dest_reg, field);
33003304
33013305 break :result MCValue{ .register = dest_reg };
......@@ -3410,9 +3414,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34103414 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
34113415 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
34123416
3413 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3414 const ptr_bytes = @divExact(ptr_bits, 8);
3415 const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
3417 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
34163418
34173419 var ptr_ty_payload: Type.Payload.ElemType = .{
34183420 .base = .{ .tag = .single_mut_pointer },
......@@ -4376,7 +4378,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
43764378 4, 8 => .str_stack,
43774379 else => unreachable, // unexpected abi size
43784380 };
4379 const rt = registerAlias(reg, abi_size);
4381 const rt = self.registerAlias(reg, ty);
43804382
43814383 _ = try self.addInst(.{
43824384 .tag = tag,
......@@ -4399,10 +4401,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
43994401 const overflow_bit_ty = ty.structFieldType(1);
44004402 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
44014403 const raw_cond_reg = try self.register_manager.allocReg(null, gp);
4402 const cond_reg = registerAlias(
4403 raw_cond_reg,
4404 @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),
4405 );
4404 const cond_reg = self.registerAlias(raw_cond_reg, overflow_bit_ty);
44064405
44074406 _ = try self.addInst(.{
44084407 .tag = .cset,
......@@ -4599,8 +4598,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
45994598 .memory => |addr| {
46004599 // The value is in memory at a hard-coded address.
46014600 // 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 });
4603 try self.genLdrRegister(reg, reg.to64(), ty);
4601 try self.genSetReg(ty, reg.toX(), .{ .immediate = addr });
4602 try self.genLdrRegister(reg, reg.toX(), ty);
46044603 },
46054604 .stack_offset => |off| {
46064605 const abi_size = ty.abiSize(self.target.*);
......@@ -4679,7 +4678,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
46794678 4, 8 => .str_immediate,
46804679 else => unreachable, // unexpected abi size
46814680 };
4682 const rt = registerAlias(reg, abi_size);
4681 const rt = self.registerAlias(reg, ty);
46834682 const offset = switch (abi_size) {
46844683 1 => blk: {
46854684 if (math.cast(u12, stack_offset)) |imm| {
......@@ -5300,7 +5299,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
53005299 assert(ret_ty.isError());
53015300 result.return_value = .{ .immediate = 0 };
53025301 } 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) };
53045303 } else {
53055304 return self.fail("TODO support more return types for ARM backend", .{});
53065305 }
......@@ -5322,7 +5321,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
53225321
53235322 if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) {
53245323 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) };
53265325 ncrn += 1;
53275326 } else {
53285327 return self.fail("TODO MCValues with multiple registers", .{});
......@@ -5358,7 +5357,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
53585357 assert(ret_ty.isError());
53595358 result.return_value = .{ .immediate = 0 };
53605359 } 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) };
53625361 } else {
53635362 // The result is returned by reference, not by
53645363 // value. This means that x0 (or w0 when pointer
......@@ -5424,14 +5423,30 @@ fn parseRegName(name: []const u8) ?Register {
54245423 return std.meta.stringToEnum(Register, name);
54255424}
54265425
5427fn registerAlias(reg: Register, size_bytes: u64) Register {
5428 if (size_bytes == 0) {
5429 unreachable; // should be comptime-known
5430 } else if (size_bytes <= 4) {
5431 return reg.to32();
5432 } else if (size_bytes <= 8) {
5433 return reg.to64();
5434 } else {
5435 unreachable; // TODO handle floating-point registers
5426fn registerAlias(self: *Self, reg: Register, ty: Type) Register {
5427 const abi_size = ty.abiSize(self.target.*);
5428
5429 switch (reg.class()) {
5430 .general_purpose => {
5431 if (abi_size == 0) {
5432 unreachable; // should be comptime-known
5433 } else if (abi_size <= 4) {
5434 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 },
54365451 }
54375452}
src/arch/aarch64/Emit.zig+4-4
......@@ -842,14 +842,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
842842 // PC-relative displacement to the entry in memory.
843843 // adrp
844844 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
847847 switch (tag) {
848848 .load_memory_got => {
849849 // ldr reg, reg, offset
850850 try emit.writeInstruction(Instruction.ldr(
851851 reg,
852 reg.to64(),
852 reg.toX(),
853853 Instruction.LoadStoreOffset.imm(0),
854854 ));
855855 },
......@@ -863,11 +863,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
863863 // Note that this can potentially be optimised out by the codegen/linker if the
864864 // target address is appropriately aligned.
865865 // 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));
867867 // ldr reg, reg, offset
868868 try emit.writeInstruction(Instruction.ldr(
869869 reg,
870 reg.to64(),
870 reg.toX(),
871871 Instruction.LoadStoreOffset.imm(0),
872872 ));
873873 },
src/arch/aarch64/bits.zig+250-139
......@@ -4,17 +4,22 @@ const DW = std.dwarf;
44const assert = std.debug.assert;
55const testing = std.testing;
66
7// zig fmt: off
7pub const RegisterClass = enum {
8 general_purpose,
9 stack_pointer,
10 floating_point,
11};
812
913/// General purpose registers in the AArch64 instruction set
10pub const Register = enum(u7) {
11 // 64-bit registers
14pub const Register = enum(u8) {
15 // zig fmt: off
16 // 64-bit general-purpose registers
1217 x0, x1, x2, x3, x4, x5, x6, x7,
1318 x8, x9, x10, x11, x12, x13, x14, x15,
1419 x16, x17, x18, x19, x20, x21, x22, x23,
1520 x24, x25, x26, x27, x28, x29, x30, xzr,
1621
17 // 32-bit registers
22 // 32-bit general-purpose registers
1823 w0, w1, w2, w3, w4, w5, w6, w7,
1924 w8, w9, w10, w11, w12, w13, w14, w15,
2025 w16, w17, w18, w19, w20, w21, w22, w23,
......@@ -23,192 +28,298 @@ pub const Register = enum(u7) {
2328 // Stack pointer
2429 sp, wsp,
2530
26 pub fn id(self: Register) u6 {
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
31 // 128-bit floating-point registers
11132 q0, q1, q2, q3, q4, q5, q6, q7,
11233 q8, q9, q10, q11, q12, q13, q14, q15,
11334 q16, q17, q18, q19, q20, q21, q22, q23,
11435 q24, q25, q26, q27, q28, q29, q30, q31,
11536
116 // 64-bit registers
37 // 64-bit floating-point registers
11738 d0, d1, d2, d3, d4, d5, d6, d7,
11839 d8, d9, d10, d11, d12, d13, d14, d15,
11940 d16, d17, d18, d19, d20, d21, d22, d23,
12041 d24, d25, d26, d27, d28, d29, d30, d31,
12142
122 // 32-bit registers
43 // 32-bit floating-point registers
12344 s0, s1, s2, s3, s4, s5, s6, s7,
12445 s8, s9, s10, s11, s12, s13, s14, s15,
12546 s16, s17, s18, s19, s20, s21, s22, s23,
12647 s24, s25, s26, s27, s28, s29, s30, s31,
12748
128 // 16-bit registers
49 // 16-bit floating-point registers
12950 h0, h1, h2, h3, h4, h5, h6, h7,
13051 h8, h9, h10, h11, h12, h13, h14, h15,
13152 h16, h17, h18, h19, h20, h21, h22, h23,
13253 h24, h25, h26, h27, h28, h29, h30, h31,
13354
134 // 8-bit registers
55 // 8-bit floating-point registers
13556 b0, b1, b2, b3, b4, b5, b6, b7,
13657 b8, b9, b10, b11, b12, b13, b14, b15,
13758 b16, b17, b18, b19, b20, b21, b22, b23,
13859 b24, b25, b26, b27, b28, b29, b30, b31,
60 // zig fmt: on
13961
140 pub fn id(self: FloatingPointRegister) u5 {
141 return @truncate(u5, @enumToInt(self));
62 pub fn class(self: Register) RegisterClass {
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 };
142111 }
143112
144113 /// 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 {
146148 return switch (@enumToInt(self)) {
147 0...31 => 128,
148 32...63 => 64,
149 64...95 => 32,
150 96...127 => 16,
151 128...159 => 8,
149 @enumToInt(Register.x0)...@enumToInt(Register.xzr) => @intToEnum(
150 Register,
151 @enumToInt(self) - @enumToInt(Register.x0) + @enumToInt(Register.w0),
152 ),
153 @enumToInt(Register.w0)...@enumToInt(Register.wzr) => @intToEnum(
154 Register,
155 @enumToInt(self) - @enumToInt(Register.w0) + @enumToInt(Register.w0),
156 ),
152157 else => unreachable,
153158 };
154159 }
155160
156 /// Convert from any register to its 128 bit alias.
157 pub fn to128(self: FloatingPointRegister) FloatingPointRegister {
158 return @intToEnum(FloatingPointRegister, self.id());
161 /// Convert from a floating-point register to its 128 bit alias.
162 pub fn toQ(self: Register) Register {
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 };
159213 }
160214
161 /// Convert from any register to its 64 bit alias.
162 pub fn to64(self: FloatingPointRegister) FloatingPointRegister {
163 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 32);
215 /// Convert from a floating-point register to its 32 bit alias.
216 pub fn toS(self: Register) Register {
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 };
164240 }
165241
166 /// Convert from any register to its 32 bit alias.
167 pub fn to32(self: FloatingPointRegister) FloatingPointRegister {
168 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 64);
242 /// Convert from a floating-point register to its 16 bit alias.
243 pub fn toH(self: Register) Register {
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 };
169267 }
170268
171 /// Convert from any register to its 16 bit alias.
172 pub fn to16(self: FloatingPointRegister) FloatingPointRegister {
173 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 96);
269 /// Convert from a floating-point register to its 8 bit alias.
270 pub fn toB(self: Register) Register {
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 };
174294 }
175295
176 /// Convert from any register to its 8 bit alias.
177 pub fn to8(self: FloatingPointRegister) FloatingPointRegister {
178 return @intToEnum(FloatingPointRegister, @as(u8, self.id()) + 128);
296 pub fn dwarfLocOp(self: Register) u8 {
297 return @as(u8, self.enc()) + DW.OP.reg0;
179298 }
180299};
181300
182// zig fmt: on
301test "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" {
185 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.b0.id());
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());
305 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
306 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
190307
191 try testing.expectEqual(@as(u5, 2), FloatingPointRegister.q2.id());
192 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d31.id());
308 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
309 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
193310}
194311
195test "FloatingPointRegister.size" {
196 try testing.expectEqual(@as(u8, 128), FloatingPointRegister.q1.size());
197 try testing.expectEqual(@as(u8, 64), FloatingPointRegister.d2.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());
312test "Register.size" {
313 try testing.expectEqual(@as(u8, 64), Register.x19.size());
314 try testing.expectEqual(@as(u8, 32), Register.w3.size());
201315}
202316
203test "FloatingPointRegister.toX" {
204 try testing.expectEqual(FloatingPointRegister.q1, FloatingPointRegister.q1.to128());
205 try testing.expectEqual(FloatingPointRegister.q2, FloatingPointRegister.b2.to128());
206 try testing.expectEqual(FloatingPointRegister.q3, FloatingPointRegister.h3.to128());
317test "Register.toX/toW" {
318 try testing.expectEqual(Register.x0, Register.w0.toX());
319 try testing.expectEqual(Register.x0, Register.x0.toX());
207320
208 try testing.expectEqual(FloatingPointRegister.d0, FloatingPointRegister.q0.to64());
209 try testing.expectEqual(FloatingPointRegister.s1, FloatingPointRegister.d1.to32());
210 try testing.expectEqual(FloatingPointRegister.h2, FloatingPointRegister.s2.to16());
211 try testing.expectEqual(FloatingPointRegister.b3, FloatingPointRegister.h3.to8());
321 try testing.expectEqual(Register.w3, Register.w3.toW());
322 try testing.expectEqual(Register.w3, Register.x3.toW());
212323}
213324
214325/// Represents an instruction in the AArch64 instruction set