Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BasicAA bug #18442

Closed
hfinkel opened this issue Nov 26, 2013 · 10 comments
Closed

BasicAA bug #18442

hfinkel opened this issue Nov 26, 2013 · 10 comments
Labels
bugzilla Issues migrated from bugzilla

Comments

@hfinkel
Copy link
Collaborator

hfinkel commented Nov 26, 2013

Bugzilla Link 18068
Resolution FIXED
Resolved on Jan 08, 2014 15:22
Version trunk
OS Linux
Blocks #16805
Attachments bugpoint reduced test case
CC @Arnaud-de-Grandmaison-ARM,@isanbard

Extended Description

ClangBugs2/diff/t43047 from #16805 is a DSE miscompile.

To reproduce:

opt -o o.bc -basicaa -dse bugpoint-tooptimize.bc
clang o.bc bugpoint-tonotoptimize.bc -o t

./t < input.txt
res = 1910

whereas running:

clang bugpoint-tooptimize.bc bugpoint-tonotoptimize.bc -o t
./t < input.txt
res = 2553

@Arnaud-de-Grandmaison-ARM
Copy link
Collaborator

Here is a first analysis of the issue. The relevant part of the IR is shown below, with some instruction prefixed for reference in the analysis.

...

codeRepl: ; preds = %for.body, %entry
E %4 = phi i32* [ %arrayidx13, %for.body ], [ %j, %entry ]
%targetBlock = call i1 @​main_for.cond(i32* %jj7)
br i1 %targetBlock, label %for.body, label %codeRepl2

for.body: ; preds = %codeRepl
%5 = load i32* %jj7, align 4, !tbaa !​1
%add = add i32 %5, 1
%idxprom = zext i32 %add to i64
%arrayidx3 = getelementptr inbounds [100 x i32]* %uh, i64 0, i64 %idxprom
%6 = load i32* %arrayidx3, align 4, !tbaa !​1
%idxprom4 = zext i32 %5 to i64
%arrayidx5 = getelementptr inbounds [100 x i32]* %oa5, i64 0, i64 %idxprom4
%7 = load i32* %arrayidx5, align 4, !tbaa !​1
%sub6 = sub i32 %7, %6
A store i32 %sub6, i32* %arrayidx5, align 4, !tbaa !​1
%8 = load i32* %j, align 4, !tbaa !​1
%sub8 = sub i32 0, %8
store i32 %sub8, i32* %j, align 4, !tbaa !​1
D %9 = load i32* %4, align 4, !tbaa !​1
B store i32 %9, i32* %arrayidx5, align 4, !tbaa !​1
%sub11 = add i32 %5, -1
%idxprom12 = zext i32 %sub11 to i64
%arrayidx13 = getelementptr inbounds [100 x i32]* %oa5, i64 0, i64 %idxprom12
C call void @​main_for.inc(i32* %jj7)
br label %codeRepl

A is (wrongly) removed by DSE, because it believes B kills it. It does not see that %4 in D may alias with %arrayidx5 in A.

BasicAA computes the difference between %arrayidx5 and %arrayidx13 and finds a constant difference, which is not valid as C can (and has !) modified %jj7, which is the index in %oa5.

@Arnaud-de-Grandmaison-ARM
Copy link
Collaborator

Manually reduced testcase
The attached testcase is a manually reduced version of the bugpoint testcase.

@hfinkel
Copy link
Collaborator Author

hfinkel commented Dec 11, 2013

Created attachment 11683 [details]
Manually reduced testcase

The attached testcase is a manually reduced version of the bugpoint testcase.

Thanks for looking at this! Do you see what part of BasicAA is at fault (I guess that BasicAliasAnalysis::aliasPHI is the problem)?

@Arnaud-de-Grandmaison-ARM
Copy link
Collaborator

I more or less see what is at fault. The problem indeed shows up in BasicAliasAnalysis::aliasPHI, but I do not (yet) understand how BasicAA handles loops, and particularly why it does not see that main_for.inc can just do whatever it wants with the pointer.

I definitely need help on this.

This bugs looks rather serious to me, and it may be the same which is biting us in llvm/llvm-bugzilla-archive#18067 , in another pass, but with a similar code structure.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 12, 2013

Wow this is indeed scary :) … and seems to have been in there for a long long time (I have tested as far back as 3.1, but at least 2.9)

define i32 @​pr18068(i32* %jj7, i32* %j) #​0 {
entry:
%oa5 = alloca [100 x i32], align 16
br label %codeRepl

codeRepl: ; preds = %for.body, %entry
%0 = phi i32* [ %arrayidx13, %for.body ], [ %j, %entry ]
%targetBlock = call i1 @​cond(i32* %jj7)
br i1 %targetBlock, label %for.body, label %bye

for.body: ; preds = %codeRepl
%1 = load i32* %jj7, align 4, !tbaa !​1

%idxprom4 = zext i32 %1 to i64
%arrayidx5 = getelementptr inbounds [100 x i32]* %oa5, i64 0, i64 %idxprom4
%2 = load i32* %arrayidx5, align 4, !tbaa !​1
%sub6 = sub i32 %2, 6
store i32 %sub6, i32* %arrayidx5, align 4, !tbaa !​1
; %0 and %arrayidx5 can be aliasing ! It is not safe to DSE the above store.
%3 = load i32* %0, align 4, !tbaa !​1
store i32 %3, i32* %arrayidx5, align 4, !tbaa !​1
%sub11 = add i32 %1, -1
%idxprom12 = zext i32 %sub11 to i64
%arrayidx13 = getelementptr inbounds [100 x i32]* %oa5, i64 0, i64 %idxprom12
call void @​inc(i32* %jj7)
br label %codeRepl

bye: ; preds = %codeRepl
%.reload = load i32* %jj7, align 4
ret i32 %.reload
}

As Arnaud correctly observed the root of this problem is that a query for "aliasCheck(%arrayidx5, %arrayidx13)" returns “NoAlias”.

This in turn makes the phi “%0” NoAlias "%arrayidx5” because it is believed that
noalias(%j, arrayidx5) and noalias(%arrayidx5, %arrayidx13)
so we believe the operands of the phi “%0” don’t alias "%arrayidx5” which makes the phi not alias “%arrayidx5”.

So, why do we believe “noalias(%arrayidx5, %arrayidx13)”?

When analyze

%arrayidx5 = gep %oa, 0, %load

%arrayidx13 = gep %oa, 0, (%load - #AConst)

aliasGEP()

GEP1BaseOffset -= GEP2BaseOffset;
GetIndexDifference(GEP1VariableIndices, GEP2VariableIndices);

if (GEP1BaseOffset != 0 && GEP1VariableIndices.empty()) {
.. return NoAlias;
}

We get a constant difference of #AConst (-4) and a variable difference which is the difference between “%load” and “%load”. Because there are paths (%arrayidx13->back edge->%arrayidx5) under which those two loads are not the same execution of a load it is not safe to assume their value is the same.
In fact, we can only assume that “function invariant” values are the same.

I.e the logic that when Dest[i] == Src[j] we can simply ignore it is not a valid one:

GetIndexDifference(SmallVectorImpl &Dest,
const SmallVectorImpl &Src) {
if (Src.empty()) return;

for (unsigned i = 0, e = Src.size(); i != e; ++i) {
const Value *V = Src[i].V;
ExtensionKind Extension = Src[i].Extension;
int64_t Scale = Src[i].Scale;

// Find V in Dest.  This is N^2, but pointer indices almost never have more
// than a few variable indexes.
for (unsigned j = 0, e = Dest.size(); j != e; ++j) {
  if (Dest[j].V != V || Dest[j].Extension != Extension) continue;

  // If we found it, subtract off Scale V's from the entry in Dest.  If it
  // goes to zero, remove the entry.
  if (Dest[j].Scale != Scale)
    Dest[j].Scale -= Scale;
  else
    Dest.erase(Dest.begin()+j); <<< Ignore if Value* are the same ?!
  Scale = 0;
  break;
}

// If we didn't consume this entry, add it to the end of the Dest list.
if (Scale) {
  VariableGEPIndex Entry = { V, Extension, -Scale };
  Dest.push_back(Entry);
}

}
}

Or alternatively we have to start looking at possible paths through the cfg (be a lot more careful at phis).

Let me try alternative one and see what that does to llvm test-suite and external (although, I fear badness).

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 13, 2013

xref: rdar://15653794

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 13, 2013

The problem really is the evaluation through the phi node:

check-alias(%0 = PHI(%j, %array13), %array5) =
check-alias(%j, %array5) V
check-alias(%array13, %array5)

because of the cycle (we are following %array13 "to the previous iteration") "Value"s don't necessarily imply value equivalence anymore.

Maybe an approach where we build a set of phi nodes we have followed and when we check value equivalence we also make sure this value dominates the phis would work ...

@hfinkel
Copy link
Collaborator Author

hfinkel commented Dec 13, 2013

The problem really is the evaluation through the phi node:

check-alias(%0 = PHI(%j, %array13), %array5) =
check-alias(%j, %array5) V
check-alias(%array13, %array5)

because of the cycle (we are following %array13 "to the previous iteration")
"Value"s don't necessarily imply value equivalence anymore.

Maybe an approach where we build a set of phi nodes we have followed and
when we check value equivalence we also make sure this value dominates the
phis would work ...

I think that makes sense. I suspect that you'll need a cutoff on the dominance search -- we should try to set this so that we don't regress at least anything in the test suite that this currently catches.

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 2, 2014

Fixed in r198290.

@Arnaud-de-Grandmaison-ARM
Copy link
Collaborator

*** Bug llvm/llvm-bugzilla-archive#18067 has been marked as a duplicate of this bug. ***

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

3 participants