#include "polly/CodeGen/IRBuilder.h"
#include "polly/ScopInfo.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Metadata.h"
using namespace llvm;
using namespace polly;
static const int MaxArraysInAliasScops = 10;
static MDNode *getID(LLVMContext &Ctx, Metadata *arg0 = nullptr,
Metadata *arg1 = nullptr) {
MDNode *ID;
SmallVector<Metadata *, 3> Args;
Args.push_back(nullptr);
if (arg0)
Args.push_back(arg0);
if (arg1)
Args.push_back(arg1);
ID = MDNode::getDistinct(Ctx, Args);
ID->replaceOperandWith(0, ID);
return ID;
}
ScopAnnotator::ScopAnnotator() : SE(nullptr), AliasScopeDomain(nullptr) {
LoopAttrEnv.emplace_back();
}
ScopAnnotator::~ScopAnnotator() {
assert(LoopAttrEnv.size() == 1 && "Loop stack imbalance");
assert(!getStagingAttrEnv() && "Forgot to clear staging attr env");
}
void ScopAnnotator::buildAliasScopes(Scop &S) {
SE = S.getSE();
LLVMContext &Ctx = SE->getContext();
AliasScopeDomain = getID(Ctx, MDString::get(Ctx, "polly.alias.scope.domain"));
AliasScopeMap.clear();
OtherAliasScopeListMap.clear();
SmallVector<ScopArrayInfo *, 10> Arrays;
for (ScopArrayInfo *Array : S.arrays())
if (Array->isArrayKind())
Arrays.push_back(Array);
if (Arrays.size() > MaxArraysInAliasScops)
return;
std::string AliasScopeStr = "polly.alias.scope.";
for (const ScopArrayInfo *Array : Arrays) {
assert(Array->getBasePtr() && "Base pointer must be present");
AliasScopeMap[Array->getBasePtr()] =
getID(Ctx, AliasScopeDomain,
MDString::get(Ctx, (AliasScopeStr + Array->getName()).c_str()));
}
for (const ScopArrayInfo *Array : Arrays) {
MDNode *AliasScopeList = MDNode::get(Ctx, {});
for (const auto &AliasScopePair : AliasScopeMap) {
if (Array->getBasePtr() == AliasScopePair.first)
continue;
Metadata *Args = {AliasScopePair.second};
AliasScopeList =
MDNode::concatenate(AliasScopeList, MDNode::get(Ctx, Args));
}
OtherAliasScopeListMap[Array->getBasePtr()] = AliasScopeList;
}
}
void ScopAnnotator::pushLoop(Loop *L, bool IsParallel) {
ActiveLoops.push_back(L);
if (IsParallel) {
LLVMContext &Ctx = SE->getContext();
MDNode *AccessGroup = MDNode::getDistinct(Ctx, {});
ParallelLoops.push_back(AccessGroup);
}
LoopAttrEnv.emplace_back();
}
void ScopAnnotator::popLoop(bool IsParallel) {
ActiveLoops.pop_back();
if (IsParallel) {
assert(!ParallelLoops.empty() && "Expected a parallel loop to pop");
ParallelLoops.pop_back();
}
assert(!getStagingAttrEnv() && "Forgot to clear staging attr env");
assert(LoopAttrEnv.size() >= 2 && "Popped too many");
LoopAttrEnv.pop_back();
}
void ScopAnnotator::annotateLoopLatch(BranchInst *B, Loop *L, bool IsParallel,
bool IsLoopVectorizerDisabled) const {
LLVMContext &Ctx = SE->getContext();
SmallVector<Metadata *, 3> Args;
Args.push_back(nullptr);
MDNode *MData = nullptr;
if (BandAttr *AttrEnv = getActiveAttrEnv()) {
MData = AttrEnv->Metadata;
if (MData)
llvm::append_range(Args, drop_begin(MData->operands(), 1));
}
if (IsLoopVectorizerDisabled) {
MDString *PropName = MDString::get(Ctx, "llvm.loop.vectorize.enable");
ConstantInt *FalseValue = ConstantInt::get(Type::getInt1Ty(Ctx), 0);
ValueAsMetadata *PropValue = ValueAsMetadata::get(FalseValue);
Args.push_back(MDNode::get(Ctx, {PropName, PropValue}));
}
if (IsParallel) {
MDString *PropName = MDString::get(Ctx, "llvm.loop.parallel_accesses");
MDNode *AccGroup = ParallelLoops.back();
Args.push_back(MDNode::get(Ctx, {PropName, AccGroup}));
}
if (!MData && Args.size() <= 1)
return;
if (!MData || Args.size() > MData->getNumOperands()) {
MData = MDNode::getDistinct(Ctx, Args);
MData->replaceOperandWith(0, MData);
}
B->setMetadata(LLVMContext::MD_loop, MData);
}
static llvm::Value *getMemAccInstPointerOperand(Instruction *Inst) {
auto MemInst = MemAccInst::dyn_cast(Inst);
if (!MemInst)
return nullptr;
return MemInst.getPointerOperand();
}
static Value *findBasePtr(Value *Val) {
while (true) {
if (auto *Gep = dyn_cast<GEPOperator>(Val)) {
Val = Gep->getPointerOperand();
continue;
}
if (auto *Cast = dyn_cast<BitCastOperator>(Val)) {
Val = Cast->getOperand(0);
continue;
}
break;
}
return Val;
}
void ScopAnnotator::annotate(Instruction *Inst) {
if (!Inst->mayReadOrWriteMemory())
return;
switch (ParallelLoops.size()) {
case 0:
break;
case 1:
Inst->setMetadata(LLVMContext::MD_access_group,
cast<MDNode>(ParallelLoops.front()));
break;
default:
Inst->setMetadata(LLVMContext::MD_access_group,
MDNode::get(SE->getContext(),
ArrayRef<Metadata *>(
(Metadata *const *)ParallelLoops.data(),
ParallelLoops.size())));
break;
}
if (!AliasScopeDomain)
return;
if (isa<CallInst>(Inst) && !isa<MemSetInst>(Inst))
return;
auto *Ptr = getMemAccInstPointerOperand(Inst);
if (!Ptr)
return;
Value *BasePtr = findBasePtr(Ptr);
if (!BasePtr)
return;
auto AliasScope = AliasScopeMap.lookup(BasePtr);
if (!AliasScope) {
BasePtr = AlternativeAliasBases.lookup(BasePtr);
if (!BasePtr)
return;
AliasScope = AliasScopeMap.lookup(BasePtr);
if (!AliasScope)
return;
}
assert(OtherAliasScopeListMap.count(BasePtr) &&
"BasePtr either expected in AliasScopeMap and OtherAlias...Map");
auto *OtherAliasScopeList = OtherAliasScopeListMap[BasePtr];
Inst->setMetadata("alias.scope", MDNode::get(SE->getContext(), AliasScope));
Inst->setMetadata("noalias", OtherAliasScopeList);
}