1- // skip-filecheck
21// unit-test: ScalarReplacementOfAggregates
32// compile-flags: -Cpanic=abort
43// no-prefer-dynamic
@@ -13,28 +12,68 @@ impl Drop for Tag {
1312 fn drop ( & mut self ) { }
1413}
1514
15+ /// Check that SROA excludes structs with a `Drop` implementation.
1616pub fn dropping ( ) {
17+ // CHECK-LABEL: fn dropping(
18+
19+ // CHECK: [[aggregate:_[0-9]+]]: S;
20+
21+ // CHECK: bb0: {
22+ // CHECK: [[aggregate]] = S
1723 S ( Tag ( 0 ) , Tag ( 1 ) , Tag ( 2 ) ) . 1 ;
1824}
1925
26+ /// Check that SROA excludes enums.
2027pub fn enums ( a : usize ) -> usize {
28+ // CHECK-LABEL: fn enums(
29+
30+ // CHECK: [[enum:_[0-9]+]]: std::option::Option<usize>;
31+
32+ // CHECK: bb0: {
33+ // CHECK: [[enum]] = Option::<usize>::Some
34+ // CHECK: _5 = (([[enum]] as Some).0: usize)
35+ // CHECK: _0 = _5
2136 if let Some ( a) = Some ( a) { a } else { 0 }
2237}
2338
39+ /// Check that SROA destructures `U`.
2440pub fn structs ( a : f32 ) -> f32 {
41+ // CHECK-LABEL: fn structs(
2542 struct U {
2643 _foo : usize ,
2744 a : f32 ,
2845 }
29-
46+ // CHECK: [[ret:_0]]: f32;
47+ // CHECK: [[struct:_[0-9]+]]: structs::U;
48+ // CHECK: [[a_tmp:_[0-9]+]]: f32;
49+ // CHECK: [[foo:_[0-9]+]]: usize;
50+ // CHECK: [[a_ret:_[0-9]+]]: f32;
51+
52+ // CHECK: bb0: {
53+ // CHECK-NOT: [[struct]]
54+ // CHECK: [[a_tmp]] = _1;
55+ // CHECK-NOT: [[struct]]
56+ // CHECK: [[foo]] = const 0_usize;
57+ // CHECK-NOT: [[struct]]
58+ // CHECK: [[a_ret]] = move [[a_tmp]];
59+ // CHECK-NOT: [[struct]]
60+ // CHECK: _0 = [[a_ret]];
61+ // CHECK-NOT: [[struct]]
3062 U { _foo : 0 , a } . a
3163}
3264
65+ /// Check that SROA excludes unions.
3366pub fn unions ( a : f32 ) -> u32 {
67+ // CHECK-LABEL: fn unions(
3468 union Repr {
3569 f : f32 ,
3670 u : u32 ,
3771 }
72+ // CHECK: [[union:_[0-9]+]]: unions::Repr;
73+
74+ // CHECK: bb0: {
75+ // CHECK: [[union]] = Repr {
76+ // CHECK: _0 = ([[union]].1: u32)
3877 unsafe { Repr { f : a } . u }
3978}
4079
@@ -46,11 +85,21 @@ struct Foo {
4685 d : Option < isize > ,
4786}
4887
49- fn g ( ) -> u32 {
50- 3
51- }
52-
88+ /// Check that non-escaping uses of a struct are destructured.
5389pub fn flat ( ) {
90+ // CHECK-LABEL: fn flat(
91+
92+ // CHECK: [[struct:_[0-9]+]]: Foo;
93+
94+ // CHECK: bb0: {
95+ // CHECK: [[init_unit:_[0-9]+]] = ();
96+ // CHECK: [[init_opt_isize:_[0-9]+]] = Option::<isize>::Some
97+
98+ // CHECK: [[destr_five:_[0-9]+]] = const 5_u8;
99+ // CHECK: [[destr_unit:_[0-9]+]] = move [[init_unit]];
100+ // CHECK: [[destr_a:_[0-9]+]] = const "a";
101+ // CHECK: [[destr_opt_isize:_[0-9]+]] = move [[init_opt_isize]];
102+
54103 let Foo { a, b, c, d } = Foo { a : 5 , b : ( ) , c : "a" , d : Some ( -4 ) } ;
55104 let _ = a;
56105 let _ = b;
@@ -65,6 +114,10 @@ struct Escaping {
65114 c : u32 ,
66115}
67116
117+ fn g ( ) -> u32 {
118+ 3
119+ }
120+
68121fn f ( a : * const u32 ) {
69122 println ! ( "{}" , unsafe { * a. add( 2 ) } ) ;
70123}
@@ -76,31 +129,91 @@ fn f(a: *const u32) {
76129// of them to `f`. However, this would lead to a miscompilation because `b` and `c`
77130// might no longer appear right after `a` in memory.
78131pub fn escaping ( ) {
132+ // CHECK-LABEL: fn escaping(
133+
134+ // CHECK: [[ptr:_[0-9]+]]: *const u32;
135+ // CHECK: [[ref:_[0-9]+]]: &u32;
136+ // CHECK: [[struct:_[0-9]+]]: Escaping;
137+ // CHECK: [[a:_[0-9]+]]: u32;
138+
139+ // CHECK: bb0: {
140+ // CHECK: [[struct]] = Escaping {
141+ // CHECK: [[ref]] = &([[struct]].0
142+ // CHECK: [[ptr]] = &raw const (*[[ref]]);
79143 f ( & Escaping { a : 1 , b : 2 , c : g ( ) } . a ) ;
80144}
81145
146+ /// Check that copies from an internal struct are destructured and reassigned to
147+ /// the original struct.
82148fn copies ( x : Foo ) {
149+ // CHECK-LABEL: fn copies(
150+
151+ // CHECK: [[external:_[0-9]+]]: Foo) ->
152+ // CHECK: [[internal:_[0-9]+]]: Foo;
153+ // CHECK: [[byte:_[0-9]+]]: u8;
154+ // CHECK: [[unit:_[0-9]+]]: ();
155+ // CHECK: [[str:_[0-9]+]]: &str;
156+ // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option<isize>;
157+
158+ // CHECK: bb0: {
159+ // CHECK: [[byte]] = ([[external]].0
160+ // CHECK: [[unit]] = ([[external]].1
161+ // CHECK: [[str]] = ([[external]].2
162+ // CHECK: [[opt_isize]] = ([[external]].3
163+
83164 let y = x;
84165 let t = y. a ;
85166 let u = y. c ;
86167 let z = y;
87168 let a = z. b ;
88169}
89170
171+ /// Check that copies from an internal struct are destructured and reassigned to
172+ /// the original struct.
90173fn ref_copies ( x : & Foo ) {
174+ // CHECK-LABEL: fn ref_copies(
175+
176+ // CHECK: [[external:_[0-9]+]]: &Foo) ->
177+ // CHECK: [[internal:_[0-9]+]]: Foo;
178+ // CHECK: [[byte:_[0-9]+]]: u8;
179+ // CHECK: [[unit:_[0-9]+]]: ();
180+ // CHECK: [[str:_[0-9]+]]: &str;
181+ // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option<isize>;
182+
183+ // CHECK: bb0: {
184+ // CHECK: [[byte]] = ((*[[external]]).0
185+ // CHECK: [[unit]] = ((*[[external]]).1
186+ // CHECK: [[str]] = ((*[[external]]).2
187+ // CHECK: [[opt_isize]] = ((*[[external]]).3
188+
91189 let y = * x;
92190 let t = y. a ;
93191 let u = y. c ;
94192}
95193
194+ /// Check that deaggregated assignments from constants are placed after the constant's
195+ /// assignment. Also check that copying field accesses from the copy of the constant are
196+ /// reassigned to copy from the constant.
96197fn constant ( ) {
198+ // CHECK-LABEL: constant(
199+
200+ // CHECK: [[constant:_[0-9]+]]: (usize, u8);
201+ // CHECK: [[t:_[0-9]+]]: usize;
202+ // CHECK: [[u:_[0-9]+]]: u8;
203+
204+ // CHECK: bb0: {
205+ // CHECK-NOT: [[constant]]
206+ // CHECK: [[constant]] = const
207+ // CHECK: [[t]] = move ([[constant]].0: usize)
208+ // CHECK: [[u]] = move ([[constant]].1: u8)
97209 const U : ( usize , u8 ) = ( 5 , 9 ) ;
98210 let y = U ;
99211 let t = y. 0 ;
100212 let u = y. 1 ;
101213}
102214
103215fn main ( ) {
216+ // CHECK-LABEL: fn main(
104217 dropping ( ) ;
105218 enums ( 5 ) ;
106219 structs ( 5. ) ;
0 commit comments