Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 55529ec

Browse files
committed
More micro-opt
1 parent 95b96c0 commit 55529ec

File tree

11 files changed

+107
-100
lines changed

11 files changed

+107
-100
lines changed

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_middle::mir;
22
use rustc_middle::mir::NonDivergingIntrinsic;
3+
use rustc_session::config::OptLevel;
34

45
use super::FunctionCx;
56
use super::LocalRef;
@@ -67,8 +68,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
6768
self.codegen_coverage(bx, coverage, statement.source_info.scope);
6869
}
6970
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
70-
let op_val = self.codegen_operand(bx, op);
71-
bx.assume(op_val.immediate());
71+
if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) {
72+
let op_val = self.codegen_operand(bx, op);
73+
bx.assume(op_val.immediate());
74+
}
7275
}
7376
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
7477
mir::CopyNonOverlapping { ref count, ref src, ref dst },

library/core/src/intrinsics.rs

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656

5757
use crate::marker::DiscriminantKind;
5858
use crate::marker::Tuple;
59-
use crate::mem;
59+
use crate::mem::{self, align_of};
6060

6161
pub mod mir;
6262
pub mod simd;
@@ -2599,10 +2599,9 @@ pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
25992599
/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
26002600
/// and only at runtime.
26012601
///
2602-
/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
2602+
/// This macro should be called as `assert_unsafe_precondition!((name: Type) => Expression)`
26032603
/// where the names specified will be moved into the macro as captured variables, and defines an item
2604-
/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
2605-
/// for the function declarations and can be omitted if there is no generics.
2604+
/// to call `const_eval_select` on.
26062605
///
26072606
/// # Safety
26082607
///
@@ -2618,27 +2617,22 @@ pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
26182617
/// the occasional mistake, and this check should help them figure things out.
26192618
#[allow_internal_unstable(const_eval_select, delayed_debug_assertions)] // permit this to be called in stably-const fn
26202619
macro_rules! assert_unsafe_precondition {
2621-
($name:expr, $([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr $(,)?) => {
2620+
($name:expr, ($($i:ident:$ty:ty),*$(,)?) => $e:expr $(,)?) => {
26222621
{
2623-
// allow non_snake_case to allow capturing const generics
2624-
#[allow(non_snake_case)]
2625-
#[inline(always)]
2626-
fn runtime$(<$($tt)*>)?($($i:$ty),*) {
2627-
#[cfg(miri)]
2628-
return;
2622+
#[inline(never)]
2623+
fn precondition_check($($i:$ty),*) {
26292624
if !$e {
2630-
// don't unwind to reduce impact on code size
26312625
::core::panicking::panic_nounwind(
26322626
concat!("unsafe precondition(s) violated: ", $name)
26332627
);
26342628
}
26352629
}
26362630
#[allow(non_snake_case)]
26372631
#[inline]
2638-
const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
2632+
const fn comptime($(_:$ty),*) {}
26392633

26402634
if ::core::intrinsics::debug_assertions() {
2641-
::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
2635+
::core::intrinsics::const_eval_select(($($i,)*), comptime, precondition_check);
26422636
}
26432637
}
26442638
};
@@ -2648,8 +2642,8 @@ pub(crate) use assert_unsafe_precondition;
26482642
/// Checks whether `ptr` is properly aligned with respect to
26492643
/// `align_of::<T>()`.
26502644
#[inline]
2651-
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
2652-
((ptr.addr() & const { crate::mem::align_of::<T>() - 1 }) == 0) & (ptr.addr() != 0)
2645+
pub(crate) fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
2646+
ptr.is_aligned_to(align) && !ptr.is_null()
26532647
}
26542648

26552649
/// Checks whether the regions of memory starting at `src` and `dst` of size
@@ -2658,9 +2652,12 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
26582652
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
26592653
let src_usize = src.addr();
26602654
let dst_usize = dst.addr();
2661-
let size = mem::size_of::<T>()
2662-
.checked_mul(count)
2663-
.expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize");
2655+
let Some(size) = mem::size_of::<T>().checked_mul(count) else {
2656+
// Use panic_nounwind instead of Option::expect, so that this function is nounwind.
2657+
crate::panicking::panic_nounwind(
2658+
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
2659+
)
2660+
};
26642661
let diff = src_usize.abs_diff(dst_usize);
26652662
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
26662663
// they do not overlap.
@@ -2772,21 +2769,24 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
27722769
// upheld by the caller.
27732770
unsafe {
27742771
if crate::intrinsics::debug_assertions() {
2775-
let args = (
2776-
src as *const (),
2777-
dst as *mut (),
2778-
crate::mem::size_of::<T>(),
2779-
crate::mem::align_of::<T>(),
2780-
count,
2772+
const_eval_select(
2773+
(
2774+
src as *const (),
2775+
dst as *mut (),
2776+
crate::mem::size_of::<T>(),
2777+
crate::mem::align_of::<T>(),
2778+
count,
2779+
),
2780+
compiletime,
2781+
check_aligned_nonoverlapping,
27812782
);
2782-
const_eval_select(args, compiletime, check_valid_copy_nonoverlapping);
27832783
}
27842784
copy_nonoverlapping(src, dst, count)
27852785
}
27862786
}
27872787

27882788
#[inline(never)]
2789-
fn check_valid_copy_nonoverlapping(
2789+
pub(crate) fn check_aligned_nonoverlapping(
27902790
src: *const (),
27912791
dst: *mut (),
27922792
size: usize,
@@ -2805,9 +2805,11 @@ fn check_valid_copy_nonoverlapping(
28052805
}
28062806
let src_usize = src.addr();
28072807
let dst_usize = dst.addr();
2808-
let size = size
2809-
.checked_mul(count)
2810-
.expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize");
2808+
let Some(size) = size.checked_mul(count) else {
2809+
crate::panicking::panic_nounwind(
2810+
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
2811+
)
2812+
};
28112813
let diff = src_usize.abs_diff(dst_usize);
28122814
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
28132815
// they do not overlap.
@@ -2907,14 +2909,18 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
29072909
// SAFETY: the safety contract for `copy` must be upheld by the caller.
29082910
unsafe {
29092911
if crate::intrinsics::debug_assertions() {
2910-
let args = (src as *const (), dst as *mut (), crate::mem::align_of::<T>());
2911-
const_eval_select(args, compiletime, check_valid_copy);
2912+
const_eval_select(
2913+
(src as *const (), dst as *mut (), align_of::<T>()),
2914+
compiletime,
2915+
check_valid_copy,
2916+
);
29122917
}
29132918
copy(src, dst, count)
29142919
}
29152920
}
29162921

29172922
#[inline(never)]
2923+
#[rustc_nounwind]
29182924
fn check_valid_copy(src: *const (), dst: *mut (), align: usize) {
29192925
if src.is_null() || dst.is_null() {
29202926
crate::panicking::panic_nounwind(
@@ -2991,11 +2997,13 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
29912997
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
29922998
}
29932999

3000+
let addr = dst as *const ();
3001+
let align = align_of::<T>();
29943002
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
29953003
unsafe {
29963004
assert_unsafe_precondition!(
29973005
"ptr::write_bytes requires that the destination pointer is aligned and non-null",
2998-
[T](dst: *mut T) => is_aligned_and_not_null(dst)
3006+
(addr: *const (), align: usize) => is_aligned_and_not_null(addr, align)
29993007
);
30003008
write_bytes(dst, val, count)
30013009
}

library/core/src/option.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,6 @@ impl<T> Option<T> {
10331033
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
10341034
#[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
10351035
pub const unsafe fn unwrap_unchecked(self) -> T {
1036-
debug_assert!(self.is_some());
10371036
match self {
10381037
Some(val) => val,
10391038
// SAFETY: the safety contract must be upheld by the caller.

library/core/src/ptr/const_ptr.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,13 +806,14 @@ impl<T: ?Sized> *const T {
806806
where
807807
T: Sized,
808808
{
809-
let this = self;
809+
let this = self as *const ();
810+
let arg = origin as *const ();
810811
// SAFETY: The comparison has no side-effects, and the intrinsic
811812
// does this check internally in the CTFE implementation.
812813
unsafe {
813814
assert_unsafe_precondition!(
814-
"ptr::sub_ptr requires `this >= origin`",
815-
[T](this: *const T, origin: *const T) => this >= origin
815+
"ptr::sub_ptr requires `self >= origin`",
816+
(this: *const (), arg: *const ()) => this >= arg
816817
)
817818
};
818819

library/core/src/ptr/mod.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,12 @@ use crate::cmp::Ordering;
381381
use crate::fmt;
382382
use crate::hash;
383383
use crate::intrinsics::{
384-
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
384+
self, assert_unsafe_precondition, check_aligned_nonoverlapping, const_eval_select,
385+
is_aligned_and_not_null,
385386
};
386387
use crate::marker::FnPtr;
387388

388-
use crate::mem::{self, MaybeUninit};
389+
use crate::mem::{self, align_of, size_of, MaybeUninit};
389390

390391
mod alignment;
391392
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
@@ -961,17 +962,15 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
961962
};
962963
}
963964

965+
const fn compiletime(_: *const (), _: *mut (), _: usize, _: usize, _: usize) {}
966+
964967
// SAFETY: the caller must guarantee that `x` and `y` are
965968
// valid for writes and properly aligned.
966969
unsafe {
967-
assert_unsafe_precondition!(
968-
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
969-
and the specified memory ranges do not overlap",
970-
[T](x: *mut T, y: *mut T, count: usize) =>
971-
is_aligned_and_not_null(x)
972-
&& is_aligned_and_not_null(y)
973-
&& is_nonoverlapping(x, y, count)
974-
);
970+
if crate::intrinsics::debug_assertions() {
971+
let args = (x as *const (), y as *mut (), size_of::<T>(), align_of::<T>(), count);
972+
const_eval_select(args, compiletime, check_aligned_nonoverlapping);
973+
}
975974
}
976975

977976
// Split up the slice into small power-of-two-sized chunks that LLVM is able
@@ -1059,9 +1058,11 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
10591058
// and cannot overlap `src` since `dst` must point to a distinct
10601059
// allocated object.
10611060
unsafe {
1061+
let addr = dst as *const ();
1062+
let align = align_of::<T>();
10621063
assert_unsafe_precondition!(
10631064
"ptr::replace requires that the pointer argument is aligned and non-null",
1064-
[T](dst: *mut T) => is_aligned_and_not_null(dst)
1065+
(addr: *const (), align: usize) => is_aligned_and_not_null(addr, align)
10651066
);
10661067
mem::swap(&mut *dst, &mut src); // cannot overlap
10671068
}
@@ -1580,9 +1581,11 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
15801581
pub unsafe fn read_volatile<T>(src: *const T) -> T {
15811582
// SAFETY: the caller must uphold the safety contract for `volatile_load`.
15821583
unsafe {
1584+
let addr = src as *const ();
1585+
let align = align_of::<T>();
15831586
assert_unsafe_precondition!(
15841587
"ptr::read_volatile requires that the pointer argument is aligned and non-null",
1585-
[T](src: *const T) => is_aligned_and_not_null(src)
1588+
(addr: *const (), align: usize) => is_aligned_and_not_null(addr, align)
15861589
);
15871590
intrinsics::volatile_load(src)
15881591
}
@@ -1655,9 +1658,11 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
16551658
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
16561659
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
16571660
unsafe {
1661+
let addr = dst as *mut ();
1662+
let align = crate::mem::align_of::<T>();
16581663
assert_unsafe_precondition!(
16591664
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
1660-
[T](dst: *mut T) => is_aligned_and_not_null(dst)
1665+
(addr: *mut (), align: usize) => is_aligned_and_not_null(addr, align)
16611666
);
16621667
intrinsics::volatile_store(dst, src);
16631668
}

library/core/src/slice/raw.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
9494
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
9595
unsafe {
9696
if crate::intrinsics::debug_assertions() {
97-
let args =
98-
(data as *mut (), len, crate::mem::size_of::<T>(), crate::mem::align_of::<T>());
99-
crate::intrinsics::const_eval_select(args, compiletime, check_valid_slice);
97+
crate::intrinsics::const_eval_select(
98+
(data as *mut (), len, crate::mem::size_of::<T>(), crate::mem::align_of::<T>()),
99+
compiletime,
100+
check_valid_slice,
101+
);
100102
}
101103
&*ptr::slice_from_raw_parts(data, len)
102104
}
@@ -143,9 +145,11 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
143145
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
144146
unsafe {
145147
if crate::intrinsics::debug_assertions() {
146-
let args =
147-
(data as *mut (), len, crate::mem::size_of::<T>(), crate::mem::align_of::<T>());
148-
crate::intrinsics::const_eval_select(args, compiletime, check_valid_slice);
148+
crate::intrinsics::const_eval_select(
149+
(data as *mut (), len, crate::mem::size_of::<T>(), crate::mem::align_of::<T>()),
150+
compiletime,
151+
check_valid_slice,
152+
);
149153
}
150154
&mut *ptr::slice_from_raw_parts_mut(data, len)
151155
}

tests/assembly/is_aligned.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// only-x86_64
33
// ignore-sgx
44
// revisions: opt-speed opt-size
5-
// [opt-speed] compile-flags: -Copt-level=1
6-
// [opt-size] compile-flags: -Copt-level=s
5+
// [opt-speed] compile-flags: -Copt-level=2 -Cdebug-assertions=no
6+
// [opt-size] compile-flags: -Copt-level=s -Cdebug-assertions=no
77
#![crate_type="rlib"]
88

99
#![feature(core_intrinsics)]

tests/mir-opt/inline/unwrap_unchecked.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
44
// ignore-debug: the debug assertions prevent the inlining we are testing for
5-
// compile-flags: -Zmir-opt-level=2 -Zinline-mir
5+
// compile-flags: -Zmir-opt-level=2 -Zinline-mir -Cdebug-assertions=no
66

77
// EMIT_MIR unwrap_unchecked.unwrap_unchecked.Inline.diff
88
// EMIT_MIR unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir

0 commit comments

Comments
 (0)