This is an archive of the discontinued LLVM Phabricator instance.

CodeGen: Emit constant array temporaries into read-only globals.
ClosedPublic

Authored by bkramer on Mar 3 2015, 7:43 AM.

Details

Summary

Instead of creating a copy on the stack just stash them in a private
constant global. This saves both the copying overhead and the stack
space, and gives the optimizer more room to constant fold.

This tries to make array temporaries more similar to regular arrays,
they can't use the same logic because a temporary has no VarDecl to be
bound to so we roll our own version here.

The original use case for this optimization was code like

for (int i : {1, 2, 3, 4, 5, 6, 7, 8, 10})
  foo(i);

where without this patch (assuming that the loop is not unrolled) we
would alloca an array on the stack, copy the 10 values over and
iterate on that. With this patch we put the array in .text use it
directly. Apart from that case this helps on virtually any passing of
a constant std::initializer_list as a function argument.

Diff Detail

Repository
rL LLVM

Event Timeline

bkramer updated this revision to Diff 21105.Mar 3 2015, 7:43 AM
bkramer retitled this revision from to CodeGen: Emit constant array temporaries into read-only globals..
bkramer updated this object.
bkramer added a reviewer: rsmith.
bkramer added a subscriber: Unknown Object (MLST).

It would be nice to give it internal linkage instead of private. That way the linker could zap these globals for targets which use COFF when they are unreferenced.

This looks like a really nice improvement!

lib/CodeGen/CGExpr.cpp
313 ↗(On Diff #21105)

If this function is in a COMDAT, this GV should be in it too.

rsmith edited edge metadata.Mar 3 2015, 12:24 PM

I support the direction here, but this patch is non-conforming. Please disable this under -fno-merge-all-constants, as we do for the similar case with a const local variable. (Generally, I think this should match what we do for const local variables to the extent possible.)

lib/CodeGen/CGExpr.cpp
308 ↗(On Diff #21105)

For const locals, we also do this "optimization" for objects of record type (see CodeGenFunction::EmitAutoVarAlloca); any reason not to do the same here?

312 ↗(On Diff #21105)

I don't think this assert is correct. For any expression where isConstantInitializer returns true, we should be able to emit the expression as a constant (well, even here there are known bugs which we work around by checking the type is POD), but I don't think the reverse is generally true. If CodeGen finds some unexpected way to emit an expression as a constant, that's OK.

315 ↗(On Diff #21105)

This name doesn't make sense. All you know is that it's an array temporary.

bkramer updated this revision to Diff 21140.Mar 3 2015, 2:24 PM
bkramer edited edge metadata.
  • Disable optimization if -fno-merge-constants is specified
  • Enable optimization for records too and update test cases
  • Remove bad assert
  • Rename globals from ".initializer_list" to ".reftmp"
  • Put new globals in the same COMDAT as the containing function
rsmith added a comment.Mar 3 2015, 2:28 PM

Don't you also need a change to avoid performing the dynamic initialization of the temporary? (If not, where and how do we catch that case?)

Don't you also need a change to avoid performing the dynamic initialization of the temporary? (If not, where and how do we catch that case?)

Not sure if I understand. If the temporary needs dynamic initialization then we can't constant fold the initializer and fall through to the existing CreateMemTemp call.

rsmith added a comment.Mar 3 2015, 2:34 PM

Not sure if I understand. If the temporary needs dynamic initialization then we can't constant fold the initializer and fall through to the existing CreateMemTemp call.

Sure, but CreateMemTemp doesn't perform the initialization; that's done by the caller. How does the caller know to not do that?

rsmith added inline comments.Mar 3 2015, 2:38 PM
lib/CodeGen/CGExpr.cpp
390–395 ↗(On Diff #21140)

Ah, here's where we deal with this. This code wasn't intended to handle the new case, but it it does the right thing, so ... OK then :)

Please update this comment to say "if the temporary is a global or is a constant temporary that we promoted to a global" or similar.

bkramer updated this revision to Diff 21147.Mar 3 2015, 2:46 PM

Update comment

rsmith added a comment.Mar 3 2015, 3:26 PM

I'm fine with this once you guys are in agreement on the linkage/comdat stuff.

test/CodeGenCXX/cxx0x-initializer-array.cpp
47 ↗(On Diff #21147)

I'm not sure this test is still testing what it's supposed to test (that we emit dynamic zero initialization properly for array temporaries). Something like:

void g(p ptr) {
  f(a{ptr});
}

with the existing check for a store i32 -1, might work.

test/CodeGenCXX/cxx0x-initializer-references.cpp
39–54 ↗(On Diff #21147)

Likewise here, changing one of the constants to a reference to a function parameter would better preserve the intention of the test.

test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
67–68 ↗(On Diff #21147)

Can you avoid testing the names of these globals?

79 ↗(On Diff #21147)

Please don't check for the name of this type; that makes the test more fragile than necessary.

223–254 ↗(On Diff #21147)

Please make both of these cases use a non-constant initializer; part of the point of these tests seems to be to check that we get the lifetime right.

This is fine by me, just check with David about the linkage. It is not clear to me if using private on COFF right now would be just a missed optimization (and can be fixed in another patch) or a miscompile.

bkramer updated this revision to Diff 21213.Mar 4 2015, 10:20 AM

Update test cases for Richard's feedback.

This revision was automatically updated to reflect the committed changes.