Bug 15951 – Inefficiencies in struct initialization
Status
RESOLVED
Resolution
DUPLICATE
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-04-23T13:12:18Z
Last change time
2017-08-25T10:06:50Z
Keywords
performance
Assigned to
No Owner
Creator
Andrei Alexandrescu
Comments
Comment #0 by andrei — 2016-04-23T13:12:18Z
I list this as an enhancement but it's a blocker for RCStr, which has a relatively large inline buffer (64 bytes). If that's compulsively initialized, it makes RCStr nigh unusable as a competitive string.
The simplest case is an entirely uninitialized struct (with the equivalent C++ code):
https://godbolt.org/g/uItGGchttps://godbolt.org/g/6E1mkr
The initialization sequence of the D code is large and slow. What we really want is to write a 0 in the last byte:
https://godbolt.org/g/twDGbPhttps://godbolt.org/g/SRO5ql
Again the D version does a lot of unnecessary work. Where we want to get is this:
https://godbolt.org/g/B0Xvq3https://godbolt.org/g/OE6N8C
Here the D version should generate the same code as the C++ version.
Please don't use URL shorteners, as they 'expire' after a while and then the historical record of bugzilla becomes lost. Better yet, simply cut&paste the data here where practical, it isn't that large.
Comment #3 by andrei — 2016-04-23T21:26:45Z
(In reply to Walter Bright from comment #2)
> Please don't use URL shorteners, as they 'expire' after a while and then the
> historical record of bugzilla becomes lost. Better yet, simply cut&paste the
> data here where practical, it isn't that large.
The short versions are a feature of the site. -- Andrei
Comment #4 by johannespfau — 2016-06-20T13:17:28Z
We're (GDC team) are aware of these problems. Iain actually had to do quite some work to get GCC to emit such bad (but correct) code ;-) But we need a spec change / refinement to do anything about this.
There are 3 spec problems:
1 First we need to define what happens for a == b and a is b if the struct
typeof(a) contains =void initialized fields (including nesting). I propose to
simply make bitwise comparison of such structs invalid. The frontend should
error if it sees a is b or a == b if there's no opEquals for such structs.
2 The more complicated issue are 'alignment holes':
struct Foo
{
ubyte a = void;
uint b = void;
}
Even with rule 1 it is not legal to avoid initializing Foo: There are 3
padding bytes between a and b. Right now we always need to zero initialize
these padding bytes to make sure bitwise comparison works as expected. A user
might expect this to work:
Foo a, b;
a.a = b.a = 0;
a.b = b.b = 1;
assert(memcmp(a, b));
But this requires the compiler to initialize the alignment holes! The spec
clearly needs to define whether structs with =void fields have initialized
padding. For performance we'd want to not initialize these fields.
3 We need to specify that struct default values are part of the public interface
(like function default parameters). We always need to know which fields are
=void and for some more advanced optimizations we'd also need to know the
default values, so .di files shouldn't strip this information.
Then we have some solutions for the compiler changes:
1 Continue copying the .init symbol into the new variable, but do not copy
void-initialized fields and padding. This will reduce the amount of memory
copied, but it will still not be optimal.
2 Use struct literal constructors instead of a symbol. This way, the backend
knows we're assigning constant values and can embed the constants into the
instructions instead of doing memory/memory transfers. Main drawback:
possible executable bloat. Maybe we can use some sort of combination, so the
backend can decide whether it'll use a memcpy for big structs or hardcoded
constants.
(i.e. generate the same code as for Foo foo = {})
Notes for GDC/Iain:
1 We currently zero-initialize void fields in constructors. We'd have to keep
empty fields in visit(StructLiteralExp) and adjust build_struct_literal.
2 Is it possible to use a CONSTRUCTOR + TREE_ADDRESSABLE + DECL_ASSEMBLER_NAME/
DECL_NAME + DECL_EXTERNAL for the initializer symbol?
Comment #5 by johannespfau — 2016-07-06T14:36:48Z
Spec problem #4:
= void initializers for fields are not even mentioned in the spec. The only part mentioning = void initializers is for variables.
We can't really do anything about this in the compiler backends as long as there's no spec explaining this feature.