#include "llvm/Analysis/CFLSteensAliasAnalysis.h"
#include "AliasAnalysisSummary.h"
#include "CFLGraph.h"
#include "StratifiedSets.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <limits>
#include <memory>
#include <utility>
using namespace llvm;
using namespace llvm::cflaa;
#define DEBUG_TYPE "cfl-steens-aa"
CFLSteensAAResult::CFLSteensAAResult(
std::function<const TargetLibraryInfo &(Function &F)> GetTLI)
: GetTLI(std::move(GetTLI)) {}
CFLSteensAAResult::CFLSteensAAResult(CFLSteensAAResult &&Arg)
: AAResultBase(std::move(Arg)), GetTLI(std::move(Arg.GetTLI)) {}
CFLSteensAAResult::~CFLSteensAAResult() = default;
class CFLSteensAAResult::FunctionInfo {
StratifiedSets<InstantiatedValue> Sets;
AliasSummary Summary;
public:
FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
StratifiedSets<InstantiatedValue> S);
const StratifiedSets<InstantiatedValue> &getStratifiedSets() const {
return Sets;
}
const AliasSummary &getAliasSummary() const { return Summary; }
};
const StratifiedIndex StratifiedLink::SetSentinel =
std::numeric_limits<StratifiedIndex>::max();
static bool canSkipAddingToSets(Value *Val) {
if (isa<Constant>(Val)) {
bool CanStoreMutableData = isa<GlobalValue>(Val) ||
isa<ConstantExpr>(Val) ||
isa<ConstantAggregate>(Val);
return !CanStoreMutableData;
}
return false;
}
CFLSteensAAResult::FunctionInfo::FunctionInfo(
Function &Fn, const SmallVectorImpl<Value *> &RetVals,
StratifiedSets<InstantiatedValue> S)
: Sets(std::move(S)) {
if (Fn.arg_size() > MaxSupportedArgsInSummary)
return;
DenseMap<StratifiedIndex, InterfaceValue> InterfaceMap;
auto AddToRetParamRelations = [&](unsigned InterfaceIndex,
StratifiedIndex SetIndex) {
unsigned Level = 0;
while (true) {
InterfaceValue CurrValue{InterfaceIndex, Level};
auto Itr = InterfaceMap.find(SetIndex);
if (Itr != InterfaceMap.end()) {
if (CurrValue != Itr->second)
Summary.RetParamRelations.push_back(
ExternalRelation{CurrValue, Itr->second, UnknownOffset});
break;
}
auto &Link = Sets.getLink(SetIndex);
InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
if (ExternalAttrs.any())
Summary.RetParamAttributes.push_back(
ExternalAttribute{CurrValue, ExternalAttrs});
if (!Link.hasBelow())
break;
++Level;
SetIndex = Link.Below;
}
};
for (auto *RetVal : RetVals) {
assert(RetVal != nullptr);
assert(RetVal->getType()->isPointerTy());
auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0});
if (RetInfo)
AddToRetParamRelations(0, RetInfo->Index);
}
unsigned I = 0;
for (auto &Param : Fn.args()) {
if (Param.getType()->isPointerTy()) {
auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0});
if (ParamInfo)
AddToRetParamRelations(I + 1, ParamInfo->Index);
}
++I;
}
}
CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, GetTLI(*Fn), *Fn);
StratifiedSetsBuilder<InstantiatedValue> SetBuilder;
auto &Graph = GraphBuilder.getCFLGraph();
for (const auto &Mapping : Graph.value_mappings()) {
auto Val = Mapping.first;
if (canSkipAddingToSets(Val))
continue;
auto &ValueInfo = Mapping.second;
assert(ValueInfo.getNumLevels() > 0);
SetBuilder.add(InstantiatedValue{Val, 0});
SetBuilder.noteAttributes(InstantiatedValue{Val, 0},
ValueInfo.getNodeInfoAtLevel(0).Attr);
for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) {
SetBuilder.add(InstantiatedValue{Val, I + 1});
SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1},
ValueInfo.getNodeInfoAtLevel(I + 1).Attr);
SetBuilder.addBelow(InstantiatedValue{Val, I},
InstantiatedValue{Val, I + 1});
}
}
for (const auto &Mapping : Graph.value_mappings()) {
auto Val = Mapping.first;
if (canSkipAddingToSets(Val))
continue;
auto &ValueInfo = Mapping.second;
for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
auto Src = InstantiatedValue{Val, I};
for (const auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges)
SetBuilder.addWith(Src, Edge.Other);
}
}
return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
}
void CFLSteensAAResult::scan(Function *Fn) {
auto InsertPair = Cache.insert(std::make_pair(Fn, Optional<FunctionInfo>()));
(void)InsertPair;
assert(InsertPair.second &&
"Trying to scan a function that has already been cached");
auto FunInfo = buildSetsFrom(Fn);
Cache[Fn] = std::move(FunInfo);
Handles.emplace_front(Fn, this);
}
void CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); }
const Optional<CFLSteensAAResult::FunctionInfo> &
CFLSteensAAResult::ensureCached(Function *Fn) {
auto Iter = Cache.find(Fn);
if (Iter == Cache.end()) {
scan(Fn);
Iter = Cache.find(Fn);
assert(Iter != Cache.end());
assert(Iter->second);
}
return Iter->second;
}
const AliasSummary *CFLSteensAAResult::getAliasSummary(Function &Fn) {
auto &FunInfo = ensureCached(&Fn);
if (FunInfo)
return &FunInfo->getAliasSummary();
else
return nullptr;
}
AliasResult CFLSteensAAResult::query(const MemoryLocation &LocA,
const MemoryLocation &LocB) {
auto *ValA = const_cast<Value *>(LocA.Ptr);
auto *ValB = const_cast<Value *>(LocB.Ptr);
if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
return AliasResult::NoAlias;
Function *Fn = nullptr;
Function *MaybeFnA = const_cast<Function *>(parentFunctionOfValue(ValA));
Function *MaybeFnB = const_cast<Function *>(parentFunctionOfValue(ValB));
if (!MaybeFnA && !MaybeFnB) {
LLVM_DEBUG(
dbgs()
<< "CFLSteensAA: could not extract parent function information.\n");
return AliasResult::MayAlias;
}
if (MaybeFnA) {
Fn = MaybeFnA;
assert((!MaybeFnB || MaybeFnB == MaybeFnA) &&
"Interprocedural queries not supported");
} else {
Fn = MaybeFnB;
}
assert(Fn != nullptr);
auto &MaybeInfo = ensureCached(Fn);
assert(MaybeInfo);
auto &Sets = MaybeInfo->getStratifiedSets();
auto MaybeA = Sets.find(InstantiatedValue{ValA, 0});
if (!MaybeA)
return AliasResult::MayAlias;
auto MaybeB = Sets.find(InstantiatedValue{ValB, 0});
if (!MaybeB)
return AliasResult::MayAlias;
auto SetA = *MaybeA;
auto SetB = *MaybeB;
auto AttrsA = Sets.getLink(SetA.Index).Attrs;
auto AttrsB = Sets.getLink(SetB.Index).Attrs;
if (SetA.Index == SetB.Index)
return AliasResult::MayAlias;
if (AttrsA.none() || AttrsB.none())
return AliasResult::NoAlias;
if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
return AliasResult::MayAlias;
if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
return AliasResult::MayAlias;
return AliasResult::NoAlias;
}
AnalysisKey CFLSteensAA::Key;
CFLSteensAAResult CFLSteensAA::run(Function &F, FunctionAnalysisManager &AM) {
auto GetTLI = [&AM](Function &F) -> const TargetLibraryInfo & {
return AM.getResult<TargetLibraryAnalysis>(F);
};
return CFLSteensAAResult(GetTLI);
}
char CFLSteensAAWrapperPass::ID = 0;
INITIALIZE_PASS(CFLSteensAAWrapperPass, "cfl-steens-aa",
"Unification-Based CFL Alias Analysis", false, true)
ImmutablePass *llvm::createCFLSteensAAWrapperPass() {
return new CFLSteensAAWrapperPass();
}
CFLSteensAAWrapperPass::CFLSteensAAWrapperPass() : ImmutablePass(ID) {
initializeCFLSteensAAWrapperPassPass(*PassRegistry::getPassRegistry());
}
void CFLSteensAAWrapperPass::initializePass() {
auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & {
return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
};
Result.reset(new CFLSteensAAResult(GetTLI));
}
void CFLSteensAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}