Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/core/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?
/// The precise instruction is guaranteed only on the following targets:
/// - On x86 targets, this produces an `int3` instruction.
/// - On aarch64 targets, this produces a `brk #0xf000` instruction.
// When adding more items above, also add cases to the test in `tests/assembly-llvm/breakpoint.rs`.
// When adding more items above, also add cases to the test in `tests/assembly-llvm/intrinsics.rs`.
// When stabilizing this, update the comment on `core::intrinsics::breakpoint`.
// NOTE: there is an alternative in `process::resumable_breakpoint`. We may or may not
// actually want to stabilize both of them.
Expand Down
43 changes: 42 additions & 1 deletion library/core/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
///
/// `abort_immediate` lowers to a trap instruction on *most* architectures; on
/// some architectures it simply lowers to call the unmangled `abort` function.
/// The exact behavior is architecture and system dependent.
/// The exact behavior is architecture- and system-dependent.
///
/// On bare-metal (no OS) systems the trap instruction usually causes a
/// *hardware* exception to be raised in a *synchronous* fashion; hardware
Expand All @@ -34,11 +34,52 @@
/// corresponds to `SIGILL` or equivalent, *unless* this signal is handled.
/// Other signals such as `SIGABRT`, `SIGTRAP`, `SIGSEGV`, and `SIGBUS` may be
/// produced instead, depending on specifics. This is not an exhaustive list.
///
/// # Examples
///
/// ```no_run
/// #![feature(abort_immediate)]
///
/// use core::process;
///
/// fn main() {
/// println!("aborting");
///
/// process::abort_immediate();
///
/// // execution never gets here
/// }
/// ```
///
/// The `abort_immediate` function terminates the process, so the destructor
/// will not get run on the example below:
///
/// ```no_run
/// #![feature(abort_immediate)]
///
/// use core::process;
///
/// struct HasDrop;
///
/// impl Drop for HasDrop {
/// fn drop(&mut self) {
/// println!("This will never be printed!");
/// }
/// }
///
/// fn main() {
/// let _x = HasDrop;
/// process::abort_immediate();
/// // the destructor implemented for HasDrop will never get run
/// }
/// ```
///
#[unstable(feature = "abort_immediate", issue = "154601")]
#[rustc_const_unstable(feature = "abort_immediate", issue = "154601")]
#[cold]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[doc(alias = "halt")]
#[doc(alias = "trap")]
pub const fn abort_immediate() -> ! {
crate::intrinsics::abort_immediate()
}
Expand Down
30 changes: 0 additions & 30 deletions tests/assembly-llvm/breakpoint.rs

This file was deleted.

167 changes: 167 additions & 0 deletions tests/assembly-llvm/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//! Verify that simple intrinsics emit the instructions we expect.

//@ add-minicore
//@ assembly-output: emit-asm
//@ revisions: AARCH64 ARM64EC ARM32 AVR BPF LOONGARCH32 LOONGARCH64 I686 M68K MIPS32 MIPS64 MSP430 PPC32 PPC64 RISCV32 RISCV64 S390X SPARC32 SPARC64 WASM32 WASI32 X86_64 XTENSA
//
//@ [AARCH64] compile-flags: --target=aarch64-unknown-linux-gnu
//@ [AARCH64] needs-llvm-components: aarch64
//@ [ARM64EC] compile-flags: --target=arm64ec-pc-windows-msvc
//@ [ARM64EC] filecheck-flags: --check-prefixes AARCH64
//@ [ARM64EC] needs-llvm-components: aarch64
//
//@ [BPF] compile-flags: --target=bpfel-unknown-none
//@ [BPF] needs-llvm-components: bpf
//
//@ [AVR] compile-flags: --target=avr-none -Ctarget-cpu=atmega328p
//@ [AVR] needs-llvm-components: avr
//
//@ [ARM32] compile-flags: --target=armv7-unknown-linux-gnueabi
//@ [ARM32] needs-llvm-components: arm
//
//@ [LOONGARCH32] compile-flags: --target=loongarch32-unknown-none
//@ [LOONGARCH32] filecheck-flags: --check-prefixes LOONGARCH
//@ [LOONGARCH32] needs-llvm-components: loongarch
//@ [LOONGARCH64] compile-flags: --target=loongarch64-unknown-linux-gnu
//@ [LOONGARCH64] filecheck-flags: --check-prefixes LOONGARCH
//@ [LOONGARCH64] needs-llvm-components: loongarch
//@ [LOONGARCH32] min-llvm-version: 22
//@ [LOONGARCH64] min-llvm-version: 22
//
//@ [M68K] compile-flags: --target=m68k-unknown-linux-gnu
//@ [M68K] needs-llvm-components: m68k
//
//@ [MIPS32] compile-flags: --target=mips-unknown-linux-gnu
//@ [MIPS32] filecheck-flags: --check-prefixes MIPS
//@ [MIPS32] needs-llvm-components: mips
//@ [MIPS64] compile-flags: --target=mips64-unknown-linux-gnuabi64
//@ [MIPS64] filecheck-flags: --check-prefixes MIPS
//@ [MIPS64] needs-llvm-components: mips
//
//@ [MSP430] compile-flags: --target=msp430-none-elf
//@ [MSP430] needs-llvm-components: msp430
//
//@ [PPC32] compile-flags: --target=powerpc-unknown-linux-gnu
//@ [PPC32] filecheck-flags: --check-prefixes PPC
//@ [PPC32] needs-llvm-components: powerpc
//@ [PPC64] compile-flags: --target=powerpc64-unknown-linux-gnu
//@ [PPC64] filecheck-flags: --check-prefixes PPC
//@ [PPC64] needs-llvm-components: powerpc
//
//@ [RISCV32] compile-flags: --target=riscv32im-unknown-none-elf
//@ [RISCV32] filecheck-flags: --check-prefixes RISCV
//@ [RISCV32] needs-llvm-components: riscv
//@ [RISCV64] compile-flags: --target=riscv64gc-unknown-linux-gnu
//@ [RISCV64] filecheck-flags: --check-prefixes RISCV
//@ [RISCV64] needs-llvm-components: riscv
//
//@ [S390X] compile-flags: --target=s390x-unknown-linux-gnu
//@ [S390X] needs-llvm-components: systemz
//
//@ [SPARC32] compile-flags: --target=sparc-unknown-linux-gnu
//@ [SPARC32] filecheck-flags: --check-prefixes SPARC
//@ [SPARC32] needs-llvm-components: sparc
//@ [SPARC64] compile-flags: --target=sparc64-unknown-linux-gnu
//@ [SPARC64] filecheck-flags: --check-prefixes SPARC
//@ [SPARC64] needs-llvm-components: sparc
//
//@ [WASM32] compile-flags: --target=wasm32-unknown-unknown
//@ [WASM32] filecheck-flags: --check-prefixes WASM
//@ [WASM32] needs-llvm-components: webassembly
//@ [WASI32] compile-flags: --target=wasm32-wasip3
//@ [WASI32] filecheck-flags: --check-prefixes WASM
//@ [WASI32] needs-llvm-components: webassembly
//
//@ [I686] compile-flags: --target=i686-unknown-linux-gnu
//@ [I686] filecheck-flags: --check-prefixes X86
//@ [I686] needs-llvm-components: x86
//@ [X86_64] compile-flags: --target=x86_64-unknown-linux-gnu
//@ [X86_64] filecheck-flags: --check-prefixes X86
//@ [X86_64] needs-llvm-components: x86
//
//@ [XTENSA] compile-flags: --target=xtensa-esp32-espidf
//@ [XTENSA] needs-llvm-components: xtensa
//@ [XTENSA] min-llvm-version: 23

#![crate_type = "lib"]
#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
#![no_core]

extern crate minicore;

mod intrinsics {
#[rustc_intrinsic]
#[rustc_nounwind]
pub fn abort_immediate() -> !;

#[rustc_intrinsic]
#[rustc_nounwind]
pub fn breakpoint();
}

// Optional `"` since labels are quoted on arm64ec. Forbid calls by default since most platforms
// shouldn't be calling out to libc for this intrinsic.
//
// Note that some platforms (MSP430, AVR) do require an abort builtin, but this is typically a
// loop or hardware reset.
//
// We don't make a user-facing guarantee about what exactly `abort` will do but it also shouldn't
// change.
//
// CHECK-LABEL: do_abort{{"?}}:
// CHECK-NOT: {{ (call|b|bl) }}
//
// AARCH64: brk #0x1
// AVR: call abort
// BPF: call __bpf_trap
// ARM32: .inst 0xe7ffdefe
// LOONGARCH: ud 0
// M68K: jsr (abort@PLT,%pc)
// MIPS: break
// MSP430: call #abort
// PPC: trap
// RISCV: unimp
// // S390x lowers to a loop
// S390X: .Ltmp{{.*}}:
// S390X: j .Ltmp{{.*}}
// SPARC: ta 5
// WASM: unreachable
// X86: ud2
// XTENSA: ill.n
#[unsafe(no_mangle)]
pub fn do_abort() {
intrinsics::abort_immediate();
}

// Optional `"` since labels are quoted on arm64ec. Similar to `abort`, there typically shouldn't
// be any libcalls here.
//
// CHECK-LABEL: do_breakpoint{{"?}}:
// CHECK-NOT: {{ (call|b|bl|j) }}
//
// Documentation guarantees these instructions:
//
// AARCH64: brk #0xf000
// X86: int3
//
// We do not guarantee exact output on the following platforms but still check them:
//
// ARM32: bkpt #0
// AVR: call abort
// BPF: call __bpf_trap
// LOONGARCH: break 0
// M68K: jsr (abort@PLT,%pc)
// MIPS: break
// MSP430: call #abort
// PPC: trap
// RISCV: ebreak
// // S390x lowers to a loop
// S390X: .Ltmp{{.*}}:
// S390X: j .Ltmp{{.*}}
// SPARC: ta 1
// WASM: unreachable
// XTENSA: break.n
#[unsafe(no_mangle)]
pub fn do_breakpoint() {
intrinsics::breakpoint();
}
Loading