mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2026-04-20 16:17:38 +00:00
Add support for llvm.vectorizer metadata
- llvm.loop.parallel metadata has been renamed to llvm.loop to be more generic
by making the root of additional loop metadata.
- Loop::isAnnotatedParallel now looks for llvm.loop and associated
llvm.mem.parallel_loop_access
- document llvm.loop and update llvm.mem.parallel_loop_access
- add support for llvm.vectorizer.width and llvm.vectorizer.unroll
- document llvm.vectorizer.* metadata
- add utility class LoopVectorizerHints for getting/setting loop metadata
- use llvm.vectorizer.width=1 to indicate already vectorized instead of
already_vectorized
- update existing tests that used llvm.loop.parallel and
llvm.vectorizer.already_vectorized
Reviewed by: Nadav Rotem
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182802 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -119,11 +119,11 @@ static const unsigned TinyTripCountUnrollThreshold = 128;
|
||||
/// than this number of comparisons.
|
||||
static const unsigned RuntimeMemoryCheckThreshold = 8;
|
||||
|
||||
/// We use a metadata with this name to indicate that a scalar loop was
|
||||
/// vectorized and that we don't need to re-vectorize it if we run into it
|
||||
/// again.
|
||||
static const char*
|
||||
AlreadyVectorizedMDName = "llvm.vectorizer.already_vectorized";
|
||||
/// Maximum simd width.
|
||||
static const unsigned MaxVectorWidth = 64;
|
||||
|
||||
/// Maximum vectorization unroll count.
|
||||
static const unsigned MaxUnrollFactor = 16;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -768,6 +768,127 @@ private:
|
||||
const TargetLibraryInfo *TLI;
|
||||
};
|
||||
|
||||
/// Utility class for getting and setting loop vectorizer hints in the form
|
||||
/// of loop metadata.
|
||||
struct LoopVectorizeHints {
|
||||
/// Vectorization width.
|
||||
unsigned Width;
|
||||
/// Vectorization unroll factor.
|
||||
unsigned Unroll;
|
||||
|
||||
LoopVectorizeHints(const Loop *L)
|
||||
: Width(VectorizationFactor)
|
||||
, Unroll(VectorizationUnroll)
|
||||
, LoopID(L->getLoopID()) {
|
||||
getHints(L);
|
||||
// The command line options override any loop metadata except for when
|
||||
// width == 1 which is used to indicate the loop is already vectorized.
|
||||
if (VectorizationFactor.getNumOccurrences() > 0 && Width != 1)
|
||||
Width = VectorizationFactor;
|
||||
if (VectorizationUnroll.getNumOccurrences() > 0)
|
||||
Unroll = VectorizationUnroll;
|
||||
}
|
||||
|
||||
/// Return the loop vectorizer metadata prefix.
|
||||
static StringRef Prefix() { return "llvm.vectorizer."; }
|
||||
|
||||
MDNode *createHint(LLVMContext &Context, StringRef Name, unsigned V) {
|
||||
SmallVector<Value*, 2> Vals;
|
||||
Vals.push_back(MDString::get(Context, Name));
|
||||
Vals.push_back(ConstantInt::get(Type::getInt32Ty(Context), V));
|
||||
return MDNode::get(Context, Vals);
|
||||
}
|
||||
|
||||
/// Mark the loop L as already vectorized by setting the width to 1.
|
||||
void setAlreadyVectorized(Loop *L) {
|
||||
LLVMContext &Context = L->getHeader()->getContext();
|
||||
|
||||
Width = 1;
|
||||
|
||||
// Create a new loop id with one more operand for the already_vectorized
|
||||
// hint. If the loop already has a loop id then copy the existing operands.
|
||||
SmallVector<Value*, 4> Vals(1);
|
||||
if (LoopID)
|
||||
for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i)
|
||||
Vals.push_back(LoopID->getOperand(i));
|
||||
|
||||
Twine Name = Prefix() + "width";
|
||||
Vals.push_back(createHint(Context, Name.str(), Width));
|
||||
|
||||
MDNode *NewLoopID = MDNode::get(Context, Vals);
|
||||
// Set operand 0 to refer to the loop id itself.
|
||||
NewLoopID->replaceOperandWith(0, NewLoopID);
|
||||
|
||||
L->setLoopID(NewLoopID);
|
||||
if (LoopID)
|
||||
LoopID->replaceAllUsesWith(NewLoopID);
|
||||
|
||||
LoopID = NewLoopID;
|
||||
}
|
||||
|
||||
private:
|
||||
MDNode *LoopID;
|
||||
|
||||
/// Find hints specified in the loop metadata.
|
||||
void getHints(const Loop *L) {
|
||||
if (!LoopID)
|
||||
return;
|
||||
|
||||
// First operand should refer to the loop id itself.
|
||||
assert(LoopID->getNumOperands() > 0 && "requires at least one operand");
|
||||
assert(LoopID->getOperand(0) == LoopID && "invalid loop id");
|
||||
|
||||
for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) {
|
||||
const MDString *S = 0;
|
||||
SmallVector<Value*, 4> Args;
|
||||
|
||||
// The expected hint is either a MDString or a MDNode with the first
|
||||
// operand a MDString.
|
||||
if (const MDNode *MD = dyn_cast<MDNode>(LoopID->getOperand(i))) {
|
||||
if (!MD || MD->getNumOperands() == 0)
|
||||
continue;
|
||||
S = dyn_cast<MDString>(MD->getOperand(0));
|
||||
for (unsigned i = 1, ie = MD->getNumOperands(); i < ie; ++i)
|
||||
Args.push_back(MD->getOperand(i));
|
||||
} else {
|
||||
S = dyn_cast<MDString>(LoopID->getOperand(i));
|
||||
assert(Args.size() == 0 && "too many arguments for MDString");
|
||||
}
|
||||
|
||||
if (!S)
|
||||
continue;
|
||||
|
||||
// Check if the hint starts with the vectorizer prefix.
|
||||
StringRef Hint = S->getString();
|
||||
if (!Hint.startswith(Prefix()))
|
||||
continue;
|
||||
// Remove the prefix.
|
||||
Hint = Hint.substr(Prefix().size(), StringRef::npos);
|
||||
|
||||
if (Args.size() == 1)
|
||||
getHint(Hint, Args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check string hint with one operand.
|
||||
void getHint(StringRef Hint, Value *Arg) {
|
||||
const ConstantInt *C = dyn_cast<ConstantInt>(Arg);
|
||||
if (!C) return;
|
||||
unsigned Val = C->getZExtValue();
|
||||
|
||||
if (Hint == "width") {
|
||||
assert(isPowerOf2_32(Val) && Val <= MaxVectorWidth &&
|
||||
"Invalid width metadata");
|
||||
Width = Val;
|
||||
} else if (Hint == "unroll") {
|
||||
assert(isPowerOf2_32(Val) && Val <= MaxUnrollFactor &&
|
||||
"Invalid unroll metadata");
|
||||
Unroll = Val;
|
||||
} else
|
||||
DEBUG(dbgs() << "LV: ignoring unknown hint " << Hint);
|
||||
}
|
||||
};
|
||||
|
||||
/// The LoopVectorize Pass.
|
||||
struct LoopVectorize : public LoopPass {
|
||||
/// Pass identification, replacement for typeid
|
||||
@@ -806,6 +927,13 @@ struct LoopVectorize : public LoopPass {
|
||||
DEBUG(dbgs() << "LV: Checking a loop in \"" <<
|
||||
L->getHeader()->getParent()->getName() << "\"\n");
|
||||
|
||||
LoopVectorizeHints Hints(L);
|
||||
|
||||
if (Hints.Width == 1) {
|
||||
DEBUG(dbgs() << "LV: Not vectorizing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it is legal to vectorize the loop.
|
||||
LoopVectorizationLegality LVL(L, SE, DL, DT, TTI, AA, TLI);
|
||||
if (!LVL.canVectorize()) {
|
||||
@@ -833,10 +961,10 @@ struct LoopVectorize : public LoopPass {
|
||||
|
||||
// Select the optimal vectorization factor.
|
||||
LoopVectorizationCostModel::VectorizationFactor VF;
|
||||
VF = CM.selectVectorizationFactor(OptForSize, VectorizationFactor);
|
||||
VF = CM.selectVectorizationFactor(OptForSize, Hints.Width);
|
||||
// Select the unroll factor.
|
||||
unsigned UF = CM.selectUnrollFactor(OptForSize, VectorizationUnroll,
|
||||
VF.Width, VF.Cost);
|
||||
unsigned UF = CM.selectUnrollFactor(OptForSize, Hints.Unroll, VF.Width,
|
||||
VF.Cost);
|
||||
|
||||
if (VF.Width == 1) {
|
||||
DEBUG(dbgs() << "LV: Vectorization is possible but not beneficial.\n");
|
||||
@@ -851,6 +979,9 @@ struct LoopVectorize : public LoopPass {
|
||||
InnerLoopVectorizer LB(L, SE, LI, DT, DL, TLI, VF.Width, UF);
|
||||
LB.vectorize(&LVL);
|
||||
|
||||
// Mark the loop as already vectorized to avoid vectorizing again.
|
||||
Hints.setAlreadyVectorized(L);
|
||||
|
||||
DEBUG(verifyFunction(*L->getHeader()->getParent()));
|
||||
return true;
|
||||
}
|
||||
@@ -1318,11 +1449,6 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) {
|
||||
BasicBlock *ExitBlock = OrigLoop->getExitBlock();
|
||||
assert(ExitBlock && "Must have an exit block");
|
||||
|
||||
// Mark the old scalar loop with metadata that tells us not to vectorize this
|
||||
// loop again if we run into it.
|
||||
MDNode *MD = MDNode::get(OldBasicBlock->getContext(), None);
|
||||
OldBasicBlock->getTerminator()->setMetadata(AlreadyVectorizedMDName, MD);
|
||||
|
||||
// Some loops have a single integer induction variable, while other loops
|
||||
// don't. One example is c++ iterators that often have multiple pointer
|
||||
// induction variables. In the code below we also support a case where we
|
||||
@@ -2516,13 +2642,6 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
|
||||
BasicBlock *PreHeader = TheLoop->getLoopPreheader();
|
||||
BasicBlock *Header = TheLoop->getHeader();
|
||||
|
||||
// If we marked the scalar loop as "already vectorized" then no need
|
||||
// to vectorize it again.
|
||||
if (Header->getTerminator()->getMetadata(AlreadyVectorizedMDName)) {
|
||||
DEBUG(dbgs() << "LV: This loop was vectorized before\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for the attribute signaling the absence of NaNs.
|
||||
Function &F = *Header->getParent();
|
||||
if (F.hasFnAttribute("no-nans-fp-math"))
|
||||
|
||||
Reference in New Issue
Block a user