mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
x64: implement div_exact for ints (signed+unsigned)
This commit is contained in:
parent
1f4aa5ef78
commit
2c13a4b87e
@ -1254,10 +1254,92 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
|
||||
|
||||
fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst))
|
||||
.dead
|
||||
else
|
||||
return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
|
||||
const dst_ty = self.air.typeOfIndex(inst);
|
||||
const tag = self.air.instructions.items(.tag)[inst];
|
||||
switch (tag) {
|
||||
.div_exact => {},
|
||||
.div_trunc, .div_floor, .div_float => return self.fail("TODO implement {}", .{tag}),
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
if (dst_ty.zigTypeTag() != .Int) {
|
||||
return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() });
|
||||
}
|
||||
|
||||
const signedness = dst_ty.intInfo(self.target.*).signedness;
|
||||
const ty = if (signedness == .signed) Type.isize else dst_ty;
|
||||
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
|
||||
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
blk: {
|
||||
switch (lhs) {
|
||||
.register => |reg| {
|
||||
if (reg.to64() == .rax) break :blk;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager
|
||||
try self.genSetReg(ty, .rax, lhs);
|
||||
}
|
||||
if (signedness == .signed) {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .cwd,
|
||||
.ops = (Mir.Ops{
|
||||
.flags = 0b11,
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
}
|
||||
const dst_mcv = MCValue{ .register = registerAlias(.rax, abi_size) };
|
||||
|
||||
try self.register_manager.getReg(.rdx, null);
|
||||
self.register_manager.freezeRegs(&.{ .rax, .rdx });
|
||||
defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });
|
||||
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
const divisor = blk: {
|
||||
switch (rhs) {
|
||||
.register, .stack_offset => break :blk rhs,
|
||||
else => {
|
||||
const reg = try self.copyToTmpRegister(ty, rhs);
|
||||
break :blk MCValue{ .register = reg };
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
switch (divisor) {
|
||||
.register => |reg| {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .idiv,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
},
|
||||
.stack_offset => |off| {
|
||||
const flags: u2 = switch (abi_size) {
|
||||
1 => 0b00,
|
||||
2 => 0b01,
|
||||
4 => 0b10,
|
||||
8 => 0b11,
|
||||
else => unreachable,
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
.tag = .idiv,
|
||||
.ops = (Mir.Ops{
|
||||
.reg2 = .rbp,
|
||||
.flags = flags,
|
||||
}).encode(),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
});
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
break :result dst_mcv;
|
||||
};
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
@ -4126,7 +4208,7 @@ fn genInlineMemset(
|
||||
}
|
||||
|
||||
fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
|
||||
switch (mcv) {
|
||||
.dead => unreachable,
|
||||
.ptr_stack_offset => |off| {
|
||||
@ -4136,7 +4218,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
_ = try self.addInst(.{
|
||||
.tag = .lea,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
.reg2 = .rbp,
|
||||
}).encode(),
|
||||
.data = .{ .imm = @bitCast(u32, -off) },
|
||||
@ -4202,7 +4284,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
}).encode(),
|
||||
.data = .{ .imm = @truncate(u32, x) },
|
||||
});
|
||||
@ -4272,8 +4354,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(reg, @divExact(src_reg.size(), 8)),
|
||||
.reg2 = src_reg,
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
.reg2 = registerAlias(src_reg, abi_size),
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
@ -4399,7 +4481,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||
.reg1 = registerAlias(reg, abi_size),
|
||||
.reg2 = .rbp,
|
||||
.flags = 0b01,
|
||||
}).encode(),
|
||||
|
||||
@ -142,6 +142,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
|
||||
.idiv => try emit.mirIMulIDiv(.idiv, inst),
|
||||
.imul_complex => try emit.mirIMulComplex(inst),
|
||||
|
||||
.cwd => try emit.mirCwd(inst),
|
||||
|
||||
.push => try emit.mirPushPop(.push, inst),
|
||||
.pop => try emit.mirPushPop(.pop, inst),
|
||||
|
||||
@ -737,6 +739,17 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
|
||||
const tag: Tag = switch (ops.flags) {
|
||||
0b00 => .cbw,
|
||||
0b01 => .cwd,
|
||||
0b10 => .cdq,
|
||||
0b11 => .cqo,
|
||||
};
|
||||
return lowerToZoEnc(tag, emit.code);
|
||||
}
|
||||
|
||||
fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
assert(tag == .lea);
|
||||
@ -1139,6 +1152,10 @@ const Tag = enum {
|
||||
sal,
|
||||
shr,
|
||||
sar,
|
||||
cbw,
|
||||
cwd,
|
||||
cdq,
|
||||
cqo,
|
||||
|
||||
fn isSetCC(tag: Tag) bool {
|
||||
return switch (tag) {
|
||||
@ -1258,6 +1275,8 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
|
||||
.brk => OpCode.oneByte(0xcc),
|
||||
.nop => OpCode.oneByte(0x90),
|
||||
.syscall => OpCode.twoByte(0x0f, 0x05),
|
||||
.cbw => OpCode.oneByte(0x98),
|
||||
.cwd, .cdq, .cqo => OpCode.oneByte(0x99),
|
||||
else => null,
|
||||
},
|
||||
.d => return switch (tag) {
|
||||
@ -1592,7 +1611,15 @@ const RegisterOrMemory = union(enum) {
|
||||
|
||||
fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
|
||||
const opc = getOpCode(tag, .zo, false).?;
|
||||
const encoder = try Encoder.init(code, 1);
|
||||
const encoder = try Encoder.init(code, 2);
|
||||
switch (tag) {
|
||||
.cqo => {
|
||||
encoder.rex(.{
|
||||
.w = true,
|
||||
});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
opc.encode(encoder);
|
||||
}
|
||||
|
||||
|
||||
@ -228,6 +228,13 @@ pub const Inst = struct {
|
||||
imul,
|
||||
idiv,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 AX <- AL
|
||||
/// 0b01 DX:AX <- AX
|
||||
/// 0b10 EDX:EAX <- EAX
|
||||
/// 0b11 RDX:RAX <- RAX
|
||||
cwd,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, reg2
|
||||
/// 0b01 reg1, [reg2 + imm32]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user