Skip to content

Commit c83eacd

Browse files
committed
[Loads] Check if Ptr can be freed between Assume and CtxI. (llvm#161255)
When using information from dereferenceable assumptions, we need to make sure that the memory is not freed between the assume and the specified context instruction. Instead of just checking canBeFreed, check if there any calls that may free between the assume and the context instruction. Note that this also adjusts the context instruction to be the terminator in the loop predecessor, if there is one and it is a branch (to avoid things like invoke). PR: llvm#161255 (cherry picked from commit 8b8c59c)
1 parent 5c9f0df commit c83eacd

File tree

3 files changed

+322
-62
lines changed

3 files changed

+322
-62
lines changed

llvm/lib/Analysis/Loads.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,13 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
3636
function_ref<bool(const RetainedKnowledge &RK)> CheckSize,
3737
const DataLayout &DL, const Instruction *CtxI, AssumptionCache *AC,
3838
const DominatorTree *DT) {
39-
// Dereferenceable information from assumptions is only valid if the value
40-
// cannot be freed between the assumption and use. For now just use the
41-
// information for values that cannot be freed in the function.
42-
// TODO: More precisely check if the pointer can be freed between assumption
43-
// and use.
44-
if (!CtxI || Ptr->canBeFreed())
39+
if (!CtxI)
4540
return false;
4641
/// Look through assumes to see if both dereferencability and alignment can
4742
/// be proven by an assume if needed.
4843
RetainedKnowledge AlignRK;
4944
RetainedKnowledge DerefRK;
45+
bool PtrCanBeFreed = Ptr->canBeFreed();
5046
bool IsAligned = Ptr->getPointerAlignment(DL) >= Alignment;
5147
return getKnowledgeForValue(
5248
Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *AC,
@@ -55,7 +51,11 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
5551
return false;
5652
if (RK.AttrKind == Attribute::Alignment)
5753
AlignRK = std::max(AlignRK, RK);
58-
if (RK.AttrKind == Attribute::Dereferenceable)
54+
55+
// Dereferenceable information from assumptions is only valid if the
56+
// value cannot be freed between the assumption and use.
57+
if ((!PtrCanBeFreed || willNotFreeBetween(Assume, CtxI)) &&
58+
RK.AttrKind == Attribute::Dereferenceable)
5959
DerefRK = std::max(DerefRK, RK);
6060
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
6161
if (IsAligned && DerefRK && CheckSize(DerefRK))
@@ -390,7 +390,11 @@ bool llvm::isDereferenceableAndAlignedInLoop(
390390
} else
391391
return false;
392392

393-
Instruction *HeaderFirstNonPHI = &*L->getHeader()->getFirstNonPHIIt();
393+
Instruction *CtxI = &*L->getHeader()->getFirstNonPHIIt();
394+
if (BasicBlock *LoopPred = L->getLoopPredecessor()) {
395+
if (isa<BranchInst>(LoopPred->getTerminator()))
396+
CtxI = LoopPred->getTerminator();
397+
}
394398
return isDereferenceableAndAlignedPointerViaAssumption(
395399
Base, Alignment,
396400
[&SE, AccessSizeSCEV, &LoopGuards](const RetainedKnowledge &RK) {
@@ -399,9 +403,9 @@ bool llvm::isDereferenceableAndAlignedInLoop(
399403
SE.applyLoopGuards(AccessSizeSCEV, *LoopGuards),
400404
SE.applyLoopGuards(SE.getSCEV(RK.IRArgValue), *LoopGuards));
401405
},
402-
DL, HeaderFirstNonPHI, AC, &DT) ||
406+
DL, CtxI, AC, &DT) ||
403407
isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
404-
HeaderFirstNonPHI, AC, &DT);
408+
CtxI, AC, &DT);
405409
}
406410

407411
static bool suppressSpeculativeLoadForSanitizers(const Instruction &CtxI) {

llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll

Lines changed: 283 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,41 +1587,286 @@ exit:
15871587
declare ptr @get_ptr()
15881588
declare void @may_free()
15891589

1590-
;.
1591-
; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
1592-
; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
1593-
; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
1594-
; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}
1595-
; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
1596-
; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]}
1597-
; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]]}
1598-
; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META1]]}
1599-
; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META1]], [[META2]]}
1600-
; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META2]], [[META1]]}
1601-
; CHECK: [[LOOP10]] = distinct !{[[LOOP10]], [[META1]], [[META2]]}
1602-
; CHECK: [[LOOP11]] = distinct !{[[LOOP11]], [[META2]], [[META1]]}
1603-
; CHECK: [[LOOP12]] = distinct !{[[LOOP12]], [[META1]], [[META2]]}
1604-
; CHECK: [[LOOP13]] = distinct !{[[LOOP13]], [[META2]], [[META1]]}
1605-
; CHECK: [[LOOP14]] = distinct !{[[LOOP14]], [[META1]], [[META2]]}
1606-
; CHECK: [[LOOP15]] = distinct !{[[LOOP15]], [[META2]], [[META1]]}
1607-
; CHECK: [[LOOP16]] = distinct !{[[LOOP16]], [[META1]], [[META2]]}
1608-
; CHECK: [[LOOP17]] = distinct !{[[LOOP17]], [[META2]], [[META1]]}
1609-
; CHECK: [[LOOP18]] = distinct !{[[LOOP18]], [[META1]], [[META2]]}
1610-
; CHECK: [[LOOP19]] = distinct !{[[LOOP19]], [[META2]], [[META1]]}
1611-
; CHECK: [[LOOP20]] = distinct !{[[LOOP20]], [[META1]], [[META2]]}
1612-
; CHECK: [[LOOP21]] = distinct !{[[LOOP21]], [[META2]], [[META1]]}
1613-
; CHECK: [[LOOP22]] = distinct !{[[LOOP22]], [[META1]], [[META2]]}
1614-
; CHECK: [[LOOP23]] = distinct !{[[LOOP23]], [[META2]], [[META1]]}
1615-
; CHECK: [[LOOP24]] = distinct !{[[LOOP24]], [[META1]], [[META2]]}
1616-
; CHECK: [[LOOP25]] = distinct !{[[LOOP25]], [[META2]], [[META1]]}
1617-
; CHECK: [[LOOP26]] = distinct !{[[LOOP26]], [[META1]], [[META2]]}
1618-
; CHECK: [[LOOP27]] = distinct !{[[LOOP27]], [[META2]], [[META1]]}
1619-
; CHECK: [[LOOP28]] = distinct !{[[LOOP28]], [[META1]], [[META2]]}
1620-
; CHECK: [[LOOP29]] = distinct !{[[LOOP29]], [[META2]], [[META1]]}
1621-
; CHECK: [[LOOP30]] = distinct !{[[LOOP30]], [[META1]], [[META2]]}
1622-
; CHECK: [[LOOP31]] = distinct !{[[LOOP31]], [[META2]], [[META1]]}
1623-
; CHECK: [[LOOP32]] = distinct !{[[LOOP32]], [[META1]], [[META2]]}
1624-
; CHECK: [[LOOP33]] = distinct !{[[LOOP33]], [[META2]], [[META1]]}
1625-
; CHECK: [[LOOP34]] = distinct !{[[LOOP34]], [[META1]], [[META2]]}
1626-
; CHECK: [[LOOP35]] = distinct !{[[LOOP35]], [[META2]], [[META1]]}
1627-
;.
1590+
define void @deref_assumption_in_header_constant_trip_count_nofree_via_context(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c) nosync {
1591+
; CHECK-LABEL: define void @deref_assumption_in_header_constant_trip_count_nofree_via_context(
1592+
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR2:[0-9]+]] {
1593+
; CHECK-NEXT: [[ENTRY:.*:]]
1594+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 4000) ]
1595+
; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
1596+
; CHECK: [[VECTOR_PH]]:
1597+
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
1598+
; CHECK: [[VECTOR_BODY]]:
1599+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
1600+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
1601+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
1602+
; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
1603+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sge <2 x i32> [[WIDE_LOAD1]], zeroinitializer
1604+
; CHECK-NEXT: [[WIDE_LOAD2:%.*]] = load <2 x i32>, ptr [[TMP1]], align 4
1605+
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[WIDE_LOAD1]], <2 x i32> [[WIDE_LOAD2]]
1606+
; CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
1607+
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
1608+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
1609+
; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000
1610+
; CHECK-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP20:![0-9]+]]
1611+
; CHECK: [[MIDDLE_BLOCK]]:
1612+
; CHECK-NEXT: br [[EXIT:label %.*]]
1613+
; CHECK: [[SCALAR_PH:.*:]]
1614+
;
1615+
entry:
1616+
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 4000) ]
1617+
br label %loop.header
1618+
1619+
loop.header:
1620+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
1621+
%gep.a = getelementptr i32, ptr %a, i64 %iv
1622+
%gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
1623+
%l.b = load i32, ptr %gep.b, align 4
1624+
%c.1 = icmp sge i32 %l.b, 0
1625+
br i1 %c.1, label %loop.latch, label %loop.then
1626+
1627+
loop.then:
1628+
%l.a = load i32, ptr %gep.a, align 4
1629+
br label %loop.latch
1630+
1631+
loop.latch:
1632+
%merge = phi i32 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
1633+
%gep.c = getelementptr inbounds i32, ptr %c, i64 %iv
1634+
store i32 %merge, ptr %gep.c, align 4
1635+
%iv.next = add nuw nsw i64 %iv, 1
1636+
%ec = icmp eq i64 %iv.next, 1000
1637+
br i1 %ec, label %exit, label %loop.header
1638+
1639+
exit:
1640+
ret void
1641+
}
1642+
1643+
define void @deref_assumption_in_header_constant_trip_count_may_free(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c) nosync {
1644+
; CHECK-LABEL: define void @deref_assumption_in_header_constant_trip_count_may_free(
1645+
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR2]] {
1646+
; CHECK-NEXT: [[ENTRY:.*:]]
1647+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 4000) ]
1648+
; CHECK-NEXT: call void @may_free()
1649+
; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
1650+
; CHECK: [[VECTOR_PH]]:
1651+
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
1652+
; CHECK: [[VECTOR_BODY]]:
1653+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
1654+
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
1655+
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP3]], align 4
1656+
; CHECK-NEXT: [[TMP4:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
1657+
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x i1> [[TMP4]], i32 0
1658+
; CHECK-NEXT: br i1 [[TMP5]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
1659+
; CHECK: [[PRED_LOAD_IF]]:
1660+
; CHECK-NEXT: [[TMP17:%.*]] = add i64 [[INDEX]], 0
1661+
; CHECK-NEXT: [[TMP6:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP17]]
1662+
; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[TMP6]], align 4
1663+
; CHECK-NEXT: [[TMP8:%.*]] = insertelement <2 x i32> poison, i32 [[TMP7]], i32 0
1664+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE]]
1665+
; CHECK: [[PRED_LOAD_CONTINUE]]:
1666+
; CHECK-NEXT: [[TMP9:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP8]], %[[PRED_LOAD_IF]] ]
1667+
; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x i1> [[TMP4]], i32 1
1668+
; CHECK-NEXT: br i1 [[TMP10]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
1669+
; CHECK: [[PRED_LOAD_IF1]]:
1670+
; CHECK-NEXT: [[TMP18:%.*]] = add i64 [[INDEX]], 1
1671+
; CHECK-NEXT: [[TMP11:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP18]]
1672+
; CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
1673+
; CHECK-NEXT: [[TMP13:%.*]] = insertelement <2 x i32> [[TMP9]], i32 [[TMP12]], i32 1
1674+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE2]]
1675+
; CHECK: [[PRED_LOAD_CONTINUE2]]:
1676+
; CHECK-NEXT: [[TMP14:%.*]] = phi <2 x i32> [ [[TMP9]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP13]], %[[PRED_LOAD_IF1]] ]
1677+
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP4]], <2 x i32> [[TMP14]], <2 x i32> [[WIDE_LOAD]]
1678+
; CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
1679+
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP15]], align 4
1680+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
1681+
; CHECK-NEXT: [[TMP16:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000
1682+
; CHECK-NEXT: br i1 [[TMP16]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP21:![0-9]+]]
1683+
; CHECK: [[MIDDLE_BLOCK]]:
1684+
; CHECK-NEXT: br [[EXIT:label %.*]]
1685+
; CHECK: [[SCALAR_PH:.*:]]
1686+
;
1687+
entry:
1688+
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 4000) ]
1689+
call void @may_free()
1690+
br label %loop.header
1691+
1692+
loop.header:
1693+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
1694+
%gep.a = getelementptr i32, ptr %a, i64 %iv
1695+
%gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
1696+
%l.b = load i32, ptr %gep.b, align 4
1697+
%c.1 = icmp sge i32 %l.b, 0
1698+
br i1 %c.1, label %loop.latch, label %loop.then
1699+
1700+
loop.then:
1701+
%l.a = load i32, ptr %gep.a, align 4
1702+
br label %loop.latch
1703+
1704+
loop.latch:
1705+
%merge = phi i32 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
1706+
%gep.c = getelementptr inbounds i32, ptr %c, i64 %iv
1707+
store i32 %merge, ptr %gep.c, align 4
1708+
%iv.next = add nuw nsw i64 %iv, 1
1709+
%ec = icmp eq i64 %iv.next, 1000
1710+
br i1 %ec, label %exit, label %loop.header
1711+
1712+
exit:
1713+
ret void
1714+
}
1715+
1716+
define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_but_missing_nosync(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c) {
1717+
; CHECK-LABEL: define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_but_missing_nosync(
1718+
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) {
1719+
; CHECK-NEXT: [[ENTRY:.*:]]
1720+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 4000) ]
1721+
; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
1722+
; CHECK: [[VECTOR_PH]]:
1723+
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
1724+
; CHECK: [[VECTOR_BODY]]:
1725+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
1726+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
1727+
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
1728+
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
1729+
; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i32 0
1730+
; CHECK-NEXT: br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
1731+
; CHECK: [[PRED_LOAD_IF]]:
1732+
; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[INDEX]], 0
1733+
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP3]]
1734+
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
1735+
; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i32 0
1736+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE]]
1737+
; CHECK: [[PRED_LOAD_CONTINUE]]:
1738+
; CHECK-NEXT: [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
1739+
; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i32 1
1740+
; CHECK-NEXT: br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
1741+
; CHECK: [[PRED_LOAD_IF1]]:
1742+
; CHECK-NEXT: [[TMP9:%.*]] = add i64 [[INDEX]], 1
1743+
; CHECK-NEXT: [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
1744+
; CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
1745+
; CHECK-NEXT: [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i32 1
1746+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE2]]
1747+
; CHECK: [[PRED_LOAD_CONTINUE2]]:
1748+
; CHECK-NEXT: [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
1749+
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
1750+
; CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
1751+
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
1752+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
1753+
; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000
1754+
; CHECK-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP22:![0-9]+]]
1755+
; CHECK: [[MIDDLE_BLOCK]]:
1756+
; CHECK-NEXT: br [[EXIT:label %.*]]
1757+
; CHECK: [[SCALAR_PH:.*:]]
1758+
;
1759+
entry:
1760+
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 4000) ]
1761+
br label %loop.header
1762+
1763+
loop.header:
1764+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
1765+
%gep.a = getelementptr i32, ptr %a, i64 %iv
1766+
%gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
1767+
%l.b = load i32, ptr %gep.b, align 4
1768+
%c.1 = icmp sge i32 %l.b, 0
1769+
br i1 %c.1, label %loop.latch, label %loop.then
1770+
1771+
loop.then:
1772+
%l.a = load i32, ptr %gep.a, align 4
1773+
br label %loop.latch
1774+
1775+
loop.latch:
1776+
%merge = phi i32 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
1777+
%gep.c = getelementptr inbounds i32, ptr %c, i64 %iv
1778+
store i32 %merge, ptr %gep.c, align 4
1779+
%iv.next = add nuw nsw i64 %iv, 1
1780+
%ec = icmp eq i64 %iv.next, 1000
1781+
br i1 %ec, label %exit, label %loop.header
1782+
1783+
exit:
1784+
ret void
1785+
}
1786+
1787+
define void @deref_assumption_in_header_constant_trip_count_multiple_loop_predecessors(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c, i1 %pre) nosync {
1788+
; CHECK-LABEL: define void @deref_assumption_in_header_constant_trip_count_multiple_loop_predecessors(
1789+
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]], i1 [[PRE:%.*]]) #[[ATTR2]] {
1790+
; CHECK-NEXT: [[ENTRY:.*:]]
1791+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 4000) ]
1792+
; CHECK-NEXT: br i1 [[PRE]], label %[[THEN:.*]], label %[[ELSE:.*]]
1793+
; CHECK: [[THEN]]:
1794+
; CHECK-NEXT: store i32 0, ptr [[A]], align 4
1795+
; CHECK-NEXT: br label %[[LOOP_HEADER_PREHEADER:.*]]
1796+
; CHECK: [[ELSE]]:
1797+
; CHECK-NEXT: store i32 0, ptr [[B]], align 4
1798+
; CHECK-NEXT: br label %[[LOOP_HEADER_PREHEADER]]
1799+
; CHECK: [[LOOP_HEADER_PREHEADER]]:
1800+
; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
1801+
; CHECK: [[VECTOR_PH]]:
1802+
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
1803+
; CHECK: [[VECTOR_BODY]]:
1804+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
1805+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
1806+
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
1807+
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
1808+
; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i32 0
1809+
; CHECK-NEXT: br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
1810+
; CHECK: [[PRED_LOAD_IF]]:
1811+
; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[INDEX]], 0
1812+
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP3]]
1813+
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
1814+
; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i32 0
1815+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE]]
1816+
; CHECK: [[PRED_LOAD_CONTINUE]]:
1817+
; CHECK-NEXT: [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
1818+
; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i32 1
1819+
; CHECK-NEXT: br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
1820+
; CHECK: [[PRED_LOAD_IF1]]:
1821+
; CHECK-NEXT: [[TMP9:%.*]] = add i64 [[INDEX]], 1
1822+
; CHECK-NEXT: [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
1823+
; CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
1824+
; CHECK-NEXT: [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i32 1
1825+
; CHECK-NEXT: br label %[[PRED_LOAD_CONTINUE2]]
1826+
; CHECK: [[PRED_LOAD_CONTINUE2]]:
1827+
; CHECK-NEXT: [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
1828+
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
1829+
; CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
1830+
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
1831+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
1832+
; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000
1833+
; CHECK-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP23:![0-9]+]]
1834+
; CHECK: [[MIDDLE_BLOCK]]:
1835+
; CHECK-NEXT: br [[EXIT:label %.*]]
1836+
; CHECK: [[SCALAR_PH:.*:]]
1837+
;
1838+
entry:
1839+
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 4000) ]
1840+
br i1 %pre, label %then, label %else
1841+
1842+
then:
1843+
store i32 0, ptr %a
1844+
br label %loop.header
1845+
1846+
else:
1847+
store i32 0, ptr %b
1848+
br label %loop.header
1849+
1850+
loop.header:
1851+
%iv = phi i64 [ 0, %then ], [ 0, %else ], [ %iv.next, %loop.latch ]
1852+
%gep.a = getelementptr i32, ptr %a, i64 %iv
1853+
%gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
1854+
%l.b = load i32, ptr %gep.b, align 4
1855+
%c.1 = icmp sge i32 %l.b, 0
1856+
br i1 %c.1, label %loop.latch, label %loop.then
1857+
1858+
loop.then:
1859+
%l.a = load i32, ptr %gep.a, align 4
1860+
br label %loop.latch
1861+
1862+
loop.latch:
1863+
%merge = phi i32 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
1864+
%gep.c = getelementptr inbounds i32, ptr %c, i64 %iv
1865+
store i32 %merge, ptr %gep.c, align 4
1866+
%iv.next = add nuw nsw i64 %iv, 1
1867+
%ec = icmp eq i64 %iv.next, 1000
1868+
br i1 %ec, label %exit, label %loop.header
1869+
1870+
exit:
1871+
ret void
1872+
}

0 commit comments

Comments
 (0)