mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 12:27:41 +00:00
stage2 ARM: implement mul_with_overflow for ints <= 32 bits
This commit is contained in:
parent
c4778fc029
commit
8c12ad98b8
@ -1500,9 +1500,115 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
|
||||
try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
|
||||
try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
|
||||
|
||||
break :result MCValue{ .stack_offset = stack_offset };
|
||||
} else if (int_info.bits <= 32) {
|
||||
const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
|
||||
|
||||
try self.spillCompareFlagsIfOccupied();
|
||||
self.compare_flags_inst = null;
|
||||
|
||||
const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
|
||||
.signed => .smull,
|
||||
.unsigned => .umull,
|
||||
};
|
||||
|
||||
// TODO extract umull etc. to binOpTwoRegister
|
||||
// once MCValue.rr is implemented
|
||||
const lhs_is_register = lhs == .register;
|
||||
const rhs_is_register = rhs == .register;
|
||||
|
||||
if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
|
||||
if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
|
||||
|
||||
const lhs_reg = if (lhs_is_register) lhs.register else blk: {
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
|
||||
break :blk reg;
|
||||
};
|
||||
defer self.register_manager.unfreezeRegs(&.{lhs_reg});
|
||||
|
||||
const rhs_reg = if (rhs_is_register) rhs.register else blk: {
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
|
||||
break :blk reg;
|
||||
};
|
||||
defer self.register_manager.unfreezeRegs(&.{rhs_reg});
|
||||
|
||||
const dest_regs = try self.register_manager.allocRegs(2, .{ null, null });
|
||||
self.register_manager.freezeRegs(&dest_regs);
|
||||
defer self.register_manager.unfreezeRegs(&dest_regs);
|
||||
const rdlo = dest_regs[0];
|
||||
const rdhi = dest_regs[1];
|
||||
|
||||
if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
|
||||
if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
|
||||
|
||||
const truncated_reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{truncated_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{truncated_reg});
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = base_tag,
|
||||
.data = .{ .rrrr = .{
|
||||
.rdlo = rdlo,
|
||||
.rdhi = rdhi,
|
||||
.rn = lhs_reg,
|
||||
.rm = rhs_reg,
|
||||
} },
|
||||
});
|
||||
|
||||
// sbfx/ubfx truncated, rdlo, #0, #bits
|
||||
try self.truncRegister(rdlo, truncated_reg, int_info.signedness, int_info.bits);
|
||||
|
||||
// str truncated, [...]
|
||||
try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
|
||||
|
||||
// cmp truncated, rdlo
|
||||
_ = try self.binOp(.cmp_eq, null, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize);
|
||||
|
||||
// mov rdlo, #0
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.data = .{ .rr_op = .{
|
||||
.rd = rdlo,
|
||||
.rn = .r0,
|
||||
.op = Instruction.Operand.fromU32(0).?,
|
||||
} },
|
||||
});
|
||||
|
||||
// movne rdlo, #1
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.cond = .ne,
|
||||
.data = .{ .rr_op = .{
|
||||
.rd = rdlo,
|
||||
.rn = .r0,
|
||||
.op = Instruction.Operand.fromU32(1).?,
|
||||
} },
|
||||
});
|
||||
|
||||
// cmp rdhi, #0
|
||||
_ = try self.binOp(.cmp_eq, null, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize);
|
||||
|
||||
// movne rdlo, #1
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.cond = .ne,
|
||||
.data = .{ .rr_op = .{
|
||||
.rd = rdlo,
|
||||
.rn = .r0,
|
||||
.op = Instruction.Operand.fromU32(1).?,
|
||||
} },
|
||||
});
|
||||
|
||||
// strb rdlo, [...]
|
||||
try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .register = rdlo });
|
||||
|
||||
break :result MCValue{ .stack_offset = stack_offset };
|
||||
} else {
|
||||
return self.fail("TODO ARM overflow operations on integers > u16/i16", .{});
|
||||
return self.fail("TODO ARM overflow operations on integers > u32/i32", .{});
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
|
||||
@ -132,6 +132,9 @@ pub fn emitMir(
|
||||
.mul => try emit.mirMultiply(inst),
|
||||
.smulbb => try emit.mirMultiply(inst),
|
||||
|
||||
.smull => try emit.mirMultiplyLong(inst),
|
||||
.umull => try emit.mirMultiplyLong(inst),
|
||||
|
||||
.nop => try emit.mirNop(),
|
||||
|
||||
.pop => try emit.mirBlockDataTransfer(inst),
|
||||
@ -695,6 +698,18 @@ fn mirMultiply(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirMultiplyLong(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const cond = emit.mir.instructions.items(.cond)[inst];
|
||||
const rrrr = emit.mir.instructions.items(.data)[inst].rrrr;
|
||||
|
||||
switch (tag) {
|
||||
.smull => try emit.writeInstruction(Instruction.smull(cond, rrrr.rdlo, rrrr.rdhi, rrrr.rn, rrrr.rm)),
|
||||
.umull => try emit.writeInstruction(Instruction.umull(cond, rrrr.rdlo, rrrr.rdhi, rrrr.rn, rrrr.rm)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirNop(emit: *Emit) !void {
|
||||
try emit.writeInstruction(Instruction.nop());
|
||||
}
|
||||
|
||||
@ -104,6 +104,8 @@ pub const Inst = struct {
|
||||
sbfx,
|
||||
/// Signed Multiply (halfwords), bottom half, bottom half
|
||||
smulbb,
|
||||
/// Signed Multiply Long
|
||||
smull,
|
||||
/// Store Register
|
||||
str,
|
||||
/// Store Register Byte
|
||||
@ -118,6 +120,8 @@ pub const Inst = struct {
|
||||
svc,
|
||||
/// Unsigned Bit Field Extract
|
||||
ubfx,
|
||||
/// Unsigned Multiply Long
|
||||
umull,
|
||||
};
|
||||
|
||||
/// The position of an MIR instruction within the `Mir` instructions array.
|
||||
@ -215,6 +219,15 @@ pub const Inst = struct {
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
},
|
||||
/// Four registers
|
||||
///
|
||||
/// Used by e.g. smull
|
||||
rrrr: struct {
|
||||
rdlo: Register,
|
||||
rdhi: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
},
|
||||
/// An unordered list of registers
|
||||
///
|
||||
/// Used by e.g. push
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user