From 2321e6a4d4c229b58f56647275894c3e45ea57dd Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 8 Jul 2010 11:39:10 +0000 Subject: Teach instcombine to transform (X >s -1) ? C1 : C2 and (X >s 31) & (C2 - C1)) + C1, avoiding the conditional. This optimization could be extended to take non-const C1 and C2 but we better stay conservative to avoid code size bloat for now. for int sel(int n) { return n >= 0 ? 60 : 100; } we now generate sarl $31, %edi andl $40, %edi leal 60(%rdi), %eax instead of testl %edi, %edi movl $60, %ecx movl $100, %eax cmovnsl %ecx, %eax llvm-svn: 107866 --- .../Transforms/InstCombine/InstCombineSelect.cpp | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'llvm/lib/Transforms/InstCombine') diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index c958cde0917..c44fe9db6e3 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -329,6 +329,37 @@ Instruction *InstCombiner::visitSelectInstWithICmp(SelectInst &SI, } } + // Transform (X >s -1) ? C1 : C2 --> ((X >>s 31) & (C2 - C1)) + C1 + // and (X ((X >>s 31) & (C2 - C1)) + C1 + // FIXME: Type and constness constraints could be lifted, but we have to + // watch code size carefully. We should consider xor instead of + // sub/add when we decide to do that. + if (const IntegerType *Ty = dyn_cast(CmpLHS->getType())) { + if (TrueVal->getType() == Ty) { + if (ConstantInt *Cmp = dyn_cast(CmpRHS)) { + ConstantInt *C1 = NULL, *C2 = NULL; + if (Pred == ICmpInst::ICMP_SGT && Cmp->isAllOnesValue()) { + C1 = dyn_cast(TrueVal); + C2 = dyn_cast(FalseVal); + } else if (Pred == ICmpInst::ICMP_SLT && Cmp->isNullValue()) { + C1 = dyn_cast(FalseVal); + C2 = dyn_cast(TrueVal); + } + if (C1 && C2) { + // This shift results in either -1 or 0. + Value *AShr = Builder->CreateAShr(CmpLHS, Ty->getBitWidth()-1); + + // Check if we can express the operation with a single or. + if (C2->isAllOnesValue()) + return ReplaceInstUsesWith(SI, Builder->CreateOr(AShr, C1)); + + Value *And = Builder->CreateAnd(AShr, C2->getValue()-C1->getValue()); + return ReplaceInstUsesWith(SI, Builder->CreateAdd(And, C1)); + } + } + } + } + if (CmpLHS == TrueVal && CmpRHS == FalseVal) { // Transform (X == Y) ? X : Y -> Y if (Pred == ICmpInst::ICMP_EQ) -- cgit v1.2.3