| Thread overview | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 04, 2014 Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into this:
This program:
import std.array, std.algorithm;
int main(string[] argv) {
auto r = argv.filter!"a.length"().count();
return r&255;
}
compiles to:
00000000004052e0 <pure nothrow @property @safe bool std.array.empty!(immutable(char)[]).empty(const(immutable(char)[][]))>:
4052e0: 48 85 ff test %rdi,%rdi
4052e3: 0f 94 c0 sete %al
4052e6: c3 retq
00000000004052f0 <_Dmain>:
4052f0: 41 54 push %r12
4052f2: 49 89 f4 mov %rsi,%r12
4052f5: 55 push %rbp
4052f6: 48 89 fd mov %rdi,%rbp
4052f9: 53 push %rbx
4052fa: 48 83 ec 10 sub $0x10,%rsp
4052fe: 48 89 ef mov %rbp,%rdi
405301: 4c 89 e6 mov %r12,%rsi
405304: 4c 89 e3 mov %r12,%rbx
405307: e8 d4 ff ff ff callq 4052e0 <pure nothrow @property @safe bool std.array.empty!(immutable(char)[]).empty(const(immutable(char)[][]))>
40530c: 84 c0 test %al,%al
40530e: 75 18 jne 405328 <_Dmain+0x38>
405310: 48 8d 45 ff lea -0x1(%rbp),%rax
405314: 49 83 c4 10 add $0x10,%r12
405318: 48 83 3b 00 cmpq $0x0,(%rbx)
40531c: 75 0a jne 405328 <_Dmain+0x38>
40531e: 48 89 c5 mov %rax,%rbp
405321: eb db jmp 4052fe <_Dmain+0xe>
405323: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
405328: 48 89 ef mov %rbp,%rdi
40532b: 48 89 de mov %rbx,%rsi
40532e: 45 31 e4 xor %r12d,%r12d
405331: e8 aa ff ff ff callq 4052e0 <pure nothrow @property @safe bool std.array.empty!(immutable(char)[]).empty(const(immutable(char)[][]))>
405336: 84 c0 test %al,%al
405338: 75 2a jne 405364 <_Dmain+0x74>
40533a: 48 83 ed 01 sub $0x1,%rbp
40533e: 48 83 c3 10 add $0x10,%rbx
405342: 48 89 ef mov %rbp,%rdi
405345: 48 89 de mov %rbx,%rsi
405348: e8 93 ff ff ff callq 4052e0 <pure nothrow @property @safe bool std.array.empty!(immutable(char)[]).empty(const(immutable(char)[][]))>
40534d: 84 c0 test %al,%al
40534f: 74 27 je 405378 <_Dmain+0x88>
405351: 48 89 ef mov %rbp,%rdi
405354: 48 89 de mov %rbx,%rsi
405357: 49 83 c4 01 add $0x1,%r12
40535b: e8 80 ff ff ff callq 4052e0 <pure nothrow @property @safe bool std.array.empty!(immutable(char)[]).empty(const(immutable(char)[][]))>
405360: 84 c0 test %al,%al
405362: 74 d6 je 40533a <_Dmain+0x4a>
405364: 48 83 c4 10 add $0x10,%rsp
405368: 41 0f b6 c4 movzbl %r12b,%eax
40536c: 5b pop %rbx
40536d: 5d pop %rbp
40536e: 41 5c pop %r12
405370: c3 retq
405378: 48 83 3b 00 cmpq $0x0,(%rbx)
40537c: 48 8d 55 ff lea -0x1(%rbp),%rdx
405380: 75 cf jne 405351 <_Dmain+0x61>
405382: 48 89 d5 mov %rdx,%rbp
405385: eb b7 jmp 40533e <_Dmain+0x4e>
That trivial std.array.empty() function is for some reason not getting
inlined, leading to the catastrophic result above.
Also checked with an old 4.6 based gdc; that one manages to inline everything when using LTO (which the newer gdcs can't handle).
If the array is wrapped in a custom range like this:
import std.array, std.algorithm;
auto range(E)(E[] e) @property {
static struct AR {
E[] arr;
inout(E) front() inout @property { return arr[0]; }
bool empty() const @property { return !arr.length; }
void popFront() { arr = arr[1..$]; }
size_t length() @property const { return arr.length; }
}
return AR(e);
}
int main(string[] argv) {
auto r = argv.range.filter!"a.length"().count();
return r&255;
}
and compiled with the same (current 4.8-based) compiler and an identical cmdline, then the result turns into:
00000000004052e0 <_Dmain>:
4052e0: 48 85 ff test %rdi,%rdi
4052e3: 75 03 jne 4052e8 <_Dmain+0x8>
4052e5: 31 c0 xor %eax,%eax
4052e7: c3 retq
4052e8: 48 83 3e 00 cmpq $0x0,(%rsi)
4052ec: 75 10 jne 4052fe <_Dmain+0x1e>
4052ee: 48 83 c6 10 add $0x10,%rsi
4052f2: 48 83 ef 01 sub $0x1,%rdi
4052f6: 74 ed je 4052e5 <_Dmain+0x5>
4052f8: 48 83 3e 00 cmpq $0x0,(%rsi)
4052fc: 74 f0 je 4052ee <_Dmain+0xe>
4052fe: 31 c0 xor %eax,%eax
405300: eb 10 jmp 405312 <_Dmain+0x32>
405302: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
405308: 48 83 c6 10 add $0x10,%rsi
40530c: 48 83 3e 00 cmpq $0x0,(%rsi)
405310: 74 04 je 405316 <_Dmain+0x36>
405312: 48 83 c0 01 add $0x1,%rax
405316: 48 83 ef 01 sub $0x1,%rdi
40531a: 75 ec jne 405308 <_Dmain+0x28>
40531c: 0f b6 c0 movzbl %al,%eax
40531f: c3 retq
Which is much more reasonable, and shouldn't require such hacks.
I thought that inlining /templated/ functions across modules already worked;
is this a different problem, and, more importantly, is it fixable?
artur
| ||||
April 04, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | Am Fri, 04 Apr 2014 11:52:13 +0200 schrieb Artur Skawina <art.08.09@gmail.com>: > Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into > this: > > Which is much more reasonable, and shouldn't require such hacks. > I thought that inlining /templated/ functions across modules already > worked; is this a different problem, and, more importantly, is it > fixable? > > artur > Please try to reduce such examples in the future ;-) http://goo.gl/SJ0iEq http://goo.gl/ykumCI @property bool empty(T)(in T[] a) @safe pure nothrow it's the 'in' which causes inlining to fail (const also fails). | |||
April 04, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | On 04/04/14 15:14, Johannes Pfau wrote: > Am Fri, 04 Apr 2014 11:52:13 +0200 > schrieb Artur Skawina <art.08.09@gmail.com>: > >> Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into >> this: >> >> Which is much more reasonable, and shouldn't require such hacks. >> I thought that inlining /templated/ functions across modules already >> worked; is this a different problem, and, more importantly, is it >> fixable? > Please try to reduce such examples in the future ;-) Sorry. Yes, I should have tried harder. [I'm probably subconsciously avoiding going near any phobos code... :)] > http://goo.gl/SJ0iEq > http://goo.gl/ykumCI > > @property bool empty(T)(in T[] a) @safe pure nothrow > > it's the 'in' which causes inlining to fail (const also fails). Hmm, I remember const-args were a problem in the past, but I had thought this was already fixed. A quick search reveals: http://gdcproject.org/bugzilla/show_bug.cgi?id=37 (-ENOPERM) https://bitbucket.org/goshawk/gdc/issue/300/array-empty-function-does-not-get-inlined (which says WONTFIX, but IIRC Iain fixed) artur | |||
April 04, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
On 04/04/14 15:42, Artur Skawina wrote: > On 04/04/14 15:14, Johannes Pfau wrote: >> Am Fri, 04 Apr 2014 11:52:13 +0200 >> schrieb Artur Skawina <art.08.09@gmail.com>: >> >>> Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into >>> this: >>> >>> Which is much more reasonable, and shouldn't require such hacks. >>> I thought that inlining /templated/ functions across modules already >>> worked; is this a different problem, and, more importantly, is it >>> fixable? >> @property bool empty(T)(in T[] a) @safe pure nothrow >> >> it's the 'in' which causes inlining to fail (const also fails). > > Hmm, I remember const-args were a problem in the past, but I had thought this was already fixed. A quick search reveals: [...] Yep, I was remembering correctly: http://forum.dlang.org/post/mailman.33.1325763631.16222.d.gnu@puremagic.com [no idea how I managed to forget that report - this bug has exactly the same symptoms] And Iain actually did fix it back then: http://forum.dlang.org/post/mailman.221.1326102842.16222.d.gnu@puremagic.com http://forum.dlang.org/post/mailman.233.1326132966.16222.d.gnu@puremagic.com But somehow the bug is now back... artur | ||||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
On 4 April 2014 14:42, Artur Skawina <art.08.09@gmail.com> wrote: > On 04/04/14 15:14, Johannes Pfau wrote: >> Am Fri, 04 Apr 2014 11:52:13 +0200 >> schrieb Artur Skawina <art.08.09@gmail.com>: >> >>> Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into >>> this: >>> >>> Which is much more reasonable, and shouldn't require such hacks. >>> I thought that inlining /templated/ functions across modules already >>> worked; is this a different problem, and, more importantly, is it >>> fixable? > >> Please try to reduce such examples in the future ;-) > > Sorry. Yes, I should have tried harder. > > [I'm probably subconsciously avoiding going near any phobos code... :)] > > >> http://goo.gl/SJ0iEq >> http://goo.gl/ykumCI >> >> @property bool empty(T)(in T[] a) @safe pure nothrow >> >> it's the 'in' which causes inlining to fail (const also fails). > > Hmm, I remember const-args were a problem in the past, but I had thought this was already fixed. A quick search reveals: > > http://gdcproject.org/bugzilla/show_bug.cgi?id=37 (-ENOPERM) http://bugzilla.gdcproject.org/show_bug.cgi?id=37 I should figure out what to do with /bugzilla. Maybe just put in a rewrite rule. | ||||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
On 4 April 2014 14:42, Artur Skawina <art.08.09@gmail.com> wrote:
> On 04/04/14 15:14, Johannes Pfau wrote:
>> Am Fri, 04 Apr 2014 11:52:13 +0200
>> schrieb Artur Skawina <art.08.09@gmail.com>:
>>
>>> Built latest gcc4-8-based gdc (fdf0c614) today; immediately ran into
>>> this:
>>>
>>> Which is much more reasonable, and shouldn't require such hacks.
>>> I thought that inlining /templated/ functions across modules already
>>> worked; is this a different problem, and, more importantly, is it
>>> fixable?
>
>> Please try to reduce such examples in the future ;-)
>
> Sorry. Yes, I should have tried harder.
>
> [I'm probably subconsciously avoiding going near any phobos code... :)]
>
>
>> http://goo.gl/SJ0iEq
>> http://goo.gl/ykumCI
>>
>> @property bool empty(T)(in T[] a) @safe pure nothrow
>>
>> it's the 'in' which causes inlining to fail (const also fails).
>
> Hmm, I remember const-args were a problem in the past, but I had thought this was already fixed.
>
The switch -fdump-ipa-inline is your friend here:
---
Inline summary for D main/3 inlinable
self time: 22
global time: 0
self size: 14
global size: 0
min size: 0
self stack: 0
global stack: 0
size:4.000000, time:2.778000, predicate:(true)
size:3.000000, time:2.000000, predicate:(not inlined)
calls:
writeln/27 function not considered for inlining
loop depth: 0 freq: 389 size: 3 time: 12 callee size:12 stack: 0
empty/26 mismatched arguments
loop depth: 0 freq:1000 size: 4 time: 13 callee size: 2 stack: 0
---
Reason for no inline is "mismatched arguments" - which means that the caller and callee disagree on the arguments to pass to the function. The fix is to make sure that caller and callee arguments match when generating the function on both sides. We could prevent this from recurring by putting in an assert in the codegen.
| ||||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | Am Sat, 5 Apr 2014 07:37:00 +0100 schrieb Iain Buclaw <ibuclaw@gdcproject.org>: > > Reason for no inline is "mismatched arguments" - which means that the caller and callee disagree on the arguments to pass to the function. The fix is to make sure that caller and callee arguments match when generating the function on both sides. We could prevent this from recurring by putting in an assert in the codegen. Root cause is that const(char)[] is a distinct type compared to char[] so I think we need to make const(char)[] a variant of char[]. We could use build_variant_type_copy and then modify the copy to use the correct basetype. Here's a proof of concept, could you finish this Iain? (We should probably check all types which have a 'next' type if a similar change makes sense for these) --- a/gcc/d/d-ctype.cc +++ b/gcc/d/d-ctype.cc @@ -496,6 +496,21 @@ TypeDArray::toCtype (void) ctype = castMod(0)->toCtype(); ctype = insert_type_modifiers (ctype, mod); } + else if (!next->isNaked()) + { + tree ptrtype = next->toCtype(); + Type *dt = new TypeDArray(next->castMod(0)); + dt = dt->semantic(Loc(NULL, 0), NULL); + ctype = build_variant_type_copy(dt->toCtype()); + + //tree f1 = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("ptr"), build_pointer_type (ptrtype)); + //DECL_CONTEXT (f1) = ctype; + //TREE_CHAIN (f1) = NULL_TREE; + //TREE_CHAIN (TYPE_FIELDS (ctype)) = f1; + + TYPE_LANG_SPECIFIC (ctype) = build_d_type_lang_specific (this); + d_keep (ctype); + } else { tree lentype = Type::tsize_t->toCtype(); | |||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau Attachments:
| On 5 Apr 2014 13:45, "Johannes Pfau" <nospam@example.com> wrote:
>
> Am Sat, 5 Apr 2014 07:37:00 +0100
> schrieb Iain Buclaw <ibuclaw@gdcproject.org>:
> >
> > Reason for no inline is "mismatched arguments" - which means that the caller and callee disagree on the arguments to pass to the function. The fix is to make sure that caller and callee arguments match when generating the function on both sides. We could prevent this from recurring by putting in an assert in the codegen.
>
> Root cause is that const(char)[] is a distinct type compared to char[]
> so I think we need to make const(char)[] a variant of char[].
>
> We could use build_variant_type_copy and then modify the copy
> to use the correct basetype. Here's a proof of concept, could you finish
> this Iain?
>
> (We should probably check all types which have a 'next' type if a similar change makes sense for these)
>
I've had another thought for a while now that involves not constifying 'in' parameters, but at the same time not loosing its guarantee.
| |||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | Am Sat, 5 Apr 2014 15:31:30 +0100
schrieb Iain Buclaw <ibuclaw@gdcproject.org>:
>
> I've had another thought for a while now that involves not constifying 'in' parameters, but at the same time not loosing its guarantee.
>
But we'd want this to work/inline nevertheless, right?:
------------
void test(const(char)[] a)
{
}
char[] abc;
test(abc);
------------
Then we still need to tell GCC that const(char)[] is a variant of
char[] or it won't inline.
| |||
April 05, 2014 Re: Inlining problems again | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | Am Sat, 5 Apr 2014 15:31:30 +0100 schrieb Iain Buclaw <ibuclaw@gdcproject.org>: > On 5 Apr 2014 13:45, "Johannes Pfau" <nospam@example.com> wrote: > > > > Root cause is that const(char)[] is a distinct type compared to > > char[] so I think we need to make const(char)[] a variant of char[]. > > > > We could use build_variant_type_copy and then modify the copy > > to use the correct basetype. Here's a proof of concept, could you > > finish this Iain? > > > > (We should probably check all types which have a 'next' type if a similar change makes sense for these) > > > > I've had another thought for a while now that involves not constifying 'in' parameters, but at the same time not loosing its guarantee. > Related: http://gcc.gnu.org/ml/gcc/2005-01/msg01656.html | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply