authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-01 22:51:18+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-01 22:51:18+02:00
log8c12ad98b857cee3f6a8bc557f08b8dfcba2db7e
tree7b2259cc40e411fdec841677cc81aa19eeffb3a0
parentc4778fc0292b7024bf815e20e31029955a7a7241
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: implement mul_with_overflow for ints <= 32 bits


3 files changed, 135 insertions(+), 1 deletions(-)

src/arch/arm/CodeGen.zig+107-1
...@@ -1500,9 +1500,115 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1500,9 +1500,115 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1500 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1500 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1501 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1501 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
15021502
1503 break :result MCValue{ .stack_offset = stack_offset };
1504 } else if (int_info.bits <= 32) {
1505 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1506
1507 try self.spillCompareFlagsIfOccupied();
1508 self.compare_flags_inst = null;
1509
1510 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
1511 .signed => .smull,
1512 .unsigned => .umull,
1513 };
1514
1515 // TODO extract umull etc. to binOpTwoRegister
1516 // once MCValue.rr is implemented
1517 const lhs_is_register = lhs == .register;
1518 const rhs_is_register = rhs == .register;
1519
1520 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1521 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
1522
1523 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1524 const reg = try self.register_manager.allocReg(null);
1525 self.register_manager.freezeRegs(&.{reg});
1526
1527 break :blk reg;
1528 };
1529 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1530
1531 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1532 const reg = try self.register_manager.allocReg(null);
1533 self.register_manager.freezeRegs(&.{reg});
1534
1535 break :blk reg;
1536 };
1537 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
1538
1539 const dest_regs = try self.register_manager.allocRegs(2, .{ null, null });
1540 self.register_manager.freezeRegs(&dest_regs);
1541 defer self.register_manager.unfreezeRegs(&dest_regs);
1542 const rdlo = dest_regs[0];
1543 const rdhi = dest_regs[1];
1544
1545 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1546 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1547
1548 const truncated_reg = try self.register_manager.allocReg(null);
1549 self.register_manager.freezeRegs(&.{truncated_reg});
1550 defer self.register_manager.unfreezeRegs(&.{truncated_reg});
1551
1552 _ = try self.addInst(.{
1553 .tag = base_tag,
1554 .data = .{ .rrrr = .{
1555 .rdlo = rdlo,
1556 .rdhi = rdhi,
1557 .rn = lhs_reg,
1558 .rm = rhs_reg,
1559 } },
1560 });
1561
1562 // sbfx/ubfx truncated, rdlo, #0, #bits
1563 try self.truncRegister(rdlo, truncated_reg, int_info.signedness, int_info.bits);
1564
1565 // str truncated, [...]
1566 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1567
1568 // cmp truncated, rdlo
1569 _ = try self.binOp(.cmp_eq, null, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize);
1570
1571 // mov rdlo, #0
1572 _ = try self.addInst(.{
1573 .tag = .mov,
1574 .data = .{ .rr_op = .{
1575 .rd = rdlo,
1576 .rn = .r0,
1577 .op = Instruction.Operand.fromU32(0).?,
1578 } },
1579 });
1580
1581 // movne rdlo, #1
1582 _ = try self.addInst(.{
1583 .tag = .mov,
1584 .cond = .ne,
1585 .data = .{ .rr_op = .{
1586 .rd = rdlo,
1587 .rn = .r0,
1588 .op = Instruction.Operand.fromU32(1).?,
1589 } },
1590 });
1591
1592 // cmp rdhi, #0
1593 _ = try self.binOp(.cmp_eq, null, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize);
1594
1595 // movne rdlo, #1
1596 _ = try self.addInst(.{
1597 .tag = .mov,
1598 .cond = .ne,
1599 .data = .{ .rr_op = .{
1600 .rd = rdlo,
1601 .rn = .r0,
1602 .op = Instruction.Operand.fromU32(1).?,
1603 } },
1604 });
1605
1606 // strb rdlo, [...]
1607 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .register = rdlo });
1608
1503 break :result MCValue{ .stack_offset = stack_offset };1609 break :result MCValue{ .stack_offset = stack_offset };
1504 } else {1610 } else {
1505 return self.fail("TODO ARM overflow operations on integers > u16/i16", .{});1611 return self.fail("TODO ARM overflow operations on integers > u32/i32", .{});
1506 }1612 }
1507 },1613 },
1508 else => unreachable,1614 else => unreachable,
src/arch/arm/Emit.zig+15
...@@ -132,6 +132,9 @@ pub fn emitMir(...@@ -132,6 +132,9 @@ pub fn emitMir(
132 .mul => try emit.mirMultiply(inst),132 .mul => try emit.mirMultiply(inst),
133 .smulbb => try emit.mirMultiply(inst),133 .smulbb => try emit.mirMultiply(inst),
134134
135 .smull => try emit.mirMultiplyLong(inst),
136 .umull => try emit.mirMultiplyLong(inst),
137
135 .nop => try emit.mirNop(),138 .nop => try emit.mirNop(),
136139
137 .pop => try emit.mirBlockDataTransfer(inst),140 .pop => try emit.mirBlockDataTransfer(inst),
...@@ -695,6 +698,18 @@ fn mirMultiply(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -695,6 +698,18 @@ fn mirMultiply(emit: *Emit, inst: Mir.Inst.Index) !void {
695 }698 }
696}699}
697700
701fn mirMultiplyLong(emit: *Emit, inst: Mir.Inst.Index) !void {
702 const tag = emit.mir.instructions.items(.tag)[inst];
703 const cond = emit.mir.instructions.items(.cond)[inst];
704 const rrrr = emit.mir.instructions.items(.data)[inst].rrrr;
705
706 switch (tag) {
707 .smull => try emit.writeInstruction(Instruction.smull(cond, rrrr.rdlo, rrrr.rdhi, rrrr.rn, rrrr.rm)),
708 .umull => try emit.writeInstruction(Instruction.umull(cond, rrrr.rdlo, rrrr.rdhi, rrrr.rn, rrrr.rm)),
709 else => unreachable,
710 }
711}
712
698fn mirNop(emit: *Emit) !void {713fn mirNop(emit: *Emit) !void {
699 try emit.writeInstruction(Instruction.nop());714 try emit.writeInstruction(Instruction.nop());
700}715}
src/arch/arm/Mir.zig+13
...@@ -104,6 +104,8 @@ pub const Inst = struct {...@@ -104,6 +104,8 @@ pub const Inst = struct {
104 sbfx,104 sbfx,
105 /// Signed Multiply (halfwords), bottom half, bottom half105 /// Signed Multiply (halfwords), bottom half, bottom half
106 smulbb,106 smulbb,
107 /// Signed Multiply Long
108 smull,
107 /// Store Register109 /// Store Register
108 str,110 str,
109 /// Store Register Byte111 /// Store Register Byte
...@@ -118,6 +120,8 @@ pub const Inst = struct {...@@ -118,6 +120,8 @@ pub const Inst = struct {
118 svc,120 svc,
119 /// Unsigned Bit Field Extract121 /// Unsigned Bit Field Extract
120 ubfx,122 ubfx,
123 /// Unsigned Multiply Long
124 umull,
121 };125 };
122126
123 /// The position of an MIR instruction within the `Mir` instructions array.127 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -215,6 +219,15 @@ pub const Inst = struct {...@@ -215,6 +219,15 @@ pub const Inst = struct {
215 rn: Register,219 rn: Register,
216 rm: Register,220 rm: Register,
217 },221 },
222 /// Four registers
223 ///
224 /// Used by e.g. smull
225 rrrr: struct {
226 rdlo: Register,
227 rdhi: Register,
228 rn: Register,
229 rm: Register,
230 },
218 /// An unordered list of registers231 /// An unordered list of registers
219 ///232 ///
220 /// Used by e.g. push233 /// Used by e.g. push