[llvm-dev] Function Inlining and undef / poison question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev
Nuno,
          One of your recent emails got me thinking about inlining.

I say this function is always well defined,
And it always executes statement S

F(a)
{
   If (a == a) S;
}

And that if this function is inlined it must still be well defined,
And still always execute statement S

But if I read your example correctly you feel that the result
of inlining is undefined behavior because “if (undef == undef)”
and “if (poison == poison)” is undefined behavior  ?

I say that if the compiler makes it so that the programmer cannot
correctly reason about how their program executes then there is
something wrong with the compiler.

My own opinion about this is that it is yet another example of why
"Since each use of ‘undef’ can yield a different result…”
is such a bad definition, and should never have been accepted into
the IR in the first place.

IIUC, both “undef” and “poison” share this undesirable definition
for which “freeze” is proposed as a fix, but if I understand your
logic correctly there is no way to fix this example with “freeze” ?

IMHO "freeze” is a bandaid over a bad definition, that doesn’t
seem to solve the inlining problem, and we should fix the definition
rather than add a bandaid.


Peter Lawrence.
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev
Hi Peter, I don't see what you're driving at here. You can perhaps move
the discussion forward with a complete, compilable example.

John


On 6/15/17 11:27 AM, Peter Lawrence via llvm-dev wrote:

> Nuno,
>           One of your recent emails got me thinking about inlining.
>
> I say this function is always well defined,
> And it always executes statement S
>
> F(a)
> {
>    If (a == a) S;
> }
>
> And that if this function is inlined it must still be well defined,
> And still always execute statement S
>
> But if I read your example correctly you feel that the result
> of inlining is undefined behavior because “if (undef == undef)”
> and “if (poison == poison)” is undefined behavior  ?
>
> I say that if the compiler makes it so that the programmer cannot
> correctly reason about how their program executes then there is
> something wrong with the compiler.
>
> My own opinion about this is that it is yet another example of why
> "Since each use of ‘undef’ can yield a different result…”
> is such a bad definition, and should never have been accepted into
> the IR in the first place.
>
> IIUC, both “undef” and “poison” share this undesirable definition
> for which “freeze” is proposed as a fix, but if I understand your
> logic correctly there is no way to fix this example with “freeze” ?
>
> IMHO "freeze” is a bandaid over a bad definition, that doesn’t
> seem to solve the inlining problem, and we should fix the definition
> rather than add a bandaid.
>
>
> Peter Lawrence.
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev

On 15 June 2017 at 23:12, John Regehr via llvm-dev <[hidden email]> wrote:
Hi Peter, I don't see what you're driving at here. You can perhaps move the discussion forward with a complete, compilable example.

John

I don't KNOW for sure, but I think I understand, see below: 



On 6/15/17 11:27 AM, Peter Lawrence via llvm-dev wrote:
Nuno,
          One of your recent emails got me thinking about inlining.

I say this function is always well defined,
And it always executes statement S

F(a)
{
   If (a == a) S;
}

I think the problem can be seen as:
void F(int a)
{
    if (a == a) do_stuff();
}

....
main()
{
    int x;
    F(x);
}

If the compiler doesn't inline F, it will definitely call F, where the compiler doesn't KNOW that x is undef, and as a result, do_stuff is guaranteed to execute. If F is inlned, x is known as undef, so the compiler decides that the comparison is false (despite x always has to be equal to itself, no matter whether it's value is undef or not), and thus do_stuff wlll not be called.

Of course, it would be easy to fix this by initializing x, but with some more complex code, it may not be so easy to follow what is going on and what the effects will be.

I don't have a good answer as to what to do - I can sort of see both sides on this one.

--
Mats

And that if this function is inlined it must still be well defined,
And still always execute statement S

But if I read your example correctly you feel that the result
of inlining is undefined behavior because “if (undef == undef)”
and “if (poison == poison)” is undefined behavior  ?

I say that if the compiler makes it so that the programmer cannot
correctly reason about how their program executes then there is
something wrong with the compiler.

My own opinion about this is that it is yet another example of why
"Since each use of ‘undef’ can yield a different result…”
is such a bad definition, and should never have been accepted into
the IR in the first place.

IIUC, both “undef” and “poison” share this undesirable definition
for which “freeze” is proposed as a fix, but if I understand your
logic correctly there is no way to fix this example with “freeze” ?

IMHO "freeze” is a bandaid over a bad definition, that doesn’t
seem to solve the inlining problem, and we should fix the definition
rather than add a bandaid.


Peter Lawrence.
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev
> void F(int a)
> {
>     if (a == a) do_stuff();
> }
>
> ....
> main()
> {
>     int x;
>     F(x);
> }

This C program unconditionally executes UB and any translation at all is
acceptable -- end of story.

John

_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev

On 16 June 2017 at 00:35, John Regehr via llvm-dev <[hidden email]> wrote:
void F(int a)
{
    if (a == a) do_stuff();
}

....
main()
{
    int x;
    F(x);
}

This C program unconditionally executes UB and any translation at all is acceptable -- end of story.

I understand that is the "letter of the law". However, I can see the argument for something that behaves in a predictable way, whether for example F is defined in a header file or in a separate translation unit - and I believe the example here is one where that would make a difference - even if the compller is perfectly fine to produce something that plays the theme tune to Mony Python's Flying Circus or prints 42 on the screen, instead of whatever "do_stuff" does.

--
Mats 

John


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Function Inlining and undef / poison question

Hal Finkel via llvm-dev
> I understand that is the "letter of the law". However, I can see the
> argument for something that behaves in a predictable way, whether for
> example F is defined in a header file or in a separate translation unit
> - and I believe the example here is one where that would make a
> difference - even if the compller is perfectly fine to produce something
> that plays the theme tune to Mony Python's Flying Circus or prints 42 on
> the screen, instead of whatever "do_stuff" does.

This ship has sailed.

If you want predictability for UB you'll need to get it through a
sanitizer, a non-optimizing compiler, a special-purpose command-line
flag that disables a class of UB-exploiting optimizations, etc.

John

_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] function inlining and undef / poison question

Hal Finkel via llvm-dev
In reply to this post by Hal Finkel via llvm-dev
John,
         the program below is not necessarily *undefined* in the C programming
sense, the C89 and C99 standards say the value of a stack auto variable that
is not initialized is “indeterminate”, not “undefined behavior”, it then goes
on to say that “indeterminate” is either “unspecified” or “trap representation”.

The standard absolutely does not require this to be “UB”, and making it
so in llvm is wrong, it leads to unexpected and unwanted transformations
that are indefensible from the users point of view.

Peter Lawrence.



C89, see section 6.5.7 Initialization.

If an object that has automatic storage duration is not initialized 
explicitely, its value is indeterminate. If an object that has static 
storage duration is not initialized explicitely, it is initialized
implicitely as if every member that has arithmetic type were assigned 
0 and every member that has pointer type were assigned a null pointer 
constant.

C99, see section 6.7.8 Initialization.

If an object that has automatic storage duration is not initialized explicitly,
its value is indeterminate. If an object that has static storage duration is
not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer; 
— if it has arithmetic type, it is initialized to (positive or unsigned) zero; 
— if it is an aggregate, every member is initialized (recursively) according to these rules; 
— if it is a union, the first named member is initialized (recursively) according to these rules.

C89, C99 see section 3.17.2 indeterminate value

either an unspecified value or a trap representation



Date: Thu, 15 Jun 2017 17:35:55 -0600
From: John Regehr via llvm-dev <[hidden email]>
To: [hidden email]
Subject: Re: [llvm-dev] Function Inlining and undef / poison question

void F(int a)
{
   if (a == a) do_stuff();
}

....
main()
{
   int x;
   F(x);
}

This C program unconditionally executes UB and any translation at all is 
acceptable -- end of story.

John



_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] function inlining and undef / poison question

Hal Finkel via llvm-dev
Trap representations are primarily just a funny way to say undefined
behavior, see 6.2.6.1 p5 of C99:

"Certain object representations need not represent a value of the object
type. If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type, the
behavior is undefined. If such a representation is produced by a side
effect that modifies all or any part of the object by an lvalue
expression that does not have character type, the behavior is undefined.
Such a representation is called a trap representation."

Here's a reasonable discussion of the issues surrounding uninitialized
storage:

   http://queue.acm.org/detail.cfm?id=3041020

This is definitely a sucky part of the standards and I hope they manage
to clear it up.

However, none of this causes problems for us at the LLVM level. Whatever
it is that reading uninitialized storage means (and I am uninterested in
debating this further, at least on this list), we almost certainly have
a mechanism for expressing that in LLVM. Thus, as far as I can tell,
there is no problem here.

John
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Loading...