mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Revert r332657: "[AA] cfl-anders-aa with field sensitivity"
I don't believe the person who LGTMed this review has appropriate context on this code. I apologize if I'm wrong. llvm-svn: 332674
This commit is contained in:
parent
8a7b8795fb
commit
e4d5ef16f2
@ -134,31 +134,18 @@ inline bool operator>=(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
using FieldOffset = int64_t;
|
||||
// We use UnknownOffset to represent pointer offsets that cannot be determined
|
||||
// at compile time. Note that MemoryLocation::UnknownSize cannot be used here
|
||||
// because we require a signed value.
|
||||
static const FieldOffset UnknownOffset =
|
||||
std::numeric_limits<FieldOffset>::max();
|
||||
static const int64_t UnknownOffset = INT64_MAX;
|
||||
|
||||
inline FieldOffset addFieldOffset(FieldOffset LHS, FieldOffset RHS) {
|
||||
inline int64_t addOffset(int64_t LHS, int64_t RHS) {
|
||||
if (LHS == UnknownOffset || RHS == UnknownOffset)
|
||||
return UnknownOffset;
|
||||
|
||||
// FIXME: Do we need to guard against integer overflow here?
|
||||
return LHS + RHS;
|
||||
}
|
||||
|
||||
inline FieldOffset subFieldOffset(FieldOffset LHS, FieldOffset RHS) {
|
||||
if (LHS == UnknownOffset || RHS == UnknownOffset)
|
||||
return UnknownOffset;
|
||||
|
||||
return LHS - RHS;
|
||||
}
|
||||
|
||||
inline FieldOffset negFieldOffset(FieldOffset Offset) {
|
||||
return subFieldOffset(0, Offset);
|
||||
}
|
||||
|
||||
/// We use ExternalRelation to describe an externally visible aliasing relations
|
||||
/// between parameters/return value of a function.
|
||||
struct ExternalRelation {
|
||||
|
@ -153,59 +153,11 @@ struct OffsetInstantiatedValue {
|
||||
bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) {
|
||||
return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Specialize DenseMapInfo for OffsetValue.
|
||||
template <> struct DenseMapInfo<OffsetValue> {
|
||||
static OffsetValue getEmptyKey() {
|
||||
return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),
|
||||
DenseMapInfo<FieldOffset>::getEmptyKey()};
|
||||
}
|
||||
static OffsetValue getTombstoneKey() {
|
||||
return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),
|
||||
DenseMapInfo<FieldOffset>::getEmptyKey()};
|
||||
}
|
||||
static unsigned getHashValue(const OffsetValue &OVal) {
|
||||
return DenseMapInfo<std::pair<const Value *, FieldOffset>>::getHashValue(
|
||||
std::make_pair(OVal.Val, OVal.Offset));
|
||||
}
|
||||
static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialize DenseMapInfo for OffsetInstantiatedValue.
|
||||
template <> struct DenseMapInfo<OffsetInstantiatedValue> {
|
||||
static OffsetInstantiatedValue getEmptyKey() {
|
||||
return OffsetInstantiatedValue{
|
||||
DenseMapInfo<InstantiatedValue>::getEmptyKey(),
|
||||
DenseMapInfo<FieldOffset>::getEmptyKey()};
|
||||
}
|
||||
static OffsetInstantiatedValue getTombstoneKey() {
|
||||
return OffsetInstantiatedValue{
|
||||
DenseMapInfo<InstantiatedValue>::getTombstoneKey(),
|
||||
DenseMapInfo<FieldOffset>::getEmptyKey()};
|
||||
}
|
||||
static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {
|
||||
return DenseMapInfo<std::pair<InstantiatedValue, FieldOffset>>::
|
||||
getHashValue(std::make_pair(OVal.IVal, OVal.Offset));
|
||||
}
|
||||
static bool isEqual(const OffsetInstantiatedValue &LHS,
|
||||
const OffsetInstantiatedValue &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
namespace {
|
||||
|
||||
// We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in
|
||||
// the paper) during the analysis.
|
||||
class ReachabilitySet {
|
||||
using ValueStateMap = DenseMap<OffsetInstantiatedValue, StateSet>;
|
||||
using ValueStateMap = DenseMap<InstantiatedValue, StateSet>;
|
||||
using ValueReachMap = DenseMap<InstantiatedValue, ValueStateMap>;
|
||||
|
||||
ValueReachMap ReachMap;
|
||||
@ -214,11 +166,10 @@ public:
|
||||
using const_valuestate_iterator = ValueStateMap::const_iterator;
|
||||
using const_value_iterator = ValueReachMap::const_iterator;
|
||||
|
||||
// Insert edge 'From->To' at state 'State' with offset 'Offset'
|
||||
bool insert(InstantiatedValue From, InstantiatedValue To, FieldOffset Offset,
|
||||
MatchState State) {
|
||||
// Insert edge 'From->To' at state 'State'
|
||||
bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) {
|
||||
assert(From != To);
|
||||
auto &States = ReachMap[To][OffsetInstantiatedValue{From, Offset}];
|
||||
auto &States = ReachMap[To][From];
|
||||
auto Idx = static_cast<size_t>(State);
|
||||
if (!States.test(Idx)) {
|
||||
States.set(Idx);
|
||||
@ -303,7 +254,6 @@ public:
|
||||
struct WorkListItem {
|
||||
InstantiatedValue From;
|
||||
InstantiatedValue To;
|
||||
FieldOffset Offset;
|
||||
MatchState State;
|
||||
};
|
||||
|
||||
@ -311,13 +261,63 @@ struct ValueSummary {
|
||||
struct Record {
|
||||
InterfaceValue IValue;
|
||||
unsigned DerefLevel;
|
||||
FieldOffset Offset;
|
||||
};
|
||||
SmallVector<Record, 4> FromRecords, ToRecords;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Specialize DenseMapInfo for OffsetValue.
|
||||
template <> struct DenseMapInfo<OffsetValue> {
|
||||
static OffsetValue getEmptyKey() {
|
||||
return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),
|
||||
DenseMapInfo<int64_t>::getEmptyKey()};
|
||||
}
|
||||
|
||||
static OffsetValue getTombstoneKey() {
|
||||
return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),
|
||||
DenseMapInfo<int64_t>::getEmptyKey()};
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const OffsetValue &OVal) {
|
||||
return DenseMapInfo<std::pair<const Value *, int64_t>>::getHashValue(
|
||||
std::make_pair(OVal.Val, OVal.Offset));
|
||||
}
|
||||
|
||||
static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialize DenseMapInfo for OffsetInstantiatedValue.
|
||||
template <> struct DenseMapInfo<OffsetInstantiatedValue> {
|
||||
static OffsetInstantiatedValue getEmptyKey() {
|
||||
return OffsetInstantiatedValue{
|
||||
DenseMapInfo<InstantiatedValue>::getEmptyKey(),
|
||||
DenseMapInfo<int64_t>::getEmptyKey()};
|
||||
}
|
||||
|
||||
static OffsetInstantiatedValue getTombstoneKey() {
|
||||
return OffsetInstantiatedValue{
|
||||
DenseMapInfo<InstantiatedValue>::getTombstoneKey(),
|
||||
DenseMapInfo<int64_t>::getEmptyKey()};
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {
|
||||
return DenseMapInfo<std::pair<InstantiatedValue, int64_t>>::getHashValue(
|
||||
std::make_pair(OVal.IVal, OVal.Offset));
|
||||
}
|
||||
|
||||
static bool isEqual(const OffsetInstantiatedValue &LHS,
|
||||
const OffsetInstantiatedValue &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
class CFLAndersAAResult::FunctionInfo {
|
||||
/// Map a value to other values that may alias it
|
||||
/// Since the alias relation is symmetric, to save some space we assume values
|
||||
@ -389,11 +389,9 @@ populateAliasMap(DenseMap<const Value *, std::vector<OffsetValue>> &AliasMap,
|
||||
auto Val = OuterMapping.first.Val;
|
||||
auto &AliasList = AliasMap[Val];
|
||||
for (const auto &InnerMapping : OuterMapping.second) {
|
||||
auto OVal = InnerMapping.first;
|
||||
// Again, AliasMap only cares about top-level values
|
||||
if (OVal.IVal.DerefLevel == 0)
|
||||
AliasList.push_back(
|
||||
OffsetValue{OVal.IVal.Val, negFieldOffset(OVal.Offset)});
|
||||
if (InnerMapping.first.DerefLevel == 0)
|
||||
AliasList.push_back(OffsetValue{InnerMapping.first.Val, UnknownOffset});
|
||||
}
|
||||
|
||||
// Sort AliasList for faster lookup
|
||||
@ -432,27 +430,24 @@ static void populateExternalRelations(
|
||||
for (const auto &OuterMapping : ReachSet.value_mappings()) {
|
||||
if (auto Dst = getInterfaceValue(OuterMapping.first, RetVals)) {
|
||||
for (const auto &InnerMapping : OuterMapping.second) {
|
||||
auto OVal = InnerMapping.first;
|
||||
auto SrcIVal = OVal.IVal;
|
||||
auto Offset = OVal.Offset;
|
||||
// If Src is a param/return value, we get a same-level assignment.
|
||||
if (auto Src = getInterfaceValue(SrcIVal, RetVals)) {
|
||||
if (auto Src = getInterfaceValue(InnerMapping.first, RetVals)) {
|
||||
// This may happen if both Dst and Src are return values
|
||||
if (*Dst == *Src)
|
||||
continue;
|
||||
|
||||
if (hasReadOnlyState(InnerMapping.second))
|
||||
ExtRelations.push_back(ExternalRelation{*Dst, *Src, Offset});
|
||||
ExtRelations.push_back(ExternalRelation{*Dst, *Src, UnknownOffset});
|
||||
// No need to check for WriteOnly state, since ReachSet is symmetric
|
||||
} else {
|
||||
// If Src is not a param/return, add it to ValueMap
|
||||
|
||||
auto SrcIVal = InnerMapping.first;
|
||||
if (hasReadOnlyState(InnerMapping.second))
|
||||
ValueMap[SrcIVal.Val].FromRecords.push_back(
|
||||
ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});
|
||||
ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
|
||||
if (hasWriteOnlyState(InnerMapping.second))
|
||||
ValueMap[SrcIVal.Val].ToRecords.push_back(
|
||||
ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});
|
||||
ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -471,20 +466,14 @@ static void populateExternalRelations(
|
||||
auto SrcLevel = FromRecord.IValue.DerefLevel;
|
||||
auto DstIndex = ToRecord.IValue.Index;
|
||||
auto DstLevel = ToRecord.IValue.DerefLevel;
|
||||
|
||||
// Offsets to be pushed to External Relations
|
||||
auto SrcOffset = FromRecord.Offset;
|
||||
auto DstOffset = ToRecord.Offset;
|
||||
|
||||
if (ToLevel > FromLevel)
|
||||
SrcLevel += ToLevel - FromLevel;
|
||||
else
|
||||
DstLevel += FromLevel - ToLevel;
|
||||
|
||||
ExtRelations.push_back(
|
||||
ExternalRelation{InterfaceValue{SrcIndex, SrcLevel},
|
||||
InterfaceValue{DstIndex, DstLevel},
|
||||
subFieldOffset(SrcOffset, DstOffset)});
|
||||
ExtRelations.push_back(ExternalRelation{
|
||||
InterfaceValue{SrcIndex, SrcLevel},
|
||||
InterfaceValue{DstIndex, DstLevel}, UnknownOffset});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -602,14 +591,12 @@ bool CFLAndersAAResult::FunctionInfo::mayAlias(const Value *LHS,
|
||||
}
|
||||
|
||||
static void propagate(InstantiatedValue From, InstantiatedValue To,
|
||||
FieldOffset Offset, MatchState State,
|
||||
ReachabilitySet &ReachSet,
|
||||
MatchState State, ReachabilitySet &ReachSet,
|
||||
std::vector<WorkListItem> &WorkList) {
|
||||
if (From == To)
|
||||
return;
|
||||
|
||||
if (ReachSet.insert(From, To, Offset, State))
|
||||
WorkList.push_back(WorkListItem{From, To, Offset, State});
|
||||
if (ReachSet.insert(From, To, State))
|
||||
WorkList.push_back(WorkListItem{From, To, State});
|
||||
}
|
||||
|
||||
static void initializeWorkList(std::vector<WorkListItem> &WorkList,
|
||||
@ -623,15 +610,13 @@ static void initializeWorkList(std::vector<WorkListItem> &WorkList,
|
||||
// Insert all immediate assignment neighbors to the worklist
|
||||
for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
|
||||
auto Src = InstantiatedValue{Val, I};
|
||||
// If we have an assignment edge from X + Offset to Y, it means that
|
||||
// (Y - Offset) is reachable from X at the state FlowToWriteOnly
|
||||
// At the same time, (X + Offset) is reachable from Y at the state
|
||||
// FlowFromReadOnly
|
||||
// If there's an assignment edge from X to Y, it means Y is reachable from
|
||||
// X at S2 and X is reachable from Y at S1
|
||||
for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) {
|
||||
propagate(Edge.Other, Src, Edge.Offset, MatchState::FlowFromReadOnly,
|
||||
ReachSet, WorkList);
|
||||
propagate(Src, Edge.Other, negFieldOffset(Edge.Offset),
|
||||
MatchState::FlowToWriteOnly, ReachSet, WorkList);
|
||||
propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet,
|
||||
WorkList);
|
||||
propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet,
|
||||
WorkList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,41 +635,37 @@ static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph,
|
||||
std::vector<WorkListItem> &WorkList) {
|
||||
auto FromNode = Item.From;
|
||||
auto ToNode = Item.To;
|
||||
auto Offset = Item.Offset;
|
||||
|
||||
auto NodeInfo = Graph.getNode(ToNode);
|
||||
assert(NodeInfo != nullptr);
|
||||
|
||||
// TODO: propagate field offsets
|
||||
|
||||
// FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds
|
||||
// relations that are symmetric, we could actually cut the storage by half by
|
||||
// sorting FromNode and ToNode before insertion happens.
|
||||
|
||||
// The newly added value alias pair may potentially generate more memory
|
||||
// alias pairs. Check for them here.
|
||||
// MemAlias reachability can only be triggered when Offset is 0 or Unknown
|
||||
if (Offset == 0 || Offset == UnknownOffset) {
|
||||
auto FromNodeBelow = getNodeBelow(Graph, FromNode);
|
||||
auto ToNodeBelow = getNodeBelow(Graph, ToNode);
|
||||
if (FromNodeBelow && ToNodeBelow &&
|
||||
MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
|
||||
propagate(*FromNodeBelow, *ToNodeBelow, Offset,
|
||||
MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
|
||||
for (const auto &Mapping :
|
||||
ReachSet.reachableValueAliases(*FromNodeBelow)) {
|
||||
auto SrcOVal = Mapping.first;
|
||||
auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {
|
||||
if (Mapping.second.test(static_cast<size_t>(FromState)))
|
||||
propagate(SrcOVal.IVal, *ToNodeBelow, SrcOVal.Offset, ToState,
|
||||
ReachSet, WorkList);
|
||||
};
|
||||
auto FromNodeBelow = getNodeBelow(Graph, FromNode);
|
||||
auto ToNodeBelow = getNodeBelow(Graph, ToNode);
|
||||
if (FromNodeBelow && ToNodeBelow &&
|
||||
MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
|
||||
propagate(*FromNodeBelow, *ToNodeBelow,
|
||||
MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
|
||||
for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {
|
||||
auto Src = Mapping.first;
|
||||
auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {
|
||||
if (Mapping.second.test(static_cast<size_t>(FromState)))
|
||||
propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList);
|
||||
};
|
||||
|
||||
MemAliasPropagate(MatchState::FlowFromReadOnly,
|
||||
MatchState::FlowFromMemAliasReadOnly);
|
||||
MemAliasPropagate(MatchState::FlowToWriteOnly,
|
||||
MatchState::FlowToMemAliasWriteOnly);
|
||||
MemAliasPropagate(MatchState::FlowToReadWrite,
|
||||
MatchState::FlowToMemAliasReadWrite);
|
||||
}
|
||||
MemAliasPropagate(MatchState::FlowFromReadOnly,
|
||||
MatchState::FlowFromMemAliasReadOnly);
|
||||
MemAliasPropagate(MatchState::FlowToWriteOnly,
|
||||
MatchState::FlowToMemAliasWriteOnly);
|
||||
MemAliasPropagate(MatchState::FlowToReadWrite,
|
||||
MatchState::FlowToMemAliasReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,23 +678,17 @@ static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph,
|
||||
// - If Y is an alias of X, then reverse assignment edges (if there is any)
|
||||
// should precede any assignment edges on the path from X to Y.
|
||||
auto NextAssignState = [&](MatchState State) {
|
||||
for (const auto &AssignEdge : NodeInfo->Edges) {
|
||||
propagate(FromNode, AssignEdge.Other,
|
||||
subFieldOffset(Offset, AssignEdge.Offset), State, ReachSet,
|
||||
WorkList);
|
||||
}
|
||||
for (const auto &AssignEdge : NodeInfo->Edges)
|
||||
propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList);
|
||||
};
|
||||
auto NextRevAssignState = [&](MatchState State) {
|
||||
for (const auto &RevAssignEdge : NodeInfo->ReverseEdges) {
|
||||
propagate(FromNode, RevAssignEdge.Other,
|
||||
addFieldOffset(Offset, RevAssignEdge.Offset), State, ReachSet,
|
||||
WorkList);
|
||||
}
|
||||
for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)
|
||||
propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList);
|
||||
};
|
||||
auto NextMemState = [&](MatchState State) {
|
||||
if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
|
||||
for (const auto &MemAlias : *AliasSet)
|
||||
propagate(FromNode, MemAlias, Offset, State, ReachSet, WorkList);
|
||||
propagate(FromNode, MemAlias, State, ReachSet, WorkList);
|
||||
}
|
||||
};
|
||||
|
||||
@ -778,7 +753,7 @@ static AliasAttrMap buildAttrMap(const CFLGraph &Graph,
|
||||
|
||||
// Propagate attr on the same level
|
||||
for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
|
||||
auto Src = Mapping.first.IVal;
|
||||
auto Src = Mapping.first;
|
||||
if (AttrMap.add(Src, DstAttr))
|
||||
NextList.push_back(Src);
|
||||
}
|
||||
@ -813,19 +788,11 @@ CFLAndersAAResult::buildInfoFrom(const Function &Fn) {
|
||||
|
||||
std::vector<WorkListItem> WorkList, NextList;
|
||||
initializeWorkList(WorkList, ReachSet, Graph);
|
||||
|
||||
bool LoopInGraph = false;
|
||||
// TODO: make sure we don't stop before the fix point is reached
|
||||
while (!WorkList.empty()) {
|
||||
for (const auto &Item : WorkList)
|
||||
processWorkListItem(Item, Graph, ReachSet, MemSet, NextList);
|
||||
|
||||
if (NextList.size() == WorkList.size()) {
|
||||
// stop if loop in CFL graph
|
||||
if (LoopInGraph)
|
||||
break;
|
||||
LoopInGraph = true;
|
||||
}
|
||||
|
||||
NextList.swap(WorkList);
|
||||
NextList.clear();
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
|
||||
struct Edge {
|
||||
Node Other;
|
||||
FieldOffset Offset;
|
||||
int64_t Offset;
|
||||
};
|
||||
|
||||
using EdgeList = std::vector<Edge>;
|
||||
@ -125,7 +125,7 @@ public:
|
||||
Info->Attr |= Attr;
|
||||
}
|
||||
|
||||
void addEdge(Node From, Node To, FieldOffset Offset = 0) {
|
||||
void addEdge(Node From, Node To, int64_t Offset = 0) {
|
||||
auto *FromInfo = getNode(From);
|
||||
assert(FromInfo != nullptr);
|
||||
auto *ToInfo = getNode(To);
|
||||
@ -219,7 +219,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
Graph.addNode(InstantiatedValue{Val, 0}, Attr);
|
||||
}
|
||||
|
||||
void addAssignEdge(Value *From, Value *To, FieldOffset Offset = 0) {
|
||||
void addAssignEdge(Value *From, Value *To, int64_t Offset = 0) {
|
||||
assert(From != nullptr && To != nullptr);
|
||||
if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())
|
||||
return;
|
||||
@ -312,7 +312,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
}
|
||||
|
||||
void visitGEP(GEPOperator &GEPOp) {
|
||||
FieldOffset Offset = UnknownOffset;
|
||||
uint64_t Offset = UnknownOffset;
|
||||
APInt APOffset(DL.getPointerSizeInBits(GEPOp.getPointerAddressSpace()),
|
||||
0);
|
||||
if (GEPOp.accumulateConstantOffset(DL, APOffset))
|
||||
@ -397,7 +397,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
if (IRelation.hasValue()) {
|
||||
Graph.addNode(IRelation->From);
|
||||
Graph.addNode(IRelation->To);
|
||||
Graph.addEdge(IRelation->From, IRelation->To, IRelation->Offset);
|
||||
Graph.addEdge(IRelation->From, IRelation->To);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -disable-basicaa -cfl-anders-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
|
||||
; RUN: opt < %s -aa-pipeline=cfl-anders-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: Function: test_simple_offsets
|
||||
; CHECK: NoAlias: i64* %b, i64** %acast
|
||||
; CHECK: NoAlias: i64** %acast, i64** %aoff
|
||||
; CHECK: NoAlias: i64* %b, i64** %acastoff
|
||||
; CHECK: NoAlias: i64** %acast, i64** %acastoff
|
||||
; CHECK: NoAlias: [2 x i64*]* %a, i64* %acastload
|
||||
; CHECK: MayAlias: i64* %acastload, i64* %b
|
||||
; CHECK: NoAlias: i64* %acastload, i64** %aoff
|
||||
; CHECK: NoAlias: i64* %acastload, i64** %acast
|
||||
; CHECK: NoAlias: i64* %acastload, i64** %acastoff
|
||||
define void @test_simple_offsets() {
|
||||
%a = alloca [2 x i64*], align 8
|
||||
%b = alloca i64, align 4
|
||||
%aoff = getelementptr inbounds [2 x i64*], [2 x i64*]* %a, i64 0, i64 1
|
||||
store i64* %b, i64** %aoff
|
||||
|
||||
%acast = bitcast [2 x i64*]* %a to i64**
|
||||
%acastoff = getelementptr inbounds i64*, i64** %acast, i64 1
|
||||
%acastload = load i64*, i64** %acastoff
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: Function: test_unknown_offset
|
||||
; CHECK: MayAlias: [3 x i32]* %a, i32* %an
|
||||
; CHECK: MayAlias: i32* %a4, i32* %an
|
||||
; CHECK: MayAlias: i32* %a8, i32* %an
|
||||
; CHECK: MayAlias: i32* %an, i32* %b
|
||||
; CHECK: MayAlias: [3 x i32]* %a, i32* %bn
|
||||
; CHECK: MayAlias: i32* %a4, i32* %bn
|
||||
; CHECK: MayAlias: i32* %a8, i32* %bn
|
||||
; CHECK: MayAlias: i32* %an, i32* %bn
|
||||
; CHECK: MayAlias: i32* %b, i32* %bn
|
||||
define void @test_unknown_offset(i32 %n) {
|
||||
%a = alloca [3 x i32], align 4
|
||||
%a4 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 1
|
||||
%a8 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 2
|
||||
%an = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 %n
|
||||
%b = bitcast [3 x i32]* %a to i32*
|
||||
%bn = getelementptr inbounds i32, i32* %b, i32 %n
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
%S = type { i32, i32, i32 }
|
||||
|
||||
define i32* @return_arg(%S* %arg1, %S* %arg2) {
|
||||
%acast = bitcast %S* %arg1 to i32*
|
||||
%aoffset = getelementptr i32, i32* %acast, i32 1
|
||||
ret i32* %aoffset
|
||||
}
|
||||
|
||||
define i32* @return_derefence_arg(%S** %arg1) {
|
||||
%deref = load %S*, %S** %arg1
|
||||
%deref2 = getelementptr %S, %S* %deref, i32 0, i32 1
|
||||
ret i32* %deref2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: Function: test_return_arg_offset
|
||||
; CHECK: NoAlias: %S* %a, %S* %b
|
||||
; CHECK: MayAlias: %S* %a, i32* %c
|
||||
; CHECK: NoAlias: %S* %b, i32* %c
|
||||
; CHECK: NoAlias: i32* %acast, i32* %c
|
||||
; CHECK: NoAlias: i32* %acast, i32* %d
|
||||
define void @test_return_arg_offset() {
|
||||
%a = alloca %S, align 8
|
||||
%b = alloca %S, align 8
|
||||
|
||||
%c = call i32* @return_arg(%S* %a, %S* %b)
|
||||
%d = getelementptr %S, %S* %a, i32 0, i32 1
|
||||
%acast = bitcast %S* %a to i32*
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: Function: test_return_derefence_arg
|
||||
; CHECK: NoAlias: %S** %p, i32* %c
|
||||
; CHECK: NoAlias: %S* %lp, %S** %p
|
||||
; CHECK: MayAlias: %S* %lp, i32* %c
|
||||
; CHECK: NoAlias: %S** %p, i32* %lp_off
|
||||
; CHECK: MayAlias: i32* %c, i32* %lp_off
|
||||
; CHECK: MayAlias: %S* %lp, i32* %lp_off
|
||||
; CHECK: NoAlias: %S** %p, i32* %acast
|
||||
; CHECK: NoAlias: i32* %acast, i32* %c
|
||||
; CHECK: MayAlias: %S* %lp, i32* %acast
|
||||
; CHECK: NoAlias: i32* %acast, i32* %lp_off
|
||||
define void @test_return_derefence_arg() {
|
||||
%a = alloca %S, align 8
|
||||
%p = alloca %S*, align 8
|
||||
|
||||
store %S* %a, %S** %p
|
||||
%c = call i32* @return_derefence_arg(%S** %p)
|
||||
|
||||
%lp = load %S*, %S** %p
|
||||
%lp_off = getelementptr %S, %S* %lp, i32 0, i32 1
|
||||
%acast = bitcast %S* %a to i32*
|
||||
|
||||
ret void
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user