[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: RFC: Support non-standard extension (call via casted function pointer)



On Wed, Jan 27, 2016 at 7:17 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Wed, Jan 27, 2016 at 4:10 PM, Thorsten Otto <halgara@yahoo.de> wrote:
>>> This frobbing of a pointer return value in %d0 only happens in the
>>> outgoing case already now, because in the non-outgoing case,
>>> m68k_function_value is (unverified claim) only called from expand_call,
>>> which replaces the PARALLEL rtx by the first list element, i.e. %a0. (or
>>> %d0 if !POINTER_TYPE_P(valtype) after my patch).
>>
>> Wether pointer values are returned in d0 or a0 only depend on the ABI, not
>> the machine type.
>>
>> BTW what does ghc expect on x86-64? The ABIs on linux and e.g Win64 are also
>> quite different with respect to which registers are used to pass/
>> parameters.
>>
>> And in the m68k-case, you will have similar problems with double values.
>> Depending on the ABI, they are returned in either fp0 or d0/d1.
>>
>> You can try the following example:
>>
>> extern void *test1(void);
>>
>> extern char a[100];
>>
>> __attribute__((noinline)) void *test2(void)
>> {
>>     return a;
>> }
>>
>> extern void *p1;
>> extern void *p2;
>>
>> void test3(void)
>> {
>>     p1 = test1();
>>     p2 = test2();
>> }
>>
>> extern double test4(void);
>>
>> extern double d;
>>
>> __attribute__((noinline)) double test5(void)
>> {
>>     return d;
>> }
>>
>> extern double d1;
>> extern double d2;
>>
>> void test6(void)
>> {
>>     d1 = test4();
>>     d2 = test5();
>> }
>>
>> m68k-atari-linux-gcc produces the following code:
>>
>>         .globl  test2
>>         .type   test2, @function
>> test2:
>>         lea a,%a0
>>         move.l %a0,%d0
>>         rts
>>         .size   test2, .-test2
>>         .align  2
>>         .globl  test3
>>         .type   test3, @function
>> test3:
>>         jsr test1
>>         move.l %a0,p1
>>         jsr test2
>>         move.l %a0,p2
>>         rts
>>         .size   test3, .-test3
>>         .align  2
>>         .globl  test5
>>         .type   test5, @function
>> test5:
>>         fmove.d d,%fp0
>>         rts
>>         .size   test5, .-test5
>>         .align  2
>>         .globl  test6
>>         .type   test6, @function
>> test6:
>>         jsr test4
>>         fmove.d %fp0,d1
>>         jsr test5
>>         fmove.d %fp0,d2
>>         rts
>>
>> You see that test2() puts the return value in both a0 and d0, and that
>> test3() expects the return value in a0 in both calls of test1() and test2().
>>
>> The same code compiled with m68k-atari-mint-gcc produces:
>>
>>         .globl  _test2
>> _test2:
>>         move.l #_a,%d0
>>         rts
>>         .even
>>         .globl  _test3
>> _test3:
>>         jsr _test1
>>         move.l %d0,_p1
>>         jsr _test2
>>         move.l %d0,_p2
>>         rts
>>         .even
>>         .globl  _test5
>> _test5:
>>         move.l _d,%a1
>>         move.l _d+4,%a0
>>         move.l %a1,%d0
>>         move.l %a0,%d1
>>         rts
>>         .even
>>         .globl  _test6
>> _test6:
>>         jsr _test4
>>         move.l %d0,_d1
>>         move.l %d1,_d1+4
>>         jsr _test5
>>         move.l %d0,_d2
>>         move.l %d1,_d2+4
>>         rts
>>
>> In this case, test2() puts the return value only in d0, and test3() expects
>> the return value in d0 in both calls of test1() and test2().
>> (BTW strange code that is produced in test5() to return the double in d0/d1;
>> why is it loaded into address registers first?)
>>
>> Conclusion: IMHO, If ghc fetches the return value from the wrong register,
>> then ghc is broken, not gcc.
>
> We are trying to support
>
> t.c
> ---
> void *foo();
>
> int bar()
> {
>   return ((int (*)())foo) ();
> }


Why can't ghc produce code like:
int bar ()
{
  int (*foo1)() = foo;
  asm("":"+r"(foo1));
  return foo1();
}

Yes it no longer produces an direct function call but it might be
better in the long run anyways.

Thanks,
Andrew

>
> t2.c
> -----
> int foo () { return 0; }
>
> thus doing a direct call to a function with a (wrong) prototype via a function
> pointer cast to the correct type and having a matching implementation of
> that function elsewhere.
>
> I think that's reasonable and what GHC expects - declare "there is a function
> foo defined, no idea what prototype yet", unfortunately C requires to specify
> a return type.
>
> Richard.
>
>>
>> Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> schrieb am 20:21
>> Dienstag, 26.Januar 2016:
>>
>>
>> On 26.01.2016 16:40, Richard Biener wrote:
>>> No, the patch looks somewhat broken to me.  A complete fix would replace
>>> the target macro FUNCTION_VALUE implementation by implementing the
>>> function_value hook instead (to also receive the function type called if
>>> no
>>> decl is available and to be able to distinguish caller vs. callee).
>>>
>>> I also don't see how changing the called function code will fix anything.
>> I definitely agree that the approach to move from the FUNCTION_VALUE
>> macro to the function_value hook is the most clean way to do it. If
>> there is a consensus among the gcc developers that a patch to support
>> this non-conforming code should be applied, I would be willing to
>> prepare a patch as suggested.
>>
>> The current patch does not change the called code at all. The only time
>> at which my suggested patch changes gcc behaviour is if a function
>> declaration is given, that declaration has a pointer type as return
>> type, but valtype is no pointer type. This (unverified claim) can not
>> happen in the callee, as the valtype when compiling the return statement
>> or assembling the epilogue is taken from the function declaration.
>>
>>> In fact the frobbing of the return value into %d0 should only happen
>>> if the 'outgoing' arg is true (in the hook implementation) and in the
>>> 'outgoing' == false case simply disregard 'func' and always use
>>> 'valtype'.
>> This frobbing of a pointer return value in %d0 only happens in the
>> outgoing case already now, because in the non-outgoing case,
>> m68k_function_value is (unverified claim) only called from expand_call,
>> which replaces the PARALLEL rtx by the first list element, i.e. %a0. (or
>> %d0 if !POINTER_TYPE_P(valtype) after my patch).
>>
>>
>>> So, hookize and change to
>>>
>>>  if (outgoing && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (func))))
>>>    ...
>>>  else if (POINTER_TYPE_P (valtype))
>>>    ...
>>>  else
>>
>>>    ...
>> Looks good and clean to me, but I expect my patch to have the same effect.
>>
>> Regards,
>>   Michael Karcher
>>
>>
>>
>>


Reply to: