diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 41202546566a7..d67f9c15a1916 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -80,6 +80,7 @@
 #![feature(const_mut_refs)]
 #![feature(const_int_pow)]
 #![feature(constctlz)]
+#![feature(const_cttz)]
 #![feature(const_panic)]
 #![feature(const_pin)]
 #![feature(const_fn)]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 5a9fd902c9ca1..716b4a90e5ec2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -6,6 +6,7 @@ use crate::str::FromStr;
 
 use super::from_str_radix;
 use super::{IntErrorKind, ParseIntError};
+use crate::intrinsics;
 
 macro_rules! doc_comment {
     ($x:expr, $($tt:tt)*) => {
@@ -189,3 +190,76 @@ macro_rules! from_str_radix_nzint_impl {
 
 from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
 NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
+
+macro_rules! nonzero_leading_trailing_zeros {
+    ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
+        $(
+            impl $Ty {
+                doc_comment! {
+                    concat!("Returns the number of leading zeros in the binary representation of `self`.
+
+On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+
+# Examples
+
+Basic usage:
+
+```
+#![feature(nonzero_leading_trailing_zeros)]
+let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();
+
+assert_eq!(n.leading_zeros(), 0);
+```"),
+                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                    #[inline]
+                    pub const fn leading_zeros(self) -> u32 {
+                        // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
+                        unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
+                    }
+                }
+
+                doc_comment! {
+                    concat!("Returns the number of trailing zeros in the binary representation
+of `self`.
+
+On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+
+# Examples
+
+Basic usage:
+
+```
+#![feature(nonzero_leading_trailing_zeros)]
+let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();
+
+assert_eq!(n.trailing_zeros(), 3);
+```"),
+                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+                    #[inline]
+                    pub const fn trailing_zeros(self) -> u32 {
+                        // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
+                        unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
+                    }
+                }
+
+            }
+        )+
+    }
+}
+
+nonzero_leading_trailing_zeros! {
+    NonZeroU8(u8), u8::MAX;
+    NonZeroU16(u16), u16::MAX;
+    NonZeroU32(u32), u32::MAX;
+    NonZeroU64(u64), u64::MAX;
+    NonZeroU128(u128), u128::MAX;
+    NonZeroUsize(usize), usize::MAX;
+    NonZeroI8(u8), -1i8;
+    NonZeroI16(u16), -1i16;
+    NonZeroI32(u32), -1i32;
+    NonZeroI64(u64), -1i64;
+    NonZeroI128(u128), -1i128;
+    NonZeroIsize(usize), -1isize;
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c9f9b890c3938..14ef03fd53eba 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -60,6 +60,8 @@
 #![feature(once_cell)]
 #![feature(unsafe_block_in_unsafe_fn)]
 #![feature(int_bits_const)]
+#![feature(nonzero_leading_trailing_zeros)]
+#![feature(const_option)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate test;
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index fb1293c99bba9..ca449b4350ede 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -1,5 +1,8 @@
 use core::convert::TryFrom;
-use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
+use core::num::{
+    IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
+    NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
+};
 use core::option::Option::{self, None, Some};
 use std::mem::size_of;
 
@@ -212,3 +215,100 @@ fn nonzero_const() {
     const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
     assert!(ONE.is_some());
 }
+
+#[test]
+fn nonzero_leading_zeros() {
+    assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7);
+    assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7);
+    assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15);
+    assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15);
+    assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31);
+    assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31);
+    assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63);
+    assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63);
+    assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127);
+    assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127);
+    assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+    assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+
+    assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
+
+    assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0);
+
+    const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros();
+    assert_eq!(LEADING_ZEROS, 15);
+}
+
+#[test]
+fn nonzero_trailing_zeros() {
+    assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0);
+
+    assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2);
+
+    assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7);
+    assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7);
+    assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15);
+    assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15);
+    assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31);
+    assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31);
+    assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63);
+    assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63);
+    assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127);
+    assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127);
+
+    assert_eq!(
+        NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+        usize::BITS - 1
+    );
+    assert_eq!(
+        NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+        usize::BITS - 1
+    );
+
+    const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
+    assert_eq!(TRAILING_ZEROS, 2);
+}