Doerfert, Johannes via llvm-dev
2020-Feb-19 07:16 UTC
[llvm-dev] The semantics of nonnull attribute
On 02/19, Juneyoung Lee via llvm-dev wrote:> Hello, > > > Would it be correct to resolve this by saying that dereferenceable(N) > > *implies* not_poison? This would be helpful as a clarification of how > > it all fits together. > > Yes, I think it makes sense.I don't we should do that. Take the `gep inbounds` example: char* foo(char *arg) { return `gep inbounds %arg, -100` } Here it depends if we want to deduce the output is dereferenceable(100) or not. If we do, we need dereferenceable to mean poison if violated, as with nonnull, because it is derived from poison. Only if we don't derive dereferenceable for the return value we can go for dereferenceable violations are UB. In the end, I think, it boils down to the question if there are situations where violation of some attributes should be poison and violation of others should be UB. If such situations exists it is unclear to me what makes the UB/poison ones special.> On Wed, Feb 19, 2020 at 12:14 PM Nicolai Hähnle <nhaehnle at gmail.com> wrote: > > > On Wed, Feb 19, 2020 at 3:51 AM Juneyoung Lee via llvm-dev > > <llvm-dev at lists.llvm.org> wrote: > > > I think not_poison (Johannes's used keyword) makes sense. We can > > simulate the original UB semantics by simply attaching it, as explained. > > > For the attributes other than nonnull, we may need more discussion; > > align attribute seems to be okay with defining it as poison, > > dereferenceable may need UB even without nonnull (because it needs to be > > non-poison as shown Nuno's hoisting example). > > > > For reference, the hoisting example was: > > > > f(dereferenceable(4) %p) { > > loop() { > > %v = load %p > > use(%v) > > } > > } > > => > > f(dereferenceable(4) %p) { > > %v = load %p > > loop() { > > use(%v) > > } > > } > > > > Would it be correct to resolve this by saying that dereferenceable(N) > > *implies* not_poison? This would be helpful as a clarification of how > > it all fits together. > > > > Cheers, > > Nicolai > > > > > -- > > Juneyoung Lee > Software Foundation Lab, Seoul National University> _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-- Johannes Doerfert Researcher Argonne National Laboratory Lemont, IL 60439, USA jdoerfert at anl.gov -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200219/bed194ee/attachment.sig>
Nicolai Hähnle via llvm-dev
2020-Feb-19 08:26 UTC
[llvm-dev] The semantics of nonnull attribute
Hi Johannes, On Wed, Feb 19, 2020 at 8:17 AM Doerfert, Johannes <johannesdoerfert at gmail.com> wrote:> On 02/19, Juneyoung Lee via llvm-dev wrote: > > Hello, > > > > > Would it be correct to resolve this by saying that dereferenceable(N) > > > *implies* not_poison? This would be helpful as a clarification of how > > > it all fits together. > > > > Yes, I think it makes sense. > > I don't we should do that. > > Take the `gep inbounds` example: > > char* foo(char *arg) { > return `gep inbounds %arg, -100` > } > > Here it depends if we want to deduce the output is dereferenceable(100) > or not. If we do, we need dereferenceable to mean poison if violated, as > with nonnull, because it is derived from poison. Only if we don't derive > dereferenceable for the return value we can go for dereferenceable > violations are UB.That's a fair point. The same kind of argument actually applies to an analog of the example 4 that started this thread. If the argument is dead, then: f(dereferenceable(N) %ptr) ==> f(dereferenceable(N) undef) ... would introduce UB and therefore be forbidden. So if that example serves as motivation for making nonnull weaker and introducing not_poison, then it should really serve as motivation for making _all_ function argument attributes weaker. Besides, there's a certain elegance in treating _all_ attributes on function arguments the same: * passing function arguments that do not satisfy the attribute constraints turn the corresponding value into poison * passing poison for a not_poison argument causes immediate UB (and this rule applies _after_ the first rule had a chance to poison things) That seems like it would be far less error prone than having to remember on a case-by-case basis whether certain attributes cause poison or immediate UB. Cheers, Nicolai> > In the end, I think, it boils down to the question if there are > situations where violation of some attributes should be poison and > violation of others should be UB. If such situations exists it is > unclear to me what makes the UB/poison ones special. > > > > On Wed, Feb 19, 2020 at 12:14 PM Nicolai Hähnle <nhaehnle at gmail.com> wrote: > > > > > On Wed, Feb 19, 2020 at 3:51 AM Juneyoung Lee via llvm-dev > > > <llvm-dev at lists.llvm.org> wrote: > > > > I think not_poison (Johannes's used keyword) makes sense. We can > > > simulate the original UB semantics by simply attaching it, as explained. > > > > For the attributes other than nonnull, we may need more discussion; > > > align attribute seems to be okay with defining it as poison, > > > dereferenceable may need UB even without nonnull (because it needs to be > > > non-poison as shown Nuno's hoisting example). > > > > > > For reference, the hoisting example was: > > > > > > f(dereferenceable(4) %p) { > > > loop() { > > > %v = load %p > > > use(%v) > > > } > > > } > > > => > > > f(dereferenceable(4) %p) { > > > %v = load %p > > > loop() { > > > use(%v) > > > } > > > } > > > > > > Would it be correct to resolve this by saying that dereferenceable(N) > > > *implies* not_poison? This would be helpful as a clarification of how > > > it all fits together. > > > > > > Cheers, > > > Nicolai > > > > > > > > > -- > > > > Juneyoung Lee > > Software Foundation Lab, Seoul National University > > > _______________________________________________ > > LLVM Developers mailing list > > llvm-dev at lists.llvm.org > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > > -- > > Johannes Doerfert > Researcher > > Argonne National Laboratory > Lemont, IL 60439, USA > > jdoerfert at anl.gov-- Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.
Finkel, Hal J. via llvm-dev
2020-Feb-19 08:29 UTC
[llvm-dev] The semantics of nonnull attribute
On 2/19/20 1:16 AM, Doerfert, Johannes via llvm-dev wrote:
On 02/19, Juneyoung Lee via llvm-dev wrote:
Hello,
Would it be correct to resolve this by saying that dereferenceable(N)
*implies* not_poison? This would be helpful as a clarification of how
it all fits together.
Yes, I think it makes sense.
I don't we should do that.
Take the `gep inbounds` example:
char* foo(char *arg) {
return `gep inbounds %arg, -100`
}
Here it depends if we want to deduce the output is dereferenceable(100)
or not. If we do, we need dereferenceable to mean poison if violated, as
with nonnull, because it is derived from poison. Only if we don't derive
dereferenceable for the return value we can go for dereferenceable
violations are UB.
Can you please clarify what it means for the output of dereferenceable to be
poison? If we tag a memory address as dereferenceable, is the optimizer free to
insert a load of the address immediately following that? Or we need to see some
other access (prior to any thread synchronization?) to say that's valid?
Thanks again,
Hal
In the end, I think, it boils down to the question if there are
situations where violation of some attributes should be poison and
violation of others should be UB. If such situations exists it is
unclear to me what makes the UB/poison ones special.
On Wed, Feb 19, 2020 at 12:14 PM Nicolai Hähnle <nhaehnle at
gmail.com><mailto:nhaehnle at gmail.com> wrote:
On Wed, Feb 19, 2020 at 3:51 AM Juneyoung Lee via llvm-dev
<llvm-dev at lists.llvm.org><mailto:llvm-dev at lists.llvm.org>
wrote:
I think not_poison (Johannes's used keyword) makes sense. We can
simulate the original UB semantics by simply attaching it, as explained.
For the attributes other than nonnull, we may need more discussion;
align attribute seems to be okay with defining it as poison,
dereferenceable may need UB even without nonnull (because it needs to be
non-poison as shown Nuno's hoisting example).
For reference, the hoisting example was:
f(dereferenceable(4) %p) {
loop() {
%v = load %p
use(%v)
}
}
=>
f(dereferenceable(4) %p) {
%v = load %p
loop() {
use(%v)
}
}
Would it be correct to resolve this by saying that dereferenceable(N)
*implies* not_poison? This would be helpful as a clarification of how
it all fits together.
Cheers,
Nicolai
--
Juneyoung Lee
Software Foundation Lab, Seoul National University
_______________________________________________
LLVM Developers mailing list
llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
_______________________________________________
LLVM Developers mailing list
llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20200219/fd3d8a4a/attachment.html>
Finkel, Hal J. via llvm-dev
2020-Feb-20 01:52 UTC
[llvm-dev] The semantics of nonnull attribute
Two thoughts:
1. I think that we should aim for regularity, to the extent possible, and so we
should treat nonnull, align, etc. similarly w.r.t. to whether they produce
poison or UB.
2. I was thinking about the following last night, and it clarified for me why
having an not_poison attribute makes sense and seems useful, and how poison/UB
might affect things on a function-call boundary itself. Imagine that we had a
fastcc lowering strategy that took a pointer argument with an alignment
attribute, followed by a suitably-small integer argument, and implemented a
calling convention that passed both in the same register. If the pointer value
might be poison, and thus violate the alignment attribute (or might violate the
alignment attribute otherwise and produce poison), then we can't implement
this just by anding together the two values (to pass them in the one register).
We need to mask off the low bits first. If the value can't be or generate
poison, and violating the alignment constraint produces UB, then the masking is
not needed and we can just and together the two values (confident that the low
bits will always be zero).
-Hal
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory
________________________________
From: llvm-dev <llvm-dev-bounces at lists.llvm.org> on behalf of Finkel,
Hal J. via llvm-dev <llvm-dev at lists.llvm.org>
Sent: Wednesday, February 19, 2020 2:29 AM
To: Doerfert, Johannes <johannesdoerfert at gmail.com>; Juneyoung Lee
<juneyoung.lee at sf.snu.ac.kr>
Cc: llvm-dev <llvm-dev at lists.llvm.org>; Nuno Lopes <nuno.lopes at
ist.utl.pt>; John Regehr <regehr at cs.utah.edu>
Subject: Re: [llvm-dev] The semantics of nonnull attribute
On 2/19/20 1:16 AM, Doerfert, Johannes via llvm-dev wrote:
On 02/19, Juneyoung Lee via llvm-dev wrote:
Hello,
Would it be correct to resolve this by saying that dereferenceable(N)
*implies* not_poison? This would be helpful as a clarification of how
it all fits together.
Yes, I think it makes sense.
I don't we should do that.
Take the `gep inbounds` example:
char* foo(char *arg) {
return `gep inbounds %arg, -100`
}
Here it depends if we want to deduce the output is dereferenceable(100)
or not. If we do, we need dereferenceable to mean poison if violated, as
with nonnull, because it is derived from poison. Only if we don't derive
dereferenceable for the return value we can go for dereferenceable
violations are UB.
Can you please clarify what it means for the output of dereferenceable to be
poison? If we tag a memory address as dereferenceable, is the optimizer free to
insert a load of the address immediately following that? Or we need to see some
other access (prior to any thread synchronization?) to say that's valid?
Thanks again,
Hal
In the end, I think, it boils down to the question if there are
situations where violation of some attributes should be poison and
violation of others should be UB. If such situations exists it is
unclear to me what makes the UB/poison ones special.
On Wed, Feb 19, 2020 at 12:14 PM Nicolai Hähnle <nhaehnle at
gmail.com><mailto:nhaehnle at gmail.com> wrote:
On Wed, Feb 19, 2020 at 3:51 AM Juneyoung Lee via llvm-dev
<llvm-dev at lists.llvm.org><mailto:llvm-dev at lists.llvm.org>
wrote:
I think not_poison (Johannes's used keyword) makes sense. We can
simulate the original UB semantics by simply attaching it, as explained.
For the attributes other than nonnull, we may need more discussion;
align attribute seems to be okay with defining it as poison,
dereferenceable may need UB even without nonnull (because it needs to be
non-poison as shown Nuno's hoisting example).
For reference, the hoisting example was:
f(dereferenceable(4) %p) {
loop() {
%v = load %p
use(%v)
}
}
=>
f(dereferenceable(4) %p) {
%v = load %p
loop() {
use(%v)
}
}
Would it be correct to resolve this by saying that dereferenceable(N)
*implies* not_poison? This would be helpful as a clarification of how
it all fits together.
Cheers,
Nicolai
--
Juneyoung Lee
Software Foundation Lab, Seoul National University
_______________________________________________
LLVM Developers mailing list
llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
_______________________________________________
LLVM Developers mailing list
llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20200220/34f692fe/attachment-0001.html>