teak-llvm/clang/test/CodeGenCXX/cxx0x-initializer-array.cpp
Benjamin Kramer 3d8aa5c77d 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
2015-03-06 20:00:03 +00:00

113 lines
2.4 KiB
C++

// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -S -emit-llvm -o - %s -Wno-address-of-temporary | FileCheck %s
// CHECK: @[[THREE_NULL_MEMPTRS:.*]] = private constant [3 x i32] [i32 -1, i32 -1, i32 -1]
struct A { int a[1]; };
typedef A x[];
int f() {
x{{{1}}};
// CHECK-LABEL: define i32 @_Z1fv
// CHECK: store i32 1
// (It's okay if the output changes here, as long as we don't crash.)
return 0;
}
namespace ValueInitArrayOfMemPtr {
struct S {};
typedef int (S::*p);
typedef p a[3];
void f(const a &);
struct Agg1 {
int n;
p x;
};
struct Agg2 {
int n;
a x;
};
struct S1 {
p x;
S1();
};
// CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1fEi
void f(int n) {
Agg1 a = { n };
// CHECK: store i32 -1,
Agg2 b = { n };
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* bitcast ([3 x i32]* @[[THREE_NULL_MEMPTRS]] to i8*), i32 12, i32 4, i1 false)
}
// Test dynamic initialization.
// CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEMNS_1SEi
void g(p ptr) {
// CHECK: store i32 -1,
f(a{ptr});
}
}
namespace array_dtor {
struct S { S(); ~S(); };
using T = S[3];
void f(const T &);
void f(T *);
// CHECK-LABEL: define void @_ZN10array_dtor1gEv(
void g() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
// Construct loop.
// CHECK: call void @_ZN10array_dtor1SC1Ev(
// CHECK: br i1
// CHECK: call void @_ZN10array_dtor1fERA3_KNS_1SE(
// CHECK: br
// Destruct loop.
// CHECK: call void @_ZN10array_dtor1SD1Ev(
// CHECK: br i1
f(T{});
// CHECK: ret void
}
// CHECK-LABEL: define void @_ZN10array_dtor1hEv(
void h() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
// CHECK: call void @_ZN10array_dtor1SC1Ev(
// CHECK: br i1
T &&t = T{};
// CHECK: call void @_ZN10array_dtor1fERA3_KNS_1SE(
// CHECK: br
f(t);
// CHECK: call void @_ZN10array_dtor1SD1Ev(
// CHECK: br i1
// CHECK: ret void
}
// CHECK-LABEL: define void @_ZN10array_dtor1iEv(
void i() {
// CHECK: %[[ARRAY:.*]] = alloca [3 x
// CHECK: br
// CHECK: call void @_ZN10array_dtor1SC1Ev(
// CHECK: br i1
// CHECK: call void @_ZN10array_dtor1fEPA3_NS_1SE(
// CHECK: br
// CHECK: call void @_ZN10array_dtor1SD1Ev(
// CHECK: br i1
f(&T{});
// CHECK: ret void
}
}