2010-12-26 19:39:38 +00:00
|
|
|
//===-- LoopIdiomRecognize.cpp - Loop idiom recognition -------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass implements an idiom recognizer that transforms simple loops into a
|
|
|
|
// non-loop form. In cases that this kicks in, it can be a significant
|
|
|
|
// performance win.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "loop-idiom"
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
2010-12-27 18:39:08 +00:00
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2010-12-26 19:39:38 +00:00
|
|
|
#include "llvm/Analysis/LoopPass.h"
|
|
|
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
#include "llvm/Analysis/ScalarEvolutionExpander.h"
|
2010-12-26 20:45:45 +00:00
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
|
|
|
#include "llvm/Target/TargetData.h"
|
2010-12-27 00:03:23 +00:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2010-12-26 19:39:38 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
#include "llvm/Support/IRBuilder.h"
|
2010-12-26 19:39:38 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// TODO: Recognize "N" size array multiplies: replace with call to blas or
|
|
|
|
// something.
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LoopIdiomRecognize : public LoopPass {
|
2010-12-26 20:45:45 +00:00
|
|
|
Loop *CurLoop;
|
|
|
|
const TargetData *TD;
|
|
|
|
ScalarEvolution *SE;
|
2010-12-26 19:39:38 +00:00
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
explicit LoopIdiomRecognize() : LoopPass(ID) {
|
|
|
|
initializeLoopIdiomRecognizePass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnLoop(Loop *L, LPPassManager &LPM);
|
|
|
|
|
2010-12-26 20:45:45 +00:00
|
|
|
bool processLoopStore(StoreInst *SI, const SCEV *BECount);
|
2010-12-26 19:39:38 +00:00
|
|
|
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
bool processLoopStoreOfSplatValue(StoreInst *SI, unsigned StoreSize,
|
|
|
|
Value *SplatValue,
|
|
|
|
const SCEVAddRecExpr *Ev,
|
|
|
|
const SCEV *BECount);
|
|
|
|
|
2010-12-26 19:39:38 +00:00
|
|
|
/// This transformation requires natural loop information & requires that
|
|
|
|
/// loop preheaders be inserted into the CFG.
|
|
|
|
///
|
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.addRequired<LoopInfo>();
|
|
|
|
AU.addPreserved<LoopInfo>();
|
|
|
|
AU.addRequiredID(LoopSimplifyID);
|
|
|
|
AU.addPreservedID(LoopSimplifyID);
|
|
|
|
AU.addRequiredID(LCSSAID);
|
|
|
|
AU.addPreservedID(LCSSAID);
|
2010-12-27 18:39:08 +00:00
|
|
|
AU.addRequired<AliasAnalysis>();
|
|
|
|
AU.addPreserved<AliasAnalysis>();
|
2010-12-26 19:39:38 +00:00
|
|
|
AU.addRequired<ScalarEvolution>();
|
|
|
|
AU.addPreserved<ScalarEvolution>();
|
|
|
|
AU.addPreserved<DominatorTree>();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
char LoopIdiomRecognize::ID = 0;
|
|
|
|
INITIALIZE_PASS_BEGIN(LoopIdiomRecognize, "loop-idiom", "Recognize loop idioms",
|
|
|
|
false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfo)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LCSSA)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
|
2010-12-27 18:39:08 +00:00
|
|
|
INITIALIZE_AG_DEPENDENCY(AliasAnalysis)
|
2010-12-26 19:39:38 +00:00
|
|
|
INITIALIZE_PASS_END(LoopIdiomRecognize, "loop-idiom", "Recognize loop idioms",
|
|
|
|
false, false)
|
|
|
|
|
|
|
|
Pass *llvm::createLoopIdiomPass() { return new LoopIdiomRecognize(); }
|
|
|
|
|
2010-12-27 00:03:23 +00:00
|
|
|
/// DeleteDeadInstruction - Delete this instruction. Before we do, go through
|
|
|
|
/// and zero out all the operands of this instruction. If any of them become
|
|
|
|
/// dead, delete them and the computation tree that feeds them.
|
|
|
|
///
|
|
|
|
static void DeleteDeadInstruction(Instruction *I, ScalarEvolution &SE) {
|
|
|
|
SmallVector<Instruction*, 32> NowDeadInsts;
|
|
|
|
|
|
|
|
NowDeadInsts.push_back(I);
|
|
|
|
|
|
|
|
// Before we touch this instruction, remove it from SE!
|
|
|
|
do {
|
|
|
|
Instruction *DeadInst = NowDeadInsts.pop_back_val();
|
|
|
|
|
|
|
|
// This instruction is dead, zap it, in stages. Start by removing it from
|
|
|
|
// SCEV.
|
|
|
|
SE.forgetValue(DeadInst);
|
|
|
|
|
|
|
|
for (unsigned op = 0, e = DeadInst->getNumOperands(); op != e; ++op) {
|
|
|
|
Value *Op = DeadInst->getOperand(op);
|
|
|
|
DeadInst->setOperand(op, 0);
|
|
|
|
|
|
|
|
// If this operand just became dead, add it to the NowDeadInsts list.
|
|
|
|
if (!Op->use_empty()) continue;
|
|
|
|
|
|
|
|
if (Instruction *OpI = dyn_cast<Instruction>(Op))
|
|
|
|
if (isInstructionTriviallyDead(OpI))
|
|
|
|
NowDeadInsts.push_back(OpI);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeadInst->eraseFromParent();
|
|
|
|
|
|
|
|
} while (!NowDeadInsts.empty());
|
|
|
|
}
|
|
|
|
|
2010-12-26 19:39:38 +00:00
|
|
|
bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) {
|
2010-12-26 20:45:45 +00:00
|
|
|
CurLoop = L;
|
|
|
|
|
2010-12-26 19:39:38 +00:00
|
|
|
// We only look at trivial single basic block loops.
|
|
|
|
// TODO: eventually support more complex loops, scanning the header.
|
|
|
|
if (L->getBlocks().size() != 1)
|
|
|
|
return false;
|
|
|
|
|
2010-12-26 20:45:45 +00:00
|
|
|
// The trip count of the loop must be analyzable.
|
|
|
|
SE = &getAnalysis<ScalarEvolution>();
|
|
|
|
if (!SE->hasLoopInvariantBackedgeTakenCount(L))
|
|
|
|
return false;
|
|
|
|
const SCEV *BECount = SE->getBackedgeTakenCount(L);
|
|
|
|
if (isa<SCEVCouldNotCompute>(BECount)) return false;
|
|
|
|
|
|
|
|
// We require target data for now.
|
|
|
|
TD = getAnalysisIfAvailable<TargetData>();
|
|
|
|
if (TD == 0) return false;
|
|
|
|
|
2010-12-26 19:39:38 +00:00
|
|
|
BasicBlock *BB = L->getHeader();
|
2010-12-26 20:45:45 +00:00
|
|
|
DEBUG(dbgs() << "loop-idiom Scanning: F[" << BB->getParent()->getName()
|
2010-12-26 19:39:38 +00:00
|
|
|
<< "] Loop %" << BB->getName() << "\n");
|
|
|
|
|
2010-12-26 20:45:45 +00:00
|
|
|
bool MadeChange = false;
|
|
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
|
|
|
|
// Look for store instructions, which may be memsets.
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
StoreInst *SI = dyn_cast<StoreInst>(I++);
|
|
|
|
if (SI == 0 || SI->isVolatile()) continue;
|
|
|
|
|
2010-12-27 18:39:08 +00:00
|
|
|
WeakVH InstPtr(SI);
|
|
|
|
if (!processLoopStore(SI, BECount)) continue;
|
|
|
|
|
|
|
|
MadeChange = true;
|
|
|
|
|
|
|
|
// If processing the store invalidated our iterator, start over from the
|
|
|
|
// head of the loop.
|
|
|
|
if (InstPtr == 0)
|
|
|
|
I = BB->begin();
|
2010-12-26 20:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return MadeChange;
|
2010-12-26 19:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// scanBlock - Look over a block to see if we can promote anything out of it.
|
2010-12-26 20:45:45 +00:00
|
|
|
bool LoopIdiomRecognize::processLoopStore(StoreInst *SI, const SCEV *BECount) {
|
|
|
|
Value *StoredVal = SI->getValueOperand();
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
Value *StorePtr = SI->getPointerOperand();
|
2010-12-26 19:39:38 +00:00
|
|
|
|
2010-12-28 18:53:48 +00:00
|
|
|
// Reject stores that are so large that they overflow an unsigned.
|
2010-12-26 20:45:45 +00:00
|
|
|
uint64_t SizeInBits = TD->getTypeSizeInBits(StoredVal->getType());
|
2010-12-28 18:53:48 +00:00
|
|
|
if ((SizeInBits & 7) || (SizeInBits >> 32) != 0)
|
2010-12-26 20:45:45 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// See if the pointer expression is an AddRec like {base,+,1} on the current
|
|
|
|
// loop, which indicates a strided store. If we have something else, it's a
|
|
|
|
// random store we can't handle.
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
const SCEVAddRecExpr *Ev = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(StorePtr));
|
2010-12-26 20:45:45 +00:00
|
|
|
if (Ev == 0 || Ev->getLoop() != CurLoop || !Ev->isAffine())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check to see if the stride matches the size of the store. If so, then we
|
|
|
|
// know that every byte is touched in the loop.
|
|
|
|
unsigned StoreSize = (unsigned)SizeInBits >> 3;
|
|
|
|
const SCEVConstant *Stride = dyn_cast<SCEVConstant>(Ev->getOperand(1));
|
2011-01-01 19:39:01 +00:00
|
|
|
|
|
|
|
// TODO: Could also handle negative stride here someday, that will require the
|
|
|
|
// validity check in mayLoopModRefLocation to be updated though.
|
2010-12-26 20:45:45 +00:00
|
|
|
if (Stride == 0 || StoreSize != Stride->getValue()->getValue())
|
|
|
|
return false;
|
2010-12-26 19:39:38 +00:00
|
|
|
|
2010-12-26 20:45:45 +00:00
|
|
|
// If the stored value is a byte-wise value (like i32 -1), then it may be
|
|
|
|
// turned into a memset of i8 -1, assuming that all the consequtive bytes
|
|
|
|
// are stored. A store of i32 0x01020304 can never be turned into a memset.
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
if (Value *SplatValue = isBytewiseValue(StoredVal))
|
|
|
|
return processLoopStoreOfSplatValue(SI, StoreSize, SplatValue, Ev, BECount);
|
|
|
|
|
|
|
|
// Handle the memcpy case here.
|
|
|
|
errs() << "Found strided store: " << *Ev << "\n";
|
2010-12-26 20:45:45 +00:00
|
|
|
|
|
|
|
|
2010-12-26 19:39:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-01-01 19:39:01 +00:00
|
|
|
/// mayLoopModRefLocation - Return true if the specified loop might do a load or
|
|
|
|
/// store to the same location that the specified store could store to, which is
|
|
|
|
/// a loop-strided access.
|
|
|
|
static bool mayLoopModRefLocation(StoreInst *SI, Loop *L, AliasAnalysis &AA) {
|
|
|
|
// Get the location that may be stored across the loop. Since the access is
|
|
|
|
// strided positively through memory, we say that the modified location starts
|
|
|
|
// at the pointer and has infinite size.
|
|
|
|
// TODO: Could improve this for constant trip-count loops.
|
|
|
|
AliasAnalysis::Location StoreLoc =
|
|
|
|
AliasAnalysis::Location(SI->getPointerOperand());
|
|
|
|
|
|
|
|
for (Loop::block_iterator BI = L->block_begin(), E = L->block_end(); BI != E;
|
|
|
|
++BI)
|
|
|
|
for (BasicBlock::iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I)
|
|
|
|
if (AA.getModRefInfo(I, StoreLoc) != AliasAnalysis::NoModRef)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
/// processLoopStoreOfSplatValue - We see a strided store of a memsetable value.
|
|
|
|
/// If we can transform this into a memset in the loop preheader, do so.
|
|
|
|
bool LoopIdiomRecognize::
|
|
|
|
processLoopStoreOfSplatValue(StoreInst *SI, unsigned StoreSize,
|
|
|
|
Value *SplatValue,
|
|
|
|
const SCEVAddRecExpr *Ev, const SCEV *BECount) {
|
2011-01-01 19:39:01 +00:00
|
|
|
// Temporarily remove the store from the loop, to avoid the mod/ref query from
|
|
|
|
// seeing it.
|
|
|
|
Instruction *InstAfterStore = ++BasicBlock::iterator(SI);
|
|
|
|
SI->removeFromParent();
|
|
|
|
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
// Okay, we have a strided store "p[i]" of a splattable value. We can turn
|
|
|
|
// this into a memset in the loop preheader now if we want. However, this
|
|
|
|
// would be unsafe to do if there is anything else in the loop that may read
|
|
|
|
// or write to the aliased location. Check for an alias.
|
2011-01-01 19:39:01 +00:00
|
|
|
bool Unsafe=mayLoopModRefLocation(SI, CurLoop, getAnalysis<AliasAnalysis>());
|
|
|
|
|
|
|
|
SI->insertBefore(InstAfterStore);
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
|
2011-01-01 19:39:01 +00:00
|
|
|
if (Unsafe) return false;
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
|
|
|
|
// Okay, everything looks good, insert the memset.
|
|
|
|
BasicBlock *Preheader = CurLoop->getLoopPreheader();
|
|
|
|
|
|
|
|
IRBuilder<> Builder(Preheader->getTerminator());
|
|
|
|
|
|
|
|
// The trip count of the loop and the base pointer of the addrec SCEV is
|
|
|
|
// guaranteed to be loop invariant, which means that it should dominate the
|
|
|
|
// header. Just insert code for it in the preheader.
|
|
|
|
SCEVExpander Expander(*SE);
|
|
|
|
|
|
|
|
unsigned AddrSpace = SI->getPointerAddressSpace();
|
|
|
|
Value *BasePtr =
|
|
|
|
Expander.expandCodeFor(Ev->getStart(), Builder.getInt8PtrTy(AddrSpace),
|
|
|
|
Preheader->getTerminator());
|
|
|
|
|
|
|
|
// The # stored bytes is (BECount+1)*Size. Expand the trip count out to
|
|
|
|
// pointer size if it isn't already.
|
|
|
|
const Type *IntPtr = TD->getIntPtrType(SI->getContext());
|
|
|
|
unsigned BESize = SE->getTypeSizeInBits(BECount->getType());
|
|
|
|
if (BESize < TD->getPointerSizeInBits())
|
|
|
|
BECount = SE->getZeroExtendExpr(BECount, IntPtr);
|
|
|
|
else if (BESize > TD->getPointerSizeInBits())
|
|
|
|
BECount = SE->getTruncateExpr(BECount, IntPtr);
|
|
|
|
|
|
|
|
const SCEV *NumBytesS = SE->getAddExpr(BECount, SE->getConstant(IntPtr, 1),
|
|
|
|
true, true /*nooverflow*/);
|
|
|
|
if (StoreSize != 1)
|
|
|
|
NumBytesS = SE->getMulExpr(NumBytesS, SE->getConstant(IntPtr, StoreSize),
|
|
|
|
true, true /*nooverflow*/);
|
|
|
|
|
|
|
|
Value *NumBytes =
|
|
|
|
Expander.expandCodeFor(NumBytesS, IntPtr, Preheader->getTerminator());
|
|
|
|
|
|
|
|
Value *NewCall =
|
|
|
|
Builder.CreateMemSet(BasePtr, SplatValue, NumBytes, SI->getAlignment());
|
|
|
|
|
|
|
|
DEBUG(dbgs() << " Formed memset: " << *NewCall << "\n"
|
|
|
|
<< " from store to: " << *Ev << " at: " << *SI << "\n");
|
2010-12-28 09:41:15 +00:00
|
|
|
(void)NewCall;
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
|
2010-12-27 00:03:23 +00:00
|
|
|
// Okay, the memset has been formed. Zap the original store and anything that
|
|
|
|
// feeds into it.
|
|
|
|
DeleteDeadInstruction(SI, *SE);
|
implement enough of the memset inference algorithm to recognize and insert
memsets. This is still missing one important validity check, but this is enough
to compile stuff like this:
void test0(std::vector<char> &X) {
for (std::vector<char>::iterator I = X.begin(), E = X.end(); I != E; ++I)
*I = 0;
}
void test1(std::vector<int> &X) {
for (long i = 0, e = X.size(); i != e; ++i)
X[i] = 0x01010101;
}
With:
$ clang t.cpp -S -o - -O2 -emit-llvm | opt -loop-idiom | opt -O3 | llc
to:
__Z5test0RSt6vectorIcSaIcEE: ## @_Z5test0RSt6vectorIcSaIcEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rsi
cmpq %rsi, %rax
je LBB0_2
## BB#1: ## %bb.nph
subq %rax, %rsi
movq %rax, %rdi
callq ___bzero
LBB0_2: ## %for.end
addq $8, %rsp
ret
...
__Z5test1RSt6vectorIiSaIiEE: ## @_Z5test1RSt6vectorIiSaIiEE
## BB#0: ## %entry
subq $8, %rsp
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
cmpq $4, %rdx
jb LBB1_2
## BB#1: ## %for.body.preheader
andq $-4, %rdx
movl $1, %esi
movq %rax, %rdi
callq _memset
LBB1_2: ## %for.end
addq $8, %rsp
ret
llvm-svn: 122573
2010-12-26 23:42:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|