Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -142,6 +142,31 @@ return hash_combine(Inst->getOpcode(), Pred, LHS, RHS); } + // Hash min/max (cmp + select) to allow for both commuted operands and + // non-canonical compare predicate (eg, the compare for smin may use 'sgt' + // rather than 'slt'). + Value *A, *B; + if (match(Inst, m_SMin(m_Value(A), m_Value(B)))) { + if (A > B) + std::swap(A, B); + return hash_combine(Inst->getOpcode(), ICmpInst::ICMP_SLT, A, B); + } + if (match(Inst, m_SMax(m_Value(A), m_Value(B)))) { + if (A > B) + std::swap(A, B); + return hash_combine(Inst->getOpcode(), ICmpInst::ICMP_SGT, A, B); + } + if (match(Inst, m_UMin(m_Value(A), m_Value(B)))) { + if (A > B) + std::swap(A, B); + return hash_combine(Inst->getOpcode(), ICmpInst::ICMP_ULT, A, B); + } + if (match(Inst, m_UMax(m_Value(A), m_Value(B)))) { + if (A > B) + std::swap(A, B); + return hash_combine(Inst->getOpcode(), ICmpInst::ICMP_UGT, A, B); + } + if (CastInst *CI = dyn_cast(Inst)) return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0)); @@ -200,6 +225,22 @@ LHSCmp->getSwappedPredicate() == RHSCmp->getPredicate(); } + // The commutative min/max matchers allow for both commuted operands and + // different compare predicates. + Value *A, *B; + if (match(LHSI, m_SMin(m_Value(A), m_Value(B))) && + match(RHSI, m_c_SMin(m_Specific(A), m_Specific(B)))) + return true; + if (match(LHSI, m_SMax(m_Value(A), m_Value(B))) && + match(RHSI, m_c_SMax(m_Specific(A), m_Specific(B)))) + return true; + if (match(LHSI, m_UMin(m_Value(A), m_Value(B))) && + match(RHSI, m_c_UMin(m_Specific(A), m_Specific(B)))) + return true; + if (match(LHSI, m_UMax(m_Value(A), m_Value(B))) && + match(RHSI, m_c_UMax(m_Specific(A), m_Specific(B)))) + return true; + return false; } Index: test/Transforms/EarlyCSE/commute.ll =================================================================== --- test/Transforms/EarlyCSE/commute.ll +++ test/Transforms/EarlyCSE/commute.ll @@ -78,8 +78,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %b, %a ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a -; CHECK-NEXT: [[R:%.*]] = mul i8 [[M1]], [[M2]] +; CHECK-NEXT: [[R:%.*]] = mul i8 [[M1]], [[M1]] ; CHECK-NEXT: ret i8 [[R]] ; %cmp1 = icmp slt i8 %a, %b @@ -97,9 +96,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[M2]], [[M1]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %cmp1 = icmp sgt i8 %a, %b %cmp2 = icmp slt i8 %a, %b @@ -114,9 +111,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %b, %a ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a -; CHECK-NEXT: [[R:%.*]] = urem i8 [[M2]], [[M1]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 0 ; %cmp1 = icmp sgt i8 %a, %b %cmp2 = icmp sgt i8 %b, %a @@ -131,9 +126,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b -; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[M1]], [[M2]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 1 ; %cmp1 = icmp slt i8 %a, %b %cmp2 = icmp sgt i8 %a, %b @@ -148,9 +141,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %b, %a ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a -; CHECK-NEXT: [[R:%.*]] = sub i8 [[M2]], [[M1]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 0 ; %cmp1 = icmp ult i8 %a, %b %cmp2 = icmp ult i8 %b, %a @@ -167,9 +158,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i8> %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult <2 x i8> %a, %b ; CHECK-NEXT: [[M1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> %b, <2 x i8> %a -; CHECK-NEXT: [[M2:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> %a, <2 x i8> %b -; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[M2]], [[M1]] -; CHECK-NEXT: ret <2 x i8> [[R]] +; CHECK-NEXT: ret <2 x i8> zeroinitializer ; %cmp1 = icmp ugt <2 x i8> %a, %b %cmp2 = icmp ult <2 x i8> %a, %b @@ -184,9 +173,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %b, %a ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a -; CHECK-NEXT: [[R:%.*]] = udiv i8 [[M1]], [[M2]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 1 ; %cmp1 = icmp ugt i8 %a, %b %cmp2 = icmp ugt i8 %b, %a @@ -201,8 +188,7 @@ ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b ; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a -; CHECK-NEXT: [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b -; CHECK-NEXT: [[R:%.*]] = add i8 [[M2]], [[M1]] +; CHECK-NEXT: [[R:%.*]] = add i8 [[M1]], [[M1]] ; CHECK-NEXT: ret i8 [[R]] ; %cmp1 = icmp ult i8 %a, %b