diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4582,6 +4582,22 @@ return FalseVal; } + if (Pred == ICmpInst::Predicate::ICMP_EQ) { + Value *X; + Value *Y; + // select(X | Y == 0, X or Y, X | Y) -> X | Y + if (match(CondVal, m_ICmp(Pred, m_Specific(FalseVal), m_Zero())) && + match(FalseVal, m_Or(m_Value(X), m_Value(Y))) && + (TrueVal == X || TrueVal == Y)) + return FalseVal; + // select(X & Y == -1, X or Y, X & Y) -> X & Y + if (Pred == ICmpInst::Predicate::ICMP_EQ && + match(CondVal, m_ICmp(Pred, m_Specific(FalseVal), m_AllOnes())) && + match(FalseVal, m_And(m_Value(X), m_Value(Y))) && + (TrueVal == X || TrueVal == Y)) + return FalseVal; + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/select_or_and.ll b/llvm/test/Transforms/InstCombine/select_or_and.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/select_or_and.ll @@ -0,0 +1,154 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes=instcombine < %s | FileCheck %s + +; select(Y | X == 0, X, Y | X) +define i32 @select_or_1(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_1( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = or i32 %1, %0 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i32 %0, i32 %3 + ret i32 %5 +} + +; select(Y | X == 0, Y, Y | X) +define i32 @select_or_2(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_2( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = or i32 %1, %0 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i32 %1, i32 %3 + ret i32 %5 +} + +; select(Y | X != 0, Y | X, X) +define i32 @select_or_3(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_3( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = or i32 %1, %0 + %4 = icmp ne i32 %3, 0 + %5 = select i1 %4, i32 %3, i32 %0 + ret i32 %5 +} + +; select(Y | X != 0, Y | X, Y) +define i32 @select_or_4(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_4( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = or i32 %1, %0 + %4 = icmp ne i32 %3, 0 + %5 = select i1 %4, i32 %3, i32 %1 + ret i32 %5 +} + +; select(Y | X == 0, Y | X, Y) +define i32 @select_or_not_1(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_not_1( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i32 0, i32 [[TMP1]] +; CHECK-NEXT: ret i32 [[TMP5]] +; + %3 = or i32 %1, %0 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i32 %3, i32 %1 + ret i32 %5 +} +; select(Y | X != 0, Y, Y | X) +define i32 @select_or_not_2(i32 %0, i32 %1) { +; CHECK-LABEL: @select_or_not_2( +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[DOTNOT]], i32 0, i32 [[TMP1]] +; CHECK-NEXT: ret i32 [[TMP4]] +; + %3 = or i32 %1, %0 + %4 = icmp ne i32 %3, 0 + %5 = select i1 %4, i32 %1, i32 %3 + ret i32 %5 +} + +; select(Y & X == -1, X, Y & X) +define i32 @select_and_1(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_1( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = and i32 %1, %0 + %4 = icmp eq i32 %3, -1 + %5 = select i1 %4, i32 %0, i32 %3 + ret i32 %5 +} + +; select(Y & X == -1, Y, Y & X) +define i32 @select_and_2(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_2( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = and i32 %1, %0 + %4 = icmp eq i32 %3, -1 + %5 = select i1 %4, i32 %1, i32 %3 + ret i32 %5 +} + + +; select(Y & X != -1, Y & X, X) +define i32 @select_and_3(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_3( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = and i32 %1, %0 + %4 = icmp ne i32 %3, -1 + %5 = select i1 %4, i32 %3, i32 %0 + ret i32 %5 +} + +; select(Y & X != -1, Y & X, Y) +define i32 @select_and_4(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_4( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] +; + %3 = and i32 %1, %0 + %4 = icmp ne i32 %3, -1 + %5 = select i1 %4, i32 %3, i32 %1 + ret i32 %5 +} + +; select(Y & X != -1, Y, Y & X) +define i32 @select_and_not_1(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_not_1( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], -1 +; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i32 -1, i32 [[TMP1]] +; CHECK-NEXT: ret i32 [[TMP5]] +; + %3 = and i32 %1, %0 + %4 = icmp eq i32 %3, -1 + %5 = select i1 %4, i32 %3, i32 %1 + ret i32 %5 +} + +; select(Y & X != -1, Y, Y & X) +define i32 @select_and_not_2(i32 %0, i32 %1) { +; CHECK-LABEL: @select_and_not_2( +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]] +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP3]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[DOTNOT]], i32 -1, i32 [[TMP1]] +; CHECK-NEXT: ret i32 [[TMP4]] +; + %3 = and i32 %1, %0 + %4 = icmp ne i32 %3, -1 + %5 = select i1 %4, i32 %1, i32 %3 + ret i32 %5 +}