mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
[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:
@@ -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;
|
||||||
|
Reference in New Issue
Block a user