Skip to content

Commit ab4aecd

Browse files
author
git apple-llvm automerger
committed
Merge commit '0daa13645702' from apple/stable/20200714 into swift/main
2 parents ca7081d + 0daa136 commit ab4aecd

File tree

6 files changed

+167
-8
lines changed

6 files changed

+167
-8
lines changed

llvm/include/llvm/Analysis/ConstraintSystem.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "llvm/ADT/APInt.h"
1313
#include "llvm/ADT/ArrayRef.h"
14+
#include "llvm/ADT/STLExtras.h"
1415
#include "llvm/ADT/SmallVector.h"
1516

1617
#include <string>
@@ -39,22 +40,28 @@ class ConstraintSystem {
3940
bool mayHaveSolutionImpl();
4041

4142
public:
42-
void addVariableRow(const SmallVector<int64_t, 8> &R) {
43+
bool addVariableRow(const SmallVector<int64_t, 8> &R) {
4344
assert(Constraints.empty() || R.size() == Constraints.back().size());
45+
// If all variable coefficients are 0, the constraint does not provide any
46+
// usable information.
47+
if (all_of(makeArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
48+
return false;
49+
4450
for (const auto &C : R) {
4551
auto A = std::abs(C);
4652
GCD = APIntOps::GreatestCommonDivisor({32, (uint32_t)A}, {32, GCD})
4753
.getZExtValue();
4854
}
4955
Constraints.push_back(R);
56+
return true;
5057
}
5158

52-
void addVariableRowFill(const SmallVector<int64_t, 8> &R) {
59+
bool addVariableRowFill(const SmallVector<int64_t, 8> &R) {
5360
for (auto &CR : Constraints) {
5461
while (CR.size() != R.size())
5562
CR.push_back(0);
5663
}
57-
addVariableRow(R);
64+
return addVariableRow(R);
5865
}
5966

6067
/// Returns true if there may be a solution for the constraints in the system.
@@ -72,6 +79,9 @@ class ConstraintSystem {
7279
bool isConditionImplied(SmallVector<int64_t, 8> R);
7380

7481
void popLastConstraint() { Constraints.pop_back(); }
82+
83+
/// Returns the number of rows in the constraint system.
84+
unsigned size() const { return Constraints.size(); }
7585
};
7686
} // namespace llvm
7787

llvm/lib/Analysis/ConstraintSystem.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ bool ConstraintSystem::eliminateUsingFM() {
8484
.getZExtValue();
8585
}
8686
NewSystem.push_back(std::move(NR));
87+
// Give up if the new system gets too big.
88+
if (NewSystem.size() > 500)
89+
return false;
8790
}
8891
}
8992
Constraints = std::move(NewSystem);
@@ -133,13 +136,18 @@ void ConstraintSystem::dump() const {
133136
}
134137

135138
bool ConstraintSystem::mayHaveSolution() {
136-
dump();
139+
LLVM_DEBUG(dump());
137140
bool HasSolution = mayHaveSolutionImpl();
138141
LLVM_DEBUG(dbgs() << (HasSolution ? "sat" : "unsat") << "\n");
139142
return HasSolution;
140143
}
141144

142145
bool ConstraintSystem::isConditionImplied(SmallVector<int64_t, 8> R) {
146+
// If all variable coefficients are 0, we have 'C >= 0'. If the constant is >=
147+
// 0, R is always true, regardless of the system.
148+
if (all_of(makeArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
149+
return R[0] >= 0;
150+
143151
// If there is no solution with the negation of R added to the system, the
144152
// condition must hold based on the existing constraints.
145153
R = ConstraintSystem::negate(R);

llvm/lib/Transforms/IPO/PassManagerBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,9 @@ void PassManagerBuilder::addFunctionSimplificationPasses(
453453
MPM.add(createMemCpyOptPass()); // Remove memcpy / form memset
454454
MPM.add(createSCCPPass()); // Constant prop with SCCP
455455

456+
if (EnableConstraintElimination)
457+
MPM.add(createConstraintEliminationPass());
458+
456459
// Delete dead bit computations (instcombine runs after to fold away the dead
457460
// computations, and then ADCE will run later to exploit any new DCE
458461
// opportunities that creates).
@@ -1028,6 +1031,9 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) {
10281031
if (EnableLoopInterchange)
10291032
PM.add(createLoopInterchangePass());
10301033

1034+
if (EnableConstraintElimination)
1035+
PM.add(createConstraintEliminationPass());
1036+
10311037
// Unroll small loops
10321038
PM.add(createSimpleLoopUnrollPass(OptLevel, DisableUnrollLoops,
10331039
ForgetAllSCEVInLoopUnroll));

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
6363
m_NUWShl(m_Value(Op0), m_ConstantInt(CI))))
6464
return {{0, nullptr},
6565
{1, GEP->getPointerOperand()},
66-
{pow(2, CI->getSExtValue()), Op0}};
66+
{std::pow(int64_t(2), CI->getSExtValue()), Op0}};
6767
if (match(GEP->getOperand(GEP->getNumOperands() - 1),
6868
m_ZExt(m_NUWShl(m_Value(Op0), m_ConstantInt(CI)))))
6969
return {{0, nullptr},
7070
{1, GEP->getPointerOperand()},
71-
{pow(2, CI->getSExtValue()), Op0}};
71+
{std::pow(int64_t(2), CI->getSExtValue()), Op0}};
7272

7373
return {{0, nullptr},
7474
{1, GEP->getPointerOperand()},
@@ -346,8 +346,10 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
346346
if (CB.Not)
347347
R = ConstraintSystem::negate(R);
348348

349-
CS.addVariableRowFill(R);
350-
DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
349+
// If R has been added to the system, queue it for removal once it goes
350+
// out-of-scope.
351+
if (CS.addVariableRowFill(R))
352+
DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
351353
}
352354

353355
return Changed;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -constraint-elimination -S %s | FileCheck %s
3+
4+
; Make sure constraints where all variable coefficients are 0 are handled
5+
; properly.
6+
7+
define i1 @test_1_always_false(i32 %A, i32 %B) {
8+
; CHECK-LABEL: @test_1_always_false(
9+
; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i32 [[A:%.*]], [[A]]
10+
; CHECK-NEXT: br i1 [[C_1]], label [[IF_END_I16:%.*]], label [[IF_THEN_I10:%.*]]
11+
; CHECK: if.then.i10:
12+
; CHECK-NEXT: ret i1 false
13+
; CHECK: if.end.i16:
14+
; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[A]], [[A]]
15+
; CHECK-NEXT: ret i1 false
16+
;
17+
%c.1 = icmp ugt i32 %A, %A
18+
br i1 %c.1, label %if.end.i16, label %if.then.i10
19+
20+
if.then.i10:
21+
ret i1 false
22+
23+
if.end.i16:
24+
%c.2 = icmp ugt i32 %A, %A
25+
ret i1 %c.2
26+
}
27+
28+
define i1 @test_2_always_true(i32 %A, i32 %B) {
29+
; CHECK-LABEL: @test_2_always_true(
30+
; CHECK-NEXT: [[C_1:%.*]] = icmp uge i32 [[A:%.*]], [[B:%.*]]
31+
; CHECK-NEXT: br i1 [[C_1]], label [[IF_END_I16:%.*]], label [[IF_THEN_I10:%.*]]
32+
; CHECK: if.then.i10:
33+
; CHECK-NEXT: ret i1 false
34+
; CHECK: if.end.i16:
35+
; CHECK-NEXT: [[C_2:%.*]] = icmp uge i32 [[A]], [[A]]
36+
; CHECK-NEXT: ret i1 true
37+
;
38+
%c.1 = icmp uge i32 %A, %B
39+
br i1 %c.1, label %if.end.i16, label %if.then.i10
40+
41+
if.then.i10:
42+
ret i1 false
43+
44+
if.end.i16:
45+
%c.2 = icmp uge i32 %A, %A
46+
ret i1 %c.2
47+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -constraint-elimination -S %s | FileCheck %s
3+
4+
; The system for the function below grows quite large. Check to make sure
5+
; we can handle that scenario.
6+
define void @test(i64 %x, i8* %y, i8* %z, i8* %w) {
7+
; CHECK-LABEL: @test(
8+
; CHECK-NEXT: [[TMP22:%.*]] = getelementptr inbounds i8, i8* [[Y:%.*]], i64 [[X:%.*]]
9+
; CHECK-NEXT: [[TMP26:%.*]] = icmp ult i8* [[TMP22]], [[Z:%.*]]
10+
; CHECK-NEXT: br i1 [[TMP26]], label [[BB28:%.*]], label [[EARLY_EXIT:%.*]]
11+
; CHECK: early.exit:
12+
; CHECK-NEXT: unreachable
13+
; CHECK: bb28:
14+
; CHECK-NEXT: [[TMP29:%.*]] = getelementptr inbounds i8, i8* [[Y]], i64 [[X]]
15+
; CHECK-NEXT: [[TMP30:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
16+
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB32:%.*]]
17+
; CHECK: bb32:
18+
; CHECK-NEXT: [[TMP33:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
19+
; CHECK-NEXT: br i1 true, label [[BB35:%.*]], label [[EARLY_EXIT]]
20+
; CHECK: bb35:
21+
; CHECK-NEXT: [[TMP36:%.*]] = icmp ult i8* [[Y]], [[Z]]
22+
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB38:%.*]]
23+
; CHECK: bb38:
24+
; CHECK-NEXT: [[TMP41:%.*]] = icmp ult i8* [[Y]], [[Z]]
25+
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB43:%.*]]
26+
; CHECK: bb43:
27+
; CHECK-NEXT: [[TMP47:%.*]] = getelementptr inbounds i8, i8* [[W:%.*]], i64 [[X]]
28+
; CHECK-NEXT: [[TMP48:%.*]] = icmp ult i8* [[TMP47]], [[Y]]
29+
; CHECK-NEXT: br i1 [[TMP48]], label [[EARLY_EXIT]], label [[BB50:%.*]]
30+
; CHECK: bb50:
31+
; CHECK-NEXT: [[TMP52:%.*]] = getelementptr inbounds i8, i8* [[W]], i64 [[X]]
32+
; CHECK-NEXT: [[TMP53:%.*]] = icmp ult i8* [[TMP52]], [[Y]]
33+
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB55:%.*]]
34+
; CHECK: bb55:
35+
; CHECK-NEXT: [[TMP57:%.*]] = icmp ult i8* [[W]], [[Y]]
36+
; CHECK-NEXT: br i1 true, label [[BB59:%.*]], label [[EARLY_EXIT]]
37+
; CHECK: bb59:
38+
; CHECK-NEXT: [[TMP60:%.*]] = icmp ult i8* [[W]], [[Y]]
39+
; CHECK-NEXT: call void @use(i1 true)
40+
; CHECK-NEXT: ret void
41+
;
42+
%tmp22 = getelementptr inbounds i8, i8* %y, i64 %x
43+
%tmp26 = icmp ult i8* %tmp22, %z
44+
br i1 %tmp26, label %bb28, label %early.exit
45+
46+
early.exit:
47+
unreachable
48+
49+
bb28:
50+
%tmp29 = getelementptr inbounds i8, i8* %y, i64 %x
51+
%tmp30 = icmp ult i8* %tmp29, %z
52+
br i1 %tmp30, label %early.exit, label %bb32
53+
54+
bb32:
55+
%tmp33 = icmp ult i8* %tmp29, %z
56+
br i1 %tmp33, label %bb35, label %early.exit
57+
58+
bb35:
59+
%tmp36 = icmp ult i8* %y, %z
60+
br i1 %tmp36, label %early.exit, label %bb38
61+
62+
bb38:
63+
%tmp41 = icmp ult i8* %y, %z
64+
br i1 %tmp41, label %early.exit, label %bb43
65+
66+
bb43:
67+
%tmp47 = getelementptr inbounds i8, i8* %w, i64 %x
68+
%tmp48 = icmp ult i8* %tmp47, %y
69+
br i1 %tmp48, label %early.exit, label %bb50
70+
71+
bb50:
72+
%tmp52 = getelementptr inbounds i8, i8* %w, i64 %x
73+
%tmp53 = icmp ult i8* %tmp52, %y
74+
br i1 %tmp53, label %early.exit, label %bb55
75+
76+
bb55:
77+
%tmp57 = icmp ult i8* %w, %y
78+
br i1 %tmp57, label %bb59, label %early.exit
79+
80+
bb59:
81+
%tmp60 = icmp ult i8* %w, %y
82+
call void @use(i1 %tmp60)
83+
ret void
84+
}
85+
86+
declare void @use(i1)

0 commit comments

Comments
 (0)