[llvm] Extending LoopVersioningLICM to handle cases where loopbound is invarint (PR #192794)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 18 07:54:01 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Manish Srivastava (mk-srivastava)
<details>
<summary>Changes</summary>
The changes extending the LoopVersioningLICM for the cases discussed in the discussion: https://github.com/llvm/llvm-project/issues/112060
---
Patch is 75.56 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/192794.diff
12 Files Affected:
- (modified) llvm/include/llvm/Transforms/Utils/LoopVersioning.h (+5-2)
- (modified) llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp (+336-8)
- (modified) llvm/lib/Transforms/Utils/LoopVersioning.cpp (+27-17)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-array-element.ll (+139)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-chained-loads.ll (+86)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-fcmp-exit.ll (+57)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-lambda.ll (+142)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-loop-varying.ll (+79)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-simple.ll (+139)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-stored-pointer.ll (+72)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-two-loads.ll (+158)
- (added) llvm/test/Transforms/LoopVersioningLICM/dynamic-bound-volatile-load.ll (+67)
``````````diff
diff --git a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h
index ea4fe27c90f5c..ec07fb9259b6a 100644
--- a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h
+++ b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h
@@ -61,11 +61,14 @@ class LoopVersioning {
/// analyze L
/// if versioning is necessary version L
/// transform L
- void versionLoop() { versionLoop(findDefsUsedOutsideOfLoop(VersionedLoop)); }
+ void versionLoop(Instruction *UserRuntimeCheck = nullptr) { versionLoop(findDefsUsedOutsideOfLoop(VersionedLoop), UserRuntimeCheck); }
/// Same but if the client has already precomputed the set of values
/// used outside the loop, this API will allows passing that.
- void versionLoop(const SmallVectorImpl<Instruction *> &DefsUsedOutside);
+ /// \p UserMemRuntimeCheck allows the caller to supply a pre-built runtime
+ /// check instruction instead of having LoopVersioning generate one.
+ void versionLoop(const SmallVectorImpl<Instruction *> &DefsUsedOutside,
+ Instruction *UserMemRuntimeCheck = nullptr);
/// Returns the versioned loop. Control flows here if pointers in the
/// loop don't alias (i.e. all memchecks passed). (This loop is actually the
diff --git a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
index 3aed643ee8065..8d973eb32189a 100644
--- a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
@@ -70,19 +70,23 @@
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/LoopVersioning.h"
+#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include <cassert>
using namespace llvm;
@@ -116,8 +120,8 @@ struct LoopVersioningLICM {
LoopVersioningLICM(AliasAnalysis *AA, ScalarEvolution *SE,
OptimizationRemarkEmitter *ORE,
LoopAccessInfoManager &LAIs, LoopInfo &LI,
- Loop *CurLoop)
- : AA(AA), SE(SE), LAIs(LAIs), LI(LI), CurLoop(CurLoop),
+ AssumptionCache *AC, Loop *CurLoop)
+ : AA(AA), SE(SE), LAIs(LAIs), LI(LI), AC(AC), CurLoop(CurLoop),
LoopDepthThreshold(LVLoopDepthThreshold),
InvariantThreshold(LVInvarThreshold), ORE(ORE) {}
@@ -138,9 +142,17 @@ struct LoopVersioningLICM {
LoopInfo &LI;
+ AssumptionCache *AC;
+
// The current loop we are working on.
Loop *CurLoop;
+ // Dynamic bound marker.
+ bool IsDynamicBound = false;
+
+ // Hoistable dependencies
+ SmallVector<Instruction *, 16> HoistedDependencies;
+
// Maximum loop nest threshold
unsigned LoopDepthThreshold;
@@ -156,6 +168,9 @@ struct LoopVersioningLICM {
// Read only loop marker.
bool IsReadOnlyLoop = true;
+ // Placeholder instruction for inserting runtime checks in the preheader.
+ Instruction *PlaceholderForRuntimeChecks = nullptr;
+
// OptimizationRemarkEmitter
OptimizationRemarkEmitter *ORE;
@@ -165,6 +180,11 @@ struct LoopVersioningLICM {
bool legalLoopMemoryAccesses();
bool isLoopAlreadyVisited();
bool instructionSafeForVersioning(Instruction *I);
+ bool isSafeToHoistBoundDep(Instruction *I,
+ const SmallPtrSetImpl<Value *> &ModifiedPtrs);
+ Instruction *insertRuntimeCheckPlaceholder(Loop *L);
+ bool generateAndAddRuntimeChecks(DominatorTree *DT);
+ void printLoopsWithPreheaders(Loop *VersionedLoop, Loop *NonVersionedLoop);
};
} // end anonymous namespace
@@ -213,12 +233,165 @@ bool LoopVersioningLICM::legalLoopStructure() {
// to generate the bound checks.
const SCEV *ExitCount = SE->getBackedgeTakenCount(CurLoop);
if (isa<SCEVCouldNotCompute>(ExitCount)) {
+ IsDynamicBound = true;
LLVM_DEBUG(dbgs() << " loop does not have trip count\n");
- return false;
+ LLVM_DEBUG(dbgs() << " checking the possibility of dynamic trip count\n");
+
+ HoistedDependencies.clear();
+
+ // Check if the loop trip count is dynamic
+ BasicBlock *ExitBlock = CurLoop->getExitingBlock();
+ assert(ExitBlock && "Exiting block guaranteed by earlier getExitingBlock() check");
+ CondBrInst *ExitBranch = dyn_cast<CondBrInst>(ExitBlock->getTerminator());
+ if (!ExitBranch) {
+ LLVM_DEBUG(dbgs() << " loop exit condition is not a conditional branch\n");
+ return false;
+ }
+ ICmpInst *ExitCmp = dyn_cast<ICmpInst>(ExitBranch->getCondition());
+ if (!ExitCmp) {
+ LLVM_DEBUG(dbgs() << " loop exit condition is not an icmp instruction\n");
+ return false;
+ }
+
+ PHINode *IndVar = CurLoop->getInductionVariable(*SE);
+ if (!IndVar) {
+ LLVM_DEBUG(dbgs() << " unable to find loop induction variable\n");
+ return false;
+ }
+ LLVM_DEBUG(dbgs() << " Induction variable: " << *IndVar << "\n");
+
+ Value *StepInst = IndVar->getIncomingValueForBlock(CurLoop->getLoopLatch());
+
+ auto IsIVOrStep = [&](Value *V) {
+ return V == IndVar || V == StepInst;
+ };
+
+ Value *DynamicUpperBound = nullptr;
+ if (IsIVOrStep(ExitCmp->getOperand(0))) {
+ DynamicUpperBound = ExitCmp->getOperand(1);
+ }
+ else if (IsIVOrStep(ExitCmp->getOperand(1))) {
+ DynamicUpperBound = ExitCmp->getOperand(0);
+ }
+ else {
+ LLVM_DEBUG(dbgs() << " unable to identify dynamic bound operand\n");
+ return false;
+ }
+ LLVM_DEBUG(dbgs() << " Dynamic upper bound: " << *DynamicUpperBound
+ << "\n");
+
+ SmallVector<Instruction *, 16> Worklist;
+
+ SmallPtrSet<Value *, 16> ModifiedPtrs;
+ for (BasicBlock *BB : CurLoop->getBlocks()) {
+ for (Instruction &I : *BB) {
+ if (StoreInst *SI = dyn_cast<StoreInst>(&I))
+ ModifiedPtrs.insert(SI->getPointerOperand());
+ }
+ }
+
+ if (Instruction *I = dyn_cast<Instruction>(DynamicUpperBound)) {
+ Worklist.push_back(I);
+ }
+
+ SmallPtrSet<Instruction *, 16> Visited;
+
+ while(!Worklist.empty()) {
+ Instruction *I = Worklist.pop_back_val();
+ if (!Visited.insert(I).second)
+ continue;
+
+ if (!CurLoop->contains(I->getParent()))
+ continue;
+
+ if (!isSafeToHoistBoundDep(I, ModifiedPtrs))
+ return false;
+
+ for (Use &U : I->operands()) {
+ if (Instruction *OpI = dyn_cast<Instruction>(U.get())) {
+ if (CurLoop->contains(OpI)) {
+ Worklist.push_back(OpI);
+ }
+ }
+ }
+
+ HoistedDependencies.push_back(I);
+ }
+ return true;
}
return true;
}
+/// Check if an instruction in the dynamic bound dependency chain is safe to
+/// hoist. Only side-effect-free arithmetic, bitwise, cast, comparison, GEP,
+/// and simple load instructions are allowed.
+bool LoopVersioningLICM::isSafeToHoistBoundDep(
+ Instruction *I, const SmallPtrSetImpl<Value *> &ModifiedPtrs) {
+ switch (I->getOpcode()) {
+ case Instruction::Load: {
+ LoadInst *LI = cast<LoadInst>(I);
+ if (!LI->isSimple()) {
+ LLVM_DEBUG(dbgs() << " Found a non-simple load, as a dependency"
+ " of exit condition\n");
+ return false;
+ }
+ Value *Ptr = LI->getPointerOperand();
+ if (ModifiedPtrs.count(Ptr)) {
+ LLVM_DEBUG(dbgs() << " Bound candidate is invalid - pointer is"
+ " stored to within loop: " << *LI << "\n");
+ return false;
+ }
+ return true;
+ }
+ // Integer arithmetic
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ // Floating-point arithmetic
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ case Instruction::FNeg:
+ // Bitwise operations
+ case Instruction::Shl:
+ case Instruction::LShr:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ // Integer casts
+ case Instruction::SExt:
+ case Instruction::ZExt:
+ case Instruction::Trunc:
+ // FP casts
+ case Instruction::FPExt:
+ case Instruction::FPTrunc:
+ case Instruction::FPToSI:
+ case Instruction::FPToUI:
+ case Instruction::SIToFP:
+ case Instruction::UIToFP:
+ // Pointer / bitcast
+ case Instruction::BitCast:
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ case Instruction::GetElementPtr:
+ // Comparisons
+ case Instruction::ICmp:
+ case Instruction::FCmp:
+ return true;
+ default:
+ LLVM_DEBUG(dbgs() << " Unsupported instruction in bound dependency"
+ " chain: " << *I << "\n");
+ return false;
+ }
+}
+
/// Check memory accesses in loop and confirms it's good for
/// LoopVersioningLICM.
bool LoopVersioningLICM::legalLoopMemoryAccesses() {
@@ -413,7 +586,7 @@ bool LoopVersioningLICM::legalLoopInstructions() {
LLVM_DEBUG(dbgs() << " Found a read-only loop!\n");
return false;
}
- // Profitability check:
+ // Profitablity check:
// Check invariant threshold, should be in limit.
if (InvariantCounter * 100 < InvariantThreshold * LoadAndStoreCounter) {
LLVM_DEBUG(
@@ -507,39 +680,193 @@ bool LoopVersioningLICM::isLegalForVersioning() {
return true;
}
+Instruction *LoopVersioningLICM::insertRuntimeCheckPlaceholder(Loop *L) {
+ // Create a preheader for our checks
+ BasicBlock *Preheader = L->getLoopPreheader();
+ if (!Preheader)
+ return nullptr;
+
+ // Determine the insertion point.
+ Instruction *InsertPt = Preheader->getTerminator();
+ LLVMContext &Context = CurLoop->getHeader()->getParent()->getContext();
+ // Create the comparison.
+ Instruction *Placeholder = nullptr;
+ Placeholder = ICmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ,
+ ConstantInt::get(Type::getInt32Ty(Context), 1),
+ ConstantInt::get(Type::getInt32Ty(Context), 1),
+ "runtime.check.placeholder", InsertPt->getIterator());
+
+ return Placeholder;
+}
+
+bool LoopVersioningLICM::generateAndAddRuntimeChecks(DominatorTree *DT) {
+ BasicBlock *RuntimeCheckBB = PlaceholderForRuntimeChecks->getParent();
+
+ const auto &RtPtrChecking = *LAI->getRuntimePointerChecking();
+
+ SCEVExpander Exp1(*RtPtrChecking.getSE(), "induction");
+
+ auto RPC = LAI->getRuntimePointerChecking();
+
+ Value *MemRuntimeChecks = llvm::addRuntimeChecks(PlaceholderForRuntimeChecks,
+ CurLoop, RPC->getChecks(), Exp1);
+
+ SCEVExpander Exp2(*SE, "scev.check");
+
+ const SCEVPredicate &Preds(LAI->getPSE().getPredicate());
+ Value *SCEVRuntimeChecks = Exp2.expandCodeForPredicate(&Preds, PlaceholderForRuntimeChecks);
+
+ IRBuilder<InstSimplifyFolder> Builder(RuntimeCheckBB->getContext(),
+ InstSimplifyFolder(RuntimeCheckBB->getModule()->getDataLayout()));
+
+ Value *RuntimeCheck = nullptr;
+ if (MemRuntimeChecks && SCEVRuntimeChecks) {
+ Builder.SetInsertPoint(PlaceholderForRuntimeChecks);
+ RuntimeCheck = Builder.CreateOr(MemRuntimeChecks, SCEVRuntimeChecks, "lver.safe");
+ } else {
+ RuntimeCheck = MemRuntimeChecks ? MemRuntimeChecks : SCEVRuntimeChecks;
+ }
+
+ RuntimeCheckBB->setName(CurLoop->getHeader()->getName() + ".lver.check");
+
+ CondBrInst *BI = dyn_cast<CondBrInst>(RuntimeCheckBB->getTerminator());
+ assert(BI && "Expected conditional branch in runtime check block");
+
+ PlaceholderForRuntimeChecks->replaceAllUsesWith(RuntimeCheck);
+ PlaceholderForRuntimeChecks->eraseFromParent();
+
+ return RuntimeCheck != nullptr;
+}
+
+void LoopVersioningLICM::printLoopsWithPreheaders(
+ Loop *VersionedLoop, Loop *NonVersionedLoop) {
+ std::string DL;
+ if (CurLoop) {
+ raw_string_ostream OS(DL);
+ if (const DebugLoc LoopDbgLoc = CurLoop->getStartLoc())
+ LoopDbgLoc.print(OS);
+ else
+ OS << CurLoop->getHeader()->getParent()->getParent()->getModuleIdentifier();
+ }
+
+ auto printLoop = [&DL](Loop *L){
+ if (!L)
+ return;
+ dbgs() << ">>>>>>>>>> Loop: ";
+ dbgs() << "Loop starts at: " << DL;
+ dbgs() << "\n";
+ BasicBlock *Header = L->getHeader();
+ BasicBlock *Preheader = L->getLoopPreheader();
+ if (Preheader)
+ Header = Preheader;
+ dbgs() << "Check :" << *Header->getSinglePredecessor() <<"\n";
+ if (Preheader) {
+ dbgs() << "Preheader: " << *Preheader << "\n";
+ } else {
+ dbgs() << "No preheader\n";
+ }
+ L->dumpVerbose();
+ dbgs() << "<<<<<<<<<<<<<< Loop: ";
+ dbgs() << "Loop starts at: " << DL;
+ dbgs() << "\n";
+ };
+
+ dbgs() << "\n--- NonVersioned Loop ---\n";
+ printLoop(NonVersionedLoop);
+ dbgs() << "\n--- Versioned Loop ---\n";
+ printLoop(VersionedLoop);
+}
+
bool LoopVersioningLICM::run(DominatorTree *DT) {
// Do not do the transformation if disabled by metadata.
if (hasLICMVersioningTransformation(CurLoop) & TM_Disable)
return false;
-
bool Changed = false;
-
// Check feasiblity of LoopVersioningLICM.
// If versioning found to be feasible and beneficial then proceed
// else simply return, by cleaning up memory.
if (isLegalForVersioning()) {
+ PlaceholderForRuntimeChecks = nullptr;
+ if (IsDynamicBound) {
+ PlaceholderForRuntimeChecks = insertRuntimeCheckPlaceholder(CurLoop);
+ if (!PlaceholderForRuntimeChecks) {
+ LLVM_DEBUG(dbgs() << "No runtime check created\n");
+ return false;
+ }
+ }
// Do loop versioning.
// Create memcheck for memory accessed inside loop.
// Clone original loop, and set blocks properly.
LoopVersioning LVer(*LAI, LAI->getRuntimePointerChecking()->getChecks(),
CurLoop, &LI, DT, SE);
- LVer.versionLoop();
+ LVer.versionLoop(PlaceholderForRuntimeChecks);
+
+ // Add the extra checks for dynamic bounds
+ if (IsDynamicBound) {
+ for (auto p = HoistedDependencies.rbegin(); p != HoistedDependencies.rend(); ++p) {
+ Instruction *I = *p;
+ if (isa<LoadInst>(I)) {
+ // Clone the load to the preheader instead of moving it. The original
+ // dead load is intentionally kept in the loop body so that the subsequent LAA recomputation sees
+ // the load and generates runtime pointer checks for its address range. The cleanup passes will erase it later.
+ LoadInst *LI = cast<LoadInst>(I);
+ LoadInst *NewLI = new LoadInst(
+ LI->getType(), LI->getPointerOperand(), LI->getName() + ".hoisted",
+ false, LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(),
+ PlaceholderForRuntimeChecks->getIterator()
+ );
+
+ NewLI->copyMetadata(*I);
+ I->replaceAllUsesWith(NewLI);
+ } else {
+ I->moveBefore(PlaceholderForRuntimeChecks->getIterator());
+ }
+ }
+
+// #ifdef EXPENSIVE_CHECKS
+ assert(!verifyFunction(*LVer.getVersionedLoop()->getHeader()->getParent(), &dbgs())
+ && "Verification failure after dynamic bounds");
+// #endif
+
+ SE->forgetLoop(CurLoop);
+ // Recompute LoopAccessInfo after hoisting the dynamic bound
+ LoopAccessInfoManager FreshLAIs(*SE, *AA, *DT, LI, nullptr, nullptr, AC);
+ LAI = &FreshLAIs.getInfo(*CurLoop);
+
+ generateAndAddRuntimeChecks(DT);
+
+// #ifdef EXPENSIVE_CHECKS
+ assert(!verifyFunction(*LVer.getVersionedLoop()->getHeader()->getParent(), &dbgs())
+ && "Verification failure after runtime checks");
+// #endif
+
+ // LAI isn't used anymore, so clear it to avoid dangling reference
+ LAI = nullptr;
+ }
// Set Loop Versioning metaData for original loop.
addStringMetadataToLoop(LVer.getNonVersionedLoop(), LICMVersioningMetaData);
// Set Loop Versioning metaData for version loop.
addStringMetadataToLoop(LVer.getVersionedLoop(), LICMVersioningMetaData);
+
// Set "llvm.mem.parallel_loop_access" metaData to versioned loop.
// FIXME: "llvm.mem.parallel_loop_access" annotates memory access
// instructions, not loops.
addStringMetadataToLoop(LVer.getVersionedLoop(),
"llvm.mem.parallel_loop_access");
+
// Update version loop with aggressive aliasing assumption.
LVer.annotateLoopWithNoAlias();
Changed = true;
+
+ LLVM_DEBUG(dbgs() << "Successfully transformed the code\n");
+ LLVM_DEBUG(printLoopsWithPreheaders(LVer.getVersionedLoop(),
+ LVer.getNonVersionedLoop()));
}
return Changed;
}
+namespace llvm {
+
PreservedAnalyses LoopVersioningLICMPass::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &LAR,
LPMUpdater &U) {
@@ -550,7 +877,8 @@ PreservedAnalyses LoopVersioningLICMPass::run(Loop &L, LoopAnalysisManager &AM,
OptimizationRemarkEmitter ORE(F);
LoopAccessInfoManager LAIs(*SE, *AA, *DT, LAR.LI, nullptr, nullptr, &LAR.AC);
- if (!LoopVersioningLICM(AA, SE, &ORE, LAIs, LAR.LI, &L).run(DT))
+ if (!LoopVersioningLICM(AA, SE, &ORE, LAIs, LAR.LI, &LAR.AC, &L).run(DT))
return PreservedAnalyses::all();
return getLoopPassPreservedAnalyses();
}
+} // namespace llvm
diff --git a/llvm/lib/Transforms/Utils/LoopVersioning.cpp b/llvm/lib/Transforms/Utils/LoopVersioning.cpp
index b90466a8c49cf..6696e3c6a6b0e 100644
--- a/llvm/lib/Transforms/Utils/LoopVersioning.cpp
+++ b/llvm/lib/Transforms/Utils/LoopVersioning.cpp
@@ -48,7 +48,7 @@ LoopVersioning::LoopVersioning(const LoopAccessInfo &LAI,
LAI(LAI), LI(LI), DT(DT), SE(SE) {}
void LoopVersioning::versionLoop(
- const SmallVectorImpl<Instruction *> &DefsUsedOutside) {
+ const SmallVectorImpl<Instruction *> &DefsUsedOutside, Instruction *UserRuntimeCheck) {
assert(VersionedLoop->getUniqueExitBlock() && "No single exit block");
assert(VersionedLoop->isLoopSimplifyForm() &&
"Loop is not in loop-simplify form");
@@ -59,27 +59,37 @@ void LoopVersioning::versionLoop(
// Add the memcheck in the original preheader (this is empty initially).
BasicBlock *RuntimeCheckBB = VersionedLoop->getLoopPreheader();
- const auto &RtPtrChecking = *LAI.getRuntimePointerChecking();
-
- SCEVExpander Exp2(*RtPtrChecking.getSE(), "induction");
- MemRuntimeCheck = addRuntimeChecks(RuntimeCheckBB->getTerminator(),
- VersionedLoop, AliasChecks, Exp2);
- SCEVExpander Exp(*SE, "scev.check");
- SCEVRuntimeCheck =
- Exp.expandCodeForPredicate(&Preds, RuntimeCheckBB->getTerminator());
+ if (!UserRuntimeCheck) {
+ const auto &RtPtrChecking = *LAI.getRuntimePointerChecking();
+
+ SCEVExpander Exp2(*RtPtrChecking.getSE(), "induction");
+ MemRuntimeCheck = addRuntimeChecks(RuntimeCheckBB->getTerminator(),
+ VersionedLoop, AliasChecks, Exp2);
+ SCEVExpander Exp(*SE, "scev.check");
+ SCEVRuntimeCheck =
+ Exp.expandCodeForPredicate(&Preds, RuntimeCheckBB->getTerminator());
+
+ IRBuilder<InstSimplifyFolder> Builder(
+ RuntimeCheckBB->getContext(),
+ InstSimplifyFolder(RuntimeCheckBB->getDataLayout()));
+ if (MemRuntimeCheck && SCEVRuntimeCheck) {
+ Builder.SetInsertPoint(RuntimeCheckBB->getTerminator());
+ RuntimeCheck =
+ Builder.CreateOr(MemRuntimeCheck, SCEVRuntimeCheck, "lver.safe");
+ } else
+ RuntimeCheck = MemRuntimeCheck ? MemRuntimeCheck : SCEVRuntimeCheck;
+
+ Exp.eraseDeadInstructions(SCEVRuntimeCheck);
+ }
+ else {
+ RuntimeCheck = UserRuntimeCheck;
+ RuntimeCheckBB = UserRuntimeCheck->getParent();
+ }
IRBuilder<InstSimplifyFolder> Builder(
RuntimeCheckBB->ge...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/192794
More information about the llvm-commits
mailing list