Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -227,6 +227,35 @@ return V; } +/// This folds: +/// select (icmp eq (and X, C), 0), 0, (shl X, K) +/// iff C is a mask and the number of its leading zeros is equal to K. +/// To the following: +/// shl X, K +static Value *foldSelectICmpAndZeroShl(SelectInst &Sel, ICmpInst *Cmp, + InstCombiner::BuilderTy &Builder) { + // TODO: vector select or vector compare. + if (Sel.getType()->isVectorTy() || Cmp->getType()->isVectorTy()) + return nullptr; + + const APInt *K; + Value *X; + if (!match(Sel.getTrueValue(), m_Zero()) || + !match(Sel.getFalseValue(), m_Shl(m_Value(X), m_APInt(K))) || + !ICmpInst::isEquality(Cmp->getPredicate()) || + !match(Cmp->getOperand(1), m_Zero())) + return nullptr; + + const APInt *C; + if (!match(Cmp->getOperand(0), m_And(m_Specific(X), m_APInt(C)))) + return nullptr; + + if (!C->isMask() || (int64_t)C->countLeadingZeros() != K->getSExtValue()) + return nullptr; + + return Sel.getFalseValue(); +} + /// We want to turn code that looks like this: /// %C = or %A, %B /// %D = select %cond, %C, %A @@ -1722,6 +1751,9 @@ if (Value *V = foldSelectICmpAnd(SI, ICI, Builder)) return replaceInstUsesWith(SI, V); + if (Value *V = foldSelectICmpAndZeroShl(SI, ICI, Builder)) + return replaceInstUsesWith(SI, V); + // NOTE: if we wanted to, this is where to detect integer MIN/MAX Value *TrueVal = SI.getTrueValue(); Value *FalseVal = SI.getFalseValue(); Index: llvm/test/Transforms/InstCombine/select-icmp-and.ll =================================================================== --- llvm/test/Transforms/InstCombine/select-icmp-and.ll +++ llvm/test/Transforms/InstCombine/select-icmp-and.ll @@ -618,3 +618,16 @@ ret i8 %t3 } +; (x << k) ? 2^k * x : 0 --> 2^k * x + +define i32 @test_select_icmp_and_shl(i32 %x) { +; CHECK-LABEL: @test_select_icmp_and_shl( +; CHECK-NEXT: [[T:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: ret i32 [[T]] +; + %shl.mask = and i32 %x, 1073741823 + %tobool.not = icmp eq i32 %shl.mask, 0 + %mul = shl i32 %x, 2 + %cond = select i1 %tobool.not, i32 0, i32 %mul + ret i32 %cond +}