| ... | @@ -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 }); |
| 1502 | | 1502 | |
| | 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, |