| 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 | 1634 | } |
| 1635 | 1635 | |
| 1636 | 1636 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1637 | _ = op; | |
| 1638 | ||
| 1639 | 1637 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1640 | 1638 | if (self.liveness.isUnused(inst)) |
| 1641 | 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 | 1644 | |
| 1647 | 1645 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1648 | 1646 | 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 | } | |
| 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 | 1722 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
src/arch/aarch64/Emit.zig+25| ... | ... | @@ -65,6 +65,7 @@ pub fn emitMir( |
| 65 | 65 | const inst = @intCast(u32, index); |
| 66 | 66 | switch (tag) { |
| 67 | 67 | .add_immediate => try emit.mirAddSubtractImmediate(inst), |
| 68 | .cmp_immediate => try emit.mirAddSubtractImmediate(inst), | |
| 68 | 69 | .sub_immediate => try emit.mirAddSubtractImmediate(inst), |
| 69 | 70 | |
| 70 | 71 | .b => try emit.mirBranch(inst), |
| ... | ... | @@ -78,6 +79,8 @@ pub fn emitMir( |
| 78 | 79 | |
| 79 | 80 | .call_extern => try emit.mirCallExtern(inst), |
| 80 | 81 | |
| 82 | .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), | |
| 83 | ||
| 81 | 84 | .dbg_line => try emit.mirDbgLine(inst), |
| 82 | 85 | |
| 83 | 86 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| ... | ... | @@ -347,6 +350,12 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 347 | 350 | rr_imm12_sh.imm12, |
| 348 | 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 | 359 | .sub_immediate => try emit.writeInstruction(Instruction.sub( |
| 351 | 360 | rr_imm12_sh.rd, |
| 352 | 361 | rr_imm12_sh.rn, |
| ... | ... | @@ -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 | 481 | fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 457 | 482 | assert(emit.mir.instructions.items(.tag)[inst] == .load_memory); |
| 458 | 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 | 36 | brk, |
| 37 | 37 | /// Pseudo-instruction: Call extern |
| 38 | 38 | call_extern, |
| 39 | /// Compare (immediate) | |
| 40 | cmp_immediate, | |
| 41 | /// Compare (shifted register) | |
| 42 | cmp_shifted_register, | |
| 39 | 43 | /// Pseudo-instruction: End of prologue |
| 40 | 44 | dbg_prologue_end, |
| 41 | 45 | /// Pseudo-instruction: Beginning of epilogue |
| ... | ... | @@ -141,6 +145,16 @@ pub const Inst = struct { |
| 141 | 145 | imm12: u12, |
| 142 | 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 | 158 | /// Three registers and a LoadStoreOffset |
| 145 | 159 | /// |
| 146 | 160 | /// Used by e.g. str_register |
src/arch/aarch64/bits.zig+88| ... | ... | @@ -295,6 +295,18 @@ pub const Instruction = union(enum) { |
| 295 | 295 | op: u1, |
| 296 | 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 | 310 | conditional_branch: struct { |
| 299 | 311 | cond: u4, |
| 300 | 312 | o0: u1, |
| ... | ... | @@ -391,6 +403,7 @@ pub const Instruction = union(enum) { |
| 391 | 403 | .no_operation => |v| @bitCast(u32, v), |
| 392 | 404 | .logical_shifted_register => |v| @bitCast(u32, v), |
| 393 | 405 | .add_subtract_immediate => |v| @bitCast(u32, v), |
| 406 | .add_subtract_shifted_register => |v| @bitCast(u32, v), | |
| 394 | 407 | // TODO once packed structs work, this can be refactored |
| 395 | 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 | 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 | 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 | 849 | fn conditionalBranch( |
| 808 | 850 | o0: u1, |
| 809 | 851 | o1: u1, |
| ... | ... | @@ -1055,6 +1097,48 @@ pub const Instruction = union(enum) { |
| 1055 | 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 | 1142 | // Conditional branch |
| 1059 | 1143 | |
| 1060 | 1144 | pub fn bCond(cond: Condition, offset: i21) Instruction { |
| ... | ... | @@ -1231,6 +1315,10 @@ test "serialize instructions" { |
| 1231 | 1315 | .inst = Instruction.cbz(.x10, 40), |
| 1232 | 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 | 1324 | for (testcases) |case| { |