diff options
author | Juergen Ributzka <juergen@apple.com> | 2014-11-13 00:36:43 +0000 |
---|---|---|
committer | Juergen Ributzka <juergen@apple.com> | 2014-11-13 00:36:43 +0000 |
commit | 424c5fd12f9e3c5ec7de218f97b410e774d63969 (patch) | |
tree | 7744c0e1a6948a18f2012fec3160e440817838ba /llvm/lib/Target | |
parent | d1a042abd088894ae307b5d8321e0c062040b147 (diff) | |
download | bcm5719-llvm-424c5fd12f9e3c5ec7de218f97b410e774d63969.tar.gz bcm5719-llvm-424c5fd12f9e3c5ec7de218f97b410e774d63969.zip |
[FastISel][AArch64] Fold the cmp into the select when possible.
This folds the compare emission into the select emission when possible, so we
can directly use the flags and don't have to emit a separate compare.
Related to rdar://problem/18960150.
llvm-svn: 221847
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64FastISel.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp index 82080c7e4b1..28e4b0a4599 100644 --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -2531,6 +2531,7 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { const SelectInst *SI = cast<SelectInst>(I); const Value *Cond = SI->getCondition(); AArch64CC::CondCode CC = AArch64CC::NE; + AArch64CC::CondCode ExtraCC = AArch64CC::AL; // Try to pickup the flags, so we don't have to emit another compare. if (foldXALUIntrinsic(CC, I, Cond)) { @@ -2538,6 +2539,54 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { unsigned CondReg = getRegForValue(Cond); if (!CondReg) return false; + } else if (isa<CmpInst>(Cond) && cast<CmpInst>(Cond)->hasOneUse() && + isValueAvailable(Cond)) { + const auto *Cmp = cast<CmpInst>(Cond); + // Try to optimize or fold the cmp. + CmpInst::Predicate Predicate = optimizeCmpPredicate(Cmp); + const Value *FoldSelect = nullptr; + switch (Predicate) { + default: + break; + case CmpInst::FCMP_FALSE: + FoldSelect = SI->getFalseValue(); + break; + case CmpInst::FCMP_TRUE: + FoldSelect = SI->getTrueValue(); + break; + } + + if (FoldSelect) { + unsigned SrcReg = getRegForValue(FoldSelect); + if (!SrcReg) + return false; + unsigned UseReg = lookUpRegForValue(SI); + if (UseReg) + MRI.clearKillFlags(UseReg); + + updateValueMap(I, SrcReg); + return true; + } + + // Emit the cmp. + if (!emitCmp(Cmp->getOperand(0), Cmp->getOperand(1), Cmp->isUnsigned())) + return false; + + // FCMP_UEQ and FCMP_ONE cannot be checked with a single select instruction. + CC = getCompareCC(Predicate); + switch (Predicate) { + default: + break; + case CmpInst::FCMP_UEQ: + ExtraCC = AArch64CC::EQ; + CC = AArch64CC::VS; + break; + case CmpInst::FCMP_ONE: + ExtraCC = AArch64CC::MI; + CC = AArch64CC::GT; + break; + } + assert((CC != AArch64CC::AL) && "Unexpected condition code."); } else { unsigned CondReg = getRegForValue(Cond); if (!CondReg) @@ -2560,6 +2609,11 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { if (!Src1Reg || !Src2Reg) return false; + if (ExtraCC != AArch64CC::AL) { + Src2Reg = fastEmitInst_rri(Opc, RC, Src1Reg, Src1IsKill, Src2Reg, + Src2IsKill, ExtraCC); + Src2IsKill = true; + } unsigned ResultReg = fastEmitInst_rri(Opc, RC, Src1Reg, Src1IsKill, Src2Reg, Src2IsKill, CC); updateValueMap(I, ResultReg); |