promotion of return value.

Below I have pasted the latest design that we discussed...
Now we would like to pick it up and do the implementation.
1) Is there any last change that we would like to add?
2) Has anyone been working on it? I haven't seen any thing new in the
code so I assume the answer is no...

Thanks

Alireza Moshtaghi
Senior Software Engineer
Development Systems, Microchip Technology

Subject:
Troubling promotion of return value to Integer ...

Let me summarize what we discussed so far:

1) The return value promotion will be removed from llvm backend and
  implemented in both front-ends (clang and llvm-gcc)

2) The promotions are only applied to the return value in the body
  of the function.
  Return value of function definition and declaration will not be
promoted

  Example for a Target with 32-bit int type:

  char foo() {
    char c = ...
    return c;
  }

  Is translated to:

  define i8 @foo() {
     ...
     %tmp = sext i8 ... to i32
     ret i32 %tmp
  }

Close. The return value of declarations also has to be promoted. foo

should be translated to:

   define i32 @foo() sign_ext_from_i8 {
      ...
      %tmp = sext i8 ... to i32
      ret i32 %tmp
   }

3) Return value promotion is the default behavior, however,
  hooks will be provided to allow the Target to disable it
  and emit diagnostics.

Sure, the front-end can do that.

4) There will be 4 new function attributes:
  sign_ext_from_i8, sign_ext_from_i16
  zero_ext_from_i8, zero_ext_from_i16
  These attributes will be placed on the function CALL node by
front-end
  to inform the backend about such promotions and enable optimization
of
  return value. This should be sufficient for direct and indirect
call.
  (syntax of these attributes to be defined)

They also go on the function definition, as above.

Am I capturing everything?

Yep! The place to start with this is introducing the new attributes.
Given the new attributes, we can mock up .ll code that uses them and
improve the optimizers to use them. When everything there is correct,

we can move each front-end over to start using them.

-Chris

Below I have pasted the latest design that we discussed...
Now we would like to pick it up and do the implementation.
1) Is there any last change that we would like to add?
2) Has anyone been working on it? I haven't seen any thing new in the
code so I assume the answer is no...

Great! I think that this is still the best plan, thanks for tackling it!

-Chris

Previously we talked about adding new attributes to function to identify the promotion class.

  sign_ext_from_i8, sign_ext_from_i16
  zero_ext_from_i8, zero_ext_from_i16

Aren't these attributes more applicable to return value? of course then the question would be if they are also applicable to parameters too? (because we use same attributes for parameters and return value)? or should we disallow then on parameters?

Thoughts?

A.

1) The return value promotion will be removed from llvm backend and
implemented in both front-ends (clang and llvm-gcc)

2) The promotions are only applied to the return value in the body
of the function.
Return value of function definition and declaration will not be
promoted

You might want to look at bug http://llvm.org/bugs/show_bug.cgi?id=3779.

If I understand what you are proposing, it is exactly the opposite of
what gcc does, which would be annoying for someone trying to link gcc
and llvm compiled code.

Cheers,

Since the LLVM IR supports arbitrary precision integers,
shouldn't there be zero_ext_from_i17 as well? At least
zero_ext_from_i1?

Ciao,

Duncan.

PS: What is the problem this is trying to solve?

4) There will be 4 new function attributes:
sign_ext_from_i8, sign_ext_from_i16
zero_ext_from_i8, zero_ext_from_i16
These attributes will be placed on the function CALL node by
front-end
to inform the backend about such promotions and enable optimization
of
return value. This should be sufficient for direct and indirect
call.
(syntax of these attributes to be defined)

I am a bit lost, but if we are going to do what gcc does (only extent
in the caller) I don't thin we need this. We can compile

char foo() {
   char c = ...
   return c;
}

into

define i8 @foo() {
     ...
   %tmp = ....
     ret i8 %tmp
}

and if a caller wants a 32 bit value it can extend it according to the
c/c++ prototype of the function.

In theory I think we could also do this for passing arguments to
functions, but I am not sure how this would
interact with existing code compiled with gcc.

Cheers,

Rafael Espindola wrote:

1) The return value promotion will be removed from llvm backend and
  implemented in both front-ends (clang and llvm-gcc)

2) The promotions are only applied to the return value in the body
  of the function.
  Return value of function definition and declaration will not be
promoted

You might want to look at bug http://llvm.org/bugs/show_bug.cgi?id=3779.

If I understand what you are proposing, it is exactly the opposite of
what gcc does, which would be annoying for someone trying to link gcc
and llvm compiled code.

That's right. In gcc we used to do this in the front-ends but we
stopped. This required quite a lot of discussion with the Linux ABI
standardization people.

Andrew.

Yes, I trust we're taking into account that some ABIs have requirements about this.
For example, ARM AAPCS requires the caller promote arguments, and the callee
promote return values.

What I was planning to do is to provide a default behavior that is
consistent with what currently llvm does (promote to 32 bit)
And then there will be control in clang for targets to do things
differently.
But I also understand you concern about gcc frontend; because the same
thing has to also take place there....
We had long discussions about this last year, and this is what has been
decided. Maybe Chris is in a better position to decide what to do.

A.

From: llvmdev-bounces@cs.uiuc.edu [mailto:llvmdev-bounces@cs.uiuc.edu]

On

Behalf Of Dale Johannesen
Sent: Thursday, March 12, 2009 11:45 AM
To: LLVM Developers Mailing List
Subject: Re: [LLVMdev] promotion of return value.

> Rafael Espindola wrote:
>>>> 1) The return value promotion will be removed from llvm backend

and

>>>> implemented in both front-ends (clang and llvm-gcc)
>>>>
>>>> 2) The promotions are only applied to the return value in the

body

>>>> of the function.
>>>> Return value of function definition and declaration will not be
>>>> promoted
>>
>> You might want to look at bug

http://llvm.org/bugs/show_bug.cgi?id=3779

>> .
>>
>> If I understand what you are proposing, it is exactly the opposite

of

>> what gcc does, which would be annoying for someone trying to link

gcc

Can you take a look at my last post on the bug and see if that could work
for all the cases you have? Since llvm-gcc and clang are the ones doing
the lowering, i think it would. Consider the code

Hi Rafael, if the nasty hack I mentioned in the PR
was removed then the following code should work for
both X86 and ARM:

define signext i16 @f() nounwind {
entry:
        %0 = tail call signext i16 @h() nounwind
        %1 = sext i16 %0 to i32
        tail call void @g(i32 %1) nounwind
        %2 = load i16* @x, align 2
        ret i16 %2
}

This is what llvm-gcc currently produces. On x86
the value would be returned in an i16 register, so
no sign extension would be performed in the callee.
Thus the sign extension to i32 would occur in the
caller.

On the other hand, consider ARM. There are no i16
registers on ARM, so the value would be returned in
an i32. The signext attribute means that the callee
would sign extend the i16 to an i32 before returning
it. Also, due to the signext attribute the caller
will know that the callee sign extended the i16 to
an i32, so the DAG combiner will drop the sign
extension in the caller as redundant.

Try the attached patch.

Ciao,

Duncan.

call.diff (890 Bytes)

Try the attached patch.

Works perfectly for me! As noted on the bug, I think we would be
better without the signext attribute, but, as your patch shows, it is
not necessary for fixing the bug.

Ciao,

Duncan.

Thanks!

Some targets want to do the promotion in the callee and some in the
caller. Now what you are discussing in your bug is we shouldn't do in
both...
Now the tricky part is that many targets (not for the sake of promotion,
but for the sake of performance) return a smaller value in a larger
register (say if the function is to return char, they return it in 32
bit register);
So they are effectively promoting the return value on the callee side,
then the caller takes the part that it needs and again promotes it to
comply with the rules of integer promotion stuff, hence double
promotion.

What we are trying to do is to add new attributes (more maybe added
later):

  sign_ext_from_i8, sign_ext_from_i16
  zero_ext_from_i8, zero_ext_from_i16

to function definition so (assuming that both caller and callee are
generated in the same front-end) the caller will know if the callee has
already extended the return value or not, then it can promote only if
needed.

You may argue that this all can be done per a target-defined convention
and I think that is the theory behind the patches that are used to fix
your bug.
However, we had this discussion last year, and it was decided to make
things more transparent by adding the aforementioned attributes. Please
look at the thread:

http://www.nabble.com/Troubling-promotion-of-return-value-to-Integer-
-to17237327.html#a17237327

Regards,
Ali

From: llvmdev-bounces@cs.uiuc.edu [mailto:llvmdev-bounces@cs.uiuc.edu]

On

Behalf Of Rafael Espindola
Sent: Friday, March 13, 2009 2:07 AM
To: LLVM Developers Mailing List
Subject: Re: [LLVMdev] promotion of return value.

> What I was planning to do is to provide a default behavior that is
> consistent with what currently llvm does (promote to 32 bit)
> And then there will be control in clang for targets to do things
> differently.
> But I also understand you concern about gcc frontend; because the

same

> thing has to also take place there....
> We had long discussions about this last year, and this is what has

been

> decided. Maybe Chris is in a better position to decide what to do.

Can you take a look at my last post on the bug and see if that could

work

for all the cases you have? Since llvm-gcc and clang are the ones

doing

Some targets want to do the promotion in the callee and some in the
caller. Now what you are discussing in your bug is we shouldn't do in
both...

exactly.

Now the tricky part is that many targets (not for the sake of promotion,
but for the sake of performance) return a smaller value in a larger
register (say if the function is to return char, they return it in 32
bit register);
So they are effectively promoting the return value on the callee side,
then the caller takes the part that it needs and again promotes it to
comply with the rules of integer promotion stuff, hence double
promotion.

What we are trying to do is to add new attributes (more maybe added
later):

sign_ext_from_i8, sign_ext_from_i16
zero_ext_from_i8, zero_ext_from_i16

to function definition so (assuming that both caller and callee are
generated in the same front-end) the caller will know if the callee has
already extended the return value or not, then it can promote only if
needed.

You may argue that this all can be done per a target-defined convention
and I think that is the theory behind the patches that are used to fix
your bug.
However, we had this discussion last year, and it was decided to make
things more transparent by adding the aforementioned attributes. Please
look at the thread:

My proposal is to make the extension as explicit as possible. If the
callee is extending an char to an int, the generated llvm code should
return an i32 and the caller can assume that the extension has been done.

Are you saying that the decision to do the extension in the callee happens
after we have generated llvm? That is, an optimization is transforming
a function that would return an i8 into one that returns i16 or i32?

Do you have a testcase for the problem you are trying to solve?

http://www.nabble.com/Troubling-promotion-of-return-value-to-Integer-
-to17237327.html#a17237327

I am sorry I missed the thread. I will take a look.

Regards,
Ali

Cheers,

Rafael Espindola a écrit :

My proposal is to make the extension as explicit as possible. If the
callee is extending an char to an int, the generated llvm code should
return an i32 and the caller can assume that the extension has been done.

Are you saying that the decision to do the extension in the callee happens
after we have generated llvm? That is, an optimization is transforming
a function that would return an i8 into one that returns i16 or i32?

Do you have a testcase for the problem you are trying to solve?
  
I think the problem was that some target don't support i32 natively (in hadware) like for exemple the PIC16. To force an extension to i32 is expensive on these target and may pose ABI compatibility problems.

Anyways, i32 on 64 bits targets may be inefficient, so solving the problem in a more general way is better. Impossing i32 as *the* default size used by everyone is wrong.

just my 2cents

Cédric

Cedric is right,
Our target, PIC16, is 8-bit and promotion to 32-bit is really bad for us...
Now what exactly is going to happen once these attributes are added, depends on the target.
For example, in our case, there will be no promotion on the callee side, but the caller will decide if it wants to promote or not...
What will happen in general is that front-end (clang and llvm-gcc) will do the promotion on return value (if so intended by the target) on the callee side, and will set the appropriate attribute both on the call node and function definition. Then the optimizers will also get a chance to modify these attributes as they deem appropriate according to the particular optimizations that they may do.
Finally, llvm codegen will use the attribute on the call node to know if there needs to be any extension on the return value or not.

This does not bound us to any particular size promotion. The solution is generic enough to address all possibilities (of course new attributes may be needed)

Regards
Ali

This does not bound us to any particular size promotion. The solution is generic enough to address all possibilities (of course new attributes may be needed)

We are both trying to do the same, I just don't see why this can't be
done completely in llvm-gcc or clang. Do you have an C example where
we
currently do sign extension and that we would be able to avoid it with
your proposal?

Regards
Ali

Cheers,

Right, I guess theoretically, this stuff could be done entirely in the
frontend, but practically I'm not sure...
At the end of the day, it is enabling an optimization, and front-end is
not necessarily the place for it.

Chris has given a C example in the below email.
http://www.nabble.com/Re%3A-Troubling-promotion-of-return-value-to-Integ
er-...-p17281950.html

Regards
Ali

From: llvmdev-bounces@cs.uiuc.edu [mailto:llvmdev-bounces@cs.uiuc.edu]

On

Behalf Of Rafael Espindola
Sent: Friday, March 13, 2009 2:51 PM
To: LLVM Developers Mailing List
Subject: Re: [LLVMdev] promotion of return value.

> This does not bound us to any particular size promotion. The

solution is

generic enough to address all possibilities (of course new attributes

may

Hi,

What we are trying to do is to add new attributes (more maybe added
later):

> sign_ext_from_i8, sign_ext_from_i16
> zero_ext_from_i8, zero_ext_from_i16

to function definition so (assuming that both caller and callee are
generated in the same front-end) the caller will know if the callee has
already extended the return value or not, then it can promote only if
needed.

I don't understand what the point of this is. Surely this can all be
handled by the calling convention and the signext/zeroext attributes?
For example, suppose a function returns a short, but on the target that
means being returned in an i32, with sign extension. Then in the IR the
function is defined as returning an i16 with the signext attribute:

  define signext i16 @f(...

The target calling convention specifies that i16's are returned in
i32's. When code is generated for @f this means that you get something
like:

      0x2696eb8: i16,ch = ... <= the i16 value
    0x2696fb0: i32 = sign_extend 0x2696eb8 <= sign extended to i32
    0x26970a8: ch = ArgFlags < >
  0x26971a0: ch = ret 0x2696ad8, 0x2696fb0, 0x26970a8 <= here returned

Perfect!

Ciao,

Duncan.

Although ABIs define the calling convention to facilitate cross language
function call on the same target, the rules of the game for return
statement in C language is also somewhat influenced by the standard and
it requirement for integer promotion, which makes it a language issue.
(if you are interested, we can discuss this later)

So in this particular issue, there is an overlap between ABI's calling
convention and C language standard for return statement. This is not a
definitive conclusion as whether we should implement return statement by
the ABI's calling convention, or by the standard. However, if we
consider practical issues such as functions without prototype, then
using the proposed attributes makes it much easier to diagnose
discrepancies in user code than if we were to rely only on the calling
convention.

For example, if a function without prototype is called, the caller
assumes int as return value, and has no information on whether the
callee has promoted the result or it is an actual int. But if we use
these attributes, then the linker would be able to set the correct
attribute on the call node once it sees the implementation of the
callee, and later optimization on the return value promotion would be
possible.

By the way, I should refine my previous assumption...
Caller and callee may very well be compiled in the different front-ends
maybe even different languages.

Regards
Ali

From: Duncan Sands [mailto:baldrick@free.fr]
Sent: Saturday, March 14, 2009 3:19 AM
To: llvmdev@cs.uiuc.edu
Cc: Alireza Moshtaghi - C13012
Subject: Re: [LLVMdev] promotion of return value.

Hi,

> What we are trying to do is to add new attributes (more maybe added
> later):
>
> > sign_ext_from_i8, sign_ext_from_i16
> > zero_ext_from_i8, zero_ext_from_i16
>
> to function definition so (assuming that both caller and callee are
> generated in the same front-end) the caller will know if the callee

has

> already extended the return value or not, then it can promote only

if

> needed.

I don't understand what the point of this is. Surely this can all be
handled by the calling convention and the signext/zeroext attributes?
For example, suppose a function returns a short, but on the target

that

means being returned in an i32, with sign extension. Then in the IR

the

function is defined as returning an i16 with the signext attribute:

  define signext i16 @f(...

The target calling convention specifies that i16's are returned in
i32's. When code is generated for @f this means that you get

something

like:

      0x2696eb8: i16,ch = ... <= the i16 value
    0x2696fb0: i32 = sign_extend 0x2696eb8 <= sign extended

to