rustc_target: switch homogeneous_aggregate to returning Result.

This commit is contained in:
Eduard-Mihai Burtescu 2020-01-22 02:52:14 +02:00
parent 1d28952631
commit 8f81593d6c
13 changed files with 107 additions and 88 deletions

View File

@ -6,7 +6,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy, Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout, C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout,
{ {
arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
let size = arg.layout.size; let size = arg.layout.size;
// Ensure we have at most four uniquely addressable members. // Ensure we have at most four uniquely addressable members.

View File

@ -7,7 +7,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy, Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout, C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout,
{ {
arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
let size = arg.layout.size; let size = arg.layout.size;
// Ensure we have at most four uniquely addressable members. // Ensure we have at most four uniquely addressable members.

View File

@ -219,26 +219,47 @@ impl CastTarget {
} }
} }
/// Returns value from the `homogeneous_aggregate` test function. /// Return value from the `homogeneous_aggregate` test function.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum HomogeneousAggregate { pub enum HomogeneousAggregate {
/// Yes, all the "leaf fields" of this struct are passed in the /// Yes, all the "leaf fields" of this struct are passed in the
/// same way (specified in the `Reg` value). /// same way (specified in the `Reg` value).
Homogeneous(Reg), Homogeneous(Reg),
/// There are distinct leaf fields passed in different ways,
/// or this is uninhabited.
Heterogeneous,
/// There are no leaf fields at all. /// There are no leaf fields at all.
NoData, NoData,
} }
/// Error from the `homogeneous_aggregate` test function, indicating
/// there are distinct leaf fields passed in different ways,
/// or this is uninhabited.
#[derive(Copy, Clone, Debug)]
pub struct Heterogeneous;
impl HomogeneousAggregate { impl HomogeneousAggregate {
/// If this is a homogeneous aggregate, returns the homogeneous /// If this is a homogeneous aggregate, returns the homogeneous
/// unit, else `None`. /// unit, else `None`.
pub fn unit(self) -> Option<Reg> { pub fn unit(self) -> Option<Reg> {
if let HomogeneousAggregate::Homogeneous(r) = self { Some(r) } else { None } match self {
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
HomogeneousAggregate::NoData => None,
}
}
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
/// the same `struct`. Only succeeds if only one of them has any data,
/// or both units are identical.
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
match (self, other) {
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
if a != b {
return Err(Heterogeneous);
}
Ok(self)
}
}
} }
} }
@ -250,8 +271,8 @@ impl<'a, Ty> TyLayout<'a, Ty> {
} }
} }
/// Returns `true` if this layout is an aggregate containing fields of only /// Returns `Homogeneous` if this layout is an aggregate containing fields of
/// a single type (e.g., `(u32, u32)`). Such aggregates are often /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
/// special-cased in ABIs. /// special-cased in ABIs.
/// ///
/// Note: We generally ignore fields of zero-sized type when computing /// Note: We generally ignore fields of zero-sized type when computing
@ -260,13 +281,13 @@ impl<'a, Ty> TyLayout<'a, Ty> {
/// This is public so that it can be used in unit tests, but /// This is public so that it can be used in unit tests, but
/// should generally only be relevant to the ABI details of /// should generally only be relevant to the ABI details of
/// specific targets. /// specific targets.
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> HomogeneousAggregate pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
where where
Ty: TyLayoutMethods<'a, C> + Copy, Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = Self>, C: LayoutOf<Ty = Ty, TyLayout = Self>,
{ {
match self.abi { match self.abi {
Abi::Uninhabited => HomogeneousAggregate::Heterogeneous, Abi::Uninhabited => Err(Heterogeneous),
// The primitive for this algorithm. // The primitive for this algorithm.
Abi::Scalar(ref scalar) => { Abi::Scalar(ref scalar) => {
@ -274,80 +295,78 @@ impl<'a, Ty> TyLayout<'a, Ty> {
abi::Int(..) | abi::Pointer => RegKind::Integer, abi::Int(..) | abi::Pointer => RegKind::Integer,
abi::F32 | abi::F64 => RegKind::Float, abi::F32 | abi::F64 => RegKind::Float,
}; };
HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }) Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
} }
Abi::Vector { .. } => { Abi::Vector { .. } => {
assert!(!self.is_zst()); assert!(!self.is_zst());
HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, size: self.size }) Ok(HomogeneousAggregate::Homogeneous(Reg {
kind: RegKind::Vector,
size: self.size,
}))
} }
Abi::ScalarPair(..) | Abi::Aggregate { .. } => { Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
let mut total = Size::ZERO; // Helper for computing `homogenous_aggregate`, allowing a custom
let mut result = None; // starting offset (TODO(eddyb): use this to handle variants).
let from_fields_at =
|layout: Self,
start: Size|
-> Result<(HomogeneousAggregate, Size), Heterogeneous> {
let is_union = match layout.fields {
FieldPlacement::Array { count, .. } => {
assert_eq!(start, Size::ZERO);
let is_union = match self.fields { let result = if count > 0 {
FieldPlacement::Array { count, .. } => { layout.field(cx, 0).homogeneous_aggregate(cx)?
if count > 0 { } else {
return self.field(cx, 0).homogeneous_aggregate(cx); HomogeneousAggregate::NoData
} else { };
return HomogeneousAggregate::NoData; return Ok((result, layout.size));
} }
} FieldPlacement::Union(_) => true,
FieldPlacement::Union(_) => true, FieldPlacement::Arbitrary { .. } => false,
FieldPlacement::Arbitrary { .. } => false, };
};
for i in 0..self.fields.count() { let mut result = HomogeneousAggregate::NoData;
if !is_union && total != self.fields.offset(i) { let mut total = start;
return HomogeneousAggregate::Heterogeneous;
}
let field = self.field(cx, i); for i in 0..layout.fields.count() {
if !is_union && total != layout.fields.offset(i) {
return Err(Heterogeneous);
}
match (result, field.homogeneous_aggregate(cx)) { let field = layout.field(cx, i);
(_, HomogeneousAggregate::NoData) => {
// Ignore fields that have no data result = result.merge(field.homogeneous_aggregate(cx)?)?;
}
(_, HomogeneousAggregate::Heterogeneous) => { // Keep track of the offset (without padding).
// The field itself must be a homogeneous aggregate. let size = field.size;
return HomogeneousAggregate::Heterogeneous; if is_union {
} total = total.max(size);
// If this is the first field, record the unit. } else {
(None, HomogeneousAggregate::Homogeneous(unit)) => { total += size;
result = Some(unit);
}
// For all following fields, the unit must be the same.
(Some(prev_unit), HomogeneousAggregate::Homogeneous(unit)) => {
if prev_unit != unit {
return HomogeneousAggregate::Heterogeneous;
} }
} }
}
// Keep track of the offset (without padding). Ok((result, total))
let size = field.size; };
if is_union {
total = total.max(size); let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
} else {
total += size;
}
}
// There needs to be no padding. // There needs to be no padding.
if total != self.size { if total != self.size {
HomogeneousAggregate::Heterogeneous Err(Heterogeneous)
} else { } else {
match result { match result {
Some(reg) => { HomogeneousAggregate::Homogeneous(_) => {
assert_ne!(total, Size::ZERO); assert_ne!(total, Size::ZERO);
HomogeneousAggregate::Homogeneous(reg)
} }
None => { HomogeneousAggregate::NoData => {
assert_eq!(total, Size::ZERO); assert_eq!(total, Size::ZERO);
HomogeneousAggregate::NoData
} }
} }
Ok(result)
} }
} }
} }

View File

@ -22,7 +22,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy, Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout, C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout,
{ {
arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
// ELFv1 only passes one-member aggregates transparently. // ELFv1 only passes one-member aggregates transparently.
// ELFv2 passes up to eight uniquely addressable members. // ELFv2 passes up to eight uniquely addressable members.
if (abi == ELFv1 && arg.layout.size > unit.size) if (abi == ELFv1 && arg.layout.size > unit.size)

View File

@ -8,7 +8,7 @@ where
Ty: TyLayoutMethods<'a, C> + Copy, Ty: TyLayoutMethods<'a, C> + Copy,
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout, C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout,
{ {
arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
// Ensure we have at most eight uniquely addressable members. // Ensure we have at most eight uniquely addressable members.
if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() { if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
return None; return None;

View File

@ -7,7 +7,7 @@ where
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout, C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout,
{ {
if val.layout.is_aggregate() { if val.layout.is_aggregate() {
if let Some(unit) = val.layout.homogeneous_aggregate(cx).unit() { if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) {
let size = val.layout.size; let size = val.layout.size;
if unit.size == size { if unit.size == size {
val.cast_to(Uniform { unit, total: size }); val.cast_to(Uniform { unit, total: size });

View File

@ -100,7 +100,7 @@ where
}; };
// At this point we know this must be a primitive of sorts. // At this point we know this must be a primitive of sorts.
let unit = arg.layout.homogeneous_aggregate(cx).unit().unwrap(); let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
assert_eq!(unit.size, arg.layout.size); assert_eq!(unit.size, arg.layout.size);
if unit.kind == RegKind::Float { if unit.kind == RegKind::Float {
continue; continue;

View File

@ -20,7 +20,7 @@ pub struct Middle {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type TestMiddle = Middle; pub type TestMiddle = Middle;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
#[repr(C)] #[repr(C)]
pub struct Final { pub struct Final {
@ -31,6 +31,6 @@ pub struct Final {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type TestFinal = Final; pub type TestFinal = Final;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
fn main() { } fn main() { }

View File

@ -1,10 +1,10 @@
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:22:1 --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:22:1
| |
LL | pub type TestMiddle = Middle; LL | pub type TestMiddle = Middle;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:33:1 --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:33:1
| |
LL | pub type TestFinal = Final; LL | pub type TestFinal = Final;

View File

@ -52,22 +52,22 @@ pub struct WithEmptyRustEnum {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type Test1 = BaseCase; pub type Test1 = BaseCase;
//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type Test2 = WithPhantomData; pub type Test2 = WithPhantomData;
//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type Test3 = WithEmptyRustStruct; pub type Test3 = WithEmptyRustStruct;
//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type Test4 = WithTransitivelyEmptyRustStruct; pub type Test4 = WithTransitivelyEmptyRustStruct;
//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
pub type Test5 = WithEmptyRustEnum; pub type Test5 = WithEmptyRustEnum;
//~^ ERROR homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
fn main() { } fn main() { }

View File

@ -1,28 +1,28 @@
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:54:1 --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:54:1
| |
LL | pub type Test1 = BaseCase; LL | pub type Test1 = BaseCase;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:58:1 --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:58:1
| |
LL | pub type Test2 = WithPhantomData; LL | pub type Test2 = WithPhantomData;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:62:1 --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:62:1
| |
LL | pub type Test3 = WithEmptyRustStruct; LL | pub type Test3 = WithEmptyRustStruct;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:66:1 --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:66:1
| |
LL | pub type Test4 = WithTransitivelyEmptyRustStruct; LL | pub type Test4 = WithTransitivelyEmptyRustStruct;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:70:1 --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:70:1
| |
LL | pub type Test5 = WithEmptyRustEnum; LL | pub type Test5 = WithEmptyRustEnum;

View File

@ -57,7 +57,7 @@ struct Baz1 {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
type TestBaz1 = Baz1; type TestBaz1 = Baz1;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
#[repr(C)] #[repr(C)]
struct Baz2 { struct Baz2 {
@ -68,7 +68,7 @@ struct Baz2 {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
type TestBaz2 = Baz2; type TestBaz2 = Baz2;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
#[repr(C)] #[repr(C)]
struct Baz3 { struct Baz3 {
@ -79,7 +79,7 @@ struct Baz3 {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
type TestBaz3 = Baz3; type TestBaz3 = Baz3;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
#[repr(C)] #[repr(C)]
struct Baz4 { struct Baz4 {
@ -90,6 +90,6 @@ struct Baz4 {
#[rustc_layout(homogeneous_aggregate)] #[rustc_layout(homogeneous_aggregate)]
type TestBaz4 = Baz4; type TestBaz4 = Baz4;
//~^ ERROR homogeneous_aggregate: Homogeneous //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
fn main() { } fn main() { }

View File

@ -1,22 +1,22 @@
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/zero-sized-array-union.rs:59:1 --> $DIR/zero-sized-array-union.rs:59:1
| |
LL | type TestBaz1 = Baz1; LL | type TestBaz1 = Baz1;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/zero-sized-array-union.rs:70:1 --> $DIR/zero-sized-array-union.rs:70:1
| |
LL | type TestBaz2 = Baz2; LL | type TestBaz2 = Baz2;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/zero-sized-array-union.rs:81:1 --> $DIR/zero-sized-array-union.rs:81:1
| |
LL | type TestBaz3 = Baz3; LL | type TestBaz3 = Baz3;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: homogeneous_aggregate: Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }) error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size { raw: 4 } }))
--> $DIR/zero-sized-array-union.rs:92:1 --> $DIR/zero-sized-array-union.rs:92:1
| |
LL | type TestBaz4 = Baz4; LL | type TestBaz4 = Baz4;