I hit a problem with Polly-generated code which llvm.org/PR32251 . The
problem is how @llvm.lifetime.start is placed after Polly transformed
the code. Basically Polly transformed
llvm.lifetime.start(&var)
[...]
llvm.lifetime.end(&var)
into
if (c) {
llvm.lifetime.start(&var)
}
[...]
llvm.lifetime.end(&var)
now the llvm.lifetime.end is not dominated by the corresponding
llvm.lifetime.start. As far as I understand the documentation [1] this
is a valid construction, meaning that the value of var is only
undefined before some point when c is true. I don't expect the
compiler to exploit this.
However, this miscompiles since r270559 ("Rework/enhance stack
coloring data flow analysis", https://reviews.llvm.org/D18827)
I modified Polly's code generator to produce
if (c) {
llvm.lifetime.start(&var)
} else {
llvm.lifetime.start(&var)
}
[...]
llvm.lifetime.end(&var)
and it does not miscompile anymore. However, Polly is currently is not
able to compute the lifetime in the general case.
Question: Is this a bug in the stack coloring algorithm or should this
be fixed in Polly?
Side question: Are there any invalid combinations of
llvm.lifetime.start/end such as
llvm.lifetime.end(&var)
llvm.lifetime.start(&var)
(my interpretation would be that var is always dead)? With invalid I
mean that the compiler does not need to handle this case.
Regards,
Michael
[1] http://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
The test case that fails as mentioned in llvm.org/PR32251 is SPEC
CPU's 2006 444.namd (version 1.1). In its main function there are
several structs on the stack and annotated with lifetime markers.
Polly does the previously mentioned transformation on one of those
markers (which is not intended).
Because the SPEC2006 is proprietary, I am not sure that I can share
any code on the public mailing list. If I can convince you to look
into it, I can send you source and the IR Polly is generating.
> More specifically, when you say "miscompiles", I assume that this means that
> StackColoring has overlapped two variables whose lifetimes are on fact not
> disjoint after all?
I diagnosed a miscompile because test-suite found that the program's
output defers from the reference output. I did not look specifically
what it does wrong. It did not miscompile before r270559 (git bisect).
> The pattern you describe (where the lifetime start doesn't strictly dominate
> the lifetime end) is referred to in the current stack coloring source code
> as a "degenerate" lifetime; there is code that specifically looks for such
> cases and treats them more conservatively than well-formed lifetimes (this
> is described in the "Implementation Notes" comment in the source starting
> around line 90). The key question however is where the uses of the variable
> are relative to the lifetime start/end markers.
I only overflew https://reviews.llvm.org/D18827 to find whether that
case is mentioned, but couldn't find something.
The degenerate case described moves the computation of the pointer
before the LIFETIME_START marker, but the markers themselves are still
(post-)dominating each other. As not being familiar with the code,
this does not seem to be equivalent to my case.
> For your side question (are there invalid ways to use lifetime start/end), I
> don't think I really have a good answer there. What I have seen on my own is
> that lifetime start/end markers tend to start out in more reasonable/sane
> configurations, but then can be perturbed / rearranged during optimization,
> resulting in orderings that don't always make sense (such as the case you
> cite). My feeling is that this is OK, and that the stack coloring code
> should be able to tolerate that sort of perturbation.
Thanks for your thoughts.
Michael
Hi @all,
I hit a problem with Polly-generated code which llvm.org/PR32251 . The
problem is how @llvm.lifetime.start is placed after Polly transformed
the code. Basically Polly transformed
llvm.lifetime.start(&var)
[...]
llvm.lifetime.end(&var)
into
if (c) {
llvm.lifetime.start(&var)
}
[...]
llvm.lifetime.end(&var)
now the llvm.lifetime.end is not dominated by the corresponding
llvm.lifetime.start.
As far as I understand the documentation [1] this
is a valid construction, meaning that the value of var is only
undefined before some point when c is true. I don't expect the
compiler to exploit this.
However, this miscompiles since r270559 ("Rework/enhance stack
coloring data flow analysis", https://reviews.llvm.org/D18827)
I modified Polly's code generator to produce
if (c) {
llvm.lifetime.start(&var)
} else {
llvm.lifetime.start(&var)
}
[...]
llvm.lifetime.end(&var)
and it does not miscompile anymore. However, Polly is currently is not
able to compute the lifetime in the general case.
Question: Is this a bug in the stack coloring algorithm or should this
be fixed in Polly?
This is actually exactly what Polly did, but only in the optimized
side of the loop versioning. The original code version is not touched,
which keeps the llvm.lifetime.start in it.
So of the bug is on Polly's side, I would "fix" it by deleting all
lifetime markers also in the original code.
Michael
2017-03-31 0:19 GMT+02:00 Daniel Berlin <dbe...@dberlin.org>:
>> I modified Polly's code generator to produce
>>
>> if (c) {
>> llvm.lifetime.start(&var)
>> } else {
>> llvm.lifetime.start(&var)
>> }
>> [...]
>> llvm.lifetime.end(&var)
>>
>> and it does not miscompile anymore. However, Polly is currently is not
>> able to compute the lifetime in the general case.
>
>
> Of course, nothing is.
> But they are also metadata, so you could just drop them if you wanted.
This is actually exactly what Polly did, but only in the optimized
side of the loop versioning. The original code version is not touched,
which keeps the llvm.lifetime.start in it.
So of the bug is on Polly's side, I would "fix" it by deleting all
lifetime markers also in the original code.
The precedes my involvement with Polly.
Polly has a list of intrinsics that can be safely ignored, e.g.
llvm.dbg.value/llvm.gbg.declare. The lifetime markers are also in this
list. Ignored intrinsic are ... well ... ignored when generating the
optimized code.
Hmm. This doesn't jive with my understanding of how things worked.
I see the lifetime intrinsics as something which _can_ be made conditional on arbitrary control flow.
I can build a consistent view of them because I also believe the lifetime intrinsics can only make sense when they are paired together.
ptr is dead. This means that it is known to never be used and has an undefined value. A load from the pointer that precedes this intrinsic can be replaced with 'undef'."If it is legal for a frontend to generate it, why is it not legal for
a transformation?
2017-03-31 1:16 GMT+02:00 Daniel Berlin <dbe...@dberlin.org>:
> if you transformed
>
> lifetime.start(%p)
> use %p
> lifetime.end(%p)
> into
>
> if (c)
> lifetime.start(%p)
> use %p
> lifetime.end(%p)
>
> That is *definitely* a bug in polly.
> Stack coloring should be able to handle it if that is the original IR but that is definitely not a legal transform of the lifetime.start.
If it is legal for a frontend to generate it, why is it not legal for
a transformation?
Michael
InstCombine transforms memset(a,1) to a single StoreInst, but keeps
the memset if the size argument is zero. A StoreInst can be optimized
away, e.g. by DeadStoreElimination. I wonder, are the semantics of
memset(a, 0) different than "do nothing"?
Where is the chain of transformations
memset(&a, '0', sizeof a);
if (c)
a = 1;
=>
if (c) {
memset(&a, '0', sizeof a);
a = 1;
} else
memset(&a, '0', sizeof a);
=>
if (c) {
memset(&a, '0', sizeof a);
a = 1;
} else
memset(&a, '0', sizeof a);
=>
if (c) {
a = 0;
a = 1;
} else
memset(&a, '0', sizeof a);
=>
if (c)
a = 1;
else
memset(&a, '0', sizeof a);
=>
if (c)
a = 0;
if (!c)
memset(&a, '0', sizeof a);
not legal?
Because the semantics are different. And you admit yourself that the
transformation can be done if the compiler show that it can do the
transformation if the compiler can show that the value received by
use(a) will be the same.
How I do understand the current the reference manual for
llvm.lifetime.start, the semantics of
llvm.lifetime.start(a)
and
if (c)
llvm.lifetime.start(a)
are the same if a is not used before that point. According to Than
McIntosh the problem is that StackColoring currently does not
correctly handle the situation.
What I would wish for is that the language reference for lifetime
markers is updated such that it reflects the what StackColoring can
handle, and that the IR verifier fails when the lifetime markes are
not well-formed according to that reference. For instance, we can
define that the end/start marker must (post-)dominate the start/end
marker.
Thank you for the clarification. I indeed did not consider that the
exit/unreachable makes a difference.
This is what happens in Polly:
llvm.lifetime.start(&var)
if (c) {
call void @_z10exit_usagepkc
unreachable // because exit_usage is no-return
}
- Optimistically assume that no functions are executed or control flow
ends in an unreachable. It can determine the condition c1 for when no
such thing ever appears (in which case c1 is just "true")
- Version the old code and the new code:
if (c1) {
// optimized code without lifetime markers
...
} else {
// Orginal code, not modified by Polly
llvm.lifetime.start(&var);
if (c) {
call void @_z10exit_usagepkc
unreachable // because exit_usage is no-return
}
}
In this case c happens to be equal to c1, in which case I guess some
pass removes the inner inner conditional because it is always true.
How do you think code versioning in general should handle this? I
looked into LoopVersioning.cpp (used by LLVM's vectorizer), but could
not see how it handles this situation. Maybe it is not affected
because lifetime markers usually do not cross loop bounds.
2017-03-31 3:38 GMT+02:00 Daniel Berlin <dbe...@dberlin.org>:
> Sure, and you definitely can't transform an unconditional store to a
> conditional one unless the uses are guarded by the same condition, or you
> can prove it already had that value (in which case, the memset would also be
> dead) :)
>
> ie
> memset(a, 0)
> use a
>
> can't be transformed to
> if (c)
> memset(a, 0)
> use a
>
> So again, if polly is making a lifetime.start conditional when the use is
> not conditional, that's a bug in polly, regardless of the bug in stack
> coloring's ability to handle it.
InstCombine transforms memset(a,1) to a single StoreInst, but keeps
the memset if the size argument is zero. A StoreInst can be optimized
away, e.g. by DeadStoreElimination. I wonder, are the semantics of
memset(a, 0) different than "do nothing"?
Michael
According to Than
McIntosh the problem is that StackColoring currently does not
correctly handle the situation.
What I would wish for is that the language reference for lifetime
markers is updated such that it reflects the what StackColoring can
handle, and that the IR verifier fails when the lifetime markes are
not well-formed according to that reference. For instance, we can
define that the end/start marker must (post-)dominate the start/end
marker.
I
looked into LoopVersioning.cpp (used by LLVM's vectorizer), but could
not see how it handles this situation. Maybe it is not affected
because lifetime markers usually do not cross loop bounds.
Small correction: c == !c1.
>>
>> How do you think code versioning in general should handle this?
>
>
> Assuming you don't want to drop them:
>
> If you are only duplicating code structurally, and not moving it past any
> statements, and assuming we fix the semantics:
> When you start, the lifetime starts for a pointer should jointly (IE
> considered as a set) dominate the lifetime ends.
> The lifetime ends for a pointer should jointly post-dominate each lifetime
> start.
This would be great to be mentioned at
http://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic
I try to summarize: One can move lifetime.start arbitrarily up into
dominators, even if crossing instructions affecting the memory pointed
to, but only downwards if anything in-between touching memory
noaliases it.
Thanks for your suggestions.