Skip to content

Commit caef91d

Browse files
committed
rustc: introduce layout::Abi for reduced general ABI "passing style".
1 parent 1dc572b commit caef91d

File tree

4 files changed

+105
-127
lines changed

4 files changed

+105
-127
lines changed

src/librustc/ty/layout.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,15 @@ impl<'a> FieldPlacement<'a> {
10541054
}
10551055
}
10561056

1057+
/// Describes how values of the type are passed by target ABIs,
1058+
/// in terms of categories of C types there are ABI rules for.
1059+
#[derive(Copy, Clone, Debug)]
1060+
pub enum Abi {
1061+
Scalar(Primitive),
1062+
Vector,
1063+
Aggregate
1064+
}
1065+
10571066
/// Type layout, from which size and alignment can be cheaply computed.
10581067
/// For ADTs, it also includes field placement and enum optimizations.
10591068
/// NOTE: Because Layout is interned, redundant information should be
@@ -1172,6 +1181,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
11721181
pub struct CachedLayout<'tcx> {
11731182
pub layout: &'tcx Layout,
11741183
pub fields: FieldPlacement<'tcx>,
1184+
pub abi: Abi,
11751185
}
11761186

11771187
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1258,9 +1268,24 @@ impl<'a, 'tcx> Layout {
12581268
}
12591269
}
12601270
};
1271+
let abi = match *layout {
1272+
Scalar { value, .. } |
1273+
RawNullablePointer { discr: value, .. } => Abi::Scalar(value),
1274+
CEnum { discr, .. } => Abi::Scalar(Int(discr)),
1275+
1276+
Vector { .. } => Abi::Vector,
1277+
1278+
Array { .. } |
1279+
FatPointer { .. } |
1280+
Univariant(_) |
1281+
UntaggedUnion(_) |
1282+
General { .. } |
1283+
StructWrappedNullablePointer { .. } => Abi::Aggregate
1284+
};
12611285
Ok(CachedLayout {
12621286
layout,
1263-
fields
1287+
fields,
1288+
abi
12641289
})
12651290
};
12661291
assert!(!ty.has_infer_types());
@@ -1670,7 +1695,8 @@ impl<'a, 'tcx> Layout {
16701695
let layout = cx.layout_of(normalized)?;
16711696
return Ok(CachedLayout {
16721697
layout: layout.layout,
1673-
fields: layout.fields
1698+
fields: layout.fields,
1699+
abi: layout.abi
16741700
});
16751701
}
16761702
ty::TyParam(_) => {
@@ -2158,6 +2184,7 @@ pub struct FullLayout<'tcx> {
21582184
pub variant_index: Option<usize>,
21592185
pub layout: &'tcx Layout,
21602186
pub fields: FieldPlacement<'tcx>,
2187+
pub abi: Abi,
21612188
}
21622189

21632190
impl<'tcx> Deref for FullLayout<'tcx> {
@@ -2225,7 +2252,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx
22252252
ty,
22262253
variant_index: None,
22272254
layout: cached.layout,
2228-
fields: cached.fields
2255+
fields: cached.fields,
2256+
abi: cached.abi
22292257
})
22302258
}
22312259
}
@@ -2255,7 +2283,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
22552283
ty,
22562284
variant_index: None,
22572285
layout: cached.layout,
2258-
fields: cached.fields
2286+
fields: cached.fields,
2287+
abi: cached.abi
22592288
})
22602289
}
22612290
}
@@ -2492,9 +2521,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement<'gcx> {
24922521
}
24932522
}
24942523

2524+
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
2525+
fn hash_stable<W: StableHasherResult>(&self,
2526+
hcx: &mut StableHashingContext<'gcx>,
2527+
hasher: &mut StableHasher<W>) {
2528+
use ty::layout::Abi::*;
2529+
mem::discriminant(self).hash_stable(hcx, hasher);
2530+
2531+
match *self {
2532+
Scalar(value) => {
2533+
value.hash_stable(hcx, hasher);
2534+
}
2535+
Vector => {
2536+
}
2537+
Aggregate => {
2538+
}
2539+
}
2540+
}
2541+
}
2542+
24952543
impl_stable_hash_for!(struct ::ty::layout::CachedLayout<'tcx> {
24962544
layout,
2497-
fields
2545+
fields,
2546+
abi
24982547
});
24992548

25002549
impl_stable_hash_for!(enum ::ty::layout::Integer {

src/librustc_trans/abi.rs

Lines changed: 31 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use rustc::ty::layout::{HasDataLayout, LayoutOf};
4040
use rustc_back::PanicStrategy;
4141

4242
use libc::c_uint;
43-
use std::iter;
43+
use std::{cmp, iter};
4444

4545
pub use syntax::abi::Abi;
4646
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
@@ -276,26 +276,17 @@ pub trait LayoutExt<'tcx> {
276276

277277
impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
278278
fn is_aggregate(&self) -> bool {
279-
match *self.layout {
280-
Layout::Scalar { .. } |
281-
Layout::RawNullablePointer { .. } |
282-
Layout::CEnum { .. } |
283-
Layout::Vector { .. } => false,
284-
285-
Layout::Array { .. } |
286-
Layout::FatPointer { .. } |
287-
Layout::Univariant { .. } |
288-
Layout::UntaggedUnion { .. } |
289-
Layout::General { .. } |
290-
Layout::StructWrappedNullablePointer { .. } => true
279+
match self.abi {
280+
layout::Abi::Scalar(_) |
281+
layout::Abi::Vector => false,
282+
layout::Abi::Aggregate => true
291283
}
292284
}
293285

294286
fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
295-
match *self.layout {
296-
// The primitives for this algorithm.
297-
Layout::Scalar { value, .. } |
298-
Layout::RawNullablePointer { discr: value, .. } => {
287+
match self.abi {
288+
// The primitive for this algorithm.
289+
layout::Abi::Scalar(value) => {
299290
let kind = match value {
300291
layout::Int(_) |
301292
layout::Pointer => RegKind::Integer,
@@ -308,70 +299,35 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
308299
})
309300
}
310301

311-
Layout::CEnum { .. } => {
312-
Some(Reg {
313-
kind: RegKind::Integer,
314-
size: self.size(ccx)
315-
})
316-
}
317-
318-
Layout::Vector { .. } => {
302+
layout::Abi::Vector => {
319303
Some(Reg {
320304
kind: RegKind::Vector,
321305
size: self.size(ccx)
322306
})
323307
}
324308

325-
Layout::Array { count, .. } => {
326-
if count > 0 {
327-
self.field(ccx, 0).homogeneous_aggregate(ccx)
328-
} else {
329-
None
309+
layout::Abi::Aggregate => {
310+
if let Layout::Array { count, .. } = *self.layout {
311+
if count > 0 {
312+
return self.field(ccx, 0).homogeneous_aggregate(ccx);
313+
}
330314
}
331-
}
332315

333-
Layout::Univariant(ref variant) => {
334-
let mut unaligned_offset = Size::from_bytes(0);
316+
let mut total = Size::from_bytes(0);
335317
let mut result = None;
336318

337-
for i in 0..self.fields.count() {
338-
if unaligned_offset != variant.offsets[i] {
339-
return None;
319+
let is_union = match self.fields {
320+
layout::FieldPlacement::Linear { stride, .. } => {
321+
stride.bytes() == 0
340322
}
323+
layout::FieldPlacement::Arbitrary { .. } => false
324+
};
341325

342-
let field = self.field(ccx, i);
343-
match (result, field.homogeneous_aggregate(ccx)) {
344-
// The field itself must be a homogeneous aggregate.
345-
(_, None) => return None,
346-
// If this is the first field, record the unit.
347-
(None, Some(unit)) => {
348-
result = Some(unit);
349-
}
350-
// For all following fields, the unit must be the same.
351-
(Some(prev_unit), Some(unit)) => {
352-
if prev_unit != unit {
353-
return None;
354-
}
355-
}
326+
for i in 0..self.fields.count() {
327+
if !is_union && total != self.fields.offset(i) {
328+
return None;
356329
}
357330

358-
// Keep track of the offset (without padding).
359-
unaligned_offset += field.size(ccx);
360-
}
361-
362-
// There needs to be no padding.
363-
if unaligned_offset != self.size(ccx) {
364-
None
365-
} else {
366-
result
367-
}
368-
}
369-
370-
Layout::UntaggedUnion { .. } => {
371-
let mut max = Size::from_bytes(0);
372-
let mut result = None;
373-
374-
for i in 0..self.fields.count() {
375331
let field = self.field(ccx, i);
376332
match (result, field.homogeneous_aggregate(ccx)) {
377333
// The field itself must be a homogeneous aggregate.
@@ -390,23 +346,20 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
390346

391347
// Keep track of the offset (without padding).
392348
let size = field.size(ccx);
393-
if size > max {
394-
max = size;
349+
if is_union {
350+
total = cmp::max(total, size);
351+
} else {
352+
total += size;
395353
}
396354
}
397355

398356
// There needs to be no padding.
399-
if max != self.size(ccx) {
357+
if total != self.size(ccx) {
400358
None
401359
} else {
402360
result
403361
}
404362
}
405-
406-
// Rust-specific types, which we can ignore for C ABIs.
407-
Layout::FatPointer { .. } |
408-
Layout::General { .. } |
409-
Layout::StructWrappedNullablePointer { .. } => None
410363
}
411364
}
412365
}
@@ -870,8 +823,9 @@ impl<'a, 'tcx> FnType<'tcx> {
870823
if abi == Abi::Rust || abi == Abi::RustCall ||
871824
abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
872825
let fixup = |arg: &mut ArgType<'tcx>| {
873-
if !arg.layout.is_aggregate() {
874-
return;
826+
match arg.layout.abi {
827+
layout::Abi::Aggregate => {}
828+
_ => return
875829
}
876830

877831
let size = arg.layout.size(ccx);

src/librustc_trans/cabi_x86_64.rs

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
6464
return Ok(());
6565
}
6666

67-
match *layout {
68-
Layout::Scalar { value, .. } |
69-
Layout::RawNullablePointer { discr: value, .. } => {
67+
match layout.abi {
68+
layout::Abi::Scalar(value) => {
7069
let reg = match value {
7170
layout::Int(_) |
7271
layout::Pointer => Class::Int,
@@ -76,47 +75,32 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
7675
unify(cls, off, reg);
7776
}
7877

79-
Layout::CEnum { .. } => {
80-
unify(cls, off, Class::Int);
81-
}
82-
83-
Layout::Vector { element, count } => {
78+
layout::Abi::Vector => {
8479
unify(cls, off, Class::Sse);
8580

8681
// everything after the first one is the upper
8782
// half of a register.
88-
let eltsz = element.size(ccx);
89-
for i in 1..count {
90-
unify(cls, off + eltsz * i, Class::SseUp);
83+
let eltsz = layout.field(ccx, 0).size(ccx);
84+
for i in 1..layout.fields.count() {
85+
unify(cls, off + eltsz * (i as u64), Class::SseUp);
9186
}
9287
}
9388

94-
Layout::Array { count, .. } => {
95-
if count > 0 {
96-
let elt = layout.field(ccx, 0);
97-
let eltsz = elt.size(ccx);
98-
for i in 0..count {
99-
classify(ccx, elt, cls, off + eltsz * i)?;
100-
}
89+
layout::Abi::Aggregate => {
90+
// FIXME(eddyb) have to work around Rust enums for now.
91+
// Fix is either guarantee no data where there is no field,
92+
// by putting variants in fields, or be more clever.
93+
match *layout {
94+
Layout::General { .. } |
95+
Layout::StructWrappedNullablePointer { .. } => return Err(Memory),
96+
_ => {}
10197
}
102-
}
103-
104-
Layout::Univariant(ref variant) => {
10598
for i in 0..layout.fields.count() {
106-
let field_off = off + variant.offsets[i];
99+
let field_off = off + layout.fields.offset(i);
107100
classify(ccx, layout.field(ccx, i), cls, field_off)?;
108101
}
109102
}
110103

111-
Layout::UntaggedUnion { .. } => {
112-
for i in 0..layout.fields.count() {
113-
classify(ccx, layout.field(ccx, i), cls, off)?;
114-
}
115-
}
116-
117-
Layout::FatPointer { .. } |
118-
Layout::General { .. } |
119-
Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
120104
}
121105

122106
Ok(())

src/librustc_trans/common.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use type_::Type;
2727
use value::Value;
2828
use rustc::traits;
2929
use rustc::ty::{self, Ty, TyCtxt};
30-
use rustc::ty::layout::{HasDataLayout, Layout, LayoutOf};
30+
use rustc::ty::layout::{self, HasDataLayout, Layout, LayoutOf};
3131
use rustc::ty::subst::{Kind, Subst, Substs};
3232
use rustc::hir;
3333

@@ -50,19 +50,10 @@ pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
5050

5151
pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
5252
let layout = ccx.layout_of(ty);
53-
match *layout {
54-
Layout::CEnum { .. } |
55-
Layout::Scalar { .. } |
56-
Layout::Vector { .. } => true,
57-
58-
Layout::FatPointer { .. } => false,
59-
60-
Layout::Array { .. } |
61-
Layout::Univariant { .. } |
62-
Layout::General { .. } |
63-
Layout::UntaggedUnion { .. } |
64-
Layout::RawNullablePointer { .. } |
65-
Layout::StructWrappedNullablePointer { .. } => {
53+
match layout.abi {
54+
layout::Abi::Scalar(_) | layout::Abi::Vector => true,
55+
56+
layout::Abi::Aggregate => {
6657
!layout.is_unsized() && layout.size(ccx).bytes() == 0
6758
}
6859
}

0 commit comments

Comments
 (0)