Skip to content

Commit f229949

Browse files
committed
Auto merge of #108106 - the8472:layout-opt, r=wesleywiser
Improve niche placement by trying two strategies and picking the better result Fixes #104807 Fixes #105371 Determining which sort order is better requires calculating the struct size (so we can calculate the niche offset). But that in turn depends on the field order, so happens after sorting. So the simple way to solve that is to run the whole thing twice and pick the better result. 1st commit is just code motion, the meat is in the later ones.
2 parents af2c7e0 + 61fb5a9 commit f229949

12 files changed

+511
-298
lines changed

compiler/rustc_abi/src/layout.rs

+371-210
Large diffs are not rendered by default.

tests/codegen/issues/issue-103840.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// compile-flags: -O
2+
// min-llvm-version: 16.0
23
#![crate_type = "lib"]
34

45
pub fn foo(t: &mut Vec<usize>) {

tests/codegen/issues/issue-105386-ub-in-debuginfo.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ pub fn outer_function(x: S, y: S) -> usize {
1919
// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
2020
// CHECK-NOT: [[load:%.*]] = load ptr, ptr
2121
// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
22-
// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x
22+
// CHECK: [[inner:%.*]] = getelementptr inbounds %"{{.*}}", ptr [[spill]]
23+
// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[inner]], ptr {{align .*}} %x

tests/codegen/issues/issue-86106.rs

+9-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// min-llvm-version: 15.0
2+
// only-64bit llvm appears to use stores instead of memset on 32bit
23
// compile-flags: -C opt-level=3 -Z merge-functions=disabled
34

45
// The below two functions ensure that both `String::new()` and `"".to_string()`
@@ -9,25 +10,19 @@
910
// CHECK-LABEL: define void @string_new
1011
#[no_mangle]
1112
pub fn string_new() -> String {
12-
// CHECK-NOT: load i8
13-
// CHECK: store i{{32|64}}
13+
// CHECK: store ptr inttoptr
1414
// CHECK-NEXT: getelementptr
15-
// CHECK-NEXT: store ptr
16-
// CHECK-NEXT: getelementptr
17-
// CHECK-NEXT: store i{{32|64}}
15+
// CHECK-NEXT: call void @llvm.memset
1816
// CHECK-NEXT: ret void
1917
String::new()
2018
}
2119

2220
// CHECK-LABEL: define void @empty_to_string
2321
#[no_mangle]
2422
pub fn empty_to_string() -> String {
25-
// CHECK-NOT: load i8
26-
// CHECK: store i{{32|64}}
27-
// CHECK-NEXT: getelementptr
28-
// CHECK-NEXT: store ptr
23+
// CHECK: store ptr inttoptr
2924
// CHECK-NEXT: getelementptr
30-
// CHECK-NEXT: store i{{32|64}}
25+
// CHECK-NEXT: call void @llvm.memset
3126
// CHECK-NEXT: ret void
3227
"".to_string()
3328
}
@@ -38,25 +33,19 @@ pub fn empty_to_string() -> String {
3833
// CHECK-LABEL: @empty_vec
3934
#[no_mangle]
4035
pub fn empty_vec() -> Vec<u8> {
41-
// CHECK: store i{{32|64}}
42-
// CHECK-NOT: load i8
36+
// CHECK: store ptr inttoptr
4337
// CHECK-NEXT: getelementptr
44-
// CHECK-NEXT: store ptr
45-
// CHECK-NEXT: getelementptr
46-
// CHECK-NEXT: store i{{32|64}}
38+
// CHECK-NEXT: call void @llvm.memset
4739
// CHECK-NEXT: ret void
4840
vec![]
4941
}
5042

5143
// CHECK-LABEL: @empty_vec_clone
5244
#[no_mangle]
5345
pub fn empty_vec_clone() -> Vec<u8> {
54-
// CHECK: store i{{32|64}}
55-
// CHECK-NOT: load i8
56-
// CHECK-NEXT: getelementptr
57-
// CHECK-NEXT: store ptr
46+
// CHECK: store ptr inttoptr
5847
// CHECK-NEXT: getelementptr
59-
// CHECK-NEXT: store i{{32|64}}
48+
// CHECK-NEXT: call void @llvm.memset
6049
// CHECK-NEXT: ret void
6150
vec![].clone()
6251
}

tests/ui/async-await/future-sizes/async-awaiting-fut.stdout

+18-22
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,34 @@ print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2]`:
22
print-type-size discriminant: 1 bytes
33
print-type-size variant `Unresumed`: 0 bytes
44
print-type-size variant `Suspend0`: 3077 bytes
5-
print-type-size local `.__awaitee`: 3077 bytes, offset: 0 bytes, alignment: 1 bytes
5+
print-type-size local `.__awaitee`: 3077 bytes
66
print-type-size variant `Returned`: 0 bytes
77
print-type-size variant `Panicked`: 0 bytes
88
print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]`: 3077 bytes, alignment: 1 bytes
99
print-type-size discriminant: 1 bytes
10-
print-type-size variant `Unresumed`: 2051 bytes
11-
print-type-size padding: 1026 bytes
12-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
10+
print-type-size variant `Unresumed`: 1025 bytes
11+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
1312
print-type-size variant `Suspend0`: 2052 bytes
14-
print-type-size local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
15-
print-type-size local `..generator_field4`: 1 bytes
13+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
1614
print-type-size padding: 1 bytes
17-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
15+
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
16+
print-type-size local `..generator_field4`: 1 bytes
1817
print-type-size local `.__awaitee`: 1 bytes
1918
print-type-size variant `Suspend1`: 3076 bytes
20-
print-type-size padding: 1024 bytes
19+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
20+
print-type-size padding: 1026 bytes
2121
print-type-size local `..generator_field4`: 1 bytes, alignment: 1 bytes
22-
print-type-size padding: 1 bytes
23-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
2422
print-type-size local `.__awaitee`: 1025 bytes
2523
print-type-size variant `Suspend2`: 2052 bytes
26-
print-type-size local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
27-
print-type-size local `..generator_field4`: 1 bytes
24+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
2825
print-type-size padding: 1 bytes
29-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
26+
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
27+
print-type-size local `..generator_field4`: 1 bytes
3028
print-type-size local `.__awaitee`: 1 bytes
31-
print-type-size variant `Returned`: 2051 bytes
32-
print-type-size padding: 1026 bytes
33-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
34-
print-type-size variant `Panicked`: 2051 bytes
35-
print-type-size padding: 1026 bytes
36-
print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
29+
print-type-size variant `Returned`: 1025 bytes
30+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
31+
print-type-size variant `Panicked`: 1025 bytes
32+
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
3733
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
3834
print-type-size field `.value`: 3077 bytes
3935
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
@@ -43,11 +39,11 @@ print-type-size field `.value`: 3077 bytes
4339
print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]`: 1025 bytes, alignment: 1 bytes
4440
print-type-size discriminant: 1 bytes
4541
print-type-size variant `Unresumed`: 1024 bytes
46-
print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
42+
print-type-size upvar `.arg`: 1024 bytes
4743
print-type-size variant `Returned`: 1024 bytes
48-
print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
44+
print-type-size upvar `.arg`: 1024 bytes
4945
print-type-size variant `Panicked`: 1024 bytes
50-
print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
46+
print-type-size upvar `.arg`: 1024 bytes
5147
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
5248
print-type-size field `.value`: 1025 bytes
5349
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes

tests/ui/async-await/future-sizes/large-arg.stdout

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ print-type-size type: `[async fn body@$DIR/large-arg.rs:6:21: 8:2]`: 3076 bytes,
22
print-type-size discriminant: 1 bytes
33
print-type-size variant `Unresumed`: 0 bytes
44
print-type-size variant `Suspend0`: 3075 bytes
5-
print-type-size local `.__awaitee`: 3075 bytes, offset: 0 bytes, alignment: 1 bytes
5+
print-type-size local `.__awaitee`: 3075 bytes
66
print-type-size variant `Returned`: 0 bytes
77
print-type-size variant `Panicked`: 0 bytes
88
print-type-size type: `[async fn body@$DIR/large-arg.rs:10:30: 12:2]`: 3075 bytes, alignment: 1 bytes
99
print-type-size discriminant: 1 bytes
1010
print-type-size variant `Unresumed`: 1024 bytes
11-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
11+
print-type-size upvar `.t`: 1024 bytes
1212
print-type-size variant `Suspend0`: 3074 bytes
13-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
13+
print-type-size upvar `.t`: 1024 bytes
1414
print-type-size local `.__awaitee`: 2050 bytes
1515
print-type-size variant `Returned`: 1024 bytes
16-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
16+
print-type-size upvar `.t`: 1024 bytes
1717
print-type-size variant `Panicked`: 1024 bytes
18-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
18+
print-type-size upvar `.t`: 1024 bytes
1919
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
2020
print-type-size field `.value`: 3075 bytes
2121
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
@@ -25,14 +25,14 @@ print-type-size field `.value`: 3075 bytes
2525
print-type-size type: `[async fn body@$DIR/large-arg.rs:13:26: 15:2]`: 2050 bytes, alignment: 1 bytes
2626
print-type-size discriminant: 1 bytes
2727
print-type-size variant `Unresumed`: 1024 bytes
28-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
28+
print-type-size upvar `.t`: 1024 bytes
2929
print-type-size variant `Suspend0`: 2049 bytes
30-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
30+
print-type-size upvar `.t`: 1024 bytes
3131
print-type-size local `.__awaitee`: 1025 bytes
3232
print-type-size variant `Returned`: 1024 bytes
33-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
33+
print-type-size upvar `.t`: 1024 bytes
3434
print-type-size variant `Panicked`: 1024 bytes
35-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
35+
print-type-size upvar `.t`: 1024 bytes
3636
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
3737
print-type-size field `.value`: 2050 bytes
3838
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
@@ -42,11 +42,11 @@ print-type-size field `.value`: 2050 bytes
4242
print-type-size type: `[async fn body@$DIR/large-arg.rs:16:26: 18:2]`: 1025 bytes, alignment: 1 bytes
4343
print-type-size discriminant: 1 bytes
4444
print-type-size variant `Unresumed`: 1024 bytes
45-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
45+
print-type-size upvar `.t`: 1024 bytes
4646
print-type-size variant `Returned`: 1024 bytes
47-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
47+
print-type-size upvar `.t`: 1024 bytes
4848
print-type-size variant `Panicked`: 1024 bytes
49-
print-type-size upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
49+
print-type-size upvar `.t`: 1024 bytes
5050
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 1025 bytes, alignment: 1 bytes
5151
print-type-size field `.value`: 1025 bytes
5252
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 1025 bytes, alignment: 1 bytes

tests/ui/consts/const-eval/raw-bytes.32bit.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec
465465
|
466466
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
467467
= note: the raw bytes of the constant (size: 8, align: 4) {
468-
00 10 00 00 00 00 00 00 │ ........
468+
00 00 00 00 00 10 00 00 │ ........
469469
}
470470

471471
error[E0080]: it is undefined behavior to use this value
@@ -476,7 +476,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche
476476
|
477477
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
478478
= note: the raw bytes of the constant (size: 8, align: 4) {
479-
09 00 00 00 03 00 00 00 │ ........
479+
03 00 00 00 09 00 00 00 │ ........
480480
}
481481

482482
error[E0080]: it is undefined behavior to use this value

tests/ui/consts/const-eval/raw-bytes.64bit.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec
465465
|
466466
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
467467
= note: the raw bytes of the constant (size: 16, align: 8) {
468-
00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
468+
00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 │ ................
469469
}
470470

471471
error[E0080]: it is undefined behavior to use this value
@@ -476,7 +476,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche
476476
|
477477
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
478478
= note: the raw bytes of the constant (size: 16, align: 8) {
479-
09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
479+
03 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 │ ................
480480
}
481481

482482
error[E0080]: it is undefined behavior to use this value

tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr

+20-20
Original file line numberDiff line numberDiff line change
@@ -370,31 +370,31 @@ error: layout_of(NicheFirst) = Layout {
370370
pref: $PREF_ALIGN,
371371
},
372372
abi: ScalarPair(
373-
Union {
373+
Initialized {
374374
value: Int(
375375
I8,
376376
false,
377377
),
378+
valid_range: 0..=4,
378379
},
379-
Initialized {
380+
Union {
380381
value: Int(
381382
I8,
382383
false,
383384
),
384-
valid_range: 0..=4,
385385
},
386386
),
387387
fields: Arbitrary {
388388
offsets: [
389-
Size(1 bytes),
389+
Size(0 bytes),
390390
],
391391
memory_index: [
392392
0,
393393
],
394394
},
395395
largest_niche: Some(
396396
Niche {
397-
offset: Size(1 bytes),
397+
offset: Size(0 bytes),
398398
value: Int(
399399
I8,
400400
false,
@@ -429,29 +429,29 @@ error: layout_of(NicheFirst) = Layout {
429429
I8,
430430
false,
431431
),
432-
valid_range: 0..=255,
432+
valid_range: 0..=2,
433433
},
434434
Initialized {
435435
value: Int(
436436
I8,
437437
false,
438438
),
439-
valid_range: 0..=2,
439+
valid_range: 0..=255,
440440
},
441441
),
442442
fields: Arbitrary {
443443
offsets: [
444-
Size(1 bytes),
445444
Size(0 bytes),
445+
Size(1 bytes),
446446
],
447447
memory_index: [
448-
1,
449448
0,
449+
1,
450450
],
451451
},
452452
largest_niche: Some(
453453
Niche {
454-
offset: Size(1 bytes),
454+
offset: Size(0 bytes),
455455
value: Int(
456456
I8,
457457
false,
@@ -514,31 +514,31 @@ error: layout_of(NicheSecond) = Layout {
514514
pref: $PREF_ALIGN,
515515
},
516516
abi: ScalarPair(
517-
Union {
517+
Initialized {
518518
value: Int(
519519
I8,
520520
false,
521521
),
522+
valid_range: 0..=4,
522523
},
523-
Initialized {
524+
Union {
524525
value: Int(
525526
I8,
526527
false,
527528
),
528-
valid_range: 0..=4,
529529
},
530530
),
531531
fields: Arbitrary {
532532
offsets: [
533-
Size(1 bytes),
533+
Size(0 bytes),
534534
],
535535
memory_index: [
536536
0,
537537
],
538538
},
539539
largest_niche: Some(
540540
Niche {
541-
offset: Size(1 bytes),
541+
offset: Size(0 bytes),
542542
value: Int(
543543
I8,
544544
false,
@@ -573,29 +573,29 @@ error: layout_of(NicheSecond) = Layout {
573573
I8,
574574
false,
575575
),
576-
valid_range: 0..=255,
576+
valid_range: 0..=2,
577577
},
578578
Initialized {
579579
value: Int(
580580
I8,
581581
false,
582582
),
583-
valid_range: 0..=2,
583+
valid_range: 0..=255,
584584
},
585585
),
586586
fields: Arbitrary {
587587
offsets: [
588-
Size(0 bytes),
589588
Size(1 bytes),
589+
Size(0 bytes),
590590
],
591591
memory_index: [
592-
0,
593592
1,
593+
0,
594594
],
595595
},
596596
largest_niche: Some(
597597
Niche {
598-
offset: Size(1 bytes),
598+
offset: Size(0 bytes),
599599
value: Int(
600600
I8,
601601
false,

0 commit comments

Comments
 (0)