Skip to content

Commit

Permalink
[X86] Merge the different CMOV instructions for each condition code i…
Browse files Browse the repository at this point in the history
…nto single instructions that store the condition code as an immediate.

Summary:
Reorder the condition code enum to match their encodings. Move it to MC layer so it can be used by the scheduler models.

This avoids needing an isel pattern for each condition code. And it removes
translation switches for converting between CMOV instructions and condition
codes.

Now the printer, encoder and disassembler take care of converting the immediate.
We use InstAliases to handle the assembly matching. But we print using the
asm string in the instruction definition. The instruction itself is marked
IsCodeGenOnly=1 to hide it from the assembly parser.

This does complicate the scheduler models a little since we can't assign the
A and BE instructions to a separate class now.

I plan to make similar changes for SETcc and Jcc.

Reviewers: RKSimon, spatel, lebedev.ri, andreadb, courbet

Reviewed By: RKSimon

Subscribers: gchatelet, hiraditya, kristina, lebedev.ri, jdoerfert, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D60041

llvm-svn: 357800
  • Loading branch information
topperc committed Apr 5, 2019
1 parent 4af5d74 commit e0bfeb5
Show file tree
Hide file tree
Showing 40 changed files with 531 additions and 469 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ enum ModRMDecisionType {
ENUM_ENTRY(ENCODING_IRC, "Immediate for static rounding control") \
ENUM_ENTRY(ENCODING_Rv, "Register code of operand size added to the " \
"opcode byte") \
ENUM_ENTRY(ENCODING_CC, "Condition code encoded in opcode") \
ENUM_ENTRY(ENCODING_DUP, "Duplicate of another operand; ID is encoded " \
"in type") \
ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") \
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,9 @@ static bool translateOperand(MCInst &mcInst, const OperandSpecifier &operand,
case ENCODING_Rv:
translateRegister(mcInst, insn.opcodeRegister);
return false;
case ENCODING_CC:
mcInst.addOperand(MCOperand::createImm(insn.immediates[0]));
return false;
case ENCODING_FP:
translateFPRegister(mcInst, insn.modRM & 7);
return false;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,9 @@ static int readOperands(struct InternalInstruction* insn) {
if (readOpcodeRegister(insn, 0))
return -1;
break;
case ENCODING_CC:
insn->immediates[0] = insn->opcode & 0xf;
break;
case ENCODING_FP:
break;
case ENCODING_VVVV:
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/Target/X86/InstPrinter/X86InstPrinterCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@

using namespace llvm;

void X86InstPrinterCommon::printCondCode(const MCInst *MI, unsigned Op,
raw_ostream &O) {
int64_t Imm = MI->getOperand(Op).getImm();
switch (Imm) {
default: llvm_unreachable("Invalid condcode argument!");
case 0: O << "o"; break;
case 1: O << "no"; break;
case 2: O << "b"; break;
case 3: O << "ae"; break;
case 4: O << "e"; break;
case 5: O << "ne"; break;
case 6: O << "be"; break;
case 7: O << "a"; break;
case 8: O << "s"; break;
case 9: O << "ns"; break;
case 0xa: O << "p"; break;
case 0xb: O << "np"; break;
case 0xc: O << "l"; break;
case 0xd: O << "ge"; break;
case 0xe: O << "le"; break;
case 0xf: O << "g"; break;
}
}

void X86InstPrinterCommon::printSSEAVXCC(const MCInst *MI, unsigned Op,
raw_ostream &O) {
int64_t Imm = MI->getOperand(Op).getImm();
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/InstPrinter/X86InstPrinterCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class X86InstPrinterCommon : public MCInstPrinter {
using MCInstPrinter::MCInstPrinter;

virtual void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) = 0;
void printCondCode(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printSSEAVXCC(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printVPCOMMnemonic(const MCInst *MI, raw_ostream &OS);
void printVPCMPMnemonic(const MCInst *MI, raw_ostream &OS);
Expand Down
48 changes: 48 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,39 @@ namespace X86 {
enum OperandType : unsigned {
/// AVX512 embedded rounding control. This should only have values 0-3.
OPERAND_ROUNDING_CONTROL = MCOI::OPERAND_FIRST_TARGET,
OPERAND_COND_CODE,
};

// X86 specific condition code. These correspond to X86_*_COND in
// X86InstrInfo.td. They must be kept in synch.
enum CondCode {
COND_O = 0,
COND_NO = 1,
COND_B = 2,
COND_AE = 3,
COND_E = 4,
COND_NE = 5,
COND_BE = 6,
COND_A = 7,
COND_S = 8,
COND_NS = 9,
COND_P = 10,
COND_NP = 11,
COND_L = 12,
COND_GE = 13,
COND_LE = 14,
COND_G = 15,
LAST_VALID_COND = COND_G,

// Artificial condition codes. These are used by AnalyzeBranch
// to indicate a block terminated with two conditional branches that together
// form a compound condition. They occur in code using FCMP_OEQ or FCMP_UNE,
// which can't be represented on x86 with a single condition. These
// are never used in MachineInstrs and are inverses of one another.
COND_NE_OR_P,
COND_E_AND_NP,

COND_INVALID
};
} // end namespace X86;

Expand Down Expand Up @@ -313,6 +346,11 @@ namespace X86II {
///
MRMSrcMemOp4 = 35,

/// MRMSrcMemCC - This form is used for instructions that use the Mod/RM
/// byte to specify the operands and also encodes a condition code.
///
MRMSrcMemCC = 36,

/// MRMXm - This form is used for instructions that use the Mod/RM byte
/// to specify a memory source, but doesn't use the middle field.
///
Expand Down Expand Up @@ -342,6 +380,11 @@ namespace X86II {
///
MRMSrcRegOp4 = 51,

/// MRMSrcRegCC - This form is used for instructions that use the Mod/RM
/// byte to specify the operands and also encodes a condition code
///
MRMSrcRegCC = 52,

/// MRMXr - This form is used for instructions that use the Mod/RM byte
/// to specify a register source, but doesn't use the middle field.
///
Expand Down Expand Up @@ -727,10 +770,15 @@ namespace X86II {
case X86II::MRMSrcMemOp4:
// Skip registers encoded in reg, VEX_VVVV, and I8IMM.
return 3;
case X86II::MRMSrcMemCC:
// Start from 1, skip any registers encoded in VEX_VVVV or I8IMM, or a
// mask register.
return 1;
case X86II::MRMDestReg:
case X86II::MRMSrcReg:
case X86II::MRMSrcReg4VOp3:
case X86II::MRMSrcRegOp4:
case X86II::MRMSrcRegCC:
case X86II::MRMXr:
case X86II::MRM0r: case X86II::MRM1r:
case X86II::MRM2r: case X86II::MRM3r:
Expand Down
28 changes: 26 additions & 2 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,16 +1060,17 @@ uint8_t X86MCCodeEmitter::DetermineREXPrefix(const MCInst &MI, uint64_t TSFlags,
REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
break;
case X86II::MRMSrcReg:
case X86II::MRMSrcRegCC:
REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
break;
case X86II::MRMSrcMem: {
case X86II::MRMSrcMem:
case X86II::MRMSrcMemCC:
REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
REX |= isREXExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
REX |= isREXExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
CurOp += X86::AddrNumOperands;
break;
}
case X86II::MRMDestReg:
REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
Expand Down Expand Up @@ -1436,6 +1437,17 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
CurOp = SrcRegNum + 1;
break;
}
case X86II::MRMSrcRegCC: {
unsigned FirstOp = CurOp++;
unsigned SecondOp = CurOp++;

unsigned CC = MI.getOperand(CurOp++).getImm();
EmitByte(BaseOpcode + CC, CurByte, OS);

EmitRegModRMByte(MI.getOperand(SecondOp),
GetX86RegNum(MI.getOperand(FirstOp)), CurByte, OS);
break;
}
case X86II::MRMSrcMem: {
unsigned FirstMemOp = CurOp+1;

Expand Down Expand Up @@ -1481,6 +1493,18 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
CurOp = FirstMemOp + X86::AddrNumOperands;
break;
}
case X86II::MRMSrcMemCC: {
unsigned RegOp = CurOp++;
unsigned FirstMemOp = CurOp;
CurOp = FirstMemOp + X86::AddrNumOperands;

unsigned CC = MI.getOperand(CurOp++).getImm();
EmitByte(BaseOpcode + CC, CurByte, OS);

emitMemModRMByte(MI, FirstMemOp, GetX86RegNum(MI.getOperand(RegOp)),
TSFlags, Rex, CurByte, OS, Fixups, STI);
break;
}

case X86II::MRMXr:
case X86II::MRM0r: case X86II::MRM1r:
Expand Down
19 changes: 9 additions & 10 deletions llvm/lib/Target/X86/X86CmovConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ bool X86CmovConverterPass::collectCmovCandidates(
// Skip debug instructions.
if (I.isDebugInstr())
continue;
X86::CondCode CC = X86::getCondFromCMovOpc(I.getOpcode());
X86::CondCode CC = X86::getCondFromCMov(I);
// Check if we found a X86::CMOVrr instruction.
if (CC != X86::COND_INVALID && (IncludeLoads || !I.mayLoad())) {
if (Group.empty()) {
Expand Down Expand Up @@ -545,7 +545,7 @@ bool X86CmovConverterPass::checkForProfitableCmovCandidates(
}

unsigned CondCost =
DepthMap[OperandToDefMap.lookup(&MI->getOperand(3))].Depth;
DepthMap[OperandToDefMap.lookup(&MI->getOperand(4))].Depth;
unsigned ValCost = getDepthOfOptCmov(
DepthMap[OperandToDefMap.lookup(&MI->getOperand(1))].Depth,
DepthMap[OperandToDefMap.lookup(&MI->getOperand(2))].Depth);
Expand Down Expand Up @@ -593,7 +593,7 @@ static bool checkEFLAGSLive(MachineInstr *MI) {
/// move all debug instructions to after the last CMOV instruction, making the
/// CMOV group consecutive.
static void packCmovGroup(MachineInstr *First, MachineInstr *Last) {
assert(X86::getCondFromCMovOpc(Last->getOpcode()) != X86::COND_INVALID &&
assert(X86::getCondFromCMov(*Last) != X86::COND_INVALID &&
"Last instruction in a CMOV group must be a CMOV instruction");

SmallVector<MachineInstr *, 2> DBGInstructions;
Expand Down Expand Up @@ -651,14 +651,14 @@ void X86CmovConverterPass::convertCmovInstsToBranches(
MachineInstr *LastCMOV = Group.back();
DebugLoc DL = MI.getDebugLoc();

X86::CondCode CC = X86::CondCode(X86::getCondFromCMovOpc(MI.getOpcode()));
X86::CondCode CC = X86::CondCode(X86::getCondFromCMov(MI));
X86::CondCode OppCC = X86::GetOppositeBranchCondition(CC);
// Potentially swap the condition codes so that any memory operand to a CMOV
// is in the *false* position instead of the *true* position. We can invert
// any non-memory operand CMOV instructions to cope with this and we ensure
// memory operand CMOVs are only included with a single condition code.
if (llvm::any_of(Group, [&](MachineInstr *I) {
return I->mayLoad() && X86::getCondFromCMovOpc(I->getOpcode()) == CC;
return I->mayLoad() && X86::getCondFromCMov(*I) == CC;
}))
std::swap(CC, OppCC);

Expand Down Expand Up @@ -712,8 +712,7 @@ void X86CmovConverterPass::convertCmovInstsToBranches(
if (!MI.mayLoad()) {
// Remember the false-side register input.
unsigned FalseReg =
MI.getOperand(X86::getCondFromCMovOpc(MI.getOpcode()) == CC ? 1 : 2)
.getReg();
MI.getOperand(X86::getCondFromCMov(MI) == CC ? 1 : 2).getReg();
// Walk back through any intermediate cmovs referenced.
while (true) {
auto FRIt = FalseBBRegRewriteTable.find(FalseReg);
Expand All @@ -728,7 +727,7 @@ void X86CmovConverterPass::convertCmovInstsToBranches(
// The condition must be the *opposite* of the one we've decided to branch
// on as the branch will go *around* the load and the load should happen
// when the CMOV condition is false.
assert(X86::getCondFromCMovOpc(MI.getOpcode()) == OppCC &&
assert(X86::getCondFromCMov(MI) == OppCC &&
"Can only handle memory-operand cmov instructions with a condition "
"opposite to the selected branch direction.");

Expand Down Expand Up @@ -767,7 +766,7 @@ void X86CmovConverterPass::convertCmovInstsToBranches(
// Move the new CMOV to just before the old one and reset any impacted
// iterator.
auto *NewCMOV = NewMIs.pop_back_val();
assert(X86::getCondFromCMovOpc(NewCMOV->getOpcode()) == OppCC &&
assert(X86::getCondFromCMov(*NewCMOV) == OppCC &&
"Last new instruction isn't the expected CMOV!");
LLVM_DEBUG(dbgs() << "\tRewritten cmov: "; NewCMOV->dump());
MBB->insert(MachineBasicBlock::iterator(MI), NewCMOV);
Expand Down Expand Up @@ -819,7 +818,7 @@ void X86CmovConverterPass::convertCmovInstsToBranches(
// If this CMOV we are processing is the opposite condition from the jump we
// generated, then we have to swap the operands for the PHI that is going to
// be generated.
if (X86::getCondFromCMovOpc(MIIt->getOpcode()) == OppCC)
if (X86::getCondFromCMov(*MIIt) == OppCC)
std::swap(Op1Reg, Op2Reg);

auto Op1Itr = RegRewriteTable.find(Op1Reg);
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/X86/X86FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2144,9 +2144,9 @@ bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
return false;

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

// Otherwise we can just rewrite in-place.
if (X86::getCondFromCMovOpc(MI.getOpcode()) != X86::COND_INVALID) {
if (X86::getCondFromCMov(MI) != X86::COND_INVALID) {
rewriteCMov(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
} else if (X86::getCondFromSETOpc(MI.getOpcode()) !=
X86::COND_INVALID) {
Expand Down Expand Up @@ -841,7 +841,7 @@ void X86FlagsCopyLoweringPass::rewriteCMov(MachineBasicBlock &TestMBB,
MachineOperand &FlagUse,
CondRegArray &CondRegs) {
// First get the register containing this specific condition.
X86::CondCode Cond = X86::getCondFromCMovOpc(CMovI.getOpcode());
X86::CondCode Cond = X86::getCondFromCMov(CMovI);
unsigned CondReg;
bool Inverted;
std::tie(CondReg, Inverted) =
Expand All @@ -852,12 +852,10 @@ void X86FlagsCopyLoweringPass::rewriteCMov(MachineBasicBlock &TestMBB,
// Insert a direct test of the saved register.
insertTest(MBB, CMovI.getIterator(), CMovI.getDebugLoc(), CondReg);

// Rewrite the CMov to use the !ZF flag from the test (but match register
// size and memory operand), and then kill its use of the flags afterward.
auto &CMovRC = *MRI->getRegClass(CMovI.getOperand(0).getReg());
CMovI.setDesc(TII->get(X86::getCMovFromCond(
Inverted ? X86::COND_E : X86::COND_NE, TRI->getRegSizeInBits(CMovRC) / 8,
!CMovI.memoperands_empty())));
// Rewrite the CMov to use the !ZF flag from the test, and then kill its use
// of the flags afterward.
CMovI.getOperand(CMovI.getDesc().getNumOperands() - 1)
.setImm(Inverted ? X86::COND_E : X86::COND_NE);
FlagUse.setIsKill(true);
LLVM_DEBUG(dbgs() << " fixed cmov: "; CMovI.dump());
}
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/X86/X86FrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,10 @@ void X86FrameLowering::emitStackProbeInline(MachineFunction &MF,
BuildMI(&MBB, DL, TII.get(X86::SUB64rr), TestReg)
.addReg(CopyReg)
.addReg(SizeReg);
BuildMI(&MBB, DL, TII.get(X86::CMOVB64rr), FinalReg)
BuildMI(&MBB, DL, TII.get(X86::CMOV64rr), FinalReg)
.addReg(TestReg)
.addReg(ZeroReg);
.addReg(ZeroReg)
.addImm(X86::COND_B);

// FinalReg now holds final stack pointer value, or zero if
// allocation would overflow. Compare against the current stack
Expand Down
23 changes: 15 additions & 8 deletions llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2321,14 +2321,21 @@ bool X86DAGToDAGISel::isSExtAbsoluteSymbolRef(unsigned Width, SDNode *N) const {
CR->getSignedMax().slt(1ull << Width);
}

static X86::CondCode getCondFromOpc(unsigned Opc) {
static X86::CondCode getCondFromNode(SDNode *N) {
assert(N->isMachineOpcode() && "Unexpected node");
X86::CondCode CC = X86::COND_INVALID;
if (CC == X86::COND_INVALID)
CC = X86::getCondFromBranchOpc(Opc);
CC = X86::getCondFromBranchOpc(N->getMachineOpcode());
if (CC == X86::COND_INVALID)
CC = X86::getCondFromSETOpc(Opc);
if (CC == X86::COND_INVALID)
CC = X86::getCondFromCMovOpc(Opc);
CC = X86::getCondFromSETOpc(N->getMachineOpcode());
if (CC == X86::COND_INVALID) {
unsigned Opc = N->getMachineOpcode();
if (Opc == X86::CMOV16rr || Opc == X86::CMOV32rr || Opc == X86::CMOV64rr)
CC = static_cast<X86::CondCode>(N->getConstantOperandVal(2));
else if (Opc == X86::CMOV16rm || Opc == X86::CMOV32rm ||
Opc == X86::CMOV64rm)
CC = static_cast<X86::CondCode>(N->getConstantOperandVal(6));
}

return CC;
}
Expand All @@ -2354,7 +2361,7 @@ bool X86DAGToDAGISel::onlyUsesZeroFlag(SDValue Flags) const {
// Anything unusual: assume conservatively.
if (!FlagUI->isMachineOpcode()) return false;
// Examine the condition code of the user.
X86::CondCode CC = getCondFromOpc(FlagUI->getMachineOpcode());
X86::CondCode CC = getCondFromNode(*FlagUI);

switch (CC) {
// Comparisons which only use the zero flag.
Expand Down Expand Up @@ -2390,7 +2397,7 @@ bool X86DAGToDAGISel::hasNoSignFlagUses(SDValue Flags) const {
// Anything unusual: assume conservatively.
if (!FlagUI->isMachineOpcode()) return false;
// Examine the condition code of the user.
X86::CondCode CC = getCondFromOpc(FlagUI->getMachineOpcode());
X86::CondCode CC = getCondFromNode(*FlagUI);

switch (CC) {
// Comparisons which don't examine the SF flag.
Expand Down Expand Up @@ -2451,7 +2458,7 @@ static bool mayUseCarryFlag(X86::CondCode CC) {
if (!FlagUI->isMachineOpcode())
return false;
// Examine the condition code of the user.
X86::CondCode CC = getCondFromOpc(FlagUI->getMachineOpcode());
X86::CondCode CC = getCondFromNode(*FlagUI);

if (mayUseCarryFlag(CC))
return false;
Expand Down
Loading

0 comments on commit e0bfeb5

Please sign in to comment.