diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 441af51de2..0846d0b45e 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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(), diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 9088a395a7..e2de913c18 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -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); } diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 83afc1612b..17d0503bda 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -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]