mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
Analyze recursive PHI nodes in BasicAA
Summary: This patch allows phi nodes like %x = phi [ %incptr, ... ] [ %var, ... ] %incptr = getelementptr %x, 1 to be analyzed by BasicAliasAnalysis. In aliasPHI, we can detect incoming values that are recursive GEPs with a constant offset. Instead of trying to analyze a recursive GEP (and failing), we now ignore it and instead set the size of the memory referenced by the PHINode to UnknownSize. This represents all the possible memory locations the pointer represented by the PHINode could be advanced to by the GEP. For now, this new behavior is turned off by default to allow debugging of performance degradations seen with SPEC/x86 and Hexagon benchmarks. The flag -basicaa-recphi turns it on. Reviewers: hfinkel, sanjoy Subscribers: tobiasvk_caf, sanjoy, llvm-commits Differential Revision: http://reviews.llvm.org/D10368 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242320 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
162c547bf6
commit
3659b8adc9
@ -42,6 +42,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
/// Enable analysis of recursive PHI nodes.
|
||||||
|
static cl::opt<bool> EnableRecPhiAnalysis("basicaa-recphi",
|
||||||
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
/// Cutoff after which to stop analysing a set of phi nodes potentially involved
|
/// Cutoff after which to stop analysing a set of phi nodes potentially involved
|
||||||
/// in a cycle. Because we are analysing 'through' phi nodes we need to be
|
/// in a cycle. Because we are analysing 'through' phi nodes we need to be
|
||||||
/// careful with value equivalence. We use reachability to make sure a value
|
/// careful with value equivalence. We use reachability to make sure a value
|
||||||
@ -1297,6 +1301,7 @@ AliasResult BasicAliasAnalysis::aliasPHI(const PHINode *PN, uint64_t PNSize,
|
|||||||
|
|
||||||
SmallPtrSet<Value*, 4> UniqueSrc;
|
SmallPtrSet<Value*, 4> UniqueSrc;
|
||||||
SmallVector<Value*, 4> V1Srcs;
|
SmallVector<Value*, 4> V1Srcs;
|
||||||
|
bool isRecursive = false;
|
||||||
for (Value *PV1 : PN->incoming_values()) {
|
for (Value *PV1 : PN->incoming_values()) {
|
||||||
if (isa<PHINode>(PV1))
|
if (isa<PHINode>(PV1))
|
||||||
// If any of the source itself is a PHI, return MayAlias conservatively
|
// If any of the source itself is a PHI, return MayAlias conservatively
|
||||||
@ -1304,12 +1309,33 @@ AliasResult BasicAliasAnalysis::aliasPHI(const PHINode *PN, uint64_t PNSize,
|
|||||||
// sides are PHI nodes. In which case, this is O(m x n) time where 'm'
|
// sides are PHI nodes. In which case, this is O(m x n) time where 'm'
|
||||||
// and 'n' are the number of PHI sources.
|
// and 'n' are the number of PHI sources.
|
||||||
return MayAlias;
|
return MayAlias;
|
||||||
|
|
||||||
|
if (EnableRecPhiAnalysis)
|
||||||
|
if (GEPOperator *PV1GEP = dyn_cast<GEPOperator>(PV1)) {
|
||||||
|
// Check whether the incoming value is a GEP that advances the pointer
|
||||||
|
// result of this PHI node (e.g. in a loop). If this is the case, we
|
||||||
|
// would recurse and always get a MayAlias. Handle this case specially
|
||||||
|
// below.
|
||||||
|
if (PV1GEP->getPointerOperand() == PN && PV1GEP->getNumIndices() == 1 &&
|
||||||
|
isa<ConstantInt>(PV1GEP->idx_begin())) {
|
||||||
|
isRecursive = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (UniqueSrc.insert(PV1).second)
|
if (UniqueSrc.insert(PV1).second)
|
||||||
V1Srcs.push_back(PV1);
|
V1Srcs.push_back(PV1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this PHI node is recursive, set the size of the accessed memory to
|
||||||
|
// unknown to represent all the possible values the GEP could advance the
|
||||||
|
// pointer to.
|
||||||
|
if (isRecursive)
|
||||||
|
PNSize = MemoryLocation::UnknownSize;
|
||||||
|
|
||||||
AliasResult Alias = aliasCheck(V2, V2Size, V2AAInfo,
|
AliasResult Alias = aliasCheck(V2, V2Size, V2AAInfo,
|
||||||
V1Srcs[0], PNSize, PNAAInfo);
|
V1Srcs[0], PNSize, PNAAInfo);
|
||||||
|
|
||||||
// Early exit if the check of the first PHI source against V2 is MayAlias.
|
// Early exit if the check of the first PHI source against V2 is MayAlias.
|
||||||
// Other results are not possible.
|
// Other results are not possible.
|
||||||
if (Alias == MayAlias)
|
if (Alias == MayAlias)
|
||||||
|
75
test/Analysis/BasicAA/phi-loop.ll
Normal file
75
test/Analysis/BasicAA/phi-loop.ll
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
; RUN: opt < %s -basicaa -basicaa-recphi=1 -gvn -S | FileCheck %s
|
||||||
|
;
|
||||||
|
; Check that section->word_ofs doesn't get reloaded in every iteration of the
|
||||||
|
; for loop.
|
||||||
|
;
|
||||||
|
; Code:
|
||||||
|
;
|
||||||
|
; typedef struct {
|
||||||
|
; unsigned num_words;
|
||||||
|
; unsigned word_ofs;
|
||||||
|
; const unsigned *data;
|
||||||
|
; } section_t;
|
||||||
|
;
|
||||||
|
;
|
||||||
|
; void test2(const section_t * restrict section, unsigned * restrict dst) {;
|
||||||
|
; while (section->data != NULL) {
|
||||||
|
; const unsigned *src = section->data;
|
||||||
|
; for (unsigned i=0; i < section->num_words; ++i) {
|
||||||
|
; dst[section->word_ofs + i] = src[i];
|
||||||
|
; }
|
||||||
|
;
|
||||||
|
; ++section;
|
||||||
|
; }
|
||||||
|
; }
|
||||||
|
;
|
||||||
|
|
||||||
|
; CHECK-LABEL: for.body:
|
||||||
|
; CHECK-NOT: load i32, i32* %word_ofs
|
||||||
|
|
||||||
|
%struct.section_t = type { i32, i32, i32* }
|
||||||
|
|
||||||
|
define void @test2(%struct.section_t* noalias nocapture readonly %section, i32* noalias nocapture %dst) {
|
||||||
|
entry:
|
||||||
|
%data13 = getelementptr inbounds %struct.section_t, %struct.section_t* %section, i32 0, i32 2
|
||||||
|
%0 = load i32*, i32** %data13, align 4
|
||||||
|
%cmp14 = icmp eq i32* %0, null
|
||||||
|
br i1 %cmp14, label %while.end, label %for.cond.preheader
|
||||||
|
|
||||||
|
for.cond.preheader: ; preds = %entry, %for.end
|
||||||
|
%1 = phi i32* [ %6, %for.end ], [ %0, %entry ]
|
||||||
|
%section.addr.015 = phi %struct.section_t* [ %incdec.ptr, %for.end ], [ %section, %entry ]
|
||||||
|
%num_words = getelementptr inbounds %struct.section_t, %struct.section_t* %section.addr.015, i32 0, i32 0
|
||||||
|
%2 = load i32, i32* %num_words, align 4
|
||||||
|
%cmp211 = icmp eq i32 %2, 0
|
||||||
|
br i1 %cmp211, label %for.end, label %for.body.lr.ph
|
||||||
|
|
||||||
|
for.body.lr.ph: ; preds = %for.cond.preheader
|
||||||
|
%word_ofs = getelementptr inbounds %struct.section_t, %struct.section_t* %section.addr.015, i32 0, i32 1
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
for.body: ; preds = %for.body.lr.ph, %for.body
|
||||||
|
%arrayidx.phi = phi i32* [ %1, %for.body.lr.ph ], [ %arrayidx.inc, %for.body ]
|
||||||
|
%i.012 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
|
||||||
|
%3 = load i32, i32* %arrayidx.phi, align 4
|
||||||
|
%4 = load i32, i32* %word_ofs, align 4
|
||||||
|
%add = add i32 %4, %i.012
|
||||||
|
%arrayidx3 = getelementptr inbounds i32, i32* %dst, i32 %add
|
||||||
|
store i32 %3, i32* %arrayidx3, align 4
|
||||||
|
%inc = add i32 %i.012, 1
|
||||||
|
%5 = load i32, i32* %num_words, align 4
|
||||||
|
%cmp2 = icmp ult i32 %inc, %5
|
||||||
|
%arrayidx.inc = getelementptr i32, i32* %arrayidx.phi, i32 1
|
||||||
|
br i1 %cmp2, label %for.body, label %for.end
|
||||||
|
|
||||||
|
for.end: ; preds = %for.body, %for.cond.preheader
|
||||||
|
%incdec.ptr = getelementptr inbounds %struct.section_t, %struct.section_t* %section.addr.015, i32 1
|
||||||
|
%data = getelementptr inbounds %struct.section_t, %struct.section_t* %section.addr.015, i32 1, i32 2
|
||||||
|
%6 = load i32*, i32** %data, align 4
|
||||||
|
%cmp = icmp eq i32* %6, null
|
||||||
|
br i1 %cmp, label %while.end, label %for.cond.preheader
|
||||||
|
|
||||||
|
while.end: ; preds = %for.end, %entry
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user