xref: /aosp_15_r20/external/clang/test/CodeGenCXX/nrvo.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
2*67e74705SXin Li // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
3*67e74705SXin Li 
4*67e74705SXin Li // Test code generation for the named return value optimization.
5*67e74705SXin Li class X {
6*67e74705SXin Li public:
7*67e74705SXin Li   X();
8*67e74705SXin Li   X(const X&);
9*67e74705SXin Li   ~X();
10*67e74705SXin Li };
11*67e74705SXin Li 
12*67e74705SXin Li template<typename T> struct Y {
13*67e74705SXin Li   Y();
fY14*67e74705SXin Li   static Y f() {
15*67e74705SXin Li     Y y;
16*67e74705SXin Li     return y;
17*67e74705SXin Li   }
18*67e74705SXin Li };
19*67e74705SXin Li 
20*67e74705SXin Li // CHECK-LABEL: define void @_Z5test0v
21*67e74705SXin Li // CHECK-EH-LABEL: define void @_Z5test0v
test0()22*67e74705SXin Li X test0() {
23*67e74705SXin Li   X x;
24*67e74705SXin Li   // CHECK:          call {{.*}} @_ZN1XC1Ev
25*67e74705SXin Li   // CHECK-NEXT:     ret void
26*67e74705SXin Li 
27*67e74705SXin Li   // CHECK-EH:       call {{.*}} @_ZN1XC1Ev
28*67e74705SXin Li   // CHECK-EH-NEXT:  ret void
29*67e74705SXin Li   return x;
30*67e74705SXin Li }
31*67e74705SXin Li 
32*67e74705SXin Li // CHECK-LABEL: define void @_Z5test1b(
33*67e74705SXin Li // CHECK-EH-LABEL: define void @_Z5test1b(
test1(bool B)34*67e74705SXin Li X test1(bool B) {
35*67e74705SXin Li   // CHECK:      tail call {{.*}} @_ZN1XC1Ev
36*67e74705SXin Li   // CHECK-NEXT: ret void
37*67e74705SXin Li   X x;
38*67e74705SXin Li   if (B)
39*67e74705SXin Li     return (x);
40*67e74705SXin Li   return x;
41*67e74705SXin Li   // CHECK-EH:      tail call {{.*}} @_ZN1XC1Ev
42*67e74705SXin Li   // CHECK-EH-NEXT: ret void
43*67e74705SXin Li }
44*67e74705SXin Li 
45*67e74705SXin Li // CHECK-LABEL: define void @_Z5test2b
46*67e74705SXin Li // CHECK-EH-LABEL: define void @_Z5test2b
47*67e74705SXin Li // CHECK-EH-SAME:  personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
test2(bool B)48*67e74705SXin Li X test2(bool B) {
49*67e74705SXin Li   // No NRVO.
50*67e74705SXin Li 
51*67e74705SXin Li   X x;
52*67e74705SXin Li   X y;
53*67e74705SXin Li   if (B)
54*67e74705SXin Li     return y;
55*67e74705SXin Li   return x;
56*67e74705SXin Li 
57*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XC1Ev
58*67e74705SXin Li   // CHECK-NEXT: {{.*}} getelementptr inbounds %class.X, %class.X* %y, i32 0, i32 0
59*67e74705SXin Li   // CHECK-NEXT: call void @llvm.lifetime.start
60*67e74705SXin Li   // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev
61*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XC1ERKS_
62*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XC1ERKS_
63*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XD1Ev
64*67e74705SXin Li   // CHECK-NEXT: call void @llvm.lifetime.end
65*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XD1Ev
66*67e74705SXin Li   // CHECK-NEXT: call void @llvm.lifetime.end
67*67e74705SXin Li   // CHECK: ret void
68*67e74705SXin Li 
69*67e74705SXin Li   // The block ordering in the -fexceptions IR is unfortunate.
70*67e74705SXin Li 
71*67e74705SXin Li   // CHECK-EH:      call void @llvm.lifetime.start
72*67e74705SXin Li   // CHECK-EH-NEXT: call {{.*}} @_ZN1XC1Ev
73*67e74705SXin Li   // CHECK-EH:      call void @llvm.lifetime.start
74*67e74705SXin Li   // CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev
75*67e74705SXin Li   // -> %invoke.cont, %lpad
76*67e74705SXin Li 
77*67e74705SXin Li   // %invoke.cont:
78*67e74705SXin Li   // CHECK-EH:      br i1
79*67e74705SXin Li   // -> %if.then, %if.end
80*67e74705SXin Li 
81*67e74705SXin Li   // %if.then: returning 'x'
82*67e74705SXin Li   // CHECK-EH:      invoke {{.*}} @_ZN1XC1ERKS_
83*67e74705SXin Li   // -> %cleanup, %lpad1
84*67e74705SXin Li 
85*67e74705SXin Li   // %lpad: landing pad for ctor of 'y', dtor of 'y'
86*67e74705SXin Li   // CHECK-EH:      [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 }
87*67e74705SXin Li   // CHECK-EH-NEXT:   cleanup
88*67e74705SXin Li   // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
89*67e74705SXin Li   // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
90*67e74705SXin Li   // CHECK-EH-NEXT: br label
91*67e74705SXin Li   // -> %eh.cleanup
92*67e74705SXin Li 
93*67e74705SXin Li   // %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
94*67e74705SXin Li   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
95*67e74705SXin Li   // -> %eh.cleanup, %terminate.lpad
96*67e74705SXin Li 
97*67e74705SXin Li   // %if.end: returning 'y'
98*67e74705SXin Li   // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
99*67e74705SXin Li   // -> %cleanup, %lpad1
100*67e74705SXin Li 
101*67e74705SXin Li   // %cleanup: normal cleanup for 'y'
102*67e74705SXin Li   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
103*67e74705SXin Li   // -> %invoke.cont11, %lpad
104*67e74705SXin Li 
105*67e74705SXin Li   // %invoke.cont11: normal cleanup for 'x'
106*67e74705SXin Li   // CHECK-EH:      call void @llvm.lifetime.end
107*67e74705SXin Li   // CHECK-EH-NEXT: call {{.*}} @_ZN1XD1Ev
108*67e74705SXin Li   // CHECK-EH-NEXT: call void @llvm.lifetime.end
109*67e74705SXin Li   // CHECK-EH-NEXT: ret void
110*67e74705SXin Li 
111*67e74705SXin Li   // %eh.cleanup:  EH cleanup for 'x'
112*67e74705SXin Li   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
113*67e74705SXin Li   // -> %invoke.cont17, %terminate.lpad
114*67e74705SXin Li 
115*67e74705SXin Li   // %invoke.cont17: rethrow block for %eh.cleanup.
116*67e74705SXin Li   // This really should be elsewhere in the function.
117*67e74705SXin Li   // CHECK-EH:      resume { i8*, i32 }
118*67e74705SXin Li 
119*67e74705SXin Li   // %terminate.lpad: terminate landing pad.
120*67e74705SXin Li   // CHECK-EH:      [[T0:%.*]] = landingpad { i8*, i32 }
121*67e74705SXin Li   // CHECK-EH-NEXT:   catch i8* null
122*67e74705SXin Li   // CHECK-EH-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
123*67e74705SXin Li   // CHECK-EH-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
124*67e74705SXin Li   // CHECK-EH-NEXT: unreachable
125*67e74705SXin Li 
126*67e74705SXin Li }
127*67e74705SXin Li 
128*67e74705SXin Li // CHECK-LABEL: define void @_Z5test3b
test3(bool B)129*67e74705SXin Li X test3(bool B) {
130*67e74705SXin Li   // CHECK: tail call {{.*}} @_ZN1XC1Ev
131*67e74705SXin Li   // CHECK-NOT: call {{.*}} @_ZN1XC1ERKS_
132*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XC1Ev
133*67e74705SXin Li   // CHECK: call {{.*}} @_ZN1XC1ERKS_
134*67e74705SXin Li   if (B) {
135*67e74705SXin Li     X y;
136*67e74705SXin Li     return y;
137*67e74705SXin Li   }
138*67e74705SXin Li   // FIXME: we should NRVO this variable too.
139*67e74705SXin Li   X x;
140*67e74705SXin Li   return x;
141*67e74705SXin Li }
142*67e74705SXin Li 
143*67e74705SXin Li extern "C" void exit(int) throw();
144*67e74705SXin Li 
145*67e74705SXin Li // CHECK-LABEL: define void @_Z5test4b
test4(bool B)146*67e74705SXin Li X test4(bool B) {
147*67e74705SXin Li   {
148*67e74705SXin Li     // CHECK: tail call {{.*}} @_ZN1XC1Ev
149*67e74705SXin Li     X x;
150*67e74705SXin Li     // CHECK: br i1
151*67e74705SXin Li     if (B)
152*67e74705SXin Li       return x;
153*67e74705SXin Li   }
154*67e74705SXin Li   // CHECK: tail call {{.*}} @_ZN1XD1Ev
155*67e74705SXin Li   // CHECK: tail call void @exit(i32 1)
156*67e74705SXin Li   exit(1);
157*67e74705SXin Li }
158*67e74705SXin Li 
159*67e74705SXin Li #ifdef __EXCEPTIONS
160*67e74705SXin Li // CHECK-EH-LABEL: define void @_Z5test5
161*67e74705SXin Li void may_throw();
test5()162*67e74705SXin Li X test5() {
163*67e74705SXin Li   try {
164*67e74705SXin Li     may_throw();
165*67e74705SXin Li   } catch (X x) {
166*67e74705SXin Li     // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
167*67e74705SXin Li     // CHECK-EH: call void @__cxa_end_catch()
168*67e74705SXin Li     // CHECK-EH: ret void
169*67e74705SXin Li     return x;
170*67e74705SXin Li   }
171*67e74705SXin Li }
172*67e74705SXin Li #endif
173*67e74705SXin Li 
174*67e74705SXin Li // rdar://problem/10430868
175*67e74705SXin Li // CHECK-LABEL: define void @_Z5test6v
test6()176*67e74705SXin Li X test6() {
177*67e74705SXin Li   X a __attribute__((aligned(8)));
178*67e74705SXin Li   return a;
179*67e74705SXin Li   // CHECK:      [[A:%.*]] = alloca [[X:%.*]], align 8
180*67e74705SXin Li   // CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds %class.X, %class.X* [[A]], i32 0, i32 0
181*67e74705SXin Li   // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[PTR]])
182*67e74705SXin Li   // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* nonnull [[A]])
183*67e74705SXin Li   // CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* nonnull dereferenceable({{[0-9]+}}) [[A]])
184*67e74705SXin Li   // CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* nonnull [[A]])
185*67e74705SXin Li   // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[PTR]])
186*67e74705SXin Li   // CHECK-NEXT: ret void
187*67e74705SXin Li }
188*67e74705SXin Li 
189*67e74705SXin Li // CHECK-LABEL: define void @_Z5test7b
test7(bool b)190*67e74705SXin Li X test7(bool b) {
191*67e74705SXin Li   // CHECK: tail call {{.*}} @_ZN1XC1Ev
192*67e74705SXin Li   // CHECK-NEXT: ret
193*67e74705SXin Li   if (b) {
194*67e74705SXin Li     X x;
195*67e74705SXin Li     return x;
196*67e74705SXin Li   }
197*67e74705SXin Li   return X();
198*67e74705SXin Li }
199*67e74705SXin Li 
200*67e74705SXin Li // CHECK-LABEL: define void @_Z5test8b
test8(bool b)201*67e74705SXin Li X test8(bool b) {
202*67e74705SXin Li   // CHECK: tail call {{.*}} @_ZN1XC1Ev
203*67e74705SXin Li   // CHECK-NEXT: ret
204*67e74705SXin Li   if (b) {
205*67e74705SXin Li     X x;
206*67e74705SXin Li     return x;
207*67e74705SXin Li   } else {
208*67e74705SXin Li     X y;
209*67e74705SXin Li     return y;
210*67e74705SXin Li   }
211*67e74705SXin Li }
212*67e74705SXin Li 
test9()213*67e74705SXin Li Y<int> test9() {
214*67e74705SXin Li   Y<int>::f();
215*67e74705SXin Li }
216*67e74705SXin Li 
217*67e74705SXin Li // CHECK-LABEL: define linkonce_odr void @_ZN1YIiE1fEv
218*67e74705SXin Li // CHECK: tail call {{.*}} @_ZN1YIiEC1Ev
219*67e74705SXin Li 
220*67e74705SXin Li // CHECK-EH: attributes [[NR_NUW]] = { noreturn nounwind }
221