[Issue 15951] Inefficiencies in struct initialization

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Mon Jun 20 06:17:28 PDT 2016


https://issues.dlang.org/show_bug.cgi?id=15951

Johannes Pfau <johannespfau at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |johannespfau at gmail.com

--- Comment #4 from Johannes Pfau <johannespfau at gmail.com> ---
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?

--


More information about the Digitalmars-d-bugs mailing list