Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3647,6 +3647,31 @@ } } + if (match(Op1, m_Power2())) { + Constant *C1, *C2 = cast(Op1); + Value *X; + // if C1 and C2 are pow2: + // ((C1 << X) & C2) ^ C2 --> (X != (Log2(C2)-Log2(C1)) ? C2 : 0 + if (match(Op0, m_OneUse(m_And(m_Shl(m_ImmConstant(C1), m_Value(X)), + m_Specific(Op1)))) && + match(C1, m_Power2())) { + Constant *CmpC = ConstantExpr::getSub(ConstantExpr::getExactLogBase2(C2), + ConstantExpr::getExactLogBase2(C1)); + Value *ICmp = Builder.CreateICmpNE(X, CmpC); + return SelectInst::Create(ICmp, Op1, Constant::getNullValue(Ty)); + } + // if C1 and C2 are pow2: + // ((C1 >> X) & C2) ^ C2 --> (X != (Log2(C1)-Log2(C2)) ? C2 : 0 + if (match(Op0, m_OneUse(m_And(m_LShr(m_ImmConstant(C1), m_Value(X)), + m_Specific(Op1)))) && + match(C1, m_Power2())) { + Constant *CmpC = ConstantExpr::getSub(ConstantExpr::getExactLogBase2(C1), + ConstantExpr::getExactLogBase2(C2)); + Value *ICmp = Builder.CreateICmpNE(X, CmpC); + return SelectInst::Create(ICmp, Op1, Constant::getNullValue(Ty)); + } + } + // FIXME: This should not be limited to scalar (pull into APInt match above). { Value *X; Index: llvm/test/Transforms/InstCombine/and.ll =================================================================== --- llvm/test/Transforms/InstCombine/and.ll +++ llvm/test/Transforms/InstCombine/and.ll @@ -1890,13 +1890,10 @@ ret i16 %r } -; TODO: this pattern can be transform to icmp+select - define i16 @shl_lshr_pow2_not_const_case2(i16 %x) { ; CHECK-LABEL: @shl_lshr_pow2_not_const_case2( -; CHECK-NEXT: [[TMP1:%.*]] = shl i16 2, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i16 [[TMP1]], 8 -; CHECK-NEXT: [[R:%.*]] = xor i16 [[AND]], 8 +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i16 [[X:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTNOT]], i16 0, i16 8 ; CHECK-NEXT: ret i16 [[R]] ; %shl = shl i16 16, %x @@ -2046,13 +2043,10 @@ ret i16 %r } -; TODO: this pattern can be transform to icmp+select - define i16 @lshr_shl_pow2_const_xor(i16 %x) { ; CHECK-LABEL: @lshr_shl_pow2_const_xor( -; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 1024, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i16 [[TMP1]], 8 -; CHECK-NEXT: [[R:%.*]] = xor i16 [[AND]], 8 +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i16 [[X:%.*]], 7 +; CHECK-NEXT: [[R:%.*]] = select i1 [[DOTNOT]], i16 0, i16 8 ; CHECK-NEXT: ret i16 [[R]] ; %lshr1 = lshr i16 256, %x Index: llvm/test/Transforms/InstCombine/icmp-and-shift.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-and-shift.ll +++ llvm/test/Transforms/InstCombine/icmp-and-shift.ll @@ -342,9 +342,8 @@ define i32 @icmp_eq_and_pow2_lshr_pow2(i32 %0) { ; CHECK-LABEL: @icmp_eq_and_pow2_lshr_pow2( -; CHECK-NEXT: [[AND:%.*]] = lshr i32 2, [[TMP0:%.*]] -; CHECK-NEXT: [[AND_LOBIT:%.*]] = and i32 [[AND]], 1 -; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[AND_LOBIT]], 1 +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp ne i32 [[TMP0:%.*]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[DOTNOT]] to i32 ; CHECK-NEXT: ret i32 [[TMP2]] ; %lshr = lshr i32 8, %0 @@ -367,9 +366,8 @@ define <2 x i32> @icmp_eq_and_pow2_lshr_pow2_vec(<2 x i32> %0) { ; CHECK-LABEL: @icmp_eq_and_pow2_lshr_pow2_vec( -; CHECK-NEXT: [[AND:%.*]] = lshr <2 x i32> , [[TMP0:%.*]] -; CHECK-NEXT: [[AND_LOBIT:%.*]] = and <2 x i32> [[AND]], -; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[AND_LOBIT]], +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp ne <2 x i32> [[TMP0:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i1> [[DOTNOT]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[TMP2]] ; %lshr = lshr <2 x i32> , %0 @@ -381,9 +379,8 @@ define i32 @icmp_ne_and_pow2_lshr_pow2(i32 %0) { ; CHECK-LABEL: @icmp_ne_and_pow2_lshr_pow2( -; CHECK-NEXT: [[AND:%.*]] = lshr i32 2, [[TMP0:%.*]] -; CHECK-NEXT: [[AND_LOBIT:%.*]] = and i32 [[AND]], 1 -; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[AND_LOBIT]], 1 +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp ne i32 [[TMP0:%.*]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[DOTNOT]] to i32 ; CHECK-NEXT: ret i32 [[TMP2]] ; %lshr = lshr i32 8, %0