Skip to content

Commit 0967d92

Browse files
committed
[CHERIoT] Teach LICM not to reorder GEP indices with different signs on CHERIoT.
Because of our tight representable bounds, any reordering of differently signed indices is very likely to generate an invalid intermediate capability.
1 parent 1b2b095 commit 0967d92

File tree

2 files changed

+97
-13
lines changed

2 files changed

+97
-13
lines changed

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -916,9 +916,9 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
916916
// to that block.
917917
if (CurLoop->hasLoopInvariantOperands(&I) &&
918918
canSinkOrHoistInst(I, AA, DT, CurLoop, MSSAU, true, Flags, ORE) &&
919-
isSafeToExecuteUnconditionally(
920-
I, DT, TLI, CurLoop, SafetyInfo, ORE,
921-
Preheader->getTerminator(), AC, AllowSpeculation)) {
919+
isSafeToExecuteUnconditionally(I, DT, TLI, CurLoop, SafetyInfo, ORE,
920+
Preheader->getTerminator(), AC,
921+
AllowSpeculation)) {
922922
hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
923923
MSSAU, SE, ORE);
924924
HoistedInstructions.push_back(&I);
@@ -1035,8 +1035,8 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
10351035
if (VerifyMemorySSA)
10361036
MSSAU.getMemorySSA()->verifyMemorySSA();
10371037

1038-
// Now that we've finished hoisting make sure that LI and DT are still
1039-
// valid.
1038+
// Now that we've finished hoisting make sure that LI and DT are still
1039+
// valid.
10401040
#ifdef EXPENSIVE_CHECKS
10411041
if (Changed) {
10421042
assert(DT->verify(DominatorTree::VerificationLevel::Fast) &&
@@ -1137,7 +1137,7 @@ bool isOnlyMemoryAccess(const Instruction *I, const Loop *L,
11371137
}
11381138
return true;
11391139
}
1140-
}
1140+
} // namespace
11411141

11421142
static MemoryAccess *getClobberingMemoryAccess(MemorySSA &MSSA,
11431143
BatchAAResults &BAA,
@@ -1186,8 +1186,8 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
11861186

11871187
bool InvariantGroup = LI->hasMetadata(LLVMContext::MD_invariant_group);
11881188

1189-
bool Invalidated = pointerInvalidatedByLoop(
1190-
MSSA, MU, CurLoop, I, Flags, InvariantGroup);
1189+
bool Invalidated =
1190+
pointerInvalidatedByLoop(MSSA, MU, CurLoop, I, Flags, InvariantGroup);
11911191
// Check loop-invariant address because this may also be a sinkable load
11921192
// whose address is not necessarily loop-invariant.
11931193
if (ORE && Invalidated && CurLoop->isLoopInvariant(LI->getPointerOperand()))
@@ -1284,7 +1284,7 @@ static bool isTriviallyReplaceablePHI(const PHINode &PN, const Instruction &I) {
12841284

12851285
/// Return true if the instruction is foldable in the loop.
12861286
static bool isFoldableInLoop(const Instruction &I, const Loop *CurLoop,
1287-
const TargetTransformInfo *TTI) {
1287+
const TargetTransformInfo *TTI) {
12881288
if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
12891289
InstructionCost CostI =
12901290
TTI->getInstructionCost(&I, TargetTransformInfo::TCK_SizeAndLatency);
@@ -1639,7 +1639,7 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
16391639
// the instruction.
16401640
// First check if I is worth sinking for all uses. Sink only when it is worth
16411641
// across all uses.
1642-
SmallSetVector<User*, 8> Users(I.user_begin(), I.user_end());
1642+
SmallSetVector<User *, 8> Users(I.user_begin(), I.user_end());
16431643
for (auto *UI : Users) {
16441644
auto *User = cast<Instruction>(UI);
16451645

@@ -1672,8 +1672,8 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
16721672
LLVM_DEBUG(dbgs() << "LICM hoisting to " << Dest->getNameOrAsOperand() << ": "
16731673
<< I << "\n");
16741674
ORE->emit([&]() {
1675-
return OptimizationRemark(DEBUG_TYPE, "Hoisted", &I) << "hoisting "
1676-
<< ore::NV("Inst", &I);
1675+
return OptimizationRemark(DEBUG_TYPE, "Hoisted", &I)
1676+
<< "hoisting " << ore::NV("Inst", &I);
16771677
});
16781678

16791679
// Metadata can be dependent on conditions we are hoisting above.
@@ -2376,7 +2376,8 @@ static bool pointerInvalidatedByLoop(MemorySSA *MSSA, MemoryUse *MU,
23762376
MemoryAccess *Source = getClobberingMemoryAccess(*MSSA, BAA, Flags, MU);
23772377
return !MSSA->isLiveOnEntryDef(Source) &&
23782378
CurLoop->contains(Source->getBlock()) &&
2379-
!(InvariantGroup && Source->getBlock() == CurLoop->getHeader() && isa<MemoryPhi>(Source));
2379+
!(InvariantGroup && Source->getBlock() == CurLoop->getHeader() &&
2380+
isa<MemoryPhi>(Source));
23802381
}
23812382

23822383
// For sinking, we'd need to check all Defs below this use. The getClobbering
@@ -2535,6 +2536,26 @@ static bool hoistGEP(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo,
25352536
all_of(Src->indices(), NonNegative) &&
25362537
all_of(GEP->indices(), NonNegative);
25372538

2539+
// CHERIoT has very tight representable bounds in its capability formatting,
2540+
// meaning that any intermediate out-of-bounds values during offsetting are
2541+
// likely to cause invalid pointers. As such, it require a much stricter
2542+
// condition to reorder indices than other targets, namely that the indices
2543+
// must be known either to be all non-negative, or all non-positive.
2544+
StringRef ABI = GEP->getModule()->getTargetABIFromMD();
2545+
bool MustStayInBounds = DL.isFatPointer(GEP->getType()) &&
2546+
(ABI == "cheriot" || ABI == "cheriot-baremetal");
2547+
if (MustStayInBounds) {
2548+
auto NonPositive = [&](Value *V) {
2549+
return !isKnownPositive(V, SimplifyQuery(DL, DT, AC, GEP));
2550+
};
2551+
bool AllNonNeg = all_of(Src->indices(), NonNegative) &&
2552+
all_of(GEP->indices(), NonNegative);
2553+
bool AllNonPos = all_of(Src->indices(), NonPositive) &&
2554+
all_of(GEP->indices(), NonPositive);
2555+
if (!AllNonNeg && !AllNonPos)
2556+
return false;
2557+
}
2558+
25382559
BasicBlock *Preheader = L.getLoopPreheader();
25392560
IRBuilder<> Builder(Preheader->getTerminator());
25402561
Value *NewSrc = Builder.CreateGEP(GEP->getSourceElementType(), SrcPtr,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
; RUN: opt < %s -S -passes=licm | FileCheck %s
2+
target datalayout = "e-m:e-p:32:32-i64:64-n32-S128-pf200:64:64:64:32-A200-P200-G200"
3+
target triple = "riscv32-unknown-cheriotrtos"
4+
5+
; Because of the tightness of representable bounds on Cheriot, LICM must not reorder
6+
; GEP indices if they are not guaranteed to be the same sign.
7+
; CHECK-LABEL: @foo1
8+
; CHECK: entry:
9+
; CHECK-NOT: getelementptr
10+
; CHECK: do.body:
11+
; CHECK: getelementptr
12+
; CHECK-SAME: i32 %inc
13+
; CHECK: getelementptr
14+
; CHECK-SAME: i32 -8
15+
16+
define void @foo1(ptr addrspace(200) noundef %r) {
17+
entry:
18+
br label %do.body
19+
20+
do.body:
21+
%ctr.0 = phi i32 [ 0, %entry ], [ %inc, %do.body ]
22+
%inc = add nuw nsw i32 %ctr.0, 1
23+
%add.ptr = getelementptr inbounds nuw i16, ptr addrspace(200) %r, i32 %inc
24+
%add.ptr1 = getelementptr inbounds i8, ptr addrspace(200) %add.ptr, i32 -8
25+
tail call void @bar(ptr addrspace(200) noundef nonnull %add.ptr1)
26+
%exitcond.not = icmp eq i32 %inc, 256
27+
br i1 %exitcond.not, label %do.end, label %do.body
28+
29+
do.end:
30+
ret void
31+
}
32+
33+
; CHECK-LABEL: @foo2
34+
; CHECK: entry:
35+
; CHECK: getelementptr
36+
; CHECK-SAME: i32 8
37+
; CHECK: do.body:
38+
; CHECK: getelementptr
39+
; CHECK-SAME: i32 %inc
40+
; CHECK-NOT: getelementptr
41+
42+
define void @foo2(ptr addrspace(200) noundef %r) {
43+
entry:
44+
br label %do.body
45+
46+
do.body:
47+
%ctr.0 = phi i32 [ 0, %entry ], [ %inc, %do.body ]
48+
%inc = add nuw nsw i32 %ctr.0, 1
49+
%add.ptr = getelementptr inbounds nuw i16, ptr addrspace(200) %r, i32 %inc
50+
%add.ptr1 = getelementptr inbounds i8, ptr addrspace(200) %add.ptr, i32 8
51+
tail call void @bar(ptr addrspace(200) noundef nonnull %add.ptr1)
52+
%exitcond.not = icmp eq i32 %inc, 256
53+
br i1 %exitcond.not, label %do.end, label %do.body
54+
55+
do.end:
56+
ret void
57+
}
58+
59+
60+
declare void @bar(ptr addrspace(200) noundef)
61+
62+
!llvm.module.flags = !{!0}
63+
!0 = !{i32 1, !"target-abi", !"cheriot"}

0 commit comments

Comments
 (0)