1 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
2 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
3 
4 // Test code generation for the named return value optimization.
5 class X {
6 public:
7   X();
8   X(const X&);
9   ~X();
10 };
11 
12 // CHECK-LABEL: define void @_Z5test0v
13 // CHECK-EH-LABEL: define void @_Z5test0v
14 X test0() {
15   X x;
16   // CHECK:          call {{.*}} @_ZN1XC1Ev
17   // CHECK-NEXT:     ret void
18 
19   // CHECK-EH:       call {{.*}} @_ZN1XC1Ev
20   // CHECK-EH-NEXT:  ret void
21   return x;
22 }
23 
24 // CHECK-LABEL: define void @_Z5test1b(
25 // CHECK-EH-LABEL: define void @_Z5test1b(
26 X test1(bool B) {
27   // CHECK:      tail call {{.*}} @_ZN1XC1Ev
28   // CHECK-NEXT: ret void
29   X x;
30   if (B)
31     return (x);
32   return x;
33   // CHECK-EH:      tail call {{.*}} @_ZN1XC1Ev
34   // CHECK-EH-NEXT: ret void
35 }
36 
37 // CHECK-LABEL: define void @_Z5test2b
38 // CHECK-EH-LABEL: define void @_Z5test2b
39 X test2(bool B) {
40   // No NRVO.
41 
42   X x;
43   X y;
44   if (B)
45     return y;
46   return x;
47 
48   // CHECK: call {{.*}} @_ZN1XC1Ev
49   // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev
50   // CHECK: call {{.*}} @_ZN1XC1ERKS_
51   // CHECK: call {{.*}} @_ZN1XC1ERKS_
52   // CHECK: call {{.*}} @_ZN1XD1Ev
53   // CHECK: call {{.*}} @_ZN1XD1Ev
54   // CHECK: ret void
55 
56   // The block ordering in the -fexceptions IR is unfortunate.
57 
58   // CHECK-EH:      call {{.*}} @_ZN1XC1Ev
59   // CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev
60   // -> %invoke.cont, %lpad
61 
62   // %invoke.cont:
63   // CHECK-EH:      br i1
64   // -> %if.then, %if.end
65 
66   // %if.then: returning 'x'
67   // CHECK-EH:      invoke {{.*}} @_ZN1XC1ERKS_
68   // -> %cleanup, %lpad1
69 
70   // %lpad: landing pad for ctor of 'y', dtor of 'y'
71   // CHECK-EH:      [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
72   // CHECK-EH-NEXT:   cleanup
73   // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
74   // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
75   // CHECK-EH-NEXT: br label
76   // -> %eh.cleanup
77 
78   // %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
79   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
80   // -> %eh.cleanup, %terminate.lpad
81 
82   // %if.end: returning 'y'
83   // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
84   // -> %cleanup, %lpad1
85 
86   // %cleanup: normal cleanup for 'y'
87   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
88   // -> %invoke.cont11, %lpad
89 
90   // %invoke.cont11: normal cleanup for 'x'
91   // CHECK-EH:      call {{.*}} @_ZN1XD1Ev
92   // CHECK-EH-NEXT: ret void
93 
94   // %eh.cleanup:  EH cleanup for 'x'
95   // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
96   // -> %invoke.cont17, %terminate.lpad
97 
98   // %invoke.cont17: rethrow block for %eh.cleanup.
99   // This really should be elsewhere in the function.
100   // CHECK-EH:      resume { i8*, i32 }
101 
102   // %terminate.lpad: terminate landing pad.
103   // CHECK-EH:      [[T0:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
104   // CHECK-EH-NEXT:   catch i8* null
105   // CHECK-EH-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
106   // CHECK-EH-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
107   // CHECK-EH-NEXT: unreachable
108 
109 }
110 
111 X test3(bool B) {
112   // FIXME: We don't manage to apply NRVO here, although we could.
113   {
114     X y;
115     return y;
116   }
117   X x;
118   return x;
119 }
120 
121 extern "C" void exit(int) throw();
122 
123 // CHECK-LABEL: define void @_Z5test4b
124 X test4(bool B) {
125   {
126     // CHECK: tail call {{.*}} @_ZN1XC1Ev
127     X x;
128     // CHECK: br i1
129     if (B)
130       return x;
131   }
132   // CHECK: tail call {{.*}} @_ZN1XD1Ev
133   // CHECK: tail call void @exit(i32 1)
134   exit(1);
135 }
136 
137 #ifdef __EXCEPTIONS
138 // CHECK-EH-LABEL: define void @_Z5test5
139 void may_throw();
140 X test5() {
141   try {
142     may_throw();
143   } catch (X x) {
144     // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
145     // CHECK-EH: call void @__cxa_end_catch()
146     // CHECK-EH: ret void
147     return x;
148   }
149 }
150 #endif
151 
152 // rdar://problem/10430868
153 // CHECK-LABEL: define void @_Z5test6v
154 X test6() {
155   X a __attribute__((aligned(8)));
156   return a;
157   // CHECK:      [[A:%.*]] = alloca [[X:%.*]], align 8
158   // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* [[A]])
159   // CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* [[A]])
160   // CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* [[A]])
161   // CHECK-NEXT: ret void
162 }
163 
164 // CHECK-EH: attributes [[NR_NUW]] = { noreturn nounwind }
165