Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -583,6 +583,37 @@ return new ZExtInst(ICmpNeZero, SelType); } +/// We want to turn: +/// (select (icmp eq (and X, C), 0), 0, (shl [nsw/nuw] X, K)); +/// iff C is a mask and the number of its leading zeros is equal to K +/// into: +/// shl X, K +static Value *foldSelectICmpAndZeroShl(const ICmpInst *Cmp, Value *TVal, + Value *FVal) { + ICmpInst::Predicate Pred; + Value *AndVal; + if (!match(Cmp, m_ICmp(Pred, m_Value(AndVal), m_Zero()))) + return nullptr; + + Value *X; + const APInt *K, *C; + if (Pred != ICmpInst::ICMP_EQ || + !match(AndVal, m_And(m_Value(X), m_APInt(C))) || !match(TVal, m_Zero()) || + !match(FVal, m_Shl(m_Specific(X), m_APInt(K)))) + return nullptr; + + if (!C->isMask() || (int64_t)C->countLeadingZeros() != K->getSExtValue()) + return nullptr; + + auto *FI = dyn_cast(FVal); + if (!FI) + return nullptr; + + FI->setHasNoSignedWrap(false); + FI->setHasNoUnsignedWrap(false); + return FVal; +} + /// We want to turn: /// (select (icmp sgt x, C), lshr (X, Y), ashr (X, Y)); iff C s>= -1 /// (select (icmp slt x, C), ashr (X, Y), lshr (X, Y)); iff C s>= 0 @@ -1810,6 +1841,9 @@ foldSelectICmpAndAnd(SI.getType(), ICI, TrueVal, FalseVal, Builder)) return V; + if (Value *V = foldSelectICmpAndZeroShl(ICI, TrueVal, FalseVal)) + return replaceInstUsesWith(SI, V); + if (Instruction *V = foldSelectCtlzToCttz(ICI, TrueVal, FalseVal, Builder)) return V; Index: llvm/test/Transforms/InstCombine/select-icmp-and-zero-shl.ll =================================================================== --- llvm/test/Transforms/InstCombine/select-icmp-and-zero-shl.ll +++ llvm/test/Transforms/InstCombine/select-icmp-and-zero-shl.ll @@ -5,11 +5,8 @@ define i32 @test1(i32 %x) { ; CHECK-LABEL: @test1( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and i32 [[X:%.*]], 1073741823 -; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[SHL_MASK]], 0 -; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X]], 2 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL_NOT]], i32 0, i32 [[MUL]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: ret i32 [[MUL]] ; %shl.mask = and i32 %x, 1073741823 %tobool.not = icmp eq i32 %shl.mask, 0 @@ -20,11 +17,8 @@ define <2 x i32> @test1_vect(<2 x i32> %x) { ; CHECK-LABEL: @test1_vect( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq <2 x i32> [[SHL_MASK]], zeroinitializer -; CHECK-NEXT: [[MUL:%.*]] = shl <2 x i32> [[X]], -; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[TOBOOL_NOT]], <2 x i32> zeroinitializer, <2 x i32> [[MUL]] -; CHECK-NEXT: ret <2 x i32> [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl <2 x i32> [[X:%.*]], +; CHECK-NEXT: ret <2 x i32> [[MUL]] ; %shl.mask = and <2 x i32> %x, %tobool.not = icmp eq <2 x i32> %shl.mask, zeroinitializer @@ -35,11 +29,8 @@ define i32 @test2(i32 %x) { ; CHECK-LABEL: @test2( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and i32 [[X:%.*]], 1073741823 -; CHECK-NEXT: [[TOBOOL_NOT_NOT:%.*]] = icmp eq i32 [[SHL_MASK]], 0 -; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X]], 2 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL_NOT_NOT]], i32 0, i32 [[MUL]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: ret i32 [[MUL]] ; %shl.mask = and i32 %x, 1073741823 %tobool.not = icmp ne i32 %shl.mask, 0 @@ -50,11 +41,8 @@ define <2 x i32> @test2_vect(<2 x i32> %x) { ; CHECK-LABEL: @test2_vect( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TOBOOL_NOT_NOT:%.*]] = icmp eq <2 x i32> [[SHL_MASK]], zeroinitializer -; CHECK-NEXT: [[MUL:%.*]] = shl <2 x i32> [[X]], -; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[TOBOOL_NOT_NOT]], <2 x i32> zeroinitializer, <2 x i32> [[MUL]] -; CHECK-NEXT: ret <2 x i32> [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl <2 x i32> [[X:%.*]], +; CHECK-NEXT: ret <2 x i32> [[MUL]] ; %shl.mask = and <2 x i32> %x, %tobool.not = icmp ne <2 x i32> %shl.mask, zeroinitializer @@ -65,11 +53,8 @@ define i32 @test3(i32 %x) { ; CHECK-LABEL: @test3( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and i32 [[X:%.*]], 1073741823 -; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[SHL_MASK]], 0 -; CHECK-NEXT: [[MUL:%.*]] = shl nuw i32 [[X]], 2 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL_NOT]], i32 0, i32 [[MUL]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: ret i32 [[MUL]] ; %shl.mask = and i32 %x, 1073741823 %tobool.not = icmp eq i32 %shl.mask, 0 @@ -80,11 +65,8 @@ define i32 @test4(i32 %x) { ; CHECK-LABEL: @test4( -; CHECK-NEXT: [[SHL_MASK:%.*]] = and i32 [[X:%.*]], 1073741823 -; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[SHL_MASK]], 0 -; CHECK-NEXT: [[MUL:%.*]] = shl nsw i32 [[X]], 2 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL_NOT]], i32 0, i32 [[MUL]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[MUL:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: ret i32 [[MUL]] ; %shl.mask = and i32 %x, 1073741823 %tobool.not = icmp eq i32 %shl.mask, 0