62 using namespace llvm::cflaa;
64 #define DEBUG_TYPE "cfl-anders-aa"
72 if (
auto *Inst = dyn_cast<Instruction>(Val)) {
74 return Bb->getParent();
77 if (
auto *Arg = dyn_cast<Argument>(Val))
78 return Arg->getParent();
92 FlowFromMemAliasNoReadWrite,
93 FlowFromMemAliasReadOnly,
105 FlowToMemAliasWriteOnly,
106 FlowToMemAliasReadWrite,
109 typedef std::bitset<7> StateSet;
110 const unsigned ReadOnlyStateMask =
111 (1U << static_cast<uint8_t>(MatchState::FlowFromReadOnly)) |
112 (1U << static_cast<uint8_t>(MatchState::FlowFromMemAliasReadOnly));
113 const unsigned WriteOnlyStateMask =
114 (1U << static_cast<uint8_t>(MatchState::FlowToWriteOnly)) |
115 (1U << static_cast<uint8_t>(MatchState::FlowToMemAliasWriteOnly));
123 bool operator==(OffsetValue LHS, OffsetValue RHS) {
124 return LHS.Val == RHS.Val && LHS.Offset == RHS.Offset;
126 bool operator<(OffsetValue LHS, OffsetValue RHS) {
127 return std::less<const Value *>()(LHS.Val, RHS.Val) ||
128 (LHS.Val == RHS.Val && LHS.Offset < RHS.Offset);
132 struct OffsetInstantiatedValue {
137 bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) {
138 return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset;
143 class ReachabilitySet {
146 ValueReachMap ReachMap;
149 typedef ValueStateMap::const_iterator const_valuestate_iterator;
150 typedef ValueReachMap::const_iterator const_value_iterator;
155 auto &States = ReachMap[To][From];
156 auto Idx =
static_cast<size_t>(State);
157 if (!States.test(Idx)) {
167 auto Itr = ReachMap.find(V);
168 if (Itr == ReachMap.end())
169 return make_range<const_valuestate_iterator>(const_valuestate_iterator(),
170 const_valuestate_iterator());
171 return make_range<const_valuestate_iterator>(Itr->second.begin(),
176 return make_range<const_value_iterator>(ReachMap.begin(), ReachMap.end());
188 typedef MemSet::const_iterator const_mem_iterator;
194 return MemMap[LHS].insert(RHS).second;
198 auto Itr = MemMap.find(V);
199 if (Itr == MemMap.end())
211 typedef MapType::const_iterator const_iterator;
214 auto &OldAttr = AttrMap[V];
215 auto NewAttr = OldAttr | Attr;
216 if (OldAttr == NewAttr)
224 auto Itr = AttrMap.find(V);
225 if (Itr != AttrMap.end())
231 return make_range<const_iterator>(AttrMap.begin(), AttrMap.end());
235 struct WorkListItem {
241 struct ValueSummary {
263 std::make_pair(OVal.Val, OVal.Offset));
265 static bool isEqual(
const OffsetValue &LHS,
const OffsetValue &RHS) {
273 return OffsetInstantiatedValue{
278 return OffsetInstantiatedValue{
284 std::make_pair(OVal.IVal, OVal.Offset));
286 static bool isEqual(
const OffsetInstantiatedValue &LHS,
287 const OffsetInstantiatedValue &RHS) {
310 const ReachabilitySet &, AliasAttrMap);
317 return (Set & StateSet(ReadOnlyStateMask)).any();
321 return (Set & StateSet(WriteOnlyStateMask)).any();
327 auto Val = IValue.
Val;
330 if (
auto Arg = dyn_cast<Argument>(Val))
331 Index = Arg->getArgNo() + 1;
341 const AliasAttrMap &AMap) {
342 for (
const auto &Mapping : AMap.mappings()) {
343 auto IVal = Mapping.first;
346 auto &Attr = AttrMap[IVal.Val];
348 if (IVal.DerefLevel == 0)
349 Attr |= Mapping.second;
355 const ReachabilitySet &ReachSet) {
356 for (
const auto &OuterMapping : ReachSet.value_mappings()) {
358 if (OuterMapping.first.DerefLevel > 0)
361 auto Val = OuterMapping.first.Val;
362 auto &AliasList = AliasMap[Val];
363 for (
const auto &InnerMapping : OuterMapping.second) {
365 if (InnerMapping.first.DerefLevel == 0)
366 AliasList.push_back(OffsetValue{InnerMapping.first.Val,
UnknownOffset});
370 std::sort(AliasList.begin(), AliasList.end());
380 for (
const auto &Arg : Fn.
args()) {
402 for (
const auto &OuterMapping : ReachSet.value_mappings()) {
404 for (
const auto &InnerMapping : OuterMapping.second) {
416 auto SrcIVal = InnerMapping.first;
418 ValueMap[SrcIVal.Val].FromRecords.push_back(
419 ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
421 ValueMap[SrcIVal.Val].ToRecords.push_back(
422 ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
428 for (
const auto &Mapping :
ValueMap) {
429 for (
const auto &FromRecord : Mapping.second.FromRecords) {
430 for (
const auto &ToRecord : Mapping.second.ToRecords) {
431 auto ToLevel = ToRecord.DerefLevel;
432 auto FromLevel = FromRecord.DerefLevel;
434 if (ToLevel == FromLevel)
437 auto SrcIndex = FromRecord.IValue.Index;
438 auto SrcLevel = FromRecord.IValue.DerefLevel;
439 auto DstIndex = ToRecord.IValue.Index;
440 auto DstLevel = ToRecord.IValue.DerefLevel;
441 if (ToLevel > FromLevel)
442 SrcLevel += ToLevel - FromLevel;
444 DstLevel += FromLevel - ToLevel;
454 std::sort(ExtRelations.begin(), ExtRelations.end());
455 ExtRelations.
erase(std::unique(ExtRelations.begin(), ExtRelations.end()),
462 for (
const auto &Mapping : AMap.mappings()) {
473 const ReachabilitySet &ReachSet, AliasAttrMap AMap) {
481 CFLAndersAAResult::FunctionInfo::getAttrs(
const Value *V)
const {
484 auto Itr = AttrMap.find(V);
485 if (Itr != AttrMap.end())
493 uint64_t RHSSize)
const {
499 auto MaybeAttrsA = getAttrs(LHS);
500 auto MaybeAttrsB = getAttrs(RHS);
501 if (!MaybeAttrsA || !MaybeAttrsB)
505 auto AttrsA = *MaybeAttrsA;
506 auto AttrsB = *MaybeAttrsB;
518 auto Itr = AliasMap.find(LHS);
519 if (Itr != AliasMap.end()) {
522 auto Comparator = [](OffsetValue LHS, OffsetValue RHS) {
523 return std::less<const Value *>()(LHS.Val, RHS.Val);
525 #ifdef EXPENSIVE_CHECKS
526 assert(std::is_sorted(Itr->second.begin(), Itr->second.end(), Comparator));
528 auto RangePair = std::equal_range(Itr->second.begin(), Itr->second.end(),
529 OffsetValue{RHS, 0}, Comparator);
531 if (RangePair.first != RangePair.second) {
533 if (LHSSize == MemoryLocation::UnknownSize ||
534 RHSSize == MemoryLocation::UnknownSize)
537 for (
const auto &OVal :
make_range(RangePair)) {
548 if (
LLVM_UNLIKELY(LHSSize > INT64_MAX || RHSSize > INT64_MAX))
551 auto LHSStart = OVal.Offset;
553 auto LHSEnd = OVal.Offset +
static_cast<int64_t
>(LHSSize);
555 auto RHSEnd =
static_cast<int64_t
>(RHSSize);
556 if (LHSEnd > RHSStart && LHSStart < RHSEnd)
567 std::vector<WorkListItem> &WorkList) {
570 if (ReachSet.insert(From, To, State))
571 WorkList.push_back(WorkListItem{From, To, State});
575 ReachabilitySet &ReachSet,
578 auto Val = Mapping.first;
587 for (
auto &Edge :
ValueInfo.getNodeInfoAtLevel(
I).Edges) {
588 propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet,
590 propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet,
600 if (Graph.getNode(NodeBelow))
606 ReachabilitySet &ReachSet, AliasMemSet &MemSet,
607 std::vector<WorkListItem> &WorkList) {
608 auto FromNode = Item.From;
609 auto ToNode = Item.To;
611 auto NodeInfo = Graph.getNode(ToNode);
612 assert(NodeInfo !=
nullptr);
624 if (FromNodeBelow && ToNodeBelow &&
625 MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
627 MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
628 for (
const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {
629 auto Src = Mapping.first;
631 if (Mapping.second.test(static_cast<size_t>(FromState)))
632 propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList);
635 MemAliasPropagate(MatchState::FlowFromReadOnly,
636 MatchState::FlowFromMemAliasReadOnly);
637 MemAliasPropagate(MatchState::FlowToWriteOnly,
638 MatchState::FlowToMemAliasWriteOnly);
639 MemAliasPropagate(MatchState::FlowToReadWrite,
640 MatchState::FlowToMemAliasReadWrite);
652 auto NextAssignState = [&](
MatchState State) {
653 for (
const auto &AssignEdge : NodeInfo->Edges)
654 propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList);
656 auto NextRevAssignState = [&](
MatchState State) {
657 for (
const auto &RevAssignEdge : NodeInfo->ReverseEdges)
658 propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList);
661 if (
auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
662 for (
const auto &MemAlias : *
AliasSet)
663 propagate(FromNode, MemAlias, State, ReachSet, WorkList);
667 switch (Item.State) {
668 case MatchState::FlowFromReadOnly: {
669 NextRevAssignState(MatchState::FlowFromReadOnly);
670 NextAssignState(MatchState::FlowToReadWrite);
671 NextMemState(MatchState::FlowFromMemAliasReadOnly);
674 case MatchState::FlowFromMemAliasNoReadWrite: {
675 NextRevAssignState(MatchState::FlowFromReadOnly);
676 NextAssignState(MatchState::FlowToWriteOnly);
679 case MatchState::FlowFromMemAliasReadOnly: {
680 NextRevAssignState(MatchState::FlowFromReadOnly);
681 NextAssignState(MatchState::FlowToReadWrite);
684 case MatchState::FlowToWriteOnly: {
685 NextAssignState(MatchState::FlowToWriteOnly);
686 NextMemState(MatchState::FlowToMemAliasWriteOnly);
689 case MatchState::FlowToReadWrite: {
690 NextAssignState(MatchState::FlowToReadWrite);
691 NextMemState(MatchState::FlowToMemAliasReadWrite);
694 case MatchState::FlowToMemAliasWriteOnly: {
695 NextAssignState(MatchState::FlowToWriteOnly);
698 case MatchState::FlowToMemAliasReadWrite: {
699 NextAssignState(MatchState::FlowToReadWrite);
706 const ReachabilitySet &ReachSet) {
707 AliasAttrMap AttrMap;
708 std::vector<InstantiatedValue> WorkList, NextList;
712 auto Val = Mapping.first;
716 AttrMap.add(Node,
ValueInfo.getNodeInfoAtLevel(
I).Attr);
717 WorkList.push_back(Node);
721 while (!WorkList.empty()) {
722 for (
const auto &Dst : WorkList) {
723 auto DstAttr = AttrMap.getAttrs(Dst);
728 for (
const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
729 auto Src = Mapping.first;
730 if (AttrMap.add(Src, DstAttr))
731 NextList.push_back(Src);
737 if (AttrMap.add(*DstBelow, DstAttr)) {
738 NextList.push_back(*DstBelow);
744 WorkList.swap(NextList);
752 CFLAndersAAResult::buildInfoFrom(
const Function &Fn) {
756 const_cast<Function &>(Fn));
757 auto &Graph = GraphBuilder.getCFLGraph();
759 ReachabilitySet ReachSet;
762 std::vector<WorkListItem> WorkList, NextList;
765 while (!WorkList.empty()) {
766 for (
const auto &Item : WorkList)
769 NextList.swap(WorkList);
777 return FunctionInfo(Fn, GraphBuilder.getReturnValues(), ReachSet,
778 std::move(IValueAttrMap));
784 assert(InsertPair.second &&
785 "Trying to scan a function that has already been cached");
790 auto FunInfo = buildInfoFrom(Fn);
791 Cache[&Fn] = std::move(FunInfo);
792 Handles.push_front(FunctionHandle(const_cast<Function *>(&Fn),
this));
795 void CFLAndersAAResult::evict(
const Function &Fn) { Cache.erase(&Fn); }
798 CFLAndersAAResult::ensureCached(
const Function &Fn) {
799 auto Iter = Cache.find(&Fn);
800 if (Iter == Cache.end()) {
802 Iter = Cache.find(&Fn);
803 assert(Iter != Cache.end());
804 assert(Iter->second.hasValue());
810 auto &FunInfo = ensureCached(Fn);
811 if (FunInfo.hasValue())
812 return &FunInfo->getAliasSummary();
819 auto *ValA = LocA.
Ptr;
820 auto *ValB = LocB.
Ptr;
822 if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
832 <<
"CFLAndersAA: could not extract parent function information.\n");
840 auto &FunInfo = ensureCached(*Fn);
843 if (FunInfo->mayAlias(ValA, LocA.
Size, ValB, LocB.
Size))
858 if (isa<Constant>(LocA.
Ptr) && isa<Constant>(LocB.
Ptr))
859 return AAResultBase::alias(LocA, LocB);
863 return AAResultBase::alias(LocA, LocB);
876 "Inclusion-Based CFL Alias Analysis",
false,
true)
887 auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
The two locations precisely alias each other.
void push_back(const T &Elt)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This is the interface for LLVM's inclusion-based alias analysis implemented with CFL graph reachabili...
CFLAndersAAResult(const TargetLibraryInfo &)
static OffsetInstantiatedValue getEmptyKey()
We use ExternalRelation to describe an externally visible aliasing relations between parameters/retur...
static void populateAliasMap(DenseMap< const Value *, std::vector< OffsetValue >> &AliasMap, const ReachabilitySet &ReachSet)
#define LLVM_UNLIKELY(EXPR)
Implements a dense probed hash-table based set.
The two locations alias, but only due to a partial overlap.
This is the result of instantiating InterfaceValue at a particular callsite.
void initializeCFLAndersAAWrapperPassPass(PassRegistry &)
void initializePass() override
initializePass - This method may be overriden by immutable passes to allow them to perform various in...
The Program Expression Graph (PEG) of CFL analysis CFLGraph is auxiliary data structure used by CFL-b...
The two locations do not alias at all.
static OffsetValue getTombstoneKey()
iterator_range< const_value_iterator > value_mappings() const
The two locations may or may not alias. This is the least precise result.
static void populateAttrMap(DenseMap< const Value *, AliasAttrs > &AttrMap, const AliasAttrMap &AMap)
We use ExternalAttribute to describe an externally visible AliasAttrs for parameters/return value...
We use InterfaceValue to describe parameters/return value, as well as potential memory locations that...
AnalysisUsage & addRequired()
const AliasSummary & getAliasSummary() const
static AliasAttrMap buildAttrMap(const CFLGraph &Graph, const ReachabilitySet &ReachSet)
INITIALIZE_PASS(CFLAndersAAWrapperPass,"cfl-anders-aa","Inclusion-Based CFL Alias Analysis", false, true) ImmutablePass *llvm
static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS)
static Optional< InterfaceValue > getInterfaceValue(InstantiatedValue IValue, const SmallVectorImpl< Value * > &RetVals)
A CRTP-driven "mixin" base class to help implement the function alias analysis results concept...
static void populateExternalAttributes(SmallVectorImpl< ExternalAttribute > &ExtAttributes, const Function &Fn, const SmallVectorImpl< Value * > &RetVals, const AliasAttrMap &AMap)
static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y, unsigned len)
This function adds the integer array x to the integer array Y and places the result in dest...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
static bool isEqual(const OffsetInstantiatedValue &LHS, const OffsetInstantiatedValue &RHS)
static const Function * parentFunctionOfValue(const Value *Val)
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
static OffsetValue getEmptyKey()
static unsigned getHashValue(const OffsetInstantiatedValue &OVal)
bool erase(const KeyT &Val)
static OffsetInstantiatedValue getTombstoneKey()
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs...ExtraArgs)
Get the result of an analysis pass for a given IR unit.
static bool hasWriteOnlyState(StateSet Set)
Legacy wrapper pass to provide the CFLAndersAAResult object.
AliasResult
The possible results of an alias query.
Represent the analysis usage information of a pass.
FunctionInfo(const Function &, const SmallVectorImpl< Value * > &, const ReachabilitySet &, AliasAttrMap)
bool isGlobalOrArgAttr(AliasAttrs Attr)
bool mayAlias(const Value *, uint64_t, const Value *, uint64_t) const
Struct to hold value either by GUID or GlobalValue*.
const Value * Ptr
The address of the start of the location.
Representation for a specific memory location.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
ImmutablePass class - This class is used to provide information that does not need to be run...
static void initializeWorkList(std::vector< WorkListItem > &WorkList, ReachabilitySet &ReachSet, const CFLGraph &Graph)
AliasAttrs getExternallyVisibleAttrs(AliasAttrs Attr)
Given an AliasAttrs, return a new AliasAttrs that only contains attributes meaningful to the caller...
A builder class used to create CFLGraph instance from a given function The CFL-AA that uses this buil...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Provides information about what library functions are available for the current target.
Alias summary information.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
A range adaptor for a pair of iterators.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This file defines CFLGraph, an auxiliary data structure used by CFL-based alias analysis.
static void propagate(InstantiatedValue From, InstantiatedValue To, MatchState State, ReachabilitySet &ReachSet, std::vector< WorkListItem > &WorkList)
static const int64_t UnknownOffset
static Optional< InstantiatedValue > getNodeBelow(const CFLGraph &Graph, InstantiatedValue V)
static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph, ReachabilitySet &ReachSet, AliasMemSet &MemSet, std::vector< WorkListItem > &WorkList)
bool hasUnknownOrCallerAttr(AliasAttrs Attr)
std::bitset< NumAliasAttrs > AliasAttrs
These are attributes that an alias analysis can use to mark certain special properties of a given poi...
static bool hasReadOnlyState(StateSet Set)
Analysis pass providing the TargetLibraryInfo.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool operator<(int64_t V1, const APSInt &V2)
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
A container for analyses that lazily runs them and caches their results.
static void populateExternalRelations(SmallVectorImpl< ExternalRelation > &ExtRelations, const Function &Fn, const SmallVectorImpl< Value * > &RetVals, const ReachabilitySet &ReachSet)
bool operator==(uint64_t V1, const APInt &V2)
ImmutablePass * createCFLAndersAAWrapperPass()
static unsigned getHashValue(const OffsetValue &OVal)
A special type used by analysis passes to provide an address that identifies that particular analysis...
static Expected< BitVector > scan(StringRef &S, StringRef Original)
iterator_range< arg_iterator > args()
uint64_t Size
The maximum size of the location, in address-units, or UnknownSize if the size is not known...
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.