Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1733,6 +1733,44 @@ return nullptr; } +/// Turn A, O = uadd.with.overflow X, Y; O ? -1 : A --> uadd_sat X, Y +/// And A, O = usub.with.overflow X, Y; O ? 0 : A --> usub_sat X, Y +static Instruction * +foldOverflowingAddSubSelect(SelectInst &SI, InstCombiner::BuilderTy &Builder) { + auto *CondVal = dyn_cast(SI.getCondition()); + Value *TrueVal = SI.getTrueValue(); + auto *FalseVal = dyn_cast(SI.getFalseValue()); + if (!CondVal || !FalseVal) + return nullptr; + + // Check the extracts point to the same instruction + if (CondVal->getNumIndices() != 1 || CondVal->getIndices()[0] != 1) + return nullptr; + if (FalseVal->getNumIndices() != 1 || FalseVal->getIndices()[0] != 0) + return nullptr; + if (CondVal->getAggregateOperand() != FalseVal->getAggregateOperand()) + return nullptr; + auto *II = dyn_cast(CondVal->getAggregateOperand()); + if (!II) + return nullptr; + + Intrinsic::ID NewIntrinsicID; + if (II->getIntrinsicID() == Intrinsic::uadd_with_overflow && + match(TrueVal, m_AllOnes())) + // A, O = uadd.with.overflow X, Y; O ? -1 : A --> uadd_sat X, Y + NewIntrinsicID = Intrinsic::uadd_sat; + else if (II->getIntrinsicID() == Intrinsic::usub_with_overflow && + match(TrueVal, m_Zero())) + // A, O = usub.with.overflow X, Y; O ? 0 : A --> usub_sat X, Y + NewIntrinsicID = Intrinsic::usub_sat; + else + return nullptr; + + Function *F = + Intrinsic::getDeclaration(SI.getModule(), NewIntrinsicID, SI.getType()); + return CallInst::Create(F, {II->getArgOperand(0), II->getArgOperand(1)}); +} + Instruction *InstCombiner::foldSelectExtConst(SelectInst &Sel) { Constant *C; if (!match(Sel.getTrueValue(), m_Constant(C)) && @@ -2399,6 +2437,8 @@ if (Instruction *Add = foldAddSubSelect(SI, Builder)) return Add; + if (Instruction *Add = foldOverflowingAddSubSelect(SI, Builder)) + return Add; // Turn (select C, (op X, Y), (op X, Z)) -> (op X, (select C, Y, Z)) auto *TI = dyn_cast(TrueVal); Index: llvm/test/Transforms/InstCombine/overflow_to_sat.ll =================================================================== --- llvm/test/Transforms/InstCombine/overflow_to_sat.ll +++ llvm/test/Transforms/InstCombine/overflow_to_sat.ll @@ -3,10 +3,7 @@ define i32 @uadd(i32 %x, i32 %y) { ; CHECK-LABEL: @uadd( -; CHECK-NEXT: [[AO:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) -; CHECK-NEXT: [[O:%.*]] = extractvalue { i32, i1 } [[AO]], 1 -; CHECK-NEXT: [[A:%.*]] = extractvalue { i32, i1 } [[AO]], 0 -; CHECK-NEXT: [[S:%.*]] = select i1 [[O]], i32 -1, i32 [[A]] +; CHECK-NEXT: [[S:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) ; CHECK-NEXT: ret i32 [[S]] ; %ao = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y) @@ -18,10 +15,7 @@ define i32 @usub(i32 %x, i32 %y) { ; CHECK-LABEL: @usub( -; CHECK-NEXT: [[AO:%.*]] = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) -; CHECK-NEXT: [[O:%.*]] = extractvalue { i32, i1 } [[AO]], 1 -; CHECK-NEXT: [[A:%.*]] = extractvalue { i32, i1 } [[AO]], 0 -; CHECK-NEXT: [[S:%.*]] = select i1 [[O]], i32 0, i32 [[A]] +; CHECK-NEXT: [[S:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) ; CHECK-NEXT: ret i32 [[S]] ; %ao = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %x, i32 %y)