Possible solution to template bloat problem?
John Colvin
john.loughran.colvin at gmail.com
Mon Aug 19 15:11:38 PDT 2013
On Monday, 19 August 2013 at 20:23:46 UTC, H. S. Teoh wrote:
> With D's honestly awesome metaprogramming features, templates
> are liable
> to be (and in fact are) used a LOT. This leads to the
> unfortunate
> situation of template bloat: every time you instantiate a
> template, it
> adds yet another copy of the templated code into your object
> file. This
> gets worse when you use templated structs/classes, each of
> which may
> define some number of methods, and each instantiation adds yet
> another
> copy of all those methods.
>
> This is doubly bad if these templates are used only during
> compile-time,
> and never referenced during runtime. That's a lot of useless
> baggage in
> the final executable. Plus, it leads to issues like this one:
>
> http://d.puremagic.com/issues/show_bug.cgi?id=10833
>
> While looking at this bug, I got an idea: what if, instead of
> emitting
> template instantiations into the same object file as
> non-templated code,
> the compiler were to emit each instantiation into a separate
> static
> *library*? For instance, if you have code in program.d, then the
> compiler would emit non-templated code like main() into
> program.o, but
> all template instantiations get put in, say, libprogram.a. Then
> during
> link time, the compiler runs `ld -oprogram program.o
> libprogram.a`, and
> then the linker will pull in symbols from libprogram.a that are
> referenced by program.o.
>
> If we were to set things up so that libprogram.a contains a
> separate
> unit for each instantiated template function, then the linker
> would
> actually pull in only code that is actually referenced at
> runtime. For
> example, say our code looks like this:
>
> struct S(T) {
> T x;
> T method1(T t) { ... }
> T method2(T t) { ... }
> T method3(T t) { ... }
> }
> void main() {
> auto sbyte = S!byte();
> auto sint = S!int();
> auto sfloat = S!float();
>
> sbyte.method1(1);
> sint.method2(2);
> sfloat.method3(3.0);
> }
>
> Then the compiler would put main() in program.o, and *nothing
> else*. In
> program.o, there would be undefined references to
> S!byte.method1,
> S!int.method2, and S!float.method3, but not the actual code.
> Instead,
> when the compiler sees S!byte, S!int, and S!float, it puts all
> of the
> instantiated methods inside libprogram.a as separate units:
>
> libprogram.a:
> struct_S_byte_method1.o:
> S!byte.method1
> struct_S_byte_method2.o:
> S!byte.method2
> struct_S_byte_method3.o:
> S!byte.method3
> struct_S_int_method1.o:
> S!int.method1
> struct_S_int_method2.o:
> S!int.method2
> struct_S_int_method3.o:
> S!int.method3
> struct_S_float_method1.o:
> S!float.method1
> struct_S_float_method2.o:
> S!float.method2
> struct_S_float_method3.o:
> S!float.method3
>
> Since the compiler doesn't know at instantiation time which of
> these
> methods will actually be used, it simply emits all of them and
> puts them
> into the static library.
>
> Then at link-time, the compiler tells the linker to include
> libprogram.a
> when linking program.o. So the linker goes through each
> undefined
> reference, and resolves them by linking in the module in
> libprogram.a
> that defines said reference. So it would link in the code for
> S!byte.method1, S!int.method2, and S!float.method3. The other 6
> instantiations are not linked into the final executable,
> because they
> are never actually referenced by the runtime code.
>
> So this way, we minimize template bloat to only the code that's
> actually
> used at runtime. If a particular template function
> instantiation is only
> used during CTFE, for example, it would be present in
> libprogram.a but
> won't get linked, because none of the runtime code references
> it. This
> would fix bug 10833.
>
> Is this workable? Is it implementable in DMD?
>
>
> T
Without link-time optimisation, this prevents inlining doesn't it?
More information about the Digitalmars-d
mailing list