diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -727,13 +727,25 @@ unsigned C2Log = C2->logBase2(); + bool SavesAnd = false; + if (IC->isEquality() && V->hasOneUse()) { + // If we are shifting by bitwidth - 1, the `and` can be optimized out. + if (C2Log > C1Log) { + SavesAnd = + (C2Log - C1Log) == (Y->getType()->getScalarSizeInBits() - 1); + } else if (C1Log > C2Log) { + SavesAnd = + (C1Log - C2Log) == (Y->getType()->getScalarSizeInBits() - 1); + } + } + bool NeedShift = C1Log != C2Log; bool NeedZExtTrunc = Y->getType()->getScalarSizeInBits() != V->getType()->getScalarSizeInBits(); // Make sure we don't create more instructions than we save. if ((NeedShift + NeedXor + NeedZExtTrunc + NeedAnd) > - (IC->hasOneUse() + BinOp->hasOneUse())) + (IC->hasOneUse() + BinOp->hasOneUse() + SavesAnd)) return nullptr; if (NeedAnd) { diff --git a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll --- a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll +++ b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll @@ -1582,10 +1582,10 @@ ; Tests factoring in cost of saving the `and` define i64 @xor_i8_to_i64_shl_save_and_eq(i8 %x, i64 %y) { ; CHECK-LABEL: @xor_i8_to_i64_shl_save_and_eq( -; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[XX]], 0 -; CHECK-NEXT: [[Z:%.*]] = xor i64 [[Y:%.*]], -9223372036854775808 -; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i64 [[Z]], i64 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 63 +; CHECK-NEXT: [[R:%.*]] = xor i64 [[TMP3]], [[Y:%.*]] ; CHECK-NEXT: ret i64 [[R]] ; %xx = and i8 %x, 1