rustc: give Layout::CEnum a discriminant field like Layout::General.
This commit is contained in:
parent
d318b9c27b
commit
658ebfc788
2 changed files with 55 additions and 55 deletions
|
@ -1203,8 +1203,7 @@ impl<'a, 'tcx> Layout {
|
||||||
let success = |layout| {
|
let success = |layout| {
|
||||||
let layout = tcx.intern_layout(layout);
|
let layout = tcx.intern_layout(layout);
|
||||||
let fields = match *layout {
|
let fields = match *layout {
|
||||||
Scalar(_) |
|
Scalar(_) => {
|
||||||
CEnum { .. } => {
|
|
||||||
FieldPlacement::union(0)
|
FieldPlacement::union(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1241,6 +1240,7 @@ impl<'a, 'tcx> Layout {
|
||||||
FieldPlacement::union(def.struct_variant().fields.len())
|
FieldPlacement::union(def.struct_variant().fields.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEnum { .. } |
|
||||||
General { .. } => FieldPlacement::union(1),
|
General { .. } => FieldPlacement::union(1),
|
||||||
|
|
||||||
NullablePointer { ref discr_offset, .. } => {
|
NullablePointer { ref discr_offset, .. } => {
|
||||||
|
@ -2356,6 +2356,7 @@ impl<'a, 'tcx> FullLayout<'tcx> {
|
||||||
match self.variant_index {
|
match self.variant_index {
|
||||||
None => match *self.layout {
|
None => match *self.layout {
|
||||||
// Discriminant field for enums (where applicable).
|
// Discriminant field for enums (where applicable).
|
||||||
|
CEnum { discr, .. } |
|
||||||
General { discr, .. } |
|
General { discr, .. } |
|
||||||
NullablePointer { discr, .. } => {
|
NullablePointer { discr, .. } => {
|
||||||
return [discr.to_ty(tcx)][i];
|
return [discr.to_ty(tcx)][i];
|
||||||
|
|
|
@ -235,7 +235,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||||
|
|
||||||
// Discriminant field of enums.
|
// Discriminant field of enums.
|
||||||
match *l {
|
match *l {
|
||||||
layout::General { .. } |
|
|
||||||
layout::NullablePointer { .. } if l.variant_index.is_none() => {
|
layout::NullablePointer { .. } if l.variant_index.is_none() => {
|
||||||
let ty = ccx.llvm_type_of(field.ty);
|
let ty = ccx.llvm_type_of(field.ty);
|
||||||
let size = field.size(ccx).bytes();
|
let size = field.size(ccx).bytes();
|
||||||
|
@ -350,60 +349,66 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for cases where the discriminant is simply loaded.
|
|
||||||
fn load_discr(self, bcx: &Builder, discr: layout::Primitive, min: u64, max: u64) -> ValueRef {
|
|
||||||
if let layout::Int(ity, _) = discr {
|
|
||||||
let bits = ity.size().bits();
|
|
||||||
assert!(bits <= 64);
|
|
||||||
let bits = bits as usize;
|
|
||||||
let mask = !0u64 >> (64 - bits);
|
|
||||||
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
|
|
||||||
// However, that is fine here (it would still represent the full range),
|
|
||||||
if max.wrapping_add(1) & mask == min & mask {
|
|
||||||
// i.e., if the range is everything. The lo==hi case would be
|
|
||||||
// rejected by the LLVM verifier (it would mean either an
|
|
||||||
// empty set, which is impossible, or the entire range of the
|
|
||||||
// type, which is pointless).
|
|
||||||
} else {
|
|
||||||
// llvm::ConstantRange can deal with ranges that wrap around,
|
|
||||||
// so an overflow on (max + 1) is fine.
|
|
||||||
return bcx.load_range_assert(self.llval, min, max.wrapping_add(1),
|
|
||||||
/* signed: */ llvm::True,
|
|
||||||
self.alignment.non_abi());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bcx.load(self.llval, self.alignment.non_abi())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtain the actual discriminant of a value.
|
/// Obtain the actual discriminant of a value.
|
||||||
pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
|
pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
|
||||||
let l = bcx.ccx.layout_of(self.ty.to_ty(bcx.tcx()));
|
let l = bcx.ccx.layout_of(self.ty.to_ty(bcx.tcx()));
|
||||||
|
|
||||||
let cast_to = bcx.ccx.immediate_llvm_type_of(cast_to);
|
let cast_to = bcx.ccx.immediate_llvm_type_of(cast_to);
|
||||||
let (val, discr) = match *l {
|
match *l {
|
||||||
layout::Univariant { .. } |
|
layout::Univariant { .. } |
|
||||||
layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
|
layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
|
||||||
layout::CEnum { discr, min, max, .. } => {
|
_ => {}
|
||||||
(self.load_discr(bcx, discr, min, max), discr)
|
}
|
||||||
|
|
||||||
|
let discr = self.project_field(bcx, 0);
|
||||||
|
let discr_layout = bcx.ccx.layout_of(discr.ty.to_ty(bcx.tcx()));
|
||||||
|
let discr_scalar = match discr_layout.abi {
|
||||||
|
layout::Abi::Scalar(discr) => discr,
|
||||||
|
_ => bug!("discriminant not scalar: {:#?}", discr_layout)
|
||||||
|
};
|
||||||
|
let (min, max) = match *l {
|
||||||
|
layout::CEnum { min, max, .. } => (min, max),
|
||||||
|
layout::General { ref variants, .. } => (0, variants.len() as u64 - 1),
|
||||||
|
_ => (0, u64::max_value()),
|
||||||
|
};
|
||||||
|
let max_next = max.wrapping_add(1);
|
||||||
|
let bits = discr_scalar.size(bcx.ccx).bits();
|
||||||
|
assert!(bits <= 64);
|
||||||
|
let mask = !0u64 >> (64 - bits);
|
||||||
|
let lldiscr = match discr_scalar {
|
||||||
|
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
|
||||||
|
// However, that is fine here (it would still represent the full range),
|
||||||
|
layout::Int(..) if max_next & mask != min & mask => {
|
||||||
|
// llvm::ConstantRange can deal with ranges that wrap around,
|
||||||
|
// so an overflow on (max + 1) is fine.
|
||||||
|
bcx.load_range_assert(discr.llval, min, max_next,
|
||||||
|
/* signed: */ llvm::True,
|
||||||
|
discr.alignment.non_abi())
|
||||||
}
|
}
|
||||||
layout::General { discr, ref variants, .. } => {
|
_ => {
|
||||||
let ptr = self.project_field(bcx, 0);
|
// i.e., if the range is everything. The lo==hi case would be
|
||||||
(ptr.load_discr(bcx, discr, 0, variants.len() as u64 - 1), discr)
|
// rejected by the LLVM verifier (it would mean either an
|
||||||
|
// empty set, which is impossible, or the entire range of the
|
||||||
|
// type, which is pointless).
|
||||||
|
bcx.load(discr.llval, discr.alignment.non_abi())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match *l {
|
||||||
|
layout::CEnum { .. } |
|
||||||
|
layout::General { .. } => {
|
||||||
|
let signed = match discr_scalar {
|
||||||
|
layout::Int(_, signed) => signed,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
bcx.intcast(lldiscr, cast_to, signed)
|
||||||
}
|
}
|
||||||
layout::NullablePointer { nndiscr, .. } => {
|
layout::NullablePointer { nndiscr, .. } => {
|
||||||
let ptr = self.project_field(bcx, 0);
|
|
||||||
let lldiscr = bcx.load(ptr.llval, ptr.alignment.non_abi());
|
|
||||||
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
|
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
|
||||||
(bcx.icmp(cmp, lldiscr, C_null(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())))),
|
let zero = C_null(bcx.ccx.llvm_type_of(discr_layout.ty));
|
||||||
layout::Int(layout::I1, false))
|
bcx.intcast(bcx.icmp(cmp, lldiscr, zero), cast_to, false)
|
||||||
},
|
}
|
||||||
_ => bug!("{} is not an enum", l.ty)
|
_ => bug!("{} is not an enum", l.ty)
|
||||||
};
|
}
|
||||||
let signed = match discr {
|
|
||||||
layout::Int(_, signed) => signed,
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
bcx.intcast(val, cast_to, signed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the discriminant for a new value of the given case of the given
|
/// Set the discriminant for a new value of the given case of the given
|
||||||
|
@ -414,20 +419,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||||
.discriminant_for_variant(bcx.tcx(), variant_index)
|
.discriminant_for_variant(bcx.tcx(), variant_index)
|
||||||
.to_u128_unchecked() as u64;
|
.to_u128_unchecked() as u64;
|
||||||
match *l {
|
match *l {
|
||||||
layout::CEnum { .. } => {
|
layout::CEnum { .. } |
|
||||||
bcx.store(C_int(bcx.ccx.llvm_type_of(self.ty.to_ty(bcx.tcx())), to as i64),
|
|
||||||
self.llval, self.alignment.non_abi());
|
|
||||||
}
|
|
||||||
layout::General { .. } => {
|
layout::General { .. } => {
|
||||||
let ptr = self.project_field(bcx, 0);
|
let ptr = self.project_field(bcx, 0);
|
||||||
bcx.store(C_int(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())), to as i64),
|
bcx.store(C_int(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())), to as i64),
|
||||||
ptr.llval, ptr.alignment.non_abi());
|
ptr.llval, ptr.alignment.non_abi());
|
||||||
}
|
}
|
||||||
layout::Univariant { .. }
|
|
||||||
| layout::UntaggedUnion { .. }
|
|
||||||
| layout::Vector { .. } => {
|
|
||||||
assert_eq!(to, 0);
|
|
||||||
}
|
|
||||||
layout::NullablePointer { nndiscr, .. } => {
|
layout::NullablePointer { nndiscr, .. } => {
|
||||||
if to != nndiscr {
|
if to != nndiscr {
|
||||||
let use_memset = match l.abi {
|
let use_memset = match l.abi {
|
||||||
|
@ -451,7 +448,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("Cannot handle {} represented as {:#?}", l.ty, l)
|
_ => {
|
||||||
|
assert_eq!(to, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue