Skip to content

[ConstraintElim] Drop invalid rows instead of failing the elimination #76299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Dec 23, 2023

This patch tries to drop invalid rows when overflow occurs instead of failing the elimination immediately.
Fixes the regression in velox/buffer/Buffer.h, which was introduced by #76262.

See also dtcxzyw/llvm-opt-benchmark#35 (comment).

@dtcxzyw dtcxzyw requested a review from fhahn December 23, 2023 20:11
@llvmbot llvmbot added llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Dec 23, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 23, 2023

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch tries to drop invalid rows when overflow occurs instead of failing the elimination immediately.
Fixes the regression in velox/buffer/Buffer.h, which was introduced by #76262.

See also dtcxzyw/llvm-opt-benchmark#35 (comment).


Full diff: https://github.com/llvm/llvm-project/pull/76299.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstraintSystem.cpp (+18-9)
  • (added) llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll (+42)
diff --git a/llvm/lib/Analysis/ConstraintSystem.cpp b/llvm/lib/Analysis/ConstraintSystem.cpp
index 8a802515b6f4fb..43bd5e5b0ccbdc 100644
--- a/llvm/lib/Analysis/ConstraintSystem.cpp
+++ b/llvm/lib/Analysis/ConstraintSystem.cpp
@@ -73,6 +73,8 @@ bool ConstraintSystem::eliminateUsingFM() {
       }
 
       SmallVector<Entry, 8> NR;
+      bool Valid = true;
+      uint32_t NextGCD = NewGCD;
       unsigned IdxUpper = 0;
       unsigned IdxLower = 0;
       auto &LowerRow = RemainingRows[LowerR];
@@ -96,27 +98,34 @@ bool ConstraintSystem::eliminateUsingFM() {
           IdxUpper++;
         }
 
-        if (MulOverflow(UpperV, ((-1) * LowerLast / GCD), M1))
-          return false;
+        if (MulOverflow(UpperV, ((-1) * LowerLast / GCD), M1)) {
+          Valid = false;
+          break;
+        }
         if (IdxLower < LowerRow.size() && LowerRow[IdxLower].Id == CurrentId) {
           LowerV = LowerRow[IdxLower].Coefficient;
           IdxLower++;
         }
 
-        if (MulOverflow(LowerV, (UpperLast / GCD), M2))
-          return false;
-        if (AddOverflow(M1, M2, N))
-          return false;
+        if (MulOverflow(LowerV, (UpperLast / GCD), M2)) {
+          Valid = false;
+          break;
+        }
+        if (AddOverflow(M1, M2, N)) {
+          Valid = false;
+          break;
+        }
         if (N == 0)
           continue;
         NR.emplace_back(N, CurrentId);
 
-        NewGCD =
-            APIntOps::GreatestCommonDivisor({32, (uint32_t)N}, {32, NewGCD})
+        NextGCD =
+            APIntOps::GreatestCommonDivisor({32, (uint32_t)N}, {32, NextGCD})
                 .getZExtValue();
       }
-      if (NR.empty())
+      if (!Valid || NR.empty())
         continue;
+      NewGCD = NextGCD;
       Constraints.push_back(std::move(NR));
       // Give up if the new system gets too big.
       if (Constraints.size() > 500)
diff --git a/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll b/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll
new file mode 100644
index 00000000000000..6200f3adf0088d
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+define void @f(i64 %a3, i64 %numElements) {
+; CHECK-LABEL: define void @f(
+; CHECK-SAME: i64 [[A3:%.*]], i64 [[NUMELEMENTS:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND:%.*]] = icmp ule i64 [[NUMELEMENTS]], 1152921504606846975
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[A1:%.*]] = shl nuw i64 [[NUMELEMENTS]], 4
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[A1]], [[A3]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_END_I:%.*]], label [[ABORT:%.*]]
+; CHECK:       if.end.i:
+; CHECK-NEXT:    br i1 false, label [[ABORT]], label [[EXIT:%.*]]
+; CHECK:       abort:
+; CHECK-NEXT:    tail call void @llvm.trap()
+; CHECK-NEXT:    unreachable
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cond = icmp ule i64 %numElements, 1152921504606846975
+  call void @llvm.assume(i1 %cond)
+  %a1 = shl nuw i64 %numElements, 4
+  br label %if.end
+if.end:
+  %cmp = icmp ugt i64 %a1, %a3
+  br i1 %cmp, label %if.end.i, label %abort
+if.end.i:
+  %cmp2.not.i = icmp ult i64 %a1, %a3
+  br i1 %cmp2.not.i, label %abort, label %exit
+abort:
+  tail call void @llvm.trap()
+  unreachable
+exit:
+  ret void
+}
+
+declare void @llvm.trap()
+declare void @llvm.assume(i1)

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Dec 23, 2023
@dtcxzyw dtcxzyw linked an issue Dec 24, 2023 that may be closed by this pull request
fhahn added a commit that referenced this pull request Dec 28, 2023
As @dtcxzyw pointed out in
#76299 (review)
the current GCD handling is effectively a no-op, as NewGCD will always
by 1, as it is initially initialized as 1.

This patch removes the uses of GCD and its computation. This slightly
reduces compile-time [1], while not causing any binary changes (due to always
dividing by 1) in the large test-set I checked.

Division by GCD could be added in the future again and it in theory
should help reduce overflows by normalizing the coefficients (sketched
in cadbfdf8605e743e092217c54e2b837245a0a330), but this also doesn't seem
to have much (any) impact in practice.

[1] https://llvm-compile-time-tracker.com/compare.php?from=0de030e4dcb798228731ab25d4dd31df4dcaba2b&to=cadbfdf8605e743e092217c54e2b837245a0a330&stat=instructions:u
Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting find!

See also dtcxzyw/llvm-opt-benchmark#35 (comment).

I am curious how you use this to spot regressions and if there's anything to automate?

The tests have been split out to a separate commit, but will get squashed on merge. Could you do a separate PR for the tests? Or commit them directly with the suggested adjustment?

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Dec 28, 2023

I am curious how you use this to spot regressions

I find these regressions by reviewing the IR diffs of real-world applications, which are generated by different version of opt. TBH it is a time-consuming job :( But I think this new system is better than my old CI because the old system creates a bunch of false positive regression reports.

and if there's anything to automate?

The system will build the trunk version of LLVM and run the benchmark every hour.

BTW, this regression was also detected by the pre-commit test dtcxzyw/llvm-opt-benchmark#30 (comment).
If you would like to test your patch before merging it, feel free to ping me and I will create a pull request in llvm-opt-benchmark :)

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Dec 28, 2023

The tests have been split out to a separate commit, but will get squashed on merge. Could you do a separate PR for the tests? Or commit them directly with the suggested adjustment?

Done. #76512

@@ -95,17 +95,19 @@ bool ConstraintSystem::eliminateUsingFM() {
IdxUpper++;
}

if (MulOverflow(UpperV, ((-1) * LowerLast), M1))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another question: Does (-1) * LowerLast never overflow?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be possible to construct a case where it overflows. Ideally we would construct such a case, add a test and check for overflow.

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Dec 28, 2023
@nikic
Copy link
Contributor

nikic commented Dec 28, 2023

Why is it valid to simply drop these rows? Doesn't this mean we lose constraints?

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Dec 28, 2023

Why is it valid to simply drop these rows? Doesn't this mean we lose constraints?

sat means that the constraint system may have a solution. Returning sat for an inconsistent system is allowed. So it is safe to drop constraints.

@nikic
Copy link
Contributor

nikic commented Jan 3, 2024

Why is it valid to simply drop these rows? Doesn't this mean we lose constraints?

sat means that the constraint system may have a solution. Returning sat for an inconsistent system is allowed. So it is safe to drop constraints.

I see. I think this should be spelled out in the eliminateUsingFM() documentation. If I understand correctly, the current implementation does preserve satisfiability during elimination (in the sense of "iff") -- but it's a stronger property than we need, so we can relax it, as this patch does. Or is it already possible for the current eliminateUsingFM() implementation to turn an unsat system into a sat one?

@dtcxzyw dtcxzyw force-pushed the constraintelim-overflow-drop branch from 87bd17c to bb4ad14 Compare January 6, 2024 17:38
@fhahn
Copy link
Contributor

fhahn commented Jan 7, 2024

Intuitively this makes sense, as dropping information/rows should only ever turn an unsatisfiable system into a satisfiable system, but not the other way around.

I'd still like to manually check the steps, as we may drop rows we created to eliminate a variable.

@dtcxzyw dtcxzyw force-pushed the constraintelim-overflow-drop branch from bb4ad14 to efbf6a5 Compare January 22, 2024 03:19
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 22, 2024

Ping.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Feb 5, 2024

Ping.

1 similar comment
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Feb 14, 2024

Ping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update diff December 23rd 2023, 3:18:28 pm
4 participants