authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-11-07 15:41:28+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-11-10 19:48:16+01:00
log8cb00519cddadae8728d2b2e51a36da71d5bfe67
treeead57c6ffab5f925d6e5a5897087fcb11c3ce7ef
parente5bc092408d7a02b74011e07beaee3c98ec9a268
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement airCmp


4 files changed, 199 insertions(+), 5 deletions(-)

src/arch/aarch64/CodeGen.zig+72-5
......@@ -1634,8 +1634,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
16341634}
16351635
16361636fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
1637 _ = op;
1638
16391637 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
16401638 if (self.liveness.isUnused(inst))
16411639 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -1646,10 +1644,79 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
16461644
16471645 const lhs = try self.resolveInst(bin_op.lhs);
16481646 const rhs = try self.resolveInst(bin_op.rhs);
1649 _ = lhs;
1650 _ = rhs;
1647 const result: MCValue = result: {
1648 const lhs_is_register = lhs == .register;
1649 const rhs_is_register = rhs == .register;
1650 // lhs should always be a register
1651 const rhs_should_be_register = switch (rhs) {
1652 .immediate => |imm| imm < 0 or imm > std.math.maxInt(u12),
1653 else => true,
1654 };
1655
1656 var lhs_mcv = lhs;
1657 var rhs_mcv = rhs;
1658
1659 // Allocate registers
1660 if (rhs_should_be_register) {
1661 if (!lhs_is_register and !rhs_is_register) {
1662 const regs = try self.register_manager.allocRegs(2, .{
1663 Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?,
1664 }, &.{});
1665 lhs_mcv = MCValue{ .register = regs[0] };
1666 rhs_mcv = MCValue{ .register = regs[1] };
1667 } else if (!rhs_is_register) {
1668 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) };
1669 }
1670 }
1671 if (!lhs_is_register) {
1672 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) };
1673 }
1674
1675 // Move the operands to the newly allocated registers
1676 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1677 if (lhs_mcv == .register and !lhs_is_register) {
1678 try self.genSetReg(ty, lhs_mcv.register, lhs);
1679 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs);
1680 }
1681 if (rhs_mcv == .register and !rhs_is_register) {
1682 try self.genSetReg(ty, rhs_mcv.register, rhs);
1683 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs);
1684 }
16511685
1652 return self.fail("TODO implement cmp for {}", .{self.target.cpu.arch});
1686 // The destination register is not present in the cmp instruction
1687 // The signedness of the integer does not matter for the cmp instruction
1688 switch (rhs_mcv) {
1689 .register => |reg| {
1690 _ = try self.addInst(.{
1691 .tag = .cmp_shifted_register,
1692 .data = .{ .rrr_imm6_shift = .{
1693 .rd = .xzr,
1694 .rn = lhs_mcv.register,
1695 .rm = reg,
1696 .imm6 = 0,
1697 .shift = .lsl,
1698 } },
1699 });
1700 },
1701 .immediate => |imm| {
1702 _ = try self.addInst(.{
1703 .tag = .cmp_immediate,
1704 .data = .{ .rr_imm12_sh = .{
1705 .rd = .xzr,
1706 .rn = lhs_mcv.register,
1707 .imm12 = @intCast(u12, imm),
1708 } },
1709 });
1710 },
1711 else => unreachable,
1712 }
1713
1714 break :result switch (ty.isSignedInt()) {
1715 true => MCValue{ .compare_flags_signed = op },
1716 false => MCValue{ .compare_flags_unsigned = op },
1717 };
1718 };
1719 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
16531720}
16541721
16551722fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
src/arch/aarch64/Emit.zig+25
......@@ -65,6 +65,7 @@ pub fn emitMir(
6565 const inst = @intCast(u32, index);
6666 switch (tag) {
6767 .add_immediate => try emit.mirAddSubtractImmediate(inst),
68 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),
6869 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
6970
7071 .b => try emit.mirBranch(inst),
......@@ -78,6 +79,8 @@ pub fn emitMir(
7879
7980 .call_extern => try emit.mirCallExtern(inst),
8081
82 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
83
8184 .dbg_line => try emit.mirDbgLine(inst),
8285
8386 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
......@@ -347,6 +350,12 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
347350 rr_imm12_sh.imm12,
348351 rr_imm12_sh.sh == 1,
349352 )),
353 .cmp_immediate => try emit.writeInstruction(Instruction.subs(
354 rr_imm12_sh.rd,
355 rr_imm12_sh.rn,
356 rr_imm12_sh.imm12,
357 rr_imm12_sh.sh == 1,
358 )),
350359 .sub_immediate => try emit.writeInstruction(Instruction.sub(
351360 rr_imm12_sh.rd,
352361 rr_imm12_sh.rn,
......@@ -453,6 +462,22 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
453462 }
454463}
455464
465fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
466 const tag = emit.mir.instructions.items(.tag)[inst];
467 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
468
469 switch (tag) {
470 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(
471 rrr_imm6_shift.rd,
472 rrr_imm6_shift.rn,
473 rrr_imm6_shift.rm,
474 rrr_imm6_shift.shift,
475 rrr_imm6_shift.imm6,
476 )),
477 else => unreachable,
478 }
479}
480
456481fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
457482 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);
458483 const payload = emit.mir.instructions.items(.data)[inst].payload;
src/arch/aarch64/Mir.zig+14
......@@ -36,6 +36,10 @@ pub const Inst = struct {
3636 brk,
3737 /// Pseudo-instruction: Call extern
3838 call_extern,
39 /// Compare (immediate)
40 cmp_immediate,
41 /// Compare (shifted register)
42 cmp_shifted_register,
3943 /// Pseudo-instruction: End of prologue
4044 dbg_prologue_end,
4145 /// Pseudo-instruction: Beginning of epilogue
......@@ -141,6 +145,16 @@ pub const Inst = struct {
141145 imm12: u12,
142146 sh: u1 = 0,
143147 },
148 /// Three registers and a shift (shift type and 6-bit amount)
149 ///
150 /// Used by e.g. cmp_shifted_register
151 rrr_imm6_shift: struct {
152 rd: Register,
153 rn: Register,
154 rm: Register,
155 imm6: u6,
156 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
157 },
144158 /// Three registers and a LoadStoreOffset
145159 ///
146160 /// Used by e.g. str_register
src/arch/aarch64/bits.zig+88
......@@ -295,6 +295,18 @@ pub const Instruction = union(enum) {
295295 op: u1,
296296 sf: u1,
297297 },
298 add_subtract_shifted_register: packed struct {
299 rd: u5,
300 rn: u5,
301 imm6: u6,
302 rm: u5,
303 fixed_1: u1 = 0b0,
304 shift: u2,
305 fixed_2: u5 = 0b01011,
306 s: u1,
307 op: u1,
308 sf: u1,
309 },
298310 conditional_branch: struct {
299311 cond: u4,
300312 o0: u1,
......@@ -391,6 +403,7 @@ pub const Instruction = union(enum) {
391403 .no_operation => |v| @bitCast(u32, v),
392404 .logical_shifted_register => |v| @bitCast(u32, v),
393405 .add_subtract_immediate => |v| @bitCast(u32, v),
406 .add_subtract_shifted_register => |v| @bitCast(u32, v),
394407 // TODO once packed structs work, this can be refactored
395408 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
396409 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
......@@ -804,6 +817,35 @@ pub const Instruction = union(enum) {
804817 };
805818 }
806819
820 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
821
822 fn addSubtractShiftedRegister(
823 op: u1,
824 s: u1,
825 shift: AddSubtractShiftedRegisterShift,
826 rd: Register,
827 rn: Register,
828 rm: Register,
829 imm6: u6,
830 ) Instruction {
831 return Instruction{
832 .add_subtract_shifted_register = .{
833 .rd = rd.id(),
834 .rn = rn.id(),
835 .imm6 = imm6,
836 .rm = rm.id(),
837 .shift = @enumToInt(shift),
838 .s = s,
839 .op = op,
840 .sf = switch (rd.size()) {
841 32 => 0b0,
842 64 => 0b1,
843 else => unreachable, // unexpected register size
844 },
845 },
846 };
847 }
848
807849 fn conditionalBranch(
808850 o0: u1,
809851 o1: u1,
......@@ -1055,6 +1097,48 @@ pub const Instruction = union(enum) {
10551097 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
10561098 }
10571099
1100 // Add/subtract (shifted register)
1101
1102 pub fn addShiftedRegister(
1103 rd: Register,
1104 rn: Register,
1105 rm: Register,
1106 shift: AddSubtractShiftedRegisterShift,
1107 imm6: u6,
1108 ) Instruction {
1109 return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6);
1110 }
1111
1112 pub fn addsShiftedRegister(
1113 rd: Register,
1114 rn: Register,
1115 rm: Register,
1116 shift: AddSubtractShiftedRegisterShift,
1117 imm6: u6,
1118 ) Instruction {
1119 return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6);
1120 }
1121
1122 pub fn subShiftedRegister(
1123 rd: Register,
1124 rn: Register,
1125 rm: Register,
1126 shift: AddSubtractShiftedRegisterShift,
1127 imm6: u6,
1128 ) Instruction {
1129 return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6);
1130 }
1131
1132 pub fn subsShiftedRegister(
1133 rd: Register,
1134 rn: Register,
1135 rm: Register,
1136 shift: AddSubtractShiftedRegisterShift,
1137 imm6: u6,
1138 ) Instruction {
1139 return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6);
1140 }
1141
10581142 // Conditional branch
10591143
10601144 pub fn bCond(cond: Condition, offset: i21) Instruction {
......@@ -1231,6 +1315,10 @@ test "serialize instructions" {
12311315 .inst = Instruction.cbz(.x10, 40),
12321316 .expected = 0b1_011010_0_0000000000000001010_01010,
12331317 },
1318 .{ // add x0, x1, x2, lsl #5
1319 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
1320 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
1321 },
12341322 };
12351323
12361324 for (testcases) |case| {