January 09, 2012
On 9 January 2012 18:15, Artur Skawina <art.08.09@gmail.com> wrote:
> On 01/09/12 10:53, Iain Buclaw wrote:
>> On 5 January 2012 11:40, Artur Skawina <art.08.09@gmail.com> wrote:
>>> IOW gdc completely gives up on inlining the function/method because of the "in".
>>> Actually, "bool empty2(T)(const T[] a)" is enough to trigger the call.
>>>
>>> This means that eg array.empty never gets inlined. "pragma(attribute, always_inline)" does not help in this case.
>>
>> I have sorted this out.
>
> Works. Thank you very much, not just for this, but for quickly fixing practically every single gdc bug that i filed.
>
> It's nice to see all the code from my example compiled to just "mov $0x1,%eax" [1] and the runtime/phobos codegen improved too, some null pointer checks gone, significantly reduced spilling, opCall()/empty() are now inlined, which means they completely disappear etc.
>
> Thanks,
>

Well, what else am I supposed to do, leave them to stack up? :-)


>
> [1] I guess omitting the frame pointer manipulation for (at least) just nonthrowing leaf functions that don't use any stack slots wouldn't be easy? (the vector extensions will probably make this even more important...)

I think the tweaks I've made for extern(D) - frame pointer turned on unless naked - trumps all other checks for whether it is ok to omit frame pointer. For extern(C) at least for x86, the frame pointer is omitted by default as is the default for that particular backend. Will need to fix the inline asm in phobos and druntime to be C calling convention friendly, then can drop all relevant attempts at matching the DMD calling convention.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
January 09, 2012
On 01/09/12 20:05, Iain Buclaw wrote:
> On 9 January 2012 18:15, Artur Skawina <art.08.09@gmail.com> wrote:
>>
>> [1] I guess omitting the frame pointer manipulation for (at least) just nonthrowing leaf functions that don't use any stack slots wouldn't be easy? (the vector extensions will probably make this even more important...)
> 
> I think the tweaks I've made for extern(D) - frame pointer turned on unless naked - trumps all other checks for whether it is ok to omit frame pointer. For extern(C) at least for x86, the frame pointer is omitted by default as is the default for that particular backend.

Didn't realize extern(C) would influence this, other than changing name mangling and calling convention - will have to try it. I'm afraid it could cause symbol collisions with the "real" C code (for wrappers). [1]

The cases i'm worried about are things like virtual methods - imagine eg
a gui toolkit where every widget has certain properties (x,width,hidden etc)
which are implemented using getters, which in many cases should be just
"mov IMM, eax; ret" or "mov OFF(eax), eax; ret" -- this is what the C
compiler will emit; setting up the frame pointer just adds overhead and
inlining cannot help here.
SIMD code can have similar properties - only access data passed via
pointers, never calling other functions nor spilling.

> Will need to fix the inline asm in phobos and druntime to be C calling convention friendly, then can drop all relevant attempts at matching the DMD calling convention.

Do I understand correctly that you want to ignore the "official" D abi,
and go with an incompatible one, as a long term goal? That has downsides,
but as i think the "D ABI" will end up being changed and gdc is currently
not compatible anyway - maybe it's a reasonable option.
But gdc's D abi won't be fully compatible with the C one, right? Then,
avoiding some of C's mistakes would be a good idea (name mangling,
default to regparm etc)


I have porting the runtime/phobos asms to gcc asm on my to-do list, will try to get to that within two weeks. What would be the preferred way - version() guards? if yes - what version? Or would you prefer replacing the asms, if the changes are not going to be merged upstream anyway?

artur

[1] Maybe extern(C) would work for the following case, but i think i'll
wait with trying it until LTO fails to build this, so far it's working. :)


A D main module with this:

---------------------------------------------
[...]
  const char* guname = glib.get_user_name();
 805139f:       e8 5c 02 00 00          call   8051600 <char* GLib2.get_user_name()>
[...]
---------------------------------------------

built with a "glib" module containing:

---------------------------------------------
[...]
extern (C) char* g_get_user_name();
char* get_user_name() {
   return g_get_user_name();
}
[...]
---------------------------------------------

results in the above call going through this "function":

---------------------------------------------
08051600 <char* GLib2.get_user_name()>:
 8051600:       55                      push   %ebp
 8051601:       89 e5                   mov    %esp,%ebp
 8051603:       5d                      pop    %ebp
 8051604:       e9 c7 f1 ff ff          jmp    80507d0 <g_get_user_name@plt>
---------------------------------------------

So clearly the compiler gets confused, it does a good job of optimizing the tail call (this also works when the called functions takes args, btw), but then fails to kill the ebp-related code.

If i use a D alias, instead of a wrapper, i get a direct call via PLT;
compiling with LTO also results in code that does not use this stub
 - at least until GDC's LTO will decide it's missing some symbols and
fail to link. :)
January 09, 2012
On 9 January 2012 22:28, Artur Skawina <art.08.09@gmail.com> wrote:
> On 01/09/12 20:05, Iain Buclaw wrote:
>> On 9 January 2012 18:15, Artur Skawina <art.08.09@gmail.com> wrote:
>>>
>>> [1] I guess omitting the frame pointer manipulation for (at least) just nonthrowing leaf functions that don't use any stack slots wouldn't be easy? (the vector extensions will probably make this even more important...)
>>
>> I think the tweaks I've made for extern(D) - frame pointer turned on unless naked - trumps all other checks for whether it is ok to omit frame pointer. For extern(C) at least for x86, the frame pointer is omitted by default as is the default for that particular backend.
>
> Didn't realize extern(C) would influence this, other than changing name mangling and calling convention - will have to try it. I'm afraid it could cause symbol collisions with the "real" C code (for wrappers). [1]
>
> The cases i'm worried about are things like virtual methods - imagine eg
> a gui toolkit where every widget has certain properties (x,width,hidden etc)
> which are implemented using getters, which in many cases should be just
> "mov IMM, eax; ret" or "mov OFF(eax), eax; ret" -- this is what the C
> compiler will emit; setting up the frame pointer just adds overhead and
> inlining cannot help here.
> SIMD code can have similar properties - only access data passed via
> pointers, never calling other functions nor spilling.
>
>> Will need to fix the inline asm in phobos and druntime to be C calling convention friendly, then can drop all relevant attempts at matching the DMD calling convention.
>
> Do I understand correctly that you want to ignore the "official" D abi,
> and go with an incompatible one, as a long term goal? That has downsides,
> but as i think the "D ABI" will end up being changed and gdc is currently
> not compatible anyway - maybe it's a reasonable option.
> But gdc's D abi won't be fully compatible with the C one, right? Then,
> avoiding some of C's mistakes would be a good idea (name mangling,
> default to regparm etc)
>

The mere mention that D required it's own ABI didn't go down too well, and to be honest, for the quirks I am currently addressing, I think there's another calling convention in GCC that may suit the bill... Naked function support for x86 has a chance of getting in without too much hassle.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
13 14 15 16 17 18 19 20 21 22 23
Next ›   Last »