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 {...@@ -1634,8 +1634,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
1634}1634}
16351635
1636fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {1636fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
1637 _ = op;
1638
1639 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1637 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1640 if (self.liveness.isUnused(inst))1638 if (self.liveness.isUnused(inst))
1641 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1639 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 {...@@ -1646,10 +1644,79 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
16461644
1647 const lhs = try self.resolveInst(bin_op.lhs);1645 const lhs = try self.resolveInst(bin_op.lhs);
1648 const rhs = try self.resolveInst(bin_op.rhs);1646 const rhs = try self.resolveInst(bin_op.rhs);
1649 _ = lhs;1647 const result: MCValue = result: {
1650 _ = rhs;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 });
1653}1720}
16541721
1655fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {1722fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
src/arch/aarch64/Emit.zig+25
...@@ -65,6 +65,7 @@ pub fn emitMir(...@@ -65,6 +65,7 @@ pub fn emitMir(
65 const inst = @intCast(u32, index);65 const inst = @intCast(u32, index);
66 switch (tag) {66 switch (tag) {
67 .add_immediate => try emit.mirAddSubtractImmediate(inst),67 .add_immediate => try emit.mirAddSubtractImmediate(inst),
68 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),
68 .sub_immediate => try emit.mirAddSubtractImmediate(inst),69 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
6970
70 .b => try emit.mirBranch(inst),71 .b => try emit.mirBranch(inst),
...@@ -78,6 +79,8 @@ pub fn emitMir(...@@ -78,6 +79,8 @@ pub fn emitMir(
7879
79 .call_extern => try emit.mirCallExtern(inst),80 .call_extern => try emit.mirCallExtern(inst),
8081
82 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
83
81 .dbg_line => try emit.mirDbgLine(inst),84 .dbg_line => try emit.mirDbgLine(inst),
8285
83 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),86 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
...@@ -347,6 +350,12 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -347,6 +350,12 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
347 rr_imm12_sh.imm12,350 rr_imm12_sh.imm12,
348 rr_imm12_sh.sh == 1,351 rr_imm12_sh.sh == 1,
349 )),352 )),
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 )),
350 .sub_immediate => try emit.writeInstruction(Instruction.sub(359 .sub_immediate => try emit.writeInstruction(Instruction.sub(
351 rr_imm12_sh.rd,360 rr_imm12_sh.rd,
352 rr_imm12_sh.rn,361 rr_imm12_sh.rn,
...@@ -453,6 +462,22 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -453,6 +462,22 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
453 }462 }
454}463}
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
456fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {481fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
457 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);482 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);
458 const payload = emit.mir.instructions.items(.data)[inst].payload;483 const payload = emit.mir.instructions.items(.data)[inst].payload;
src/arch/aarch64/Mir.zig+14
...@@ -36,6 +36,10 @@ pub const Inst = struct {...@@ -36,6 +36,10 @@ pub const Inst = struct {
36 brk,36 brk,
37 /// Pseudo-instruction: Call extern37 /// Pseudo-instruction: Call extern
38 call_extern,38 call_extern,
39 /// Compare (immediate)
40 cmp_immediate,
41 /// Compare (shifted register)
42 cmp_shifted_register,
39 /// Pseudo-instruction: End of prologue43 /// Pseudo-instruction: End of prologue
40 dbg_prologue_end,44 dbg_prologue_end,
41 /// Pseudo-instruction: Beginning of epilogue45 /// Pseudo-instruction: Beginning of epilogue
...@@ -141,6 +145,16 @@ pub const Inst = struct {...@@ -141,6 +145,16 @@ pub const Inst = struct {
141 imm12: u12,145 imm12: u12,
142 sh: u1 = 0,146 sh: u1 = 0,
143 },147 },
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 },
144 /// Three registers and a LoadStoreOffset158 /// Three registers and a LoadStoreOffset
145 ///159 ///
146 /// Used by e.g. str_register160 /// Used by e.g. str_register
src/arch/aarch64/bits.zig+88
...@@ -295,6 +295,18 @@ pub const Instruction = union(enum) {...@@ -295,6 +295,18 @@ pub const Instruction = union(enum) {
295 op: u1,295 op: u1,
296 sf: u1,296 sf: u1,
297 },297 },
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 },
298 conditional_branch: struct {310 conditional_branch: struct {
299 cond: u4,311 cond: u4,
300 o0: u1,312 o0: u1,
...@@ -391,6 +403,7 @@ pub const Instruction = union(enum) {...@@ -391,6 +403,7 @@ pub const Instruction = union(enum) {
391 .no_operation => |v| @bitCast(u32, v),403 .no_operation => |v| @bitCast(u32, v),
392 .logical_shifted_register => |v| @bitCast(u32, v),404 .logical_shifted_register => |v| @bitCast(u32, v),
393 .add_subtract_immediate => |v| @bitCast(u32, v),405 .add_subtract_immediate => |v| @bitCast(u32, v),
406 .add_subtract_shifted_register => |v| @bitCast(u32, v),
394 // TODO once packed structs work, this can be refactored407 // TODO once packed structs work, this can be refactored
395 .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),408 .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),
396 .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),409 .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) {...@@ -804,6 +817,35 @@ pub const Instruction = union(enum) {
804 };817 };
805 }818 }
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
807 fn conditionalBranch(849 fn conditionalBranch(
808 o0: u1,850 o0: u1,
809 o1: u1,851 o1: u1,
...@@ -1055,6 +1097,48 @@ pub const Instruction = union(enum) {...@@ -1055,6 +1097,48 @@ pub const Instruction = union(enum) {
1055 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);1097 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
1056 }1098 }
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
1058 // Conditional branch1142 // Conditional branch
10591143
1060 pub fn bCond(cond: Condition, offset: i21) Instruction {1144 pub fn bCond(cond: Condition, offset: i21) Instruction {
...@@ -1231,6 +1315,10 @@ test "serialize instructions" {...@@ -1231,6 +1315,10 @@ test "serialize instructions" {
1231 .inst = Instruction.cbz(.x10, 40),1315 .inst = Instruction.cbz(.x10, 40),
1232 .expected = 0b1_011010_0_0000000000000001010_01010,1316 .expected = 0b1_011010_0_0000000000000001010_01010,
1233 },1317 },
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 },
1234 };1322 };
12351323
1236 for (testcases) |case| {1324 for (testcases) |case| {