| author | |
| committer | |
| log | 8cb00519cddadae8728d2b2e51a36da71d5bfe67 |
| tree | ead57c6ffab5f925d6e5a5897087fcb11c3ce7ef |
| parent | e5bc092408d7a02b74011e07beaee3c98ec9a268 |
| signature |
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 | } |
| 1635 | 1635 | ||
| 1636 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 1636 | fn 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 { |
| 1646 | 1644 | ||
| 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 | } | ||
| 1651 | 1685 | ||
| 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 | } |
| 1654 | 1721 | ||
| 1655 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | 1722 | fn 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), |
| 69 | 70 | ||
| 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( |
| 78 | 79 | ||
| 79 | .call_extern => try emit.mirCallExtern(inst), | 80 | .call_extern => try emit.mirCallExtern(inst), |
| 80 | 81 | ||
| 82 | .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), | ||
| 83 | |||
| 81 | .dbg_line => try emit.mirDbgLine(inst), | 84 | .dbg_line => try emit.mirDbgLine(inst), |
| 82 | 85 | ||
| 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 | } |
| 455 | 464 | ||
| 465 | fn 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 | |||
| 456 | fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { | 481 | fn 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 extern | 37 | /// 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 prologue | 43 | /// Pseudo-instruction: End of prologue |
| 40 | dbg_prologue_end, | 44 | dbg_prologue_end, |
| 41 | /// Pseudo-instruction: Beginning of epilogue | 45 | /// 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 LoadStoreOffset | 158 | /// Three registers and a LoadStoreOffset |
| 145 | /// | 159 | /// |
| 146 | /// Used by e.g. str_register | 160 | /// 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 refactored | 407 | // 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 | } |
| 806 | 819 | ||
| 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 | } |
| 1057 | 1099 | ||
| 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 branch | 1142 | // Conditional branch |
| 1059 | 1143 | ||
| 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 | }; |
| 1235 | 1323 | ||
| 1236 | for (testcases) |case| { | 1324 | for (testcases) |case| { |