Skip to content

Commit 1a4b399

Browse files
committed
Move LoopNoOpElimination logic to IndVarSimplify
Responding to review comments by moving the LoopNoOpElimination logic into IndVarSimplify. Also removed LoopNoOpElimination and related code. Change-Id: I9fa9ffaede7c65e7a89fa3c3e03fb20774c41058
1 parent f3ef02e commit 1a4b399

File tree

8 files changed

+248
-333
lines changed

8 files changed

+248
-333
lines changed

llvm/include/llvm/Transforms/Scalar/LoopNoOpElimination.h

Lines changed: 0 additions & 52 deletions
This file was deleted.

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@
302302
#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
303303
#include "llvm/Transforms/Scalar/LoopInterchange.h"
304304
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
305-
#include "llvm/Transforms/Scalar/LoopNoOpElimination.h"
306305
#include "llvm/Transforms/Scalar/LoopPassManager.h"
307306
#include "llvm/Transforms/Scalar/LoopPredication.h"
308307
#include "llvm/Transforms/Scalar/LoopRotation.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@
110110
#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
111111
#include "llvm/Transforms/Scalar/LoopInterchange.h"
112112
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
113-
#include "llvm/Transforms/Scalar/LoopNoOpElimination.h"
114113
#include "llvm/Transforms/Scalar/LoopPassManager.h"
115114
#include "llvm/Transforms/Scalar/LoopRotation.h"
116115
#include "llvm/Transforms/Scalar/LoopSimplifyCFG.h"
@@ -217,10 +216,9 @@ static cl::opt<bool> EnableLoopFlatten("enable-loop-flatten", cl::init(false),
217216
cl::Hidden,
218217
cl::desc("Enable the LoopFlatten Pass"));
219218

220-
static cl::opt<bool>
221-
EnableLoopNoOpElimination("enable-loop-noop-elimination", cl::init(false),
222-
cl::Hidden,
223-
cl::desc("Enable Loop no-op elimination pass"));
219+
static cl::opt<bool> EnableIndVarLoopNoOpElimination(
220+
"enable-indvar-loop-noop-elim", cl::init(false), cl::Hidden,
221+
cl::desc("Enable loop no-op elimination in IndVarSimplify pass"));
224222

225223
// Experimentally allow loop header duplication. This should allow for better
226224
// optimization at Oz, since loop-idiom recognition can then recognize things
@@ -1313,8 +1311,17 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
13131311
FPM.addPass(LoopVectorizePass(
13141312
LoopVectorizeOptions(!PTO.LoopInterleaving, !PTO.LoopVectorization)));
13151313

1316-
if (EnableLoopNoOpElimination)
1317-
FPM.addPass(LoopNoOpEliminationPass());
1314+
if (EnableIndVarLoopNoOpElimination) {
1315+
// Loop no-op elimination, which is done in IndVarSimplify
1316+
// makes use of post-vectorization IR such as runtime check blocks.
1317+
// As a consequence it needs to be run after vectorization to be effective
1318+
LoopPassManager LPM;
1319+
LPM.addPass(IndVarSimplifyPass());
1320+
FPM.addPass(
1321+
createFunctionToLoopPassAdaptor(std::move(LPM),
1322+
/*UseMemorySSA=*/false,
1323+
/*UseBlockFrequencyInfo=*/false));
1324+
}
13181325

13191326
FPM.addPass(InferAlignmentPass());
13201327
if (IsFullLTO) {

llvm/lib/Passes/PassRegistry.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,6 @@ FUNCTION_PASS("view-dom-only", DomOnlyViewer())
566566
FUNCTION_PASS("view-post-dom", PostDomViewer())
567567
FUNCTION_PASS("view-post-dom-only", PostDomOnlyViewer())
568568
FUNCTION_PASS("wasm-eh-prepare", WasmEHPreparePass())
569-
FUNCTION_PASS("loop-noop-elim", LoopNoOpEliminationPass())
570569
#undef FUNCTION_PASS
571570

572571
#ifndef FUNCTION_PASS_WITH_PARAMS

llvm/lib/Transforms/Scalar/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ add_llvm_component_library(LLVMScalarOpts
3737
LoopFuse.cpp
3838
LoopIdiomRecognize.cpp
3939
LoopInstSimplify.cpp
40-
LoopNoOpElimination.cpp
4140
LoopInterchange.cpp
4241
LoopFlatten.cpp
4342
LoopLoadElimination.cpp

llvm/lib/Transforms/Scalar/IndVarSimplify.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class IndVarSimplify {
159159

160160
bool sinkUnusedInvariants(Loop *L);
161161

162+
bool simplifyNoOpPHINodeUsers(Loop *L);
163+
162164
public:
163165
IndVarSimplify(LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT,
164166
const DataLayout &DL, TargetLibraryInfo *TLI,
@@ -1869,6 +1871,161 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) {
18691871
return Changed;
18701872
}
18711873

1874+
static BasicBlock *getSCEVCheckBB(Function &F) {
1875+
for (BasicBlock &BB : F)
1876+
if (BB.getName() == "vector.scevcheck")
1877+
return &BB;
1878+
1879+
return nullptr;
1880+
}
1881+
1882+
// Use vector.check block to determine if we can eliminate a bounds check on
1883+
// the IV if we know that we can only enter the vector block if the tripcount
1884+
// is within certain bounds.
1885+
static bool tryElimAndMaskOnPHI(Loop *L, Instruction *AndInstr, PHINode *IndVar,
1886+
ScalarEvolution *SE, Function *F) {
1887+
Value *Op0 = AndInstr->getOperand(0);
1888+
Value *Op1 = AndInstr->getOperand(1);
1889+
1890+
auto *Mask = dyn_cast<ConstantInt>(Op0 == IndVar ? Op1 : Op0);
1891+
if (!Mask)
1892+
return false;
1893+
1894+
auto CheckConditional = [](BranchInst *BranchI, CmpInst *CmpI,
1895+
unsigned ExpectedPred, BasicBlock *Header,
1896+
BasicBlock *PreHeader, Loop *L,
1897+
Value *LatchCmpV) -> bool {
1898+
// Make sure that the conditional operator is what we
1899+
// expect
1900+
unsigned CmpIOpcode = CmpI->getPredicate();
1901+
if (CmpIOpcode != ExpectedPred)
1902+
return false;
1903+
1904+
// Check that in the case of a true result we actually
1905+
// branch to the loop
1906+
Value *TrueDest = BranchI->getOperand(1);
1907+
if (TrueDest != PreHeader && TrueDest != Header)
1908+
return false;
1909+
1910+
// Check that the conditional variable that is used for the
1911+
// SCEV check is actually used in the latch compare instruction
1912+
auto *LatchCmpInst = L->getLatchCmpInst();
1913+
if (!LatchCmpInst)
1914+
return false;
1915+
1916+
if (LatchCmpInst->getOperand(0) != LatchCmpV &&
1917+
LatchCmpInst->getOperand(1) != LatchCmpV) {
1918+
return false;
1919+
}
1920+
1921+
return true;
1922+
};
1923+
1924+
// Determine if there's a runtime SCEV check block
1925+
// and use that to determine if we can elim the phinode
1926+
if (auto *SCEVCheckBB = getSCEVCheckBB(*F)) {
1927+
// Determine if the SCEV check BB branches to the loop preheader
1928+
// or header
1929+
BasicBlock *PreHeader = L->getLoopPreheader();
1930+
BasicBlock *Header = L->getHeader();
1931+
if (PreHeader && PreHeader->getUniquePredecessor() != SCEVCheckBB &&
1932+
Header != SCEVCheckBB)
1933+
return false;
1934+
1935+
// We're interested in a SCEV check block with a branch instruction
1936+
// terminator
1937+
if (auto *BranchI = dyn_cast<BranchInst>(SCEVCheckBB->getTerminator())) {
1938+
if (!BranchI->isConditional())
1939+
return false;
1940+
1941+
Value *Condition = BranchI->getCondition();
1942+
if (auto *CmpI = dyn_cast<CmpInst>(Condition)) {
1943+
// Check if the condition for the terminating instruction
1944+
// is doing some comparison with a constant integer. If not
1945+
// we can't elim our AND mask
1946+
Value *CmpOp0 = CmpI->getOperand(0);
1947+
Value *CmpOp1 = CmpI->getOperand(1);
1948+
auto *CmpConstant = (dyn_cast<ConstantInt>(CmpOp0))
1949+
? dyn_cast<ConstantInt>(CmpOp0)
1950+
: dyn_cast<ConstantInt>(CmpOp1);
1951+
if (!CmpConstant)
1952+
return false;
1953+
1954+
if ((CmpConstant == CmpOp1 &&
1955+
CheckConditional(BranchI, CmpI, CmpInst::ICMP_UGT, Header,
1956+
PreHeader, L, CmpOp0)) ||
1957+
(CmpConstant == CmpOp0 &&
1958+
CheckConditional(BranchI, CmpI, CmpInst::ICMP_ULT, Header,
1959+
PreHeader, L, CmpOp1))) {
1960+
1961+
// TODO: inverse operation needs to be checked
1962+
// We can eliminate the AND mask
1963+
if (CmpConstant->uge(Mask->getZExtValue())) {
1964+
AndInstr->replaceAllUsesWith(IndVar);
1965+
return true;
1966+
}
1967+
}
1968+
}
1969+
}
1970+
}
1971+
1972+
return false;
1973+
}
1974+
1975+
static bool tryElimPHINodeUsers(Loop *L, PHINode *PN, ScalarEvolution *SE,
1976+
Function *F) {
1977+
bool Changed = false;
1978+
for (auto *U : PN->users()) {
1979+
auto *I = dyn_cast<Instruction>(U);
1980+
switch (I->getOpcode()) {
1981+
case Instruction::And:
1982+
if (tryElimAndMaskOnPHI(L, I, PN, SE, F)) {
1983+
Changed |= true;
1984+
}
1985+
break;
1986+
default:
1987+
break;
1988+
}
1989+
}
1990+
return Changed;
1991+
}
1992+
1993+
// Attemps to spot and eliminate no-op operations in loop bodies.
1994+
// For example loop Vectorization may create loops like the following.
1995+
//
1996+
// vector.scevcheck:
1997+
// %1 = add i64 %flatten.tripcount, -1
1998+
// %2 = icmp ugt i64 %1, 4294967295
1999+
// br i1 %2, label %scalar.ph, label %vector.ph
2000+
// vector.ph:
2001+
// %iv = phi i64 [ 0, %vector.scevcheck], [ %iv.next, %vector.ph ]
2002+
// %m = and i64 %iv, 4294967295 ; 0xffff_fffe no op
2003+
// %p = getelementptr inbounds <4 x i32>, ptr %A, i64 %m
2004+
// %load = load <4 x i32>, ptr %p, align 4
2005+
// %1 = add <4 x i32> %load, %X
2006+
// store <4 x i32> %1, ptr %p, align 4
2007+
// %iv.next = add nuw i64 %iv, 4
2008+
// %c = icmp ult i64 %iv.next, %N
2009+
// br i1 %c, label %vector.ph, label %exit
2010+
// exit:
2011+
// ret void
2012+
//
2013+
// The vectorizer creates the SCEV check block to perform
2014+
// runtime IV checks. This block can be used to determine true
2015+
// range of the the IV as entry into the vector loop is only possible
2016+
// for certain tripcount values.
2017+
//
2018+
// Currently this only supports spotting no-op AND operations in loop
2019+
// bodies.
2020+
bool IndVarSimplify::simplifyNoOpPHINodeUsers(Loop *L) {
2021+
bool Changed = false;
2022+
for (BasicBlock *BB : L->blocks())
2023+
for (Instruction &I : *BB)
2024+
if (auto *PN = dyn_cast<PHINode>(&I))
2025+
Changed |= tryElimPHINodeUsers(L, PN, SE, L->getHeader()->getParent());
2026+
2027+
return Changed;
2028+
}
18722029
//===----------------------------------------------------------------------===//
18732030
// IndVarSimplify driver. Manage several subpasses of IV simplification.
18742031
//===----------------------------------------------------------------------===//
@@ -1909,6 +2066,7 @@ bool IndVarSimplify::run(Loop *L) {
19092066
// set no-wrap flags before normalizing sign/zero extension.
19102067
Rewriter.disableCanonicalMode();
19112068
Changed |= simplifyAndExtend(L, Rewriter, LI);
2069+
Changed |= simplifyNoOpPHINodeUsers(L);
19122070

19132071
// Check to see if we can compute the final value of any expressions
19142072
// that are recurrent in the loop, and substitute the exit values from the

0 commit comments

Comments
 (0)