summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExpr.cpp
diff options
context:
space:
mode:
authorBenjamin Kramer <benny.kra@googlemail.com>2015-03-06 20:00:03 +0000
committerBenjamin Kramer <benny.kra@googlemail.com>2015-03-06 20:00:03 +0000
commit3d8aa5c77db1de8f5c913abdb63885cc4d9143c5 (patch)
tree033dee13a1df9d6fbdf7852bfabc93d4f14cd4af /clang/lib/CodeGen/CGExpr.cpp
parent898d11e86468564d796ec87457ca060320ff46a1 (diff)
downloadbcm5719-llvm-3d8aa5c77db1de8f5c913abdb63885cc4d9143c5.tar.gz
bcm5719-llvm-3d8aa5c77db1de8f5c913abdb63885cc4d9143c5.zip
CodeGen: Emit constant temporaries into read-only globals.
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. Differential Revision: http://reviews.llvm.org/D8034 llvm-svn: 231508
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp24
1 files changed, 22 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 78e80a15836..a1cbef26457 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -301,6 +301,25 @@ createReferenceTemporary(CodeGenFunction &CGF,
switch (M->getStorageDuration()) {
case SD_FullExpression:
case SD_Automatic:
+ // If we have a constant temporary array or record try to promote it into a
+ // constant global under the same rules a normal constant would've been
+ // promoted. This is easier on the optimizer and generally emits fewer
+ // instructions.
+ if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
+ (M->getType()->isArrayType() || M->getType()->isRecordType()) &&
+ CGF.CGM.isTypeConstant(M->getType(), true))
+ if (llvm::Constant *Init =
+ CGF.CGM.EmitConstantExpr(Inner, M->getType(), &CGF)) {
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
+ GV->setAlignment(
+ CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity());
+ // Put the new global in the same COMDAT the function containing the
+ // temporary is in.
+ GV->setComdat(CGF.CurFn->getComdat());
+ return GV;
+ }
return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
case SD_Thread:
@@ -370,8 +389,9 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
// Create and initialize the reference temporary.
llvm::Value *Object = createReferenceTemporary(*this, M, E);
if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
- // If the temporary is a global and has a constant initializer, we may
- // have already initialized it.
+ // If the temporary is a global and has a constant initializer or is a
+ // constant temporary that we promoted to a global, we may have already
+ // initialized it.
if (!Var->hasInitializer()) {
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
OpenPOWER on IntegriCloud