Skip to content

[X86] Support APX CMOV/CFCMOV instructions #82592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4068,7 +4068,7 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {

if (UseApxExtendedReg && !X86II::canUseApxExtendedReg(MCID))
return Match_Unsupported;
if (ForcedNoFlag != !!(MCID.TSFlags & X86II::EVEX_NF))
if (ForcedNoFlag == !(MCID.TSFlags & X86II::EVEX_NF) && !X86::isCFCMOVCC(Opc))
return Match_Unsupported;

if (ForcedVEXEncoding == VEXEncoding_EVEX &&
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,14 @@ enum : uint64_t {
/// PrefixByte - This form is used for instructions that represent a prefix
/// byte like data16 or rep.
PrefixByte = 10,
/// MRMDestRegCC - This form is used for the cfcmov instructions, which use
/// the Mod/RM byte to specify the operands reg(r/m) and reg(reg) and also
/// encodes a condition code.
MRMDestRegCC = 18,
/// MRMDestMemCC - This form is used for the cfcmov instructions, which use
/// the Mod/RM byte to specify the operands mem(r/m) and reg(reg) and also
/// encodes a condition code.
MRMDestMemCC = 19,
/// MRMDestMem4VOp3CC - This form is used for instructions that use the Mod/RM
/// byte to specify a destination which in this case is memory and operand 3
/// with VEX.VVVV, and also encodes a condition code.
Expand Down Expand Up @@ -1032,6 +1040,7 @@ inline int getMemoryOperandNo(uint64_t TSFlags) {
return -1;
case X86II::MRMDestMem:
case X86II::MRMDestMemFSIB:
case X86II::MRMDestMemCC:
return hasNewDataDest(TSFlags);
case X86II::MRMSrcMem:
case X86II::MRMSrcMemFSIB:
Expand All @@ -1045,11 +1054,13 @@ inline int getMemoryOperandNo(uint64_t TSFlags) {
// Skip registers encoded in reg, VEX_VVVV, and I8IMM.
return 3;
case X86II::MRMSrcMemCC:
return 1 + hasNewDataDest(TSFlags);
case X86II::MRMDestMem4VOp3CC:
// Start from 1, skip any registers encoded in VEX_VVVV or I8IMM, or a
// mask register.
return 1;
case X86II::MRMDestReg:
case X86II::MRMDestRegCC:
case X86II::MRMSrcReg:
case X86II::MRMSrcReg4VOp3:
case X86II::MRMSrcRegOp4:
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ void X86InstPrinterCommon::printInstFlags(const MCInst *MI, raw_ostream &O,
else if (Flags & X86::IP_HAS_REPEAT)
O << "\trep\t";

if (TSFlags & X86II::EVEX_NF)
if (TSFlags & X86II::EVEX_NF && !X86::isCFCMOVCC(MI->getOpcode()))
O << "\t{nf}";

// These all require a pseudo prefix
Expand Down
27 changes: 27 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
case X86II::MRM_C0:
case X86II::RawFrm:
break;
case X86II::MRMDestMemCC:
case X86II::MRMDestMemFSIB:
case X86II::MRMDestMem: {
// MRMDestMem instructions forms:
Expand Down Expand Up @@ -1102,6 +1103,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
}
break;
}
case X86II::MRMSrcMemCC:
case X86II::MRMSrcMemFSIB:
case X86II::MRMSrcMem: {
// MRMSrcMem instructions forms:
Expand Down Expand Up @@ -1180,6 +1182,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
}
break;
}
case X86II::MRMSrcRegCC:
case X86II::MRMSrcReg: {
// MRMSrcReg instructions forms:
// dst(ModR/M), src1(VEX_4V), src2(ModR/M), src3(Imm[7:4])
Expand Down Expand Up @@ -1242,6 +1245,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
++CurOp;
break;
}
case X86II::MRMDestRegCC:
case X86II::MRMDestReg: {
// MRMDestReg instructions forms:
// dst(ModR/M), src(ModR/M)
Expand Down Expand Up @@ -1638,6 +1642,15 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
CurOp = SrcRegNum + 1;
break;
}
case X86II::MRMDestRegCC: {
unsigned FirstOp = CurOp++;
unsigned SecondOp = CurOp++;
unsigned CC = MI.getOperand(CurOp++).getImm();
emitByte(BaseOpcode + CC, CB);
emitRegModRMByte(MI.getOperand(FirstOp),
getX86RegNum(MI.getOperand(SecondOp)), CB);
break;
}
case X86II::MRMDestMem4VOp3CC: {
unsigned CC = MI.getOperand(8).getImm();
emitByte(BaseOpcode + CC, CB);
Expand Down Expand Up @@ -1667,6 +1680,16 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
CurOp = SrcRegNum + 1;
break;
}
case X86II::MRMDestMemCC: {
unsigned MemOp = CurOp;
CurOp = MemOp + X86::AddrNumOperands;
unsigned RegOp = CurOp++;
unsigned CC = MI.getOperand(CurOp++).getImm();
emitByte(BaseOpcode + CC, CB);
emitMemModRMByte(MI, MemOp, getX86RegNum(MI.getOperand(RegOp)), TSFlags,
Kind, StartByte, CB, Fixups, STI);
break;
}
case X86II::MRMSrcReg: {
emitByte(BaseOpcode, CB);
unsigned SrcRegNum = CurOp + 1;
Expand Down Expand Up @@ -1717,6 +1740,8 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
break;
}
case X86II::MRMSrcRegCC: {
if (IsND) // Skip new data destination
++CurOp;
unsigned FirstOp = CurOp++;
unsigned SecondOp = CurOp++;

Expand Down Expand Up @@ -1778,6 +1803,8 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
break;
}
case X86II::MRMSrcMemCC: {
if (IsND) // Skip new data destination
++CurOp;
unsigned RegOp = CurOp++;
unsigned FirstMemOp = CurOp;
CurOp = FirstMemOp + X86::AddrNumOperands;
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/X86/X86FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,7 +2133,8 @@ bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
return false;

const TargetRegisterInfo &TRI = *Subtarget->getRegisterInfo();
unsigned Opc = X86::getCMovOpcode(TRI.getRegSizeInBits(*RC)/8);
unsigned Opc = X86::getCMovOpcode(TRI.getRegSizeInBits(*RC) / 8, false,
Subtarget->hasNDD());
Register ResultReg = fastEmitInst_rri(Opc, RC, RHSReg, LHSReg, CC);
updateValueMap(I, ResultReg);
return true;
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/Target/X86/X86FlagsCopyLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,8 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
}

// Otherwise we can just rewrite in-place.
if (X86::getCondFromCMov(MI) != X86::COND_INVALID) {
if (X86::getCondFromCMov(MI) != X86::COND_INVALID ||
X86::getCondFromCFCMov(MI) != X86::COND_INVALID) {
rewriteCMov(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
} else if (getCondFromFCMOV(MI.getOpcode()) != X86::COND_INVALID) {
rewriteFCMov(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
Expand Down Expand Up @@ -829,7 +830,9 @@ void X86FlagsCopyLoweringPass::rewriteCMov(MachineBasicBlock &TestMBB,
MachineOperand &FlagUse,
CondRegArray &CondRegs) {
// First get the register containing this specific condition.
X86::CondCode Cond = X86::getCondFromCMov(CMovI);
X86::CondCode Cond = X86::getCondFromCMov(CMovI) == X86::COND_INVALID
? X86::getCondFromCFCMov(CMovI)
: X86::getCondFromCMov(CMovI);
unsigned CondReg;
bool Inverted;
std::tie(CondReg, Inverted) =
Expand Down
71 changes: 71 additions & 0 deletions llvm/lib/Target/X86/X86InstrAsmAlias.td
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,12 @@ defm : IntegerCondCodeMnemonicAlias<"cmov", "q", "att">;
// No size suffix for intel-style asm.
defm : IntegerCondCodeMnemonicAlias<"cmov", "", "intel">;

// Aliases for cfcmov<CC>{w,l,q}
defm : IntegerCondCodeMnemonicAlias<"cfcmov", "w", "att">;
defm : IntegerCondCodeMnemonicAlias<"cfcmov", "l", "att">;
defm : IntegerCondCodeMnemonicAlias<"cfcmov", "q", "att">;
// No size suffix for intel-style asm.
defm : IntegerCondCodeMnemonicAlias<"cfcmov", "", "intel">;
//===----------------------------------------------------------------------===//
// Assembler Instruction Aliases
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -768,6 +774,20 @@ multiclass CMOV_SETCC_Aliases<string Cond, int CC> {
(CMOV64rr GR64:$dst, GR64:$src, CC), 0>;
def : InstAlias<"cmov"#Cond#"{q}\t{$src, $dst|$dst, $src}",
(CMOV64rm GR64:$dst, i64mem:$src, CC), 0>;
let Predicates = [In64BitMode] in {
def : InstAlias<"cmov"#Cond#"{w}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV16rr_ND GR16:$dst, GR16:$src1, GR16:$src2, CC), 0>;
def : InstAlias<"cmov"#Cond#"{w}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV16rm_ND GR16:$dst, GR16:$src1, i16mem:$src2, CC), 0>;
def : InstAlias<"cmov"#Cond#"{l}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV32rr_ND GR32:$dst, GR32:$src1, GR32:$src2, CC), 0>;
def : InstAlias<"cmov"#Cond#"{l}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV32rm_ND GR32:$dst, GR32:$src1, i32mem:$src2, CC), 0>;
def : InstAlias<"cmov"#Cond#"{q}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV64rr_ND GR64:$dst, GR64:$src1, GR64:$src2, CC), 0>;
def : InstAlias<"cmov"#Cond#"{q}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CMOV64rm_ND GR64:$dst, GR64:$src1, i64mem:$src2, CC), 0>;
}

def : InstAlias<"set"#Cond#"\t$dst", (SETCCr GR8:$dst, CC), 0>;
def : InstAlias<"set"#Cond#"\t$dst", (SETCCm i8mem:$dst, CC), 0>;
Expand All @@ -790,6 +810,57 @@ defm : CMOV_SETCC_Aliases<"ge", 13>;
defm : CMOV_SETCC_Aliases<"le", 14>;
defm : CMOV_SETCC_Aliases<"g" , 15>;

multiclass CFCMOV_Aliases<string Cond, int CC> {
let Predicates = [In64BitMode] in {
def : InstAlias<"cfcmov"#Cond#"{w}\t{$src, $dst|$dst, $src}",
(CFCMOV16rr GR16:$dst, GR16:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{l}\t{$src, $dst|$dst, $src}",
(CFCMOV32rr GR32:$dst, GR32:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{q}\t{$src, $dst|$dst, $src}",
(CFCMOV64rr GR64:$dst, GR64:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{w}\t{$src, $dst|$dst, $src}",
(CFCMOV16rm GR16:$dst, i16mem:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{l}\t{$src, $dst|$dst, $src}",
(CFCMOV32rm GR32:$dst, i32mem:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{q}\t{$src, $dst|$dst, $src}",
(CFCMOV64rm GR64:$dst, i64mem:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{w}\t{$src, $dst|$dst, $src}",
(CFCMOV16mr i16mem:$dst, GR16:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{l}\t{$src, $dst|$dst, $src}",
(CFCMOV32mr i32mem:$dst, GR32:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{q}\t{$src, $dst|$dst, $src}",
(CFCMOV64mr i64mem:$dst, GR64:$src, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{w}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV16rr_ND GR16:$dst, GR16:$src1, GR16:$src2, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{l}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV32rr_ND GR32:$dst, GR32:$src1, GR32:$src2, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{q}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV64rr_ND GR64:$dst, GR64:$src1, GR64:$src2, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{w}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV16rm_ND GR16:$dst, GR16:$src1, i16mem:$src2, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{l}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV32rm_ND GR32:$dst, GR32:$src1, i32mem:$src2, CC), 0>;
def : InstAlias<"cfcmov"#Cond#"{q}\t{$src2, $src1, $dst|$dst, $src1, $src2}",
(CFCMOV64rm_ND GR64:$dst, GR64:$src1, i64mem:$src2, CC), 0>;
}
}
defm : CFCMOV_Aliases<"o" , 0>;
defm : CFCMOV_Aliases<"no", 1>;
defm : CFCMOV_Aliases<"b" , 2>;
defm : CFCMOV_Aliases<"ae", 3>;
defm : CFCMOV_Aliases<"e" , 4>;
defm : CFCMOV_Aliases<"ne", 5>;
defm : CFCMOV_Aliases<"be", 6>;
defm : CFCMOV_Aliases<"a" , 7>;
defm : CFCMOV_Aliases<"s" , 8>;
defm : CFCMOV_Aliases<"ns", 9>;
defm : CFCMOV_Aliases<"p" , 10>;
defm : CFCMOV_Aliases<"np", 11>;
defm : CFCMOV_Aliases<"l" , 12>;
defm : CFCMOV_Aliases<"ge", 13>;
defm : CFCMOV_Aliases<"le", 14>;
defm : CFCMOV_Aliases<"g" , 15>;

// Condition dump instructions Alias
def : InstAlias<"jo\t$dst", (JCC_1 brtarget8:$dst, 0), 0>;
def : InstAlias<"jno\t$dst", (JCC_1 brtarget8:$dst, 1), 0>;
Expand Down
Loading