[FastISel][X86] More refactoring of select lowering and XALU folding. NFC.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211740 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Juergen Ributzka
2014-06-25 22:50:59 +00:00
parent dd0966efd4
commit 0956faba3d

View File

@@ -111,11 +111,11 @@ private:
bool X86SelectDivRem(const Instruction *I); bool X86SelectDivRem(const Instruction *I);
bool X86FastEmitCMoveSelect(const Instruction *I); bool X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I);
bool X86FastEmitSSESelect(const Instruction *I); bool X86FastEmitSSESelect(MVT RetVT, const Instruction *I);
bool X86FastEmitPseudoSelect(const Instruction *I); bool X86FastEmitPseudoSelect(MVT RetVT, const Instruction *I);
bool X86SelectSelect(const Instruction *I); bool X86SelectSelect(const Instruction *I);
@@ -158,8 +158,8 @@ private:
bool TryEmitSmallMemcpy(X86AddressMode DestAM, bool TryEmitSmallMemcpy(X86AddressMode DestAM,
X86AddressMode SrcAM, uint64_t Len); X86AddressMode SrcAM, uint64_t Len);
std::pair<bool, X86::CondCode> bool foldX86XALUIntrinsic(X86::CondCode &CC, const Instruction *I,
foldX86XALUIntrinsic(const Instruction *I, const Value *Cond); const Value *Cond);
}; };
} // end anonymous namespace. } // end anonymous namespace.
@@ -278,15 +278,15 @@ getX86SSECondtionCode(CmpInst::Predicate Predicate) {
} }
/// \brief Check if it is possible to fold the condition from the XALU intrinsic /// \brief Check if it is possible to fold the condition from the XALU intrinsic
/// into the user. /// into the user. The condition code will only be updated on success.
std::pair<bool, X86::CondCode> bool X86FastISel::foldX86XALUIntrinsic(X86::CondCode &CC, const Instruction *I,
X86FastISel::foldX86XALUIntrinsic(const Instruction *I, const Value *Cond) { const Value *Cond) {
if (!isa<ExtractValueInst>(Cond)) if (!isa<ExtractValueInst>(Cond))
return std::make_pair(false, X86::COND_INVALID); return false;
const auto *EV = cast<ExtractValueInst>(Cond); const auto *EV = cast<ExtractValueInst>(Cond);
if (!isa<IntrinsicInst>(EV->getAggregateOperand())) if (!isa<IntrinsicInst>(EV->getAggregateOperand()))
return std::make_pair(false, X86::COND_INVALID); return false;
const auto *II = cast<IntrinsicInst>(EV->getAggregateOperand()); const auto *II = cast<IntrinsicInst>(EV->getAggregateOperand());
MVT RetVT; MVT RetVT;
@@ -294,25 +294,25 @@ X86FastISel::foldX86XALUIntrinsic(const Instruction *I, const Value *Cond) {
Type *RetTy = Type *RetTy =
cast<StructType>(Callee->getReturnType())->getTypeAtIndex(0U); cast<StructType>(Callee->getReturnType())->getTypeAtIndex(0U);
if (!isTypeLegal(RetTy, RetVT)) if (!isTypeLegal(RetTy, RetVT))
return std::make_pair(false, X86::COND_INVALID); return false;
if (RetVT != MVT::i32 && RetVT != MVT::i64) if (RetVT != MVT::i32 && RetVT != MVT::i64)
return std::make_pair(false, X86::COND_INVALID); return false;
X86::CondCode CC; X86::CondCode TmpCC;
switch (II->getIntrinsicID()) { switch (II->getIntrinsicID()) {
default: return std::make_pair(false, X86::COND_INVALID); default: return false;
case Intrinsic::sadd_with_overflow: case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow: case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow: case Intrinsic::smul_with_overflow:
case Intrinsic::umul_with_overflow: CC = X86::COND_O; break; case Intrinsic::umul_with_overflow: TmpCC = X86::COND_O; break;
case Intrinsic::uadd_with_overflow: case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow: CC = X86::COND_B; break; case Intrinsic::usub_with_overflow: TmpCC = X86::COND_B; break;
} }
// Check if both instructions are in the same basic block. // Check if both instructions are in the same basic block.
if (II->getParent() != I->getParent()) if (II->getParent() != I->getParent())
return std::make_pair(false, X86::COND_INVALID); return false;
// Make sure nothing is in the way // Make sure nothing is in the way
BasicBlock::const_iterator Start = I; BasicBlock::const_iterator Start = I;
@@ -321,15 +321,16 @@ X86FastISel::foldX86XALUIntrinsic(const Instruction *I, const Value *Cond) {
// We only expect extractvalue instructions between the intrinsic and the // We only expect extractvalue instructions between the intrinsic and the
// instruction to be selected. // instruction to be selected.
if (!isa<ExtractValueInst>(Itr)) if (!isa<ExtractValueInst>(Itr))
return std::make_pair(false, X86::COND_INVALID); return false;
// Check that the extractvalue operand comes from the intrinsic. // Check that the extractvalue operand comes from the intrinsic.
const auto *EVI = cast<ExtractValueInst>(Itr); const auto *EVI = cast<ExtractValueInst>(Itr);
if (EVI->getAggregateOperand() != II) if (EVI->getAggregateOperand() != II)
return std::make_pair(false, X86::COND_INVALID); return false;
} }
return std::make_pair(true, CC); CC = TmpCC;
return true;
} }
bool X86FastISel::isTypeLegal(Type *Ty, MVT &VT, bool AllowI1) { bool X86FastISel::isTypeLegal(Type *Ty, MVT &VT, bool AllowI1) {
@@ -1335,6 +1336,7 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
// Fold the common case of a conditional branch with a comparison // Fold the common case of a conditional branch with a comparison
// in the same block (values defined on other blocks may not have // in the same block (values defined on other blocks may not have
// initialized registers). // initialized registers).
X86::CondCode CC;
if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) { if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) {
if (CI->hasOneUse() && CI->getParent() == I->getParent()) { if (CI->hasOneUse() && CI->getParent() == I->getParent()) {
EVT VT = TLI.getValueType(CI->getOperand(0)->getType()); EVT VT = TLI.getValueType(CI->getOperand(0)->getType());
@@ -1382,7 +1384,6 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
break; break;
} }
X86::CondCode CC;
bool SwapArgs; bool SwapArgs;
unsigned BranchOpc; unsigned BranchOpc;
std::tie(CC, SwapArgs) = getX86ConditonCode(Predicate); std::tie(CC, SwapArgs) = getX86ConditonCode(Predicate);
@@ -1456,29 +1457,24 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
return true; return true;
} }
} }
} else { } else if (foldX86XALUIntrinsic(CC, BI, BI->getCondition())) {
bool FoldIntrinsic; // Fake request the condition, otherwise the intrinsic might be completely
X86::CondCode CC; // optimized away.
std::tie(FoldIntrinsic, CC) = foldX86XALUIntrinsic(BI, BI->getCondition()); unsigned TmpReg = getRegForValue(BI->getCondition());
if (FoldIntrinsic) { if (TmpReg == 0)
// Fake request the condition, otherwise the intrinsic might be completely return false;
// optimized away.
unsigned TmpReg = getRegForValue(BI->getCondition());
if (TmpReg == 0)
return false;
unsigned BranchOpc = X86::GetCondBranchFromCond(CC); unsigned BranchOpc = X86::GetCondBranchFromCond(CC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc)) BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc))
.addMBB(TrueMBB); .addMBB(TrueMBB);
FastEmitBranch(FalseMBB, DbgLoc); FastEmitBranch(FalseMBB, DbgLoc);
uint32_t BranchWeight = 0; uint32_t BranchWeight = 0;
if (FuncInfo.BPI) if (FuncInfo.BPI)
BranchWeight = FuncInfo.BPI->getEdgeWeight(BI->getParent(), BranchWeight = FuncInfo.BPI->getEdgeWeight(BI->getParent(),
TrueMBB->getBasicBlock()); TrueMBB->getBasicBlock());
FuncInfo.MBB->addSuccessor(TrueMBB, BranchWeight); FuncInfo.MBB->addSuccessor(TrueMBB, BranchWeight);
return true; return true;
}
} }
// Otherwise do a clumsy setcc and re-test it. // Otherwise do a clumsy setcc and re-test it.
@@ -1735,27 +1731,19 @@ bool X86FastISel::X86SelectDivRem(const Instruction *I) {
/// \brief Emit a conditional move instruction (if the are supported) to lower /// \brief Emit a conditional move instruction (if the are supported) to lower
/// the select. /// the select.
bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) { bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
MVT RetVT;
if (!isTypeLegal(I->getType(), RetVT))
return false;
// Check if the subtarget supports these instructions. // Check if the subtarget supports these instructions.
if (!Subtarget->hasCMov()) if (!Subtarget->hasCMov())
return false; return false;
// FIXME: Add support for i8. // FIXME: Add support for i8.
unsigned Opc; if (RetVT < MVT::i16 || RetVT > MVT::i64)
switch (RetVT.SimpleTy) { return false;
default: return false;
case MVT::i16: Opc = X86::CMOVNE16rr; break;
case MVT::i32: Opc = X86::CMOVNE32rr; break;
case MVT::i64: Opc = X86::CMOVNE64rr; break;
}
const Value *Cond = I->getOperand(0); const Value *Cond = I->getOperand(0);
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT); const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
bool NeedTest = true; bool NeedTest = true;
X86::CondCode CC = X86::COND_NE;
// Optimize conditons coming from a compare if both instructions are in the // Optimize conditons coming from a compare if both instructions are in the
// same basic block (values defined in other basic blocks may not have // same basic block (values defined in other basic blocks may not have
@@ -1782,11 +1770,9 @@ bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) {
break; break;
} }
X86::CondCode CC;
bool NeedSwap; bool NeedSwap;
std::tie(CC, NeedSwap) = getX86ConditonCode(Predicate); std::tie(CC, NeedSwap) = getX86ConditonCode(Predicate);
assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code."); assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code.");
Opc = X86::getCMovFromCond(CC, RC->getSize());
const Value *CmpLHS = CI->getOperand(0); const Value *CmpLHS = CI->getOperand(0);
const Value *CmpRHS = CI->getOperand(1); const Value *CmpRHS = CI->getOperand(1);
@@ -1816,21 +1802,14 @@ bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) {
} }
} }
NeedTest = false; NeedTest = false;
} else { } else if (foldX86XALUIntrinsic(CC, I, Cond)) {
bool FoldIntrinsic; // Fake request the condition, otherwise the intrinsic might be completely
X86::CondCode CC; // optimized away.
std::tie(FoldIntrinsic, CC) = foldX86XALUIntrinsic(I, Cond); unsigned TmpReg = getRegForValue(Cond);
if (TmpReg == 0)
return false;
if (FoldIntrinsic) { NeedTest = false;
// Fake request the condition, otherwise the intrinsic might be completely
// optimized away.
unsigned TmpReg = getRegForValue(Cond);
if (TmpReg == 0)
return false;
Opc = X86::getCMovFromCond(CC, RC->getSize());
NeedTest = false;
}
} }
if (NeedTest) { if (NeedTest) {
@@ -1860,6 +1839,7 @@ bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) {
if (!LHSReg || !RHSReg) if (!LHSReg || !RHSReg)
return false; return false;
unsigned Opc = X86::getCMovFromCond(CC, RC->getSize());
unsigned ResultReg = FastEmitInst_rr(Opc, RC, RHSReg, RHSIsKill, unsigned ResultReg = FastEmitInst_rr(Opc, RC, RHSReg, RHSIsKill,
LHSReg, LHSIsKill); LHSReg, LHSIsKill);
UpdateValueMap(I, ResultReg); UpdateValueMap(I, ResultReg);
@@ -1871,11 +1851,7 @@ bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) {
/// Try to use SSE1/SSE2 instructions to simulate a select without branches. /// Try to use SSE1/SSE2 instructions to simulate a select without branches.
/// This lowers fp selects into a CMP/AND/ANDN/OR sequence when the necessary /// This lowers fp selects into a CMP/AND/ANDN/OR sequence when the necessary
/// SSE instructions are available. /// SSE instructions are available.
bool X86FastISel::X86FastEmitSSESelect(const Instruction *I) { bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
MVT RetVT;
if (!isTypeLegal(I->getType(), RetVT))
return false;
// Optimize conditons coming from a compare if both instructions are in the // Optimize conditons coming from a compare if both instructions are in the
// same basic block (values defined in other basic blocks may not have // same basic block (values defined in other basic blocks may not have
// initialized registers). // initialized registers).
@@ -1956,11 +1932,7 @@ bool X86FastISel::X86FastEmitSSESelect(const Instruction *I) {
return true; return true;
} }
bool X86FastISel::X86FastEmitPseudoSelect(const Instruction *I) { bool X86FastISel::X86FastEmitPseudoSelect(MVT RetVT, const Instruction *I) {
MVT RetVT;
if (!isTypeLegal(I->getType(), RetVT))
return false;
// These are pseudo CMOV instructions and will be later expanded into control- // These are pseudo CMOV instructions and will be later expanded into control-
// flow. // flow.
unsigned Opc; unsigned Opc;
@@ -2055,16 +2027,16 @@ bool X86FastISel::X86SelectSelect(const Instruction *I) {
} }
// First try to use real conditional move instructions. // First try to use real conditional move instructions.
if (X86FastEmitCMoveSelect(I)) if (X86FastEmitCMoveSelect(RetVT, I))
return true; return true;
// Try to use a sequence of SSE instructions to simulate a conditonal move. // Try to use a sequence of SSE instructions to simulate a conditonal move.
if (X86FastEmitSSESelect(I)) if (X86FastEmitSSESelect(RetVT, I))
return true; return true;
// Fall-back to pseudo conditional move instructions, which will be later // Fall-back to pseudo conditional move instructions, which will be later
// converted to control-flow. // converted to control-flow.
if (X86FastEmitPseudoSelect(I)) if (X86FastEmitPseudoSelect(RetVT, I))
return true; return true;
return false; return false;