diff options
author | Juergen Ributzka <juergen@apple.com> | 2014-06-24 23:51:21 +0000 |
---|---|---|
committer | Juergen Ributzka <juergen@apple.com> | 2014-06-24 23:51:21 +0000 |
commit | 35a6a814073e9ce8c0722d23788eae2eb86832d9 (patch) | |
tree | b96a3133c2116644c9536592dea803db18477924 /lib/Target | |
parent | 11580ee62d39a0ae333fc86a1253d8e1d998cafe (diff) | |
download | llvm-35a6a814073e9ce8c0722d23788eae2eb86832d9.tar.gz llvm-35a6a814073e9ce8c0722d23788eae2eb86832d9.tar.bz2 llvm-35a6a814073e9ce8c0722d23788eae2eb86832d9.tar.xz |
[FastISel][X86] Fold XALU condition into branch and compare.
Optimize the codegen of select and branch instructions to directly use the
EFLAGS from the {s|u}{add|sub|mul}.with.overflow intrinsics.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211645 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r-- | lib/Target/X86/X86FastISel.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 6625a706d2..17999a59aa 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -1398,6 +1398,84 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) { return true; } } + } else if (auto *EV = dyn_cast<ExtractValueInst>(BI->getCondition())) { + bool FoldIntrinsic = false; + if (const auto *II = dyn_cast<IntrinsicInst>(EV->getAggregateOperand())) { + switch (II->getIntrinsicID()) { + default: break; + case Intrinsic::sadd_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::umul_with_overflow: FoldIntrinsic = true; break; + } + + // Check if both instructions are in the same basic block. + if (FoldIntrinsic && (II->getParent() != I->getParent())) + FoldIntrinsic = false; + + // Make sure nothing is in the way + if (FoldIntrinsic) { + BasicBlock::const_iterator Start = I; + BasicBlock::const_iterator End = II; + for (auto Itr = std::prev(Start); Itr != End; --Itr) { + // We only expect extractvalue instructions between the intrinsic and + // the branch. + if (!isa<ExtractValueInst>(Itr)) { + FoldIntrinsic = false; + break; + } + + // Check that the extractvalue operand comes from the intrinsic. + const auto *EVI = cast<ExtractValueInst>(Itr); + if (EVI->getAggregateOperand() != II) { + FoldIntrinsic = false; + break; + } + } + } + } + + if (FoldIntrinsic) { + MVT RetVT; + const IntrinsicInst *II = cast<IntrinsicInst>(EV->getAggregateOperand()); + const Function *Callee = II->getCalledFunction(); + Type *RetTy = + cast<StructType>(Callee->getReturnType())->getTypeAtIndex(0U); + if (!isTypeLegal(RetTy, RetVT)) + return false; + + if (RetVT != MVT::i32 && RetVT != MVT::i64) + return false; + + // Fake request the condition, otherwise the intrinsic might be completely + // optimized away. + unsigned TmpReg = getRegForValue(EV); + if (TmpReg == 0) + return false; + + unsigned BranchOpc = 0; + switch (II->getIntrinsicID()) { + default: llvm_unreachable("Unexpected intrinsic instruction."); + case Intrinsic::sadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::umul_with_overflow: BranchOpc = X86::JO_4; break; + case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: BranchOpc = X86::JB_4; break; + } + + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc)) + .addMBB(TrueMBB); + FastEmitBranch(FalseMBB, DbgLoc); + uint32_t BranchWeight = 0; + if (FuncInfo.BPI) + BranchWeight = FuncInfo.BPI->getEdgeWeight(BI->getParent(), + TrueMBB->getBasicBlock()); + FuncInfo.MBB->addSuccessor(TrueMBB, BranchWeight); + return true; + } } // Otherwise do a clumsy setcc and re-test it. @@ -1732,6 +1810,78 @@ bool X86FastISel::X86FastEmitCMoveSelect(const Instruction *I) { } } NeedTest = false; + } else if (auto *EV = dyn_cast<ExtractValueInst>(Cond)) { + bool FoldIntrinsic = false; + if (const auto *II = dyn_cast<IntrinsicInst>(EV->getAggregateOperand())) { + switch (II->getIntrinsicID()) { + default: break; + case Intrinsic::sadd_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::umul_with_overflow: FoldIntrinsic = true; break; + } + + // Check if both instructions are in the same basic block. + if (FoldIntrinsic && (II->getParent() != I->getParent())) + FoldIntrinsic = false; + + // Make sure nothing is in the way + if (FoldIntrinsic) { + BasicBlock::const_iterator Start = I; + BasicBlock::const_iterator End = II; + for (auto Itr = std::prev(Start); Itr != End; --Itr) { + // We only expect extractvalue instructions between the intrinsic and + // the branch. + if (!isa<ExtractValueInst>(Itr)) { + FoldIntrinsic = false; + break; + } + + // Check that the extractvalue operand comes from the intrinsic. + const auto *EVI = cast<ExtractValueInst>(Itr); + if (EVI->getAggregateOperand() != II) { + FoldIntrinsic = false; + break; + } + } + } + } + + if (FoldIntrinsic) { + MVT RetVT; + const IntrinsicInst *II = cast<IntrinsicInst>(EV->getAggregateOperand()); + const Function *Callee = II->getCalledFunction(); + Type *RetTy = + cast<StructType>(Callee->getReturnType())->getTypeAtIndex(0U); + if (!isTypeLegal(RetTy, RetVT)) + return false; + + if (RetVT != MVT::i32 && RetVT != MVT::i64) + return false; + + // Fake request the condition, otherwise the intrinsic might be completely + // optimized away. + unsigned TmpReg = getRegForValue(EV); + if (TmpReg == 0) + return false; + + switch (II->getIntrinsicID()) { + default: llvm_unreachable("Unexpected intrinsic instruction."); + case Intrinsic::sadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::umul_with_overflow: + Opc = X86::getCMovFromCond(X86::COND_O, RC->getSize()); + break; + case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: + Opc = X86::getCMovFromCond(X86::COND_B, RC->getSize()); + break; + } + NeedTest = false; + } } if (NeedTest) { |