Skip to content

Commit 361b536

Browse files
committed
[Attributor] Simplify switches with more than one potential condition
Before, we allowed the condition to be simplified to a simple constant only, otherwise we assumed all successors are live. Now we allow multiple constants, and mark the default successor as dead accordingly.
1 parent a9167c2 commit 361b536

File tree

2 files changed

+171
-13
lines changed

2 files changed

+171
-13
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4776,23 +4776,53 @@ identifyAliveSuccessors(Attributor &A, const SwitchInst &SI,
47764776
AbstractAttribute &AA,
47774777
SmallVectorImpl<const Instruction *> &AliveSuccessors) {
47784778
bool UsedAssumedInformation = false;
4779-
std::optional<Constant *> C =
4780-
A.getAssumedConstant(*SI.getCondition(), AA, UsedAssumedInformation);
4781-
if (!C || isa_and_nonnull<UndefValue>(*C)) {
4782-
// No value yet, assume all edges are dead.
4783-
} else if (isa_and_nonnull<ConstantInt>(*C)) {
4784-
for (const auto &CaseIt : SI.cases()) {
4785-
if (CaseIt.getCaseValue() == *C) {
4786-
AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());
4787-
return UsedAssumedInformation;
4788-
}
4789-
}
4790-
AliveSuccessors.push_back(&SI.getDefaultDest()->front());
4779+
SmallVector<AA::ValueAndContext> Values;
4780+
if (!A.getAssumedSimplifiedValues(IRPosition::value(*SI.getCondition()), &AA,
4781+
Values, AA::AnyScope,
4782+
UsedAssumedInformation)) {
4783+
// Something went wrong, assume all successors are live.
4784+
for (const BasicBlock *SuccBB : successors(SI.getParent()))
4785+
AliveSuccessors.push_back(&SuccBB->front());
4786+
return false;
4787+
}
4788+
4789+
if (Values.empty() ||
4790+
(Values.size() == 1 &&
4791+
isa_and_nonnull<UndefValue>(Values.front().getValue()))) {
4792+
// No valid value yet, assume all edges are dead.
47914793
return UsedAssumedInformation;
4792-
} else {
4794+
}
4795+
4796+
Type &Ty = *SI.getCondition()->getType();
4797+
SmallPtrSet<ConstantInt *, 8> Constants;
4798+
auto CheckForConstantInt = [&](Value *V) {
4799+
if (auto *CI = dyn_cast_if_present<ConstantInt>(AA::getWithType(*V, Ty))) {
4800+
Constants.insert(CI);
4801+
return true;
4802+
}
4803+
return false;
4804+
};
4805+
4806+
if (!all_of(Values, [&](AA::ValueAndContext &VAC) {
4807+
return CheckForConstantInt(VAC.getValue());
4808+
})) {
47934809
for (const BasicBlock *SuccBB : successors(SI.getParent()))
47944810
AliveSuccessors.push_back(&SuccBB->front());
4811+
return UsedAssumedInformation;
47954812
}
4813+
4814+
unsigned MatchedCases = 0;
4815+
for (const auto &CaseIt : SI.cases()) {
4816+
if (Constants.count(CaseIt.getCaseValue())) {
4817+
++MatchedCases;
4818+
AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());
4819+
}
4820+
}
4821+
4822+
// If all potential values have been matched, we will not visit the default
4823+
// case.
4824+
if (MatchedCases < Constants.size())
4825+
AliveSuccessors.push_back(&SI.getDefaultDest()->front());
47964826
return UsedAssumedInformation;
47974827
}
47984828

llvm/test/Transforms/Attributor/value-simplify.ll

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,134 @@ define i1 @constexpr_icmp2() {
15051505
ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
15061506
}
15071507

1508+
define i8 @switch(i1 %c1, i1 %c2) {
1509+
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
1510+
; TUNIT-LABEL: define {{[^@]+}}@switch
1511+
; TUNIT-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR2]] {
1512+
; TUNIT-NEXT: entry:
1513+
; TUNIT-NEXT: br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
1514+
; TUNIT: t:
1515+
; TUNIT-NEXT: br label [[M:%.*]]
1516+
; TUNIT: f:
1517+
; TUNIT-NEXT: br label [[M]]
1518+
; TUNIT: m:
1519+
; TUNIT-NEXT: [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
1520+
; TUNIT-NEXT: switch i32 [[J]], label [[DEFAULT1:%.*]] [
1521+
; TUNIT-NEXT: i32 1, label [[DEAD1:%.*]]
1522+
; TUNIT-NEXT: i32 2, label [[DEAD2:%.*]]
1523+
; TUNIT-NEXT: i32 3, label [[DEAD3:%.*]]
1524+
; TUNIT-NEXT: i32 4, label [[ALIVE1:%.*]]
1525+
; TUNIT-NEXT: ]
1526+
; TUNIT: default1:
1527+
; TUNIT-NEXT: br label [[ALIVE1]]
1528+
; TUNIT: alive1:
1529+
; TUNIT-NEXT: [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
1530+
; TUNIT-NEXT: switch i32 [[K]], label [[DEAD4:%.*]] [
1531+
; TUNIT-NEXT: i32 1, label [[END1:%.*]]
1532+
; TUNIT-NEXT: i32 2, label [[DEAD5:%.*]]
1533+
; TUNIT-NEXT: i32 4, label [[END2:%.*]]
1534+
; TUNIT-NEXT: ]
1535+
; TUNIT: end1:
1536+
; TUNIT-NEXT: ret i8 -1
1537+
; TUNIT: end2:
1538+
; TUNIT-NEXT: ret i8 -2
1539+
; TUNIT: dead1:
1540+
; TUNIT-NEXT: unreachable
1541+
; TUNIT: dead2:
1542+
; TUNIT-NEXT: unreachable
1543+
; TUNIT: dead3:
1544+
; TUNIT-NEXT: unreachable
1545+
; TUNIT: dead4:
1546+
; TUNIT-NEXT: unreachable
1547+
; TUNIT: dead5:
1548+
; TUNIT-NEXT: unreachable
1549+
;
1550+
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
1551+
; CGSCC-LABEL: define {{[^@]+}}@switch
1552+
; CGSCC-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1]] {
1553+
; CGSCC-NEXT: entry:
1554+
; CGSCC-NEXT: br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
1555+
; CGSCC: t:
1556+
; CGSCC-NEXT: br label [[M:%.*]]
1557+
; CGSCC: f:
1558+
; CGSCC-NEXT: br label [[M]]
1559+
; CGSCC: m:
1560+
; CGSCC-NEXT: [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
1561+
; CGSCC-NEXT: switch i32 [[J]], label [[DEFAULT1:%.*]] [
1562+
; CGSCC-NEXT: i32 1, label [[DEAD1:%.*]]
1563+
; CGSCC-NEXT: i32 2, label [[DEAD2:%.*]]
1564+
; CGSCC-NEXT: i32 3, label [[DEAD3:%.*]]
1565+
; CGSCC-NEXT: i32 4, label [[ALIVE1:%.*]]
1566+
; CGSCC-NEXT: ]
1567+
; CGSCC: default1:
1568+
; CGSCC-NEXT: br label [[ALIVE1]]
1569+
; CGSCC: alive1:
1570+
; CGSCC-NEXT: [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
1571+
; CGSCC-NEXT: switch i32 [[K]], label [[DEAD4:%.*]] [
1572+
; CGSCC-NEXT: i32 1, label [[END1:%.*]]
1573+
; CGSCC-NEXT: i32 2, label [[DEAD5:%.*]]
1574+
; CGSCC-NEXT: i32 4, label [[END2:%.*]]
1575+
; CGSCC-NEXT: ]
1576+
; CGSCC: end1:
1577+
; CGSCC-NEXT: ret i8 -1
1578+
; CGSCC: end2:
1579+
; CGSCC-NEXT: ret i8 -2
1580+
; CGSCC: dead1:
1581+
; CGSCC-NEXT: unreachable
1582+
; CGSCC: dead2:
1583+
; CGSCC-NEXT: unreachable
1584+
; CGSCC: dead3:
1585+
; CGSCC-NEXT: unreachable
1586+
; CGSCC: dead4:
1587+
; CGSCC-NEXT: unreachable
1588+
; CGSCC: dead5:
1589+
; CGSCC-NEXT: unreachable
1590+
;
1591+
entry:
1592+
br i1 %c1, label %t, label %f
1593+
1594+
t:
1595+
br label %m
1596+
1597+
f:
1598+
br label %m
1599+
1600+
m:
1601+
%j = phi i32 [ 0, %t ], [ 4, %f ]
1602+
switch i32 %j, label %default1 [
1603+
i32 1, label %dead1
1604+
i32 2, label %dead2
1605+
i32 3, label %dead3
1606+
i32 4, label %alive1
1607+
]
1608+
1609+
default1:
1610+
br label %alive1
1611+
1612+
alive1:
1613+
%k = phi i32 [ 1, %m ], [ 4, %default1 ]
1614+
switch i32 %k, label %dead4 [
1615+
i32 1, label %end1
1616+
i32 2, label %dead5
1617+
i32 4, label %end2
1618+
]
1619+
1620+
end1:
1621+
ret i8 -1
1622+
end2:
1623+
ret i8 -2
1624+
dead1:
1625+
ret i8 1
1626+
dead2:
1627+
ret i8 2
1628+
dead3:
1629+
ret i8 3
1630+
dead4:
1631+
ret i8 4
1632+
dead5:
1633+
ret i8 5
1634+
}
1635+
15081636
;.
15091637
; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
15101638
; TUNIT: attributes #[[ATTR1]] = { memory(readwrite, argmem: none) }

0 commit comments

Comments
 (0)