Skip to content

Commit c0dc515

Browse files
committed
Auto merge of #152681 - scottmcm:also-simplify-of-sized-val, r=<try>
Also simplify `size/align_of_val<T: Sized>` to `size/align_of<T>` instead
2 parents 873b4be + 160c52a commit c0dc515

50 files changed

Lines changed: 758 additions & 304 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_codegen_cranelift/example/mini_core.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,12 @@ pub union MaybeUninit<T> {
645645
pub value: ManuallyDrop<T>,
646646
}
647647

648+
pub mod ptr {
649+
#[lang = "Alignment"]
650+
#[repr(transparent)]
651+
pub struct Alignment(pub usize);
652+
}
653+
648654
pub mod intrinsics {
649655
#[rustc_intrinsic]
650656
pub fn abort() -> !;
@@ -653,9 +659,9 @@ pub mod intrinsics {
653659
#[rustc_intrinsic]
654660
pub unsafe fn size_of_val<T: ?crate::Sized>(val: *const T) -> usize;
655661
#[rustc_intrinsic]
656-
pub const fn align_of<T>() -> usize;
662+
pub const fn align_of<T>() -> crate::ptr::Alignment;
657663
#[rustc_intrinsic]
658-
pub unsafe fn align_of_val<T: ?crate::Sized>(val: *const T) -> usize;
664+
pub unsafe fn align_of_val<T: ?crate::Sized>(val: *const T) -> crate::ptr::Alignment;
659665
#[rustc_intrinsic]
660666
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
661667
#[rustc_intrinsic]
@@ -723,15 +729,15 @@ pub const fn size_of<T>() -> usize {
723729
}
724730

725731
pub const fn align_of<T>() -> usize {
726-
<T as SizedTypeProperties>::ALIGN
732+
<T as SizedTypeProperties>::ALIGN.0
727733
}
728734

729735
trait SizedTypeProperties: Sized {
730736
#[lang = "mem_size_const"]
731737
const SIZE: usize = intrinsics::size_of::<Self>();
732738

733739
#[lang = "mem_align_const"]
734-
const ALIGN: usize = intrinsics::align_of::<Self>();
740+
const ALIGN: crate::ptr::Alignment = intrinsics::align_of::<Self>();
735741
}
736742
impl<T> SizedTypeProperties for T {}
737743

compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ fn main() {
216216
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
217217

218218
assert_eq!(align_of::<u16>() as u8, 2);
219-
assert_eq!(intrinsics::align_of_val(&a) as u8, align_of::<&str>() as u8);
219+
assert_eq!(intrinsics::align_of_val(&a).0 as u8, align_of::<&str>() as u8);
220220

221221
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
222222
assert!(!u8_needs_drop);

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
602602
None
603603
};
604604
let (_size, align) = crate::unsize::size_and_align_of(fx, layout, meta);
605-
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
605+
let alignment_layout = fx.layout_of(fx.tcx.ty_alignment(source_info.span));
606+
ret.write_cvalue(fx, CValue::by_val(align, alignment_layout));
606607
}
607608

608609
sym::vtable_size => {

compiler/rustc_codegen_gcc/example/mini_core.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,12 @@ pub union MaybeUninit<T> {
651651
pub value: ManuallyDrop<T>,
652652
}
653653

654+
pub mod ptr {
655+
#[lang = "Alignment"]
656+
#[repr(transparent)]
657+
pub struct Alignment(pub usize);
658+
}
659+
654660
pub mod intrinsics {
655661
#[rustc_intrinsic]
656662
pub const fn black_box<T>(_dummy: T) -> T;
@@ -661,9 +667,9 @@ pub mod intrinsics {
661667
#[rustc_intrinsic]
662668
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
663669
#[rustc_intrinsic]
664-
pub const fn align_of<T>() -> usize;
670+
pub const fn align_of<T>() -> crate::ptr::Alignment;
665671
#[rustc_intrinsic]
666-
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
672+
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> crate::ptr::Alignment;
667673
#[rustc_intrinsic]
668674
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
669675
#[rustc_intrinsic]
@@ -704,15 +710,15 @@ pub const fn size_of<T>() -> usize {
704710
}
705711

706712
pub const fn align_of<T>() -> usize {
707-
<T as SizedTypeProperties>::ALIGN
713+
<T as SizedTypeProperties>::ALIGN.0
708714
}
709715

710716
trait SizedTypeProperties: Sized {
711717
#[lang = "mem_size_const"]
712718
const SIZE: usize = intrinsics::size_of::<Self>();
713719

714720
#[lang = "mem_align_const"]
715-
const ALIGN: usize = intrinsics::align_of::<Self>();
721+
const ALIGN: crate::ptr::Alignment = intrinsics::align_of::<Self>();
716722
}
717723

718724
impl<T> SizedTypeProperties for T {}

compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ fn main() {
196196
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
197197

198198
assert_eq!(align_of::<u16>() as u8, 2);
199-
assert_eq!(intrinsics::align_of_val(&a) as u8, align_of::<&str>() as u8);
199+
assert_eq!(intrinsics::align_of_val(&a).0 as u8, align_of::<&str>() as u8);
200200

201201
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
202202
assert!(!u8_needs_drop);

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ language_item_table! {
156156
MetaSized, sym::meta_sized, meta_sized_trait, Target::Trait, GenericRequirement::Exact(0);
157157
PointeeSized, sym::pointee_sized, pointee_sized_trait, Target::Trait, GenericRequirement::Exact(0);
158158
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
159+
Alignment, sym::Alignment, alignment_type, Target::Struct, GenericRequirement::Exact(0);
159160
AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0);
160161
SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0);
161162
OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1);

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ pub(crate) fn check_intrinsic_type(
292292
sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),
293293
sym::unreachable => (0, 0, vec![], tcx.types.never),
294294
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
295-
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
296-
sym::size_of_val | sym::align_of_val => {
297-
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
298-
}
295+
sym::size_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
296+
sym::align_of => (1, 0, vec![], tcx.ty_alignment(span)),
297+
sym::size_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize),
298+
sym::align_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.ty_alignment(span)),
299299
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
300300
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
301301
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),

compiler/rustc_middle/src/ty/context.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,13 @@ impl<'tcx> TyCtxt<'tcx> {
10791079
self.type_of(ordering_enum).no_bound_vars().unwrap()
10801080
}
10811081

1082+
/// Gets a `Ty` representing the [`LangItem::Alignment`]
1083+
#[track_caller]
1084+
pub fn ty_alignment(self, span: Span) -> Ty<'tcx> {
1085+
let alignment = self.require_lang_item(hir::LangItem::Alignment, span);
1086+
self.type_of(alignment).no_bound_vars().unwrap()
1087+
}
1088+
10821089
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
10831090
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
10841091
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {

compiler/rustc_mir_transform/src/check_alignment.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,23 @@ fn insert_alignment_check<'tcx>(
5555
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
5656

5757
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
58-
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
58+
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Move(thin_ptr), tcx.types.usize);
5959
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
6060
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
6161

6262
// Get the alignment of the pointee
6363
let align_def_id = tcx.require_lang_item(LangItem::AlignOf, source_info.span);
64+
let alignment_usize =
65+
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
6466
let alignment =
6567
Operand::unevaluated_constant(tcx, align_def_id, &[pointee_ty.into()], source_info.span);
68+
stmts.push(Statement::new(
69+
source_info,
70+
StatementKind::Assign(Box::new((
71+
alignment_usize,
72+
Rvalue::Cast(CastKind::Transmute, alignment.clone(), tcx.types.usize),
73+
))),
74+
));
6675

6776
// Subtract 1 from the alignment to get the alignment mask
6877
let alignment_mask =
@@ -76,7 +85,7 @@ fn insert_alignment_check<'tcx>(
7685
source_info,
7786
StatementKind::Assign(Box::new((
7887
alignment_mask,
79-
Rvalue::BinaryOp(BinOp::Sub, Box::new((alignment.clone(), one))),
88+
Rvalue::BinaryOp(BinOp::SubUnchecked, Box::new((Operand::Move(alignment_usize), one))),
8089
))),
8190
));
8291

@@ -139,10 +148,10 @@ fn insert_alignment_check<'tcx>(
139148
// Emit a check that asserts on the alignment and otherwise triggers a
140149
// AssertKind::MisalignedPointerDereference.
141150
PointerCheck {
142-
cond: Operand::Copy(is_ok),
151+
cond: Operand::Move(is_ok),
143152
assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
144153
required: alignment,
145-
found: Operand::Copy(addr),
154+
found: Operand::Move(addr),
146155
}),
147156
}
148157
}

compiler/rustc_mir_transform/src/instsimplify.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
5656

5757
let terminator = block.terminator.as_mut().unwrap();
5858
ctx.simplify_primitive_clone(terminator, &mut block.statements);
59-
ctx.simplify_align_of_slice_val(terminator, &mut block.statements);
59+
ctx.simplify_size_or_align_of_val(terminator, &mut block.statements);
6060
ctx.simplify_intrinsic_assert(terminator);
6161
ctx.simplify_nounwind_call(terminator);
6262
simplify_duplicate_switch_targets(terminator);
@@ -246,13 +246,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
246246
terminator.kind = TerminatorKind::Goto { target: *destination_block };
247247
}
248248

249-
// Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
250-
// alignment of a slice doesn't actually depend on metadata at all
251-
// and the element type is always `Sized`.
252-
//
253-
// This is here so it can run after inlining, where it's more useful.
254-
// (LowerIntrinsics is done in cleanup, before the optimization passes.)
255-
fn simplify_align_of_slice_val(
249+
/// Simplify `size_of_val` and `align_of_val` if we don't actually need
250+
/// to look at the value in order to calculate the result:
251+
/// - For `Sized` types we can always do this for both,
252+
/// - For `align_of_val::<[T]>` we can return `align_of::<T>()`, since it
253+
/// doesn't depend on the slice's length and the elements are sized.
254+
///
255+
/// This is here so it can run after inlining, where it's more useful.
256+
/// (LowerIntrinsics is done in cleanup, before the optimization passes.)
257+
///
258+
/// Note that we intentionally just produce the lang item constants so this
259+
/// works on generic types and avoids any risk of layout calculation cycles.
260+
fn simplify_size_or_align_of_val(
256261
&self,
257262
terminator: &mut Terminator<'tcx>,
258263
statements: &mut Vec<Statement<'tcx>>,
@@ -263,19 +268,35 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
263268
} = &terminator.kind
264269
&& args.len() == 1
265270
&& let Some((fn_def_id, generics)) = func.const_fn_def()
266-
&& self.tcx.is_intrinsic(fn_def_id, sym::align_of_val)
267-
&& let ty::Slice(elem_ty) = *generics.type_at(0).kind()
268271
{
269-
let align_def_id = self.tcx.require_lang_item(LangItem::AlignOf, source_info.span);
270-
let align_const = Operand::unevaluated_constant(
272+
let lang_item = if self.tcx.is_intrinsic(fn_def_id, sym::size_of_val) {
273+
LangItem::SizeOf
274+
} else if self.tcx.is_intrinsic(fn_def_id, sym::align_of_val) {
275+
LangItem::AlignOf
276+
} else {
277+
return;
278+
};
279+
let generic_ty = generics.type_at(0);
280+
let ty = if generic_ty.is_sized(self.tcx, self.typing_env) {
281+
generic_ty
282+
} else if let LangItem::AlignOf = lang_item
283+
&& let ty::Slice(elem_ty) = *generic_ty.kind()
284+
{
285+
elem_ty
286+
} else {
287+
return;
288+
};
289+
290+
let const_def_id = self.tcx.require_lang_item(lang_item, source_info.span);
291+
let const_op = Operand::unevaluated_constant(
271292
self.tcx,
272-
align_def_id,
273-
&[elem_ty.into()],
293+
const_def_id,
294+
&[ty.into()],
274295
source_info.span,
275296
);
276297
statements.push(Statement::new(
277298
source_info,
278-
StatementKind::Assign(Box::new((*destination, Rvalue::Use(align_const)))),
299+
StatementKind::Assign(Box::new((*destination, Rvalue::Use(const_op)))),
279300
));
280301
terminator.kind = TerminatorKind::Goto { target: *destination_block };
281302
}

0 commit comments

Comments
 (0)