Skip to content

Commit 88b5d23

Browse files
committed
[Attributor] Allow multiple LHS/RHS values when simplifying comparisons
We use to deal with multiple values but not in the handleCmp function. Now we also allow multiple simplified operands there.
1 parent 160ae64 commit 88b5d23

12 files changed

+212
-214
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 91 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10889,64 +10889,104 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
1088910889

1089010890
// Simplify the operands first.
1089110891
bool UsedAssumedInformation = false;
10892-
const auto &SimplifiedLHS = A.getAssumedSimplified(
10893-
IRPosition::value(*LHS, getCallBaseContext()), *this,
10894-
UsedAssumedInformation, AA::Intraprocedural);
10895-
if (!SimplifiedLHS.has_value())
10892+
SmallVector<AA::ValueAndContext> LHSValues, RHSValues;
10893+
auto GetSimplifiedValues = [&](Value &V,
10894+
SmallVector<AA::ValueAndContext> &Values) {
10895+
if (!A.getAssumedSimplifiedValues(
10896+
IRPosition::value(V, getCallBaseContext()), this, Values,
10897+
AA::Intraprocedural, UsedAssumedInformation)) {
10898+
Values.clear();
10899+
Values.push_back(AA::ValueAndContext{V, II.I.getCtxI()});
10900+
}
10901+
return Values.empty();
10902+
};
10903+
if (GetSimplifiedValues(*LHS, LHSValues))
1089610904
return true;
10897-
if (!*SimplifiedLHS)
10898-
return false;
10899-
LHS = *SimplifiedLHS;
10900-
10901-
const auto &SimplifiedRHS = A.getAssumedSimplified(
10902-
IRPosition::value(*RHS, getCallBaseContext()), *this,
10903-
UsedAssumedInformation, AA::Intraprocedural);
10904-
if (!SimplifiedRHS.has_value())
10905+
if (GetSimplifiedValues(*RHS, RHSValues))
1090510906
return true;
10906-
if (!*SimplifiedRHS)
10907-
return false;
10908-
RHS = *SimplifiedRHS;
1090910907

1091010908
LLVMContext &Ctx = LHS->getContext();
10911-
// Handle the trivial case first in which we don't even need to think about
10912-
// null or non-null.
10913-
if (LHS == RHS &&
10914-
(CmpInst::isTrueWhenEqual(Pred) || CmpInst::isFalseWhenEqual(Pred))) {
10915-
Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
10916-
CmpInst::isTrueWhenEqual(Pred));
10917-
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,
10918-
getAnchorScope());
10919-
return true;
10920-
}
1092110909

10922-
// From now on we only handle equalities (==, !=).
10923-
if (!CmpInst::isEquality(Pred))
10924-
return false;
10910+
InformationCache &InfoCache = A.getInfoCache();
10911+
Instruction *CmpI = dyn_cast<Instruction>(&Cmp);
10912+
Function *F = CmpI ? CmpI->getFunction() : nullptr;
10913+
const auto *DT =
10914+
F ? InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*F)
10915+
: nullptr;
10916+
const auto *TLI =
10917+
F ? A.getInfoCache().getTargetLibraryInfoForFunction(*F) : nullptr;
10918+
auto *AC =
10919+
F ? InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*F)
10920+
: nullptr;
1092510921

10926-
bool LHSIsNull = isa<ConstantPointerNull>(LHS);
10927-
bool RHSIsNull = isa<ConstantPointerNull>(RHS);
10928-
if (!LHSIsNull && !RHSIsNull)
10929-
return false;
10922+
const DataLayout &DL = A.getDataLayout();
10923+
SimplifyQuery Q(DL, TLI, DT, AC, CmpI);
1093010924

10931-
// Left is the nullptr ==/!= non-nullptr case. We'll use AANonNull on the
10932-
// non-nullptr operand and if we assume it's non-null we can conclude the
10933-
// result of the comparison.
10934-
assert((LHSIsNull || RHSIsNull) &&
10935-
"Expected nullptr versus non-nullptr comparison at this point");
10925+
auto CheckPair = [&](Value &LHSV, Value &RHSV) {
10926+
if (isa<UndefValue>(LHSV) || isa<UndefValue>(RHSV)) {
10927+
addValue(A, getState(), *UndefValue::get(Cmp.getType()),
10928+
/* CtxI */ nullptr, II.S, getAnchorScope());
10929+
return true;
10930+
}
1093610931

10937-
// The index is the operand that we assume is not null.
10938-
unsigned PtrIdx = LHSIsNull;
10939-
bool IsKnownNonNull;
10940-
bool IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(
10941-
A, this, IRPosition::value(*(PtrIdx ? RHS : LHS)), DepClassTy::REQUIRED,
10942-
IsKnownNonNull);
10943-
if (!IsAssumedNonNull)
10944-
return false;
10932+
// Handle the trivial case first in which we don't even need to think
10933+
// about null or non-null.
10934+
if (&LHSV == &RHSV &&
10935+
(CmpInst::isTrueWhenEqual(Pred) || CmpInst::isFalseWhenEqual(Pred))) {
10936+
Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
10937+
CmpInst::isTrueWhenEqual(Pred));
10938+
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,
10939+
getAnchorScope());
10940+
return true;
10941+
}
10942+
10943+
auto *TypedLHS = AA::getWithType(LHSV, *LHS->getType());
10944+
auto *TypedRHS = AA::getWithType(RHSV, *RHS->getType());
10945+
if (TypedLHS && TypedRHS) {
10946+
Value *NewV = simplifyCmpInst(Pred, TypedLHS, TypedRHS, Q);
10947+
if (NewV && NewV != &Cmp) {
10948+
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,
10949+
getAnchorScope());
10950+
return true;
10951+
}
10952+
}
10953+
10954+
// From now on we only handle equalities (==, !=).
10955+
if (!CmpInst::isEquality(Pred))
10956+
return false;
1094510957

10946-
// The new value depends on the predicate, true for != and false for ==.
10947-
Constant *NewV =
10948-
ConstantInt::get(Type::getInt1Ty(Ctx), Pred == CmpInst::ICMP_NE);
10949-
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S, getAnchorScope());
10958+
bool LHSIsNull = isa<ConstantPointerNull>(LHSV);
10959+
bool RHSIsNull = isa<ConstantPointerNull>(RHSV);
10960+
if (!LHSIsNull && !RHSIsNull)
10961+
return false;
10962+
10963+
// Left is the nullptr ==/!= non-nullptr case. We'll use AANonNull on the
10964+
// non-nullptr operand and if we assume it's non-null we can conclude the
10965+
// result of the comparison.
10966+
assert((LHSIsNull || RHSIsNull) &&
10967+
"Expected nullptr versus non-nullptr comparison at this point");
10968+
10969+
// The index is the operand that we assume is not null.
10970+
unsigned PtrIdx = LHSIsNull;
10971+
bool IsKnownNonNull;
10972+
bool IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(
10973+
A, this, IRPosition::value(*(PtrIdx ? &RHSV : &LHSV)),
10974+
DepClassTy::REQUIRED, IsKnownNonNull);
10975+
if (!IsAssumedNonNull)
10976+
return false;
10977+
10978+
// The new value depends on the predicate, true for != and false for ==.
10979+
Constant *NewV =
10980+
ConstantInt::get(Type::getInt1Ty(Ctx), Pred == CmpInst::ICMP_NE);
10981+
addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,
10982+
getAnchorScope());
10983+
return true;
10984+
};
10985+
10986+
for (auto &LHSValue : LHSValues)
10987+
for (auto &RHSValue : RHSValues)
10988+
if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
10989+
return false;
1095010990
return true;
1095110991
}
1095210992

@@ -11161,9 +11201,8 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
1116111201
SmallVectorImpl<ItemInfo> &Worklist,
1116211202
SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
1116311203
if (auto *CI = dyn_cast<CmpInst>(&I))
11164-
if (handleCmp(A, *CI, CI->getOperand(0), CI->getOperand(1),
11165-
CI->getPredicate(), II, Worklist))
11166-
return true;
11204+
return handleCmp(A, *CI, CI->getOperand(0), CI->getOperand(1),
11205+
CI->getPredicate(), II, Worklist);
1116711206

1116811207
switch (I.getOpcode()) {
1116911208
case Instruction::Select:

llvm/test/Transforms/Attributor/assumes_info.ll

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@
33
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
44

55
define dso_local void @entry(i1 %cond) #0 {
6-
; CHECK-LABEL: define {{[^@]+}}@entry
7-
; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
8-
; CHECK-NEXT: entry:
9-
; CHECK-NEXT: call void @foo(i1 [[COND]]) #[[ATTR1:[0-9]+]]
10-
; CHECK-NEXT: call void @bar() #[[ATTR2:[0-9]+]]
11-
; CHECK-NEXT: call void @qux() #[[ATTR1]]
12-
; CHECK-NEXT: ret void
6+
; TUNIT-LABEL: define {{[^@]+}}@entry
7+
; TUNIT-SAME: (i1 [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
8+
; TUNIT-NEXT: entry:
9+
; TUNIT-NEXT: call void @foo(i1 [[COND]]) #[[ATTR1:[0-9]+]]
10+
; TUNIT-NEXT: call void @bar() #[[ATTR2:[0-9]+]]
11+
; TUNIT-NEXT: call void @qux() #[[ATTR1]]
12+
; TUNIT-NEXT: ret void
13+
;
14+
; CGSCC-LABEL: define {{[^@]+}}@entry
15+
; CGSCC-SAME: (i1 noundef [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
16+
; CGSCC-NEXT: entry:
17+
; CGSCC-NEXT: call void @foo(i1 noundef [[COND]]) #[[ATTR1:[0-9]+]]
18+
; CGSCC-NEXT: call void @bar() #[[ATTR2:[0-9]+]]
19+
; CGSCC-NEXT: call void @qux() #[[ATTR1]]
20+
; CGSCC-NEXT: ret void
1321
;
1422
entry:
1523
call void @foo(i1 %cond)
@@ -19,11 +27,17 @@ entry:
1927
}
2028

2129
define internal void @foo(i1 %cond) #1 {
22-
; CHECK-LABEL: define {{[^@]+}}@foo
23-
; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] {
24-
; CHECK-NEXT: entry:
25-
; CHECK-NEXT: call void @baz(i1 [[COND]]) #[[ATTR1]]
26-
; CHECK-NEXT: ret void
30+
; TUNIT-LABEL: define {{[^@]+}}@foo
31+
; TUNIT-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] {
32+
; TUNIT-NEXT: entry:
33+
; TUNIT-NEXT: call void @baz(i1 [[COND]]) #[[ATTR1]]
34+
; TUNIT-NEXT: ret void
35+
;
36+
; CGSCC-LABEL: define {{[^@]+}}@foo
37+
; CGSCC-SAME: (i1 noundef [[COND:%.*]]) #[[ATTR1]] {
38+
; CGSCC-NEXT: entry:
39+
; CGSCC-NEXT: call void @baz(i1 noundef [[COND]]) #[[ATTR1]]
40+
; CGSCC-NEXT: ret void
2741
;
2842
entry:
2943
call void @baz(i1 %cond)
@@ -32,7 +46,7 @@ entry:
3246

3347
define internal void @bar() #2 {
3448
; CHECK-LABEL: define {{[^@]+}}@bar
35-
; CHECK-SAME: () #[[ATTR2]] {
49+
; CHECK-SAME: () #[[ATTR2:[0-9]+]] {
3650
; CHECK-NEXT: entry:
3751
; CHECK-NEXT: call void @baz(i1 noundef false) #[[ATTR2]]
3852
; CHECK-NEXT: ret void
@@ -46,8 +60,7 @@ define internal void @baz(i1 %Cond) {
4660
; TUNIT-LABEL: define {{[^@]+}}@baz
4761
; TUNIT-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] {
4862
; TUNIT-NEXT: entry:
49-
; TUNIT-NEXT: [[TOBOOL:%.*]] = icmp ne i1 [[COND]], false
50-
; TUNIT-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
63+
; TUNIT-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
5164
; TUNIT: if.then:
5265
; TUNIT-NEXT: call void @baz(i1 noundef false) #[[ATTR1]]
5366
; TUNIT-NEXT: br label [[IF_END]]
@@ -56,10 +69,9 @@ define internal void @baz(i1 %Cond) {
5669
; TUNIT-NEXT: ret void
5770
;
5871
; CGSCC-LABEL: define {{[^@]+}}@baz
59-
; CGSCC-SAME: (i1 [[COND:%.*]]) #[[ATTR3:[0-9]+]] {
72+
; CGSCC-SAME: (i1 noundef [[COND:%.*]]) #[[ATTR3:[0-9]+]] {
6073
; CGSCC-NEXT: entry:
61-
; CGSCC-NEXT: [[TOBOOL:%.*]] = icmp ne i1 [[COND]], false
62-
; CGSCC-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
74+
; CGSCC-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
6375
; CGSCC: if.then:
6476
; CGSCC-NEXT: call void @baz(i1 noundef false) #[[ATTR3]]
6577
; CGSCC-NEXT: br label [[IF_END]]

llvm/test/Transforms/Attributor/dereferenceable-2-inseltpoison.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,10 @@ define i32 @require_cfg_analysis(i32 %c, ptr %p) {
517517
; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0
518518
; CHECK-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]]
519519
; CHECK: l1:
520-
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[C]], 1
521-
; CHECK-NEXT: br i1 [[TOBOOL2]], label [[L3:%.*]], label [[L4:%.*]]
520+
; CHECK-NEXT: br label [[L4:%.*]]
522521
; CHECK: l2:
523522
; CHECK-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2
524-
; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3]], label [[L4]]
523+
; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3:%.*]], label [[L4]]
525524
; CHECK: l3:
526525
; CHECK-NEXT: br label [[L5:%.*]]
527526
; CHECK: l4:

llvm/test/Transforms/Attributor/dereferenceable-2.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,10 @@ define i32 @require_cfg_analysis(i32 %c, ptr %p) {
517517
; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0
518518
; CHECK-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]]
519519
; CHECK: l1:
520-
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[C]], 1
521-
; CHECK-NEXT: br i1 [[TOBOOL2]], label [[L3:%.*]], label [[L4:%.*]]
520+
; CHECK-NEXT: br label [[L4:%.*]]
522521
; CHECK: l2:
523522
; CHECK-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2
524-
; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3]], label [[L4]]
523+
; CHECK-NEXT: br i1 [[TOBOOL3]], label [[L3:%.*]], label [[L4]]
525524
; CHECK: l3:
526525
; CHECK-NEXT: br label [[L5:%.*]]
527526
; CHECK: l4:

llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ define i8 @test1(i32 %a, i32 %length) {
1010
; CHECK-NEXT: br label [[LOOP:%.*]]
1111
; CHECK: loop:
1212
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
13-
; CHECK-NEXT: [[CND:%.*]] = icmp sge i32 [[IV]], 0
14-
; CHECK-NEXT: br i1 [[CND]], label [[BACKEDGE]], label [[EXIT:%.*]]
13+
; CHECK-NEXT: br label [[BACKEDGE]]
1514
; CHECK: backedge:
1615
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
1716
; CHECK-NEXT: [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400
18-
; CHECK-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT]]
17+
; CHECK-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT:%.*]]
1918
; CHECK: exit:
2019
; CHECK-NEXT: ret i8 0
2120
;
@@ -45,10 +44,8 @@ define i8 @test2(i32 %n) {
4544
; CHECK: loop:
4645
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
4746
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[IV2_NEXT:%.*]], [[BACKEDGE]] ]
48-
; CHECK-NEXT: [[CND1:%.*]] = icmp sge i32 [[IV]], 0
4947
; CHECK-NEXT: [[CND2:%.*]] = icmp sgt i32 [[IV2]], 0
50-
; CHECK-NEXT: [[CND:%.*]] = and i1 [[CND1]], [[CND2]]
51-
; CHECK-NEXT: br i1 [[CND]], label [[BACKEDGE]], label [[EXIT:%.*]]
48+
; CHECK-NEXT: br i1 [[CND2]], label [[BACKEDGE]], label [[EXIT:%.*]]
5249
; CHECK: backedge:
5350
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
5451
; CHECK-NEXT: [[IV2_NEXT]] = sub nsw i32 [[IV2]], 1

llvm/test/Transforms/Attributor/nocapture-2.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,9 @@ define i32 @is_null_control(ptr %p) #0 {
5353
; CHECK-NEXT: store i32 1, ptr [[RETVAL]], align 4
5454
; CHECK-NEXT: br label [[RETURN:%.*]]
5555
; CHECK: if.end:
56-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr null, [[P]]
57-
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
56+
; CHECK-NEXT: br label [[IF_END3:%.*]]
5857
; CHECK: if.then2:
59-
; CHECK-NEXT: store i32 1, ptr [[RETVAL]], align 4
60-
; CHECK-NEXT: br label [[RETURN]]
58+
; CHECK-NEXT: unreachable
6159
; CHECK: if.end3:
6260
; CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
6361
; CHECK-NEXT: br label [[RETURN]]

0 commit comments

Comments
 (0)