[llvm] [InstCombine] Fold usub_sat((sub nuw C1, A), C2) to usub_sat(C1 - C2, A) or 0 (PR #82280)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 10 08:08:11 PDT 2024


================
@@ -2139,6 +2139,23 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       }
     }
 
+    // usub_sat((sub nuw C1, A), C2) -> usub_sat(C1 - C2, A) if C2 u< C1
+    // usub_sat((sub nuw C1, A), C2) -> 0 otherwise
+    const APInt *C1, *C2;
+    Value *A;
+    if (IID == Intrinsic::usub_sat &&
+        match(Arg0, m_OneUse(m_NUWSub(m_APInt(C1), m_Value(A)))) &&
+        match(Arg1, m_APInt(C2))) {
+
+      if (C2->ult(*C1)) {
+        auto *New = Builder.CreateBinaryIntrinsic(
+            Intrinsic::usub_sat, ConstantInt::get(Ty, *C1 - *C2), A);
+        return replaceInstUsesWith(*SI, New);
+      } else {
+        return replaceInstUsesWith(*SI, ConstantInt::get(Ty, 0));
+      }
+    }
----------------
nikic wrote:

An alternative way to phrase this would be like this: https://alive2.llvm.org/ce/z/_Gw9fQ

This way we don't have to check the C2->ult(C1) condition explicitly, which means that we can more easily generalize this to non-splat vectors.

It would look something like this:
```
if (IID == Intrinsic::usub_sat &&
    match(Arg0, m_NUWSub(m_ImmConstant(C1), m_Value(A))) &&
    match(Arg1, m_ImmConstant(C2))) {
  auto *NewC = Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, C1, C2);
  auto *NewSub = Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, NewC, A);
  return replaceInstUsesWith(*SI, NewSub);
}
```

What do you think?

https://github.com/llvm/llvm-project/pull/82280


More information about the llvm-commits mailing list