[ConstraintElim] Decompose 'or disjoint' like 'add nsw'. - #220990
Conversation
Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox
|
@llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesUse m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in Leads to a number of additional folds end-to-end: Compile-time impact is in the noise in almost all cases except lencod Together with #220968 the Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox Full diff: https://github.com/llvm/llvm-project/pull/220990.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 93c3f2ff9900b..0e122b3a7480d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -574,7 +574,7 @@ static Decomposition decompose(Value *V, const ConstraintInfo &Info,
V = Op0;
}
- if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
+ if (match(V, m_NSWAddLike(m_Value(Op0), m_Value(Op1)))) {
if (auto Decomp = MergeResults(Op0, Op1, IsSigned))
return *Decomp;
return V;
diff --git a/llvm/test/Transforms/ConstraintElimination/or-disjoint.ll b/llvm/test/Transforms/ConstraintElimination/or-disjoint.ll
new file mode 100644
index 0000000000000..4f3de9e5d476e
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/or-disjoint.ll
@@ -0,0 +1,159 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @use(i1)
+
+; Check or disjoint is treated as add nsw in queries.
+define void @test_or_disjoint_as_add_slt(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_or_disjoint_as_add_slt(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A_PLUS_3:%.*]] = add nsw i8 [[A]], 3
+; CHECK-NEXT: [[PRE:%.*]] = icmp sge i8 [[A_PLUS_3]], [[B]]
+; CHECK-NEXT: br i1 [[PRE]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: [[I_1:%.*]] = or disjoint i8 [[A]], 1
+; CHECK-NEXT: [[C_1:%.*]] = icmp slt i8 [[I_1]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[C_1]])
+; CHECK-NEXT: [[I_4:%.*]] = or disjoint i8 [[A]], 4
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: ret void
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[A_1:%.*]] = or disjoint i8 [[A]], 1
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[A_2:%.*]] = or disjoint i8 [[A]], 2
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[A_3:%.*]] = or disjoint i8 [[A]], 3
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[A_4:%.*]] = or disjoint i8 [[A]], 4
+; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[A_4]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[C_2]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %a.plus.3 = add nsw i8 %a, 3
+ %pre = icmp sge i8 %a.plus.3, %b
+ br i1 %pre, label %then, label %else
+
+then:
+ %i.1 = or disjoint i8 %a, 1
+ %c.1 = icmp slt i8 %i.1, %b
+ call void @use(i1 %c.1)
+ %i.4 = or disjoint i8 %a, 4
+ %f.1 = icmp slt i8 %i.4, %b
+ call void @use(i1 %f.1)
+ ret void
+
+else:
+ %a.1 = or disjoint i8 %a, 1
+ %t.1 = icmp slt i8 %a.1, %b
+ call void @use(i1 %t.1)
+ %a.2 = or disjoint i8 %a, 2
+ %t.2 = icmp slt i8 %a.2, %b
+ call void @use(i1 %t.2)
+ %a.3 = or disjoint i8 %a, 3
+ %t.3 = icmp slt i8 %a.3, %b
+ call void @use(i1 %t.3)
+ %a.4 = or disjoint i8 %a, 4
+ %c.2 = icmp slt i8 %a.4, %b
+ call void @use(i1 %c.2)
+ ret void
+}
+
+define void @test_or_disjoint_as_add_variable_operands(i8 %a, i8 %b, i8 %c) {
+; CHECK-LABEL: define void @test_or_disjoint_as_add_variable_operands(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A_PLUS_B:%.*]] = add nsw i8 [[A]], [[B]]
+; CHECK-NEXT: [[PRE:%.*]] = icmp sge i8 [[A_PLUS_B]], [[C]]
+; CHECK-NEXT: br i1 [[PRE]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: [[OR_1:%.*]] = or disjoint i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: ret void
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[OR_2:%.*]] = or disjoint i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: ret void
+;
+entry:
+ %a.plus.b = add nsw i8 %a, %b
+ %pre = icmp sge i8 %a.plus.b, %c
+ br i1 %pre, label %then, label %else
+
+then:
+ %or.1 = or disjoint i8 %a, %b
+ %f.1 = icmp slt i8 %or.1, %c
+ call void @use(i1 %f.1)
+ ret void
+
+else:
+ %or.2 = or disjoint i8 %a, %b
+ %t.1 = icmp slt i8 %or.2, %c
+ call void @use(i1 %t.1)
+ ret void
+}
+
+; Check or disjoint is treated as add nsw when adding facts.
+define void @test_or_disjoint_as_add_fact(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_or_disjoint_as_add_fact(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A_OR_4:%.*]] = or disjoint i8 [[A]], 4
+; CHECK-NEXT: [[PRE:%.*]] = icmp sle i8 [[A_OR_4]], [[B]]
+; CHECK-NEXT: br i1 [[PRE]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: ret void
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[C_1:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[C_1]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %a.or.4 = or disjoint i8 %a, 4
+ %pre = icmp sle i8 %a.or.4, %b
+ br i1 %pre, label %then, label %else
+
+then:
+ %t.1 = icmp slt i8 %a, %b
+ call void @use(i1 %t.1)
+ ret void
+
+else:
+ %c.1 = icmp slt i8 %a, %b
+ call void @use(i1 %c.1)
+ ret void
+}
+
+define void @test_or_without_disjoint_not_decomposed(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_or_without_disjoint_not_decomposed(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A_OR_4:%.*]] = or i8 [[A]], 4
+; CHECK-NEXT: [[C_1:%.*]] = icmp sle i8 [[A_OR_4]], [[B]]
+; CHECK-NEXT: br i1 [[C_1]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[C_2]])
+; CHECK-NEXT: ret void
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[C_3:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT: call void @use(i1 [[C_3]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %a.or.4 = or i8 %a, 4
+ %c.1 = icmp sle i8 %a.or.4, %b
+ br i1 %c.1, label %then, label %else
+
+then:
+ %c.2 = icmp slt i8 %a, %b
+ call void @use(i1 %c.2)
+ ret void
+
+else:
+ %c.3 = icmp slt i8 %a, %b
+ call void @use(i1 %c.3)
+ ret void
+}
|
|
Do you plan to also make the corresponding unsigned/nuw change?
As it just exposes an SLP issue, I don't think so. |
…#220990) Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm/llvm-project#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox PR: llvm/llvm-project#220990
…#220990) Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm/llvm-project#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox PR: llvm/llvm-project#220990
Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox PR: llvm#220990
Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox PR: llvm#220990
'or disjoint' can be treated as 'add nuw nsw'. Update solveBlockValueBinaryOp to try to treat 'or disjoint' as both 'add nuw nsw' and binary or, taking the intersection as result. In some cases the binary or logic can yield better results (`@or_disjoint_known_bits_more_precise` test). This updates LVI to support 'or disjoint' similar to ConstraintElimination (llvm#221175, llvm#220990) Compile-time impact is in the noise https://llvm-compile-time-tracker.com/compare.php?from=137d8e684984df207576c8f24bd8743ddb71c5c9&to=94f20b7fe67d745a55f4ba31f4f15249e7e22f1c&stat=instructions:u Enables additional simplifications in a number of real-world cases dtcxzyw/llvm-opt-benchmark-nightly#1222.
'or disjoint' can be treated as 'add nuw nsw'. Update solveBlockValueBinaryOp to try to treat 'or disjoint' as both 'add nuw nsw' and binary or, taking the intersection as result. In some cases the binary or logic can yield better results (`@or_disjoint_known_bits_more_precise` test). This updates LVI to support 'or disjoint' similar to ConstraintElimination (llvm#221175, llvm#220990) Compile-time impact is in the noise https://llvm-compile-time-tracker.com/compare.php?from=137d8e684984df207576c8f24bd8743ddb71c5c9&to=94f20b7fe67d745a55f4ba31f4f15249e7e22f1c&stat=instructions:u Enables additional simplifications in a number of real-world cases dtcxzyw/llvm-opt-benchmark-nightly#1222.
'or disjoint' can be treated as 'add nuw nsw'. Update solveBlockValueBinaryOp to try to treat 'or disjoint' as both 'add nuw nsw' and binary or, taking the intersection as result. In some cases the binary or logic can yield better results (`@or_disjoint_known_bits_more_precise` test). This updates LVI to support 'or disjoint' similar to ConstraintElimination (llvm#221175, llvm#220990) Compile-time impact is in the noise https://llvm-compile-time-tracker.com/compare.php?from=137d8e684984df207576c8f24bd8743ddb71c5c9&to=94f20b7fe67d745a55f4ba31f4f15249e7e22f1c&stat=instructions:u Enables additional simplifications in a number of real-world cases dtcxzyw/llvm-opt-benchmark-nightly#1222.
Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in signed decomposition. Leads to a number of additional folds end-to-end: dtcxzyw/llvm-opt-benchmark-nightly#1188 Compile-time impact is in the noise in almost all cases except lencod with ThinLTO. On current main, compile-time for the workload regresses by ~3%, but almost all additional time is spent in SLP: after some branches got removed and BBs got merged got bigger, and SLP compile-time scales super-linearly in block size in some cases. Together with llvm#220968 the regression goes down to ~+1.18% on the workload. I have 2 more prototype patches that reduce the overhead by another ~0.30%. I am not sure if the compile-time issue should block the patch. https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox PR: llvm#220990
'or disjoint' can be treated as 'add nuw nsw'. Update solveBlockValueBinaryOp to try to treat 'or disjoint' as both 'add nuw nsw' and binary or, taking the intersection as result. In some cases the binary or logic can yield better results (`@or_disjoint_known_bits_more_precise` test). This updates LVI to support 'or disjoint' similar to ConstraintElimination (llvm#221175, llvm#220990) Compile-time impact is in the noise https://llvm-compile-time-tracker.com/compare.php?from=137d8e684984df207576c8f24bd8743ddb71c5c9&to=94f20b7fe67d745a55f4ba31f4f15249e7e22f1c&stat=instructions:u Enables additional simplifications in a number of real-world cases dtcxzyw/llvm-opt-benchmark-nightly#1222.
'or disjoint' can be treated as 'add nuw nsw'. Update solveBlockValueBinaryOp to try to treat 'or disjoint' as both 'add nuw nsw' and binary or, taking the intersection as result. In some cases the binary or logic can yield better results (`@or_disjoint_known_bits_more_precise` test). This updates LVI to support 'or disjoint' similar to ConstraintElimination (llvm#221175, llvm#220990) Compile-time impact is in the noise https://llvm-compile-time-tracker.com/compare.php?from=137d8e684984df207576c8f24bd8743ddb71c5c9&to=94f20b7fe67d745a55f4ba31f4f15249e7e22f1c&stat=instructions:u Enables additional simplifications in a number of real-world cases dtcxzyw/llvm-opt-benchmark-nightly#1222.
Use m_NSWAddLike instead of m_NSWAdd to also handle 'or disjoint' in
signed decomposition.
Leads to a number of additional folds end-to-end:
dtcxzyw/llvm-opt-benchmark-nightly#1188
Compile-time impact is in the noise in almost all cases except lencod
with ThinLTO. On current main, compile-time for the workload regresses
by ~3%, but almost all additional time is spent in SLP: after some
branches got removed and BBs got merged got bigger, and SLP compile-time
scales super-linearly in block size in some cases.
Together with #220968 the
regression goes down to ~+1.18% on the workload. I have 2 more prototype
patches that reduce the overhead by another ~0.30%. I am not sure if the
compile-time issue should block the patch.
https://llvm-compile-time-tracker.com/compare.php?from=ffe87191eb7090340f12056455104145670ed7e8&to=c073db66b714d3dd26c573ad8371ab8b117890a9&stat=instructions:u
Alive2 Proof: https://alive2.llvm.org/ce/z/ZVFEox