Skip to content

Commit

Permalink
Auto merge of #54071 - eddyb:alignsssss, r=oli-obk
Browse files Browse the repository at this point in the history
rustc_target: separate out an individual alignment quantity type from Align.

Before this PR, `rustc_target::abi::Align` combined "power-of-two alignment quantity" semantics, with a distinction between ABI (required) and preferred alignment (by having two quantities).

After this PR, `Align` is only *one* such quantity, and a new `AbiAndPrefAlign` type is introduced to hold the pair of ABI and preferred `Align` quantities.

`Align` is used everywhere one quantity is necessary/sufficient, simplifying some of the code in codegen/miri, while `AbiAndPrefAlign` only in layout computation (to propagate preferred alignment).

r? @oli-obk cc @nagisa @RalfJung @nikomatsakis
  • Loading branch information
bors committed Nov 23, 2018
2 parents 00e03ee + 5b4747d commit 6a2d1b4
Show file tree
Hide file tree
Showing 41 changed files with 363 additions and 374 deletions.
2 changes: 1 addition & 1 deletion src/librustc/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<Tag, Extra: Default> Allocation<Tag, Extra> {
}

pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
Allocation::from_bytes(slice, Align::from_bytes(1).unwrap())
}

pub fn undef(size: Size, align: Align) -> Self {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
AlignmentCheckFailed { required, has } =>
write!(f, "tried to access memory with alignment {}, but alignment {} is required",
has.abi(), required.abi()),
has.bytes(), required.bytes()),
TypeNotPrimitive(ty) =>
write!(f, "expected primitive type, got {}", ty),
Layout(ref err) =>
Expand All @@ -537,8 +537,9 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
MachineError(ref inner) =>
write!(f, "{}", inner),
IncorrectAllocationInformation(size, size2, align, align2) =>
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and \
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
write!(f, "incorrect alloc info: expected size {} and align {}, \
got size {} and align {}",
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
Panic { ref msg, line, col, ref file } =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
InvalidDiscriminant(val) =>
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/session/code_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl CodeStats {
let info = TypeSizeInfo {
kind,
type_description: type_desc.to_string(),
align: align.abi(),
align: align.bytes(),
overall_size: overall_size.bytes(),
packed: packed,
opt_discr_size: opt_discr_size.map(|s| s.bytes()),
Expand Down
105 changes: 52 additions & 53 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value)))
};
let scalar_pair = |a: Scalar, b: Scalar| {
let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align);
let b_offset = a.value.size(dl).abi_align(b.value.align(dl));
let size = (b_offset + b.value.size(dl)).abi_align(align);
let b_align = b.value.align(dl);
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
let b_offset = a.value.size(dl).align_to(b_align.abi);
let size = (b_offset + b.value.size(dl)).align_to(align.abi);
LayoutDetails {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldPlacement::Arbitrary {
Expand Down Expand Up @@ -257,10 +258,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
bug!("struct cannot be packed and aligned");
}

let pack = {
let pack = repr.pack as u64;
Align::from_bytes(pack, pack).unwrap()
};
let pack = Align::from_bytes(repr.pack as u64).unwrap();

let mut align = if packed {
dl.i8_align
Expand All @@ -274,7 +272,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {

let mut optimize = !repr.inhibit_struct_field_reordering_opt();
if let StructKind::Prefixed(_, align) = kind {
optimize &= align.abi() == 1;
optimize &= align.bytes() == 1;
}

if optimize {
Expand All @@ -285,7 +283,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
};
let optimizing = &mut inverse_memory_index[..end];
let field_align = |f: &TyLayout<'_>| {
if packed { f.align.min(pack).abi() } else { f.align.abi() }
if packed { f.align.abi.min(pack) } else { f.align.abi }
};
match kind {
StructKind::AlwaysSized |
Expand All @@ -312,13 +310,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let mut offset = Size::ZERO;

if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
if packed {
let prefix_align = prefix_align.min(pack);
align = align.max(prefix_align);
let prefix_align = if packed {
prefix_align.min(pack)
} else {
align = align.max(prefix_align);
}
offset = prefix_size.abi_align(prefix_align);
prefix_align
};
align = align.max(AbiAndPrefAlign::new(prefix_align));
offset = prefix_size.align_to(prefix_align);
}

for &i in &inverse_memory_index {
Expand All @@ -333,15 +331,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}

// Invariant: offset < dl.obj_size_bound() <= 1<<61
if packed {
let field_pack = field.align.min(pack);
offset = offset.abi_align(field_pack);
align = align.max(field_pack);
}
else {
offset = offset.abi_align(field.align);
align = align.max(field.align);
}
let field_align = if packed {
field.align.min(AbiAndPrefAlign::new(pack))
} else {
field.align
};
offset = offset.align_to(field_align.abi);
align = align.max(field_align);

debug!("univariant offset: {:?} field: {:#?}", offset, field);
offsets[i as usize] = offset;
Expand All @@ -352,7 +348,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {

if repr.align > 0 {
let repr_align = repr.align as u64;
align = align.max(Align::from_bytes(repr_align, repr_align).unwrap());
align = align.max(AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap()));
debug!("univariant repr_align: {:?}", repr_align);
}

Expand All @@ -377,7 +373,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
memory_index = inverse_memory_index;
}

let size = min_size.abi_align(align);
let size = min_size.align_to(align.abi);
let mut abi = Abi::Aggregate { sized };

// Unpack newtype ABIs and find scalar pairs.
Expand All @@ -394,7 +390,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
(Some((i, field)), None, None) => {
// Field fills the struct and it has a scalar or scalar pair ABI.
if offsets[i].bytes() == 0 &&
align.abi() == field.align.abi() &&
align.abi == field.align.abi &&
size == field.size {
match field.abi {
// For plain scalars, or vectors of them, we can't unpack
Expand Down Expand Up @@ -648,7 +644,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
let align = dl.vector_align(size);
let size = size.abi_align(align);
let size = size.align_to(align.abi);

tcx.intern_layout(LayoutDetails {
variants: Variants::Single { index: VariantIdx::new(0) },
Expand Down Expand Up @@ -680,10 +676,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
bug!("Union cannot be packed and aligned");
}

let pack = {
let pack = def.repr.pack as u64;
Align::from_bytes(pack, pack).unwrap()
};
let pack = Align::from_bytes(def.repr.pack as u64).unwrap();

let mut align = if packed {
dl.i8_align
Expand All @@ -694,7 +687,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
if def.repr.align > 0 {
let repr_align = def.repr.align as u64;
align = align.max(
Align::from_bytes(repr_align, repr_align).unwrap());
AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap()));
}

let optimize = !def.repr.inhibit_union_abi_opt();
Expand All @@ -704,12 +697,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
for field in &variants[index] {
assert!(!field.is_unsized());

if packed {
let field_pack = field.align.min(pack);
align = align.max(field_pack);
let field_align = if packed {
field.align.min(AbiAndPrefAlign::new(pack))
} else {
align = align.max(field.align);
}
field.align
};
align = align.max(field_align);

// If all non-ZST fields have the same ABI, forward this ABI
if optimize && !field.is_zst() {
Expand Down Expand Up @@ -749,7 +742,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
fields: FieldPlacement::Union(variants[index].len()),
abi,
align,
size: size.abi_align(align)
size: size.align_to(align.abi)
}));
}

Expand Down Expand Up @@ -964,19 +957,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let mut size = Size::ZERO;

// We're interested in the smallest alignment, so start large.
let mut start_align = Align::from_bytes(256, 256).unwrap();
assert_eq!(Integer::for_abi_align(dl, start_align), None);
let mut start_align = Align::from_bytes(256).unwrap();
assert_eq!(Integer::for_align(dl, start_align), None);

// repr(C) on an enum tells us to make a (tag, union) layout,
// so we need to grow the prefix alignment to be at least
// the alignment of the union. (This value is used both for
// determining the alignment of the overall enum, and the
// determining the alignment of the payload after the tag.)
let mut prefix_align = min_ity.align(dl);
let mut prefix_align = min_ity.align(dl).abi;
if def.repr.c() {
for fields in &variants {
for field in fields {
prefix_align = prefix_align.max(field.align);
prefix_align = prefix_align.max(field.align.abi);
}
}
}
Expand All @@ -989,8 +982,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
// Find the first field we can't move later
// to make room for a larger discriminant.
for field in st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) {
if !field.is_zst() || field.align.abi() != 1 {
start_align = start_align.min(field.align);
if !field.is_zst() || field.align.abi.bytes() != 1 {
start_align = start_align.min(field.align.abi);
break;
}
}
Expand All @@ -1000,7 +993,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}).collect::<Result<IndexVec<VariantIdx, _>, _>>()?;

// Align the maximum variant size to the largest alignment.
size = size.abi_align(align);
size = size.align_to(align.abi);

if size.bytes() >= dl.obj_size_bound() {
return Err(LayoutError::SizeOverflow(ty));
Expand Down Expand Up @@ -1036,7 +1029,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let mut ity = if def.repr.c() || def.repr.int.is_some() {
min_ity
} else {
Integer::for_abi_align(dl, start_align).unwrap_or(min_ity)
Integer::for_align(dl, start_align).unwrap_or(min_ity)
};

// If the alignment is not larger than the chosen discriminant size,
Expand Down Expand Up @@ -1204,7 +1197,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let type_desc = format!("{:?}", layout.ty);
self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
layout.align,
layout.align.abi,
layout.size,
packed,
opt_discr_size,
Expand Down Expand Up @@ -1251,7 +1244,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
name: name.to_string(),
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi(),
align: field_layout.align.abi.bytes(),
}
}
}
Expand All @@ -1264,7 +1257,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
} else {
session::SizeKind::Exact
},
align: layout.align.abi(),
align: layout.align.abi.bytes(),
size: if min_size.bytes() == 0 {
layout.size.bytes()
} else {
Expand Down Expand Up @@ -1823,7 +1816,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
Abi::ScalarPair(ref a, ref b) => {
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
// returns the last maximum.
let niche = iter::once((b, a.value.size(self).abi_align(b.value.align(self))))
let niche = iter::once(
(b, a.value.size(self).align_to(b.value.align(self).abi))
)
.chain(iter::once((a, Size::ZERO)))
.filter_map(|(scalar, offset)| scalar_niche(scalar, offset))
.max_by_key(|niche| niche.available);
Expand Down Expand Up @@ -1994,12 +1989,16 @@ impl_stable_hash_for!(enum ::ty::layout::Primitive {
Pointer
});

impl_stable_hash_for!(struct ::ty::layout::AbiAndPrefAlign {
abi,
pref
});

impl<'gcx> HashStable<StableHashingContext<'gcx>> for Align {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
self.abi().hash_stable(hcx, hasher);
self.pref().hash_stable(hcx, hasher);
self.bytes().hash_stable(hcx, hasher);
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/librustc_codegen_llvm/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl ArgAttributesExt for ArgAttributes {
if let Some(align) = self.pointee_align {
llvm::LLVMRustAddAlignmentAttr(llfn,
idx.as_uint(),
align.abi() as u32);
align.bytes() as u32);
}
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
}
Expand All @@ -98,7 +98,7 @@ impl ArgAttributesExt for ArgAttributes {
if let Some(align) = self.pointee_align {
llvm::LLVMRustAddAlignmentCallSiteAttr(callsite,
idx.as_uint(),
align.abi() as u32);
align.bytes() as u32);
}
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
}
Expand Down Expand Up @@ -204,7 +204,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
return;
}
if self.is_sized_indirect() {
OperandValue::Ref(val, None, self.layout.align).store(bx, dst)
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
} else if self.is_unsized_indirect() {
bug!("unsized ArgType must be handled through store_fn_arg");
} else if let PassMode::Cast(cast) = self.mode {
Expand All @@ -214,7 +214,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
if can_store_through_cast_ptr {
let cast_ptr_llty = bx.cx().type_ptr_to(cast.llvm_type(bx.cx()));
let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
bx.store(val, cast_dst, self.layout.align);
bx.store(val, cast_dst, self.layout.align.abi);
} else {
// The actual return type is a struct, but the ABI
// adaptation code has cast it into some scalar type. The
Expand Down Expand Up @@ -242,7 +242,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
// ...and then memcpy it to the intended destination.
bx.memcpy(
dst.llval,
self.layout.align,
self.layout.align.abi,
llscratch,
scratch_align,
bx.cx().const_usize(self.layout.size.bytes()),
Expand Down Expand Up @@ -273,7 +273,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
OperandValue::Pair(next(), next()).store(bx, dst);
}
PassMode::Indirect(_, Some(_)) => {
OperandValue::Ref(next(), Some(next()), self.layout.align).store(bx, dst);
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
}
PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => {
self.store(bx, next(), dst);
Expand Down Expand Up @@ -545,7 +545,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
adjust_for_rust_scalar(&mut b_attrs,
b,
arg.layout,
a.value.size(cx).abi_align(b.value.align(cx)),
a.value.size(cx).align_to(b.value.align(cx).abi),
false);
arg.mode = PassMode::Pair(a_attrs, b_attrs);
return arg;
Expand Down
Loading

0 comments on commit 6a2d1b4

Please sign in to comment.