mirror of
https://github.com/ziglang/zig.git
synced 2026-01-06 05:25:10 +00:00
x86_64: add helpers for CMOVcc and SETcc at the MIR level
This commit is contained in:
parent
f61a70e812
commit
7221cd8ec9
@ -400,6 +400,29 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .setcc,
|
||||
.ops = .r_c,
|
||||
.data = .{ .r_c = .{
|
||||
.r1 = reg,
|
||||
.cc = cc,
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn asmCmovCCRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .cmovcc,
|
||||
.ops = .rr_c,
|
||||
.data = .{ .rr_c = .{
|
||||
.r1 = reg1,
|
||||
.r2 = reg2,
|
||||
.cc = cc,
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag,
|
||||
@ -1346,15 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.unsigned => .b,
|
||||
.signed => .l,
|
||||
};
|
||||
_ = cc;
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_mov,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = dst_mcv.register,
|
||||
// .reg2 = lhs_reg,
|
||||
// }),
|
||||
// .data = .{ .cc = cc },
|
||||
// });
|
||||
try self.asmCmovCCRegisterRegister(dst_mcv.register, lhs_reg, cc);
|
||||
|
||||
break :result dst_mcv;
|
||||
};
|
||||
@ -1554,14 +1569,7 @@ fn genSetStackTruncatedOverflowCompare(
|
||||
.signed => .o,
|
||||
.unsigned => .c,
|
||||
};
|
||||
_ = cc;
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = overflow_reg.to8(),
|
||||
// }),
|
||||
// .data = .{ .cc = cc },
|
||||
// });
|
||||
try self.asmSetCCRegister(overflow_reg.to8(), cc);
|
||||
|
||||
const scratch_reg = temp_regs[1];
|
||||
try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg });
|
||||
@ -1574,12 +1582,7 @@ fn genSetStackTruncatedOverflowCompare(
|
||||
);
|
||||
|
||||
const eq_reg = temp_regs[2];
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
|
||||
// .data = .{ .cc = .ne },
|
||||
// });
|
||||
|
||||
try self.asmSetCCRegister(eq_reg.to8(), .ne);
|
||||
try self.genBinOpMir(
|
||||
.@"or",
|
||||
Type.u8,
|
||||
@ -1829,14 +1832,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
|
||||
// }),
|
||||
// .data = undefined,
|
||||
// });
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_mov,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = divisor.to64(),
|
||||
// .reg2 = .rdx,
|
||||
// }),
|
||||
// .data = .{ .cc = .e },
|
||||
// });
|
||||
try self.asmCmovCCRegisterRegister(divisor.to64(), .rdx, .e);
|
||||
try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
|
||||
return MCValue{ .register = divisor };
|
||||
}
|
||||
@ -2881,13 +2877,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
||||
const overflow_bit_ty = value_ty.structFieldType(1);
|
||||
const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
|
||||
const tmp_reg = try self.register_manager.allocReg(null, gp);
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = tmp_reg.to8(),
|
||||
// }),
|
||||
// .data = .{ .cc = ro.eflags },
|
||||
// });
|
||||
try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
|
||||
try self.genInlineMemcpyRegisterRegister(
|
||||
overflow_bit_ty,
|
||||
reg,
|
||||
@ -3185,13 +3175,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
defer self.register_manager.unlockReg(reg_lock);
|
||||
|
||||
const dst_reg = try self.register_manager.allocReg(inst, gp);
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = dst_reg.to8(),
|
||||
// }),
|
||||
// .data = .{ .cc = ro.eflags },
|
||||
// });
|
||||
try self.asmSetCCRegister(dst_reg.to8(), ro.eflags);
|
||||
break :result MCValue{ .register = dst_reg.to8() };
|
||||
},
|
||||
else => unreachable,
|
||||
@ -5577,13 +5561,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
|
||||
const overflow_bit_ty = ty.structFieldType(1);
|
||||
const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
|
||||
const tmp_reg = try self.register_manager.allocReg(null, gp);
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = tmp_reg.to8(),
|
||||
// }),
|
||||
// .data = .{ .cc = ro.eflags },
|
||||
// });
|
||||
try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
|
||||
|
||||
return self.genSetStack(
|
||||
overflow_bit_ty,
|
||||
@ -6114,14 +6092,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
}
|
||||
},
|
||||
.eflags => |cc| {
|
||||
_ = cc;
|
||||
// _ = try self.addInst(.{
|
||||
// .tag = .cond_set_byte,
|
||||
// .ops = Mir.Inst.Ops.encode(.{
|
||||
// .reg1 = reg.to8(),
|
||||
// }),
|
||||
// .data = .{ .cc = cc },
|
||||
// });
|
||||
return self.asmSetCCRegister(reg.to8(), cc);
|
||||
},
|
||||
.immediate => |x| {
|
||||
if (x == 0) {
|
||||
|
||||
@ -118,6 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
|
||||
=> try emit.mirEncodeGeneric(tag, inst),
|
||||
|
||||
// Pseudo-instructions
|
||||
.cmovcc => try emit.mirCmovCC(inst),
|
||||
.setcc => try emit.mirSetCC(inst),
|
||||
|
||||
.dbg_line => try emit.mirDbgLine(inst),
|
||||
.dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
|
||||
.dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
|
||||
@ -200,9 +203,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
|
||||
.{ .imm = Immediate.u(data.ri_u.imm) },
|
||||
},
|
||||
.ri64 => {
|
||||
operands[0] = .{ .reg = data.rx.r1 };
|
||||
const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
|
||||
operands[1] = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
|
||||
operands[0..2].* = .{
|
||||
.{ .reg = data.rx.r1 },
|
||||
.{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
|
||||
};
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -215,6 +220,42 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
|
||||
});
|
||||
}
|
||||
|
||||
fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
|
||||
inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
|
||||
if (mem.eql(u8, field.name, @tagName(cc)))
|
||||
return @field(Instruction.Mnemonic, basename ++ field.name);
|
||||
} else unreachable;
|
||||
}
|
||||
|
||||
fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const ops = emit.mir.instructions.items(.ops)[inst];
|
||||
switch (ops) {
|
||||
.rr_c => {
|
||||
const data = emit.mir.instructions.items(.data)[inst].rr_c;
|
||||
const mnemonic = mnemonicFromCC("cmov", data.cc);
|
||||
return emit.encode(mnemonic, .{
|
||||
.op1 = .{ .reg = data.r1 },
|
||||
.op2 = .{ .reg = data.r2 },
|
||||
});
|
||||
},
|
||||
else => unreachable, // TODO
|
||||
}
|
||||
}
|
||||
|
||||
fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const ops = emit.mir.instructions.items(.ops)[inst];
|
||||
switch (ops) {
|
||||
.r_c => {
|
||||
const data = emit.mir.instructions.items(.data)[inst].r_c;
|
||||
const mnemonic = mnemonicFromCC("set", data.cc);
|
||||
return emit.encode(mnemonic, .{
|
||||
.op1 = .{ .reg = data.r1 },
|
||||
});
|
||||
},
|
||||
else => unreachable, // TODO
|
||||
}
|
||||
}
|
||||
|
||||
fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
|
||||
const payload = emit.mir.instructions.items(.data)[inst].payload;
|
||||
const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
|
||||
@ -333,107 +374,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)
|
||||
// });
|
||||
// }
|
||||
|
||||
// fn mirCondSetByte(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
// const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
// assert(tag == .cond_set_byte);
|
||||
// const ops = emit.mir.instructions.items(.ops)[inst].decode();
|
||||
// const cc = emit.mir.instructions.items(.data)[inst].cc;
|
||||
// const mnemonic: Instruction.Mnemonic = switch (cc) {
|
||||
// .a => .seta,
|
||||
// .ae => .setae,
|
||||
// .b => .setb,
|
||||
// .be => .setbe,
|
||||
// .c => .setc,
|
||||
// .e => .sete,
|
||||
// .g => .setg,
|
||||
// .ge => .setge,
|
||||
// .l => .setl,
|
||||
// .le => .setle,
|
||||
// .na => .setna,
|
||||
// .nae => .setnae,
|
||||
// .nb => .setnb,
|
||||
// .nbe => .setnbe,
|
||||
// .nc => .setnc,
|
||||
// .ne => .setne,
|
||||
// .ng => .setng,
|
||||
// .nge => .setnge,
|
||||
// .nl => .setnl,
|
||||
// .nle => .setnle,
|
||||
// .no => .setno,
|
||||
// .np => .setnp,
|
||||
// .ns => .setns,
|
||||
// .nz => .setnz,
|
||||
// .o => .seto,
|
||||
// .p => .setp,
|
||||
// .pe => .setpe,
|
||||
// .po => .setpo,
|
||||
// .s => .sets,
|
||||
// .z => .setz,
|
||||
// };
|
||||
// return emit.encode(mnemonic, .{ .op1 = .{ .reg = ops.reg1 } });
|
||||
// }
|
||||
|
||||
// fn mirCondMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
// const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
// assert(tag == .cond_mov);
|
||||
// const ops = emit.mir.instructions.items(.ops)[inst].decode();
|
||||
// const cc = emit.mir.instructions.items(.data)[inst].cc;
|
||||
// const mnemonic: Instruction.Mnemonic = switch (cc) {
|
||||
// .a => .cmova,
|
||||
// .ae => .cmovae,
|
||||
// .b => .cmovb,
|
||||
// .be => .cmovbe,
|
||||
// .c => .cmovc,
|
||||
// .e => .cmove,
|
||||
// .g => .cmovg,
|
||||
// .ge => .cmovge,
|
||||
// .l => .cmovl,
|
||||
// .le => .cmovle,
|
||||
// .na => .cmovna,
|
||||
// .nae => .cmovnae,
|
||||
// .nb => .cmovnb,
|
||||
// .nbe => .cmovnbe,
|
||||
// .nc => .cmovnc,
|
||||
// .ne => .cmovne,
|
||||
// .ng => .cmovng,
|
||||
// .nge => .cmovnge,
|
||||
// .nl => .cmovnl,
|
||||
// .nle => .cmovnle,
|
||||
// .no => .cmovno,
|
||||
// .np => .cmovnp,
|
||||
// .ns => .cmovns,
|
||||
// .nz => .cmovnz,
|
||||
// .o => .cmovo,
|
||||
// .p => .cmovp,
|
||||
// .pe => .cmovpe,
|
||||
// .po => .cmovpo,
|
||||
// .s => .cmovs,
|
||||
// .z => .cmovz,
|
||||
// };
|
||||
// const op1: Instruction.Operand = .{ .reg = ops.reg1 };
|
||||
|
||||
// if (ops.flags == 0b00) {
|
||||
// return emit.encode(mnemonic, .{
|
||||
// .op1 = op1,
|
||||
// .op2 = .{ .reg = ops.reg2 },
|
||||
// });
|
||||
// }
|
||||
// const disp = emit.mir.instructions.items(.data)[inst].disp;
|
||||
// const ptr_size: Memory.PtrSize = switch (ops.flags) {
|
||||
// 0b00 => unreachable,
|
||||
// 0b01 => .word,
|
||||
// 0b10 => .dword,
|
||||
// 0b11 => .qword,
|
||||
// };
|
||||
// return emit.encode(mnemonic, .{
|
||||
// .op1 = op1,
|
||||
// .op2 = .{ .mem = Memory.sib(ptr_size, .{
|
||||
// .base = ops.reg2,
|
||||
// .disp = disp,
|
||||
// }) },
|
||||
// });
|
||||
// }
|
||||
|
||||
// fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
// const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
// assert(tag == .lea);
|
||||
|
||||
@ -56,8 +56,6 @@ pub const Inst = struct {
|
||||
cqo,
|
||||
/// Logical compare
|
||||
cmp,
|
||||
/// Conditional move
|
||||
cmovcc,
|
||||
/// Unsigned division
|
||||
div,
|
||||
/// Store integer with truncation
|
||||
@ -134,6 +132,9 @@ pub const Inst = struct {
|
||||
/// Unordered compare scalar double-precision floating-point values
|
||||
ucomisd,
|
||||
|
||||
/// Conditional move
|
||||
cmovcc,
|
||||
|
||||
/// End of prologue
|
||||
dbg_prologue_end,
|
||||
/// Start of epilogue
|
||||
@ -161,6 +162,12 @@ pub const Inst = struct {
|
||||
/// Register, register, register operands.
|
||||
/// Uses `rrr` payload.
|
||||
rrr,
|
||||
/// Register with condition code (CC).
|
||||
/// Uses `r_c` payload.
|
||||
r_c,
|
||||
/// Register, register with condition code (CC).
|
||||
/// Uses `rr_c` payload.
|
||||
rr_c,
|
||||
/// Register, immediate (sign-extended) operands.
|
||||
/// Uses `ri_s` payload.
|
||||
ri_s,
|
||||
@ -241,6 +248,17 @@ pub const Inst = struct {
|
||||
r2: Register,
|
||||
r3: Register,
|
||||
},
|
||||
/// Register with condition code (CC).
|
||||
r_c: struct {
|
||||
r1: Register,
|
||||
cc: bits.Condition,
|
||||
},
|
||||
/// Register, register with condition code (CC).
|
||||
rr_c: struct {
|
||||
r1: Register,
|
||||
r2: Register,
|
||||
cc: bits.Condition,
|
||||
},
|
||||
/// Register, signed immediate.
|
||||
ri_s: struct {
|
||||
r1: Register,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user