Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -675,6 +675,23 @@ return IsNegative ? Builder.CreateSub(B, Max) : Builder.CreateSub(Max, B); } +static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal, + InstCombiner::BuilderTy &Builder) { + // Match an unsigned saturated add with constant. + Value *X = Cmp->getOperand(0); + const APInt *CmpC, *AddC; + if (!Cmp->hasOneUse() || Cmp->getPredicate() != ICmpInst::ICMP_ULT || + !match(Cmp->getOperand(1), m_APInt(CmpC)) || !match(FVal, m_AllOnes()) || + !match(TVal, m_Add(m_Specific(X), m_APInt(AddC))) || ~(*AddC) != *CmpC) + return nullptr; + + // Commute compare and select operands: + // select (icmp ult X, C), (add X, ~C), -1 --> + // select (icmp ugt X, C), -1, (add X, ~C) + Value *NewCmp = Builder.CreateICmp(ICmpInst::ICMP_UGT, X, Cmp->getOperand(1)); + return Builder.CreateSelect(NewCmp, FVal, TVal); +} + /// Attempt to fold a cttz/ctlz followed by a icmp plus select into a single /// call to cttz/ctlz with flag 'is_zero_undef' cleared. /// @@ -1048,6 +1065,9 @@ if (Value *V = canonicalizeSaturatedSubtract(ICI, TrueVal, FalseVal, Builder)) return replaceInstUsesWith(SI, V); + if (Value *V = canonicalizeSaturatedAdd(ICI, TrueVal, FalseVal, Builder)) + return replaceInstUsesWith(SI, V); + return Changed ? &SI : nullptr; } Index: llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll +++ llvm/trunk/test/Transforms/InstCombine/saturating-add-sub.ll @@ -655,9 +655,9 @@ define i32 @uadd_sat_constant_commute(i32 %x) { ; CHECK-LABEL: @uadd_sat_constant_commute( ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 42 -; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X]], -43 -; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], -43 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 -1, i32 [[A]] +; CHECK-NEXT: ret i32 [[TMP2]] ; %a = add i32 %x, 42 %c = icmp ult i32 %x, -43 @@ -681,9 +681,9 @@ define <4 x i32> @uadd_sat_constant_vec_commute(<4 x i32> %x) { ; CHECK-LABEL: @uadd_sat_constant_vec_commute( ; CHECK-NEXT: [[A:%.*]] = add <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[C:%.*]] = icmp ult <4 x i32> [[X]], -; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[C]], <4 x i32> [[A]], <4 x i32> -; CHECK-NEXT: ret <4 x i32> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <4 x i32> [[X]], +; CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> , <4 x i32> [[A]] +; CHECK-NEXT: ret <4 x i32> [[TMP2]] ; %a = add <4 x i32> %x, %c = icmp ult <4 x i32> %x,