diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp --- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -191,6 +191,19 @@ Pred = ICmpInst::getSwappedPredicate(Pred); } + // Check for inverted variants of min/max by swapping operands. + switch (Pred) { + case CmpInst::ICMP_ULE: + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_SLE: + case CmpInst::ICMP_SGE: + Pred = CmpInst::getInversePredicate(Pred); + std::swap(A, B); + break; + default: + break; + } + switch (Pred) { case CmpInst::ICMP_UGT: Flavor = SPF_UMAX; break; case CmpInst::ICMP_ULT: Flavor = SPF_UMIN; break; diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll --- a/llvm/test/Transforms/EarlyCSE/commute.ll +++ b/llvm/test/Transforms/EarlyCSE/commute.ll @@ -684,6 +684,25 @@ ret i32 %r } +; This test is a reproducer for a bug involving inverted min/max selects +; hashing differently but comparing as equal. It exhibits such a pair of +; values, and we run this test with -earlycse-debug-hash which would catch +; the disagreement and fail if it regressed. +define i32 @inverted_max(i32 %i) { +; CHECK-LABEL: @inverted_max( +; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 0, [[I:%.*]] +; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP]], i32 [[I]], i32 0 +; CHECK-NEXT: [[CMPINV:%.*]] = icmp sgt i32 0, [[I:%.*]] +; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMPINV]], i32 0, i32 [[I]] +; CHECK-NEXT: [[R:%.*]] = add i32 [[M1]], [[M2]] +; CHECK-NEXT: ret i32 [[R]] + %cmp = icmp sle i32 0, %i + %m1 = select i1 %cmp, i32 %i, i32 0 + %cmpinv = icmp sgt i32 0, %i + %m2 = select i1 %cmpinv, i32 0, i32 %i + %r = add i32 %m1, %m2 + ret i32 %r +} ; This test is a reproducer for a bug involving inverted min/max selects ; hashing differently but comparing as equal. It exhibits such a pair of