mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 19:36:05 +00:00

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
82 lines
2.2 KiB
C++
82 lines
2.2 KiB
C++
// RUN: %clang_cc1 -std=c++11 -S -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
|
|
|
|
namespace reference {
|
|
struct A {
|
|
int i1, i2;
|
|
};
|
|
|
|
void single_init() {
|
|
// No superfluous instructions allowed here, they could be
|
|
// hiding extra temporaries.
|
|
|
|
// CHECK: store i32 1, i32*
|
|
// CHECK-NEXT: store i32* %{{.*}}, i32**
|
|
const int &cri2a = 1;
|
|
|
|
// CHECK-NEXT: store i32 1, i32*
|
|
// CHECK-NEXT: store i32* %{{.*}}, i32**
|
|
const int &cri1a = {1};
|
|
|
|
// CHECK-NEXT: store i32 1, i32*
|
|
int i = 1;
|
|
// CHECK-NEXT: store i32* %{{.*}}, i32**
|
|
int &ri1a = {i};
|
|
|
|
// CHECK-NEXT: bitcast
|
|
// CHECK-NEXT: memcpy
|
|
A a{1, 2};
|
|
// CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
|
|
A &ra1a = {a};
|
|
|
|
using T = A&;
|
|
// CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
|
|
A &ra1b = T{a};
|
|
|
|
// CHECK-NEXT: ret
|
|
}
|
|
|
|
void reference_to_aggregate(int i) {
|
|
// CHECK: getelementptr {{.*}}, i32 0, i32 0
|
|
// CHECK-NEXT: store i32 1
|
|
// CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1
|
|
// CHECK-NEXT: %[[I1:.*]] = load i32, i32*
|
|
// CHECK-NEXT: store i32 %[[I1]]
|
|
// CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
|
|
const A &ra1{1, i};
|
|
|
|
// CHECK-NEXT: getelementptr inbounds [3 x i32], [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0
|
|
// CHECK-NEXT: store i32 1
|
|
// CHECK-NEXT: getelementptr inbounds i32, i32* %{{.*}}, i{{32|64}} 1
|
|
// CHECK-NEXT: store i32 2
|
|
// CHECK-NEXT: getelementptr inbounds i32, i32* %{{.*}}, i{{32|64}} 1
|
|
// CHECK-NEXT: %[[I2:.*]] = load i32, i32*
|
|
// CHECK-NEXT: store i32 %[[I2]]
|
|
// CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
|
|
const int (&arrayRef)[] = {1, 2, i};
|
|
|
|
// CHECK: store %{{.*}}* @{{.*}}, %{{.*}}** %{{.*}}, align
|
|
const A &constra1{1, 2};
|
|
|
|
// CHECK-NEXT: store [3 x i32]* @{{.*}}, [3 x i32]** %{{.*}}, align
|
|
const int (&constarrayRef)[] = {1, 2, 3};
|
|
|
|
// CHECK-NEXT: ret
|
|
}
|
|
|
|
struct B {
|
|
B();
|
|
~B();
|
|
};
|
|
|
|
void single_init_temp_cleanup()
|
|
{
|
|
// Ensure lifetime extension.
|
|
|
|
// CHECK: call %"struct.reference::B"* @_ZN9reference1BC1Ev
|
|
// CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
|
|
const B &rb{ B() };
|
|
// CHECK: call %"struct.reference::B"* @_ZN9reference1BD1Ev
|
|
}
|
|
|
|
}
|