From cd0752276e18fbef0e4898d27cdf261cae69b0cd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 6 Mar 2021 09:38:19 +0000 Subject: [PATCH] Convert all uses of llvm_asm! to asm! --- crates/core_arch/src/acle/barrier/cp15.rs | 15 ++++- crates/core_arch/src/acle/hints.rs | 38 ++++--------- crates/core_arch/src/acle/registers/mod.rs | 8 +-- crates/core_arch/src/arm/armclang.rs | 65 ++++++++-------------- crates/core_arch/src/lib.rs | 1 - crates/core_arch/src/macros.rs | 7 +++ crates/core_arch/src/x86/bt.rs | 48 ++++++++++------ crates/core_arch/src/x86/cpuid.rs | 43 +++++++------- crates/core_arch/src/x86/eflags.rs | 8 +-- crates/core_arch/src/x86_64/bt.rs | 48 ++++++++++------ crates/std_detect/src/detect/os/aarch64.rs | 18 +++++- crates/std_detect/src/lib.rs | 2 +- 12 files changed, 161 insertions(+), 140 deletions(-) diff --git a/crates/core_arch/src/acle/barrier/cp15.rs b/crates/core_arch/src/acle/barrier/cp15.rs index a4d101ad82..25d4c3c8cb 100644 --- a/crates/core_arch/src/acle/barrier/cp15.rs +++ b/crates/core_arch/src/acle/barrier/cp15.rs @@ -8,20 +8,29 @@ pub struct SY; impl super::super::sealed::Dmb for SY { #[inline(always)] unsafe fn __dmb(&self) { - llvm_asm!("mcr p15, 0, r0, c7, c10, 5" : : : "memory" : "volatile") + asm!( + "mcr p15, 0, r0, c7, c10, 5", + options(preserves_flags, nostack) + ) } } impl super::super::sealed::Dsb for SY { #[inline(always)] unsafe fn __dsb(&self) { - llvm_asm!("mcr p15, 0, r0, c7, c10, 4" : : : "memory" : "volatile") + asm!( + "mcr p15, 0, r0, c7, c10, 4", + options(preserves_flags, nostack) + ) } } impl super::super::sealed::Isb for SY { #[inline(always)] unsafe fn __isb(&self) { - llvm_asm!("mcr p15, 0, r0, c7, c5, 4" : : : "memory" : "volatile") + asm!( + "mcr p15, 0, r0, c7, c5, 4", + options(preserves_flags, nostack) + ) } } diff --git a/crates/core_arch/src/acle/hints.rs b/crates/core_arch/src/acle/hints.rs index 892d4f517f..280aa00cf8 100644 --- a/crates/core_arch/src/acle/hints.rs +++ b/crates/core_arch/src/acle/hints.rs @@ -80,33 +80,13 @@ pub unsafe fn __yield() { // and ARMv7-R edition (ARM DDI 0406C.c) sections D12.4.1 "ARM instruction set support" and D12.4.2 // "Thumb instruction set support" #[cfg(target_feature = "v7")] +#[cfg(any(target_arch = "arm", doc))] +#[doc(cfg(target_arch = "arm"))] #[inline(always)] -#[rustc_args_required_const(0)] -pub unsafe fn __dbg(imm4: u32) { - macro_rules! call { - ($imm4:expr) => { - llvm_asm!(concat!("DBG ", stringify!($imm4)) : : : : "volatile") - } - } - - match imm4 & 0b1111 { - 0 => call!(0), - 1 => call!(1), - 2 => call!(2), - 3 => call!(3), - 4 => call!(4), - 5 => call!(5), - 6 => call!(6), - 7 => call!(7), - 8 => call!(8), - 9 => call!(9), - 10 => call!(10), - 11 => call!(11), - 12 => call!(12), - 13 => call!(13), - 14 => call!(14), - _ => call!(15), - } +#[rustc_legacy_const_generics(0)] +pub unsafe fn __dbg() { + static_assert_imm4!(IMM4); + dbg(IMM4); } /// Generates an unspecified no-op instruction. @@ -117,13 +97,17 @@ pub unsafe fn __dbg(imm4: u32) { /// will increase execution time. #[inline(always)] pub unsafe fn __nop() { - llvm_asm!("NOP" : : : : "volatile") + asm!("nop", options(nomem, nostack, preserves_flags)); } extern "C" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.hint")] #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.hint")] fn hint(_: i32); + + #[cfg(target_arch = "arm")] + #[link_name = "llvm.arm.dbg"] + fn dbg(_: i32); } // from LLVM 7.0.1's lib/Target/ARM/{ARMInstrThumb,ARMInstrInfo,ARMInstrThumb2}.td diff --git a/crates/core_arch/src/acle/registers/mod.rs b/crates/core_arch/src/acle/registers/mod.rs index 391a5f0824..71e94ee5cb 100644 --- a/crates/core_arch/src/acle/registers/mod.rs +++ b/crates/core_arch/src/acle/registers/mod.rs @@ -4,7 +4,7 @@ macro_rules! rsr { impl super::super::sealed::Rsr for $R { unsafe fn __rsr(&self) -> u32 { let r: u32; - llvm_asm!(concat!("mrs $0,", stringify!($R)) : "=r"(r) : : : "volatile"); + asm!(concat!("mrs {},", stringify!($R)), out(reg) r, options(nomem, nostack)); r } } @@ -17,7 +17,7 @@ macro_rules! rsrp { impl super::super::sealed::Rsrp for $R { unsafe fn __rsrp(&self) -> *const u8 { let r: *const u8; - llvm_asm!(concat!("mrs $0,", stringify!($R)) : "=r"(r) : : : "volatile"); + asm!(concat!("mrs {},", stringify!($R)), out(reg) r, options(nomem, nostack)); r } } @@ -29,7 +29,7 @@ macro_rules! wsr { ($R:ident) => { impl super::super::sealed::Wsr for $R { unsafe fn __wsr(&self, value: u32) { - llvm_asm!(concat!("msr ", stringify!($R), ",$0") : : "r"(value) : : "volatile"); + asm!(concat!("msr ", stringify!($R), ", {}"), in(reg) value, options(nomem, nostack)); } } }; @@ -40,7 +40,7 @@ macro_rules! wsrp { ($R:ident) => { impl super::super::sealed::Wsrp for $R { unsafe fn __wsrp(&self, value: *const u8) { - llvm_asm!(concat!("msr ", stringify!($R), ",$0") : : "r"(value) : : "volatile"); + asm!(concat!("msr ", stringify!($R), ", {}"), in(reg) value, options(nomem, nostack)); } } }; diff --git a/crates/core_arch/src/arm/armclang.rs b/crates/core_arch/src/arm/armclang.rs index 2604727984..aa4bab49f1 100644 --- a/crates/core_arch/src/arm/armclang.rs +++ b/crates/core_arch/src/arm/armclang.rs @@ -11,58 +11,41 @@ use stdarch_test::assert_instr; /// Inserts a breakpoint instruction. /// -/// `val` is a compile-time constant integer in range `[0, 255]`. +/// `VAL` is a compile-time constant integer in range `[0, 65535]`. /// -/// The breakpoint instruction inserted is: -/// -/// * `BKPT` when compiling as T32, -/// * `BRK` when compiling as A32 or A64. +/// The breakpoint instruction inserted is `BRK` on A64. +#[cfg(all(target_arch = "aarch64", not(doc)))] +#[cfg_attr(test, assert_instr(brk, VAL = 0))] +#[inline(always)] +#[rustc_legacy_const_generics(0)] +pub unsafe fn __breakpoint() { + static_assert_imm16!(VAL); + asm!("brk {}", const VAL); +} + +/// Inserts a breakpoint instruction. /// -/// # Safety +/// `VAL` is a compile-time constant integer in range `[0, 255]`. /// -/// If `val` is out-of-range the behavior is **undefined**. +/// The breakpoint instruction inserted is `BKPT` on A32/T32. /// /// # Note /// /// [ARM's documentation][arm_docs] defines that `__breakpoint` accepts the -/// following values for `val`: +/// following values for `VAL`: /// -/// - `0...65535` when compiling as A32 or A64, +/// - `0...65535` when compiling as A32, /// - `0...255` when compiling as T32. /// -/// The current implementation only accepts values in range `[0, 255]` - if the -/// value is out-of-range the behavior is **undefined**. +/// The current implementation only accepts values in range `[0, 255]`. /// /// [arm_docs]: https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))] +#[cfg(any(target_arch = "arm", doc))] +#[doc(cfg(target_arch = "arm"))] +#[cfg_attr(test, assert_instr(bkpt, VAL = 0))] #[inline(always)] -#[rustc_args_required_const(0)] -pub unsafe fn __breakpoint(val: i32) { - // Ensure that this compiles correctly on non-arm architectures, so libstd - // doc builds work. The proper macro will shadow this definition below. - #[allow(unused_macros)] - macro_rules! call { - ($e:expr) => { - () - }; - } - - #[cfg(target_arch = "arm")] - macro_rules! call { - ($imm8:expr) => { - llvm_asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile") - } - } - - #[cfg(target_arch = "aarch64")] - macro_rules! call { - ($imm8:expr) => { - llvm_asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile") - } - } - - // We can't `panic!` inside this intrinsic, so we can't really validate the - // arguments here. If `val` is out-of-range this macro uses `val == 255`: - constify_imm8!(val, call); +#[rustc_legacy_const_generics(0)] +pub unsafe fn __breakpoint() { + static_assert_imm8!(VAL); + asm!("bkpt #{}", const VAL); } diff --git a/crates/core_arch/src/lib.rs b/crates/core_arch/src/lib.rs index 57fa44bd8b..4dca758148 100644 --- a/crates/core_arch/src/lib.rs +++ b/crates/core_arch/src/lib.rs @@ -12,7 +12,6 @@ platform_intrinsics, repr_simd, simd_ffi, - llvm_asm, proc_macro_hygiene, stmt_expr_attributes, core_intrinsics, diff --git a/crates/core_arch/src/macros.rs b/crates/core_arch/src/macros.rs index 87e49fba4b..d7735c76d9 100644 --- a/crates/core_arch/src/macros.rs +++ b/crates/core_arch/src/macros.rs @@ -58,6 +58,13 @@ macro_rules! static_assert_imm8 { }; } +#[allow(unused_macros)] +macro_rules! static_assert_imm16 { + ($imm:ident) => { + let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 16) - 1 }>::VALID; + }; +} + #[allow(unused)] macro_rules! static_assert { ($imm:ident : $ty:ty where $e:expr) => { diff --git a/crates/core_arch/src/x86/bt.rs b/crates/core_arch/src/x86/bt.rs index dc172f6f38..4c588b424c 100644 --- a/crates/core_arch/src/x86/bt.rs +++ b/crates/core_arch/src/x86/bt.rs @@ -7,10 +7,14 @@ use stdarch_test::assert_instr; #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittest(p: *const i32, b: i32) -> u8 { let r: u8; - llvm_asm!("btl $2, $1\n\tsetc ${0:b}" - : "=r"(r) - : "*m"(p), "r"(b) - : "cc", "memory"); + asm!( + "bt [{p}], {b:e}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(readonly, nostack, pure) + ); r } @@ -20,10 +24,14 @@ pub unsafe fn _bittest(p: *const i32, b: i32) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandset(p: *mut i32, b: i32) -> u8 { let r: u8; - llvm_asm!("btsl $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "bts [{p}], {b:e}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } @@ -33,10 +41,14 @@ pub unsafe fn _bittestandset(p: *mut i32, b: i32) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandreset(p: *mut i32, b: i32) -> u8 { let r: u8; - llvm_asm!("btrl $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "btr [{p}], {b:e}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } @@ -46,10 +58,14 @@ pub unsafe fn _bittestandreset(p: *mut i32, b: i32) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandcomplement(p: *mut i32, b: i32) -> u8 { let r: u8; - llvm_asm!("btcl $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "btc [{p}], {b:e}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } diff --git a/crates/core_arch/src/x86/cpuid.rs b/crates/core_arch/src/x86/cpuid.rs index 42cc95b4d0..3574ee178a 100644 --- a/crates/core_arch/src/x86/cpuid.rs +++ b/crates/core_arch/src/x86/cpuid.rs @@ -125,30 +125,25 @@ pub fn has_cpuid() -> bool { // the 21st bit of the EFLAGS register is modifiable or not. // If it is, then `cpuid` is available. let result: u32; - let _temp: u32; - llvm_asm!(r#" - # Read eflags into $0 and copy it into $1: - pushfd - pop $0 - mov $1, $0 - # Flip 21st bit of $0. - xor $0, 0x200000 - # Set eflags to the value of $0 - # - # Bit 21st can only be modified if cpuid is available - push $0 - popfd # A - # Read eflags into $0: - pushfd # B - pop $0 - # xor with the original eflags sets the bits that - # have been modified: - xor $0, $1 - "# - : "=r"(result), "=r"(_temp) - : - : "cc", "memory" - : "intel"); + asm!( + // Read eflags and save a copy of it + "pushfd", + "pop {result}", + "mov {saved_flags}, {result}", + // Flip 21st bit of the flags + "xor {result}, 0x200000", + // Load the modified flags and read them back. + // Bit 21 can only be modified if cpuid is available. + "push {result}", + "popfd", + "pushfd", + "pop {result}", + // Use xor to find out whether bit 21 has changed + "xor {result}, {saved_flags}", + result = out(reg) result, + saved_flags = out(reg) _, + options(nomem), + ); // There is a race between popfd (A) and pushfd (B) // where other bits beyond 21st may have been modified due to // interrupts, a debugger stepping through the asm, etc. diff --git a/crates/core_arch/src/x86/eflags.rs b/crates/core_arch/src/x86/eflags.rs index acb77bc3ec..80e950e456 100644 --- a/crates/core_arch/src/x86/eflags.rs +++ b/crates/core_arch/src/x86/eflags.rs @@ -13,7 +13,7 @@ #[doc(hidden)] pub unsafe fn __readeflags() -> u32 { let eflags: u32; - llvm_asm!("pushfd; popl $0" : "=r"(eflags) : : : "volatile"); + asm!("pushfd", "pop {}", out(reg) eflags, options(nomem)); eflags } @@ -30,7 +30,7 @@ pub unsafe fn __readeflags() -> u32 { #[doc(hidden)] pub unsafe fn __readeflags() -> u64 { let eflags: u64; - llvm_asm!("pushfq; popq $0" : "=r"(eflags) : : : "volatile"); + asm!("pushfq", "pop {}", out(reg) eflags, options(nomem)); eflags } @@ -46,7 +46,7 @@ pub unsafe fn __readeflags() -> u64 { )] #[doc(hidden)] pub unsafe fn __writeeflags(eflags: u32) { - llvm_asm!("pushl $0; popfd" : : "r"(eflags) : "cc", "flags" : "volatile"); + asm!("push {}", "popfd", in(reg) eflags, options(nomem)); } /// Write EFLAGS. @@ -61,7 +61,7 @@ pub unsafe fn __writeeflags(eflags: u32) { )] #[doc(hidden)] pub unsafe fn __writeeflags(eflags: u64) { - llvm_asm!("pushq $0; popfq" : : "r"(eflags) : "cc", "flags" : "volatile"); + asm!("push {}", "popfq", in(reg) eflags, options(nomem)); } #[cfg(test)] diff --git a/crates/core_arch/src/x86_64/bt.rs b/crates/core_arch/src/x86_64/bt.rs index f0b16baab6..0e4fcd7b2a 100644 --- a/crates/core_arch/src/x86_64/bt.rs +++ b/crates/core_arch/src/x86_64/bt.rs @@ -7,10 +7,14 @@ use stdarch_test::assert_instr; #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittest64(p: *const i64, b: i64) -> u8 { let r: u8; - llvm_asm!("btq $2, $1\n\tsetc ${0:b}" - : "=r"(r) - : "*m"(p), "r"(b) - : "cc", "memory"); + asm!( + "bt [{p}], {b}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(readonly, nostack, pure) + ); r } @@ -20,10 +24,14 @@ pub unsafe fn _bittest64(p: *const i64, b: i64) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandset64(p: *mut i64, b: i64) -> u8 { let r: u8; - llvm_asm!("btsq $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "bts [{p}], {b}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } @@ -33,10 +41,14 @@ pub unsafe fn _bittestandset64(p: *mut i64, b: i64) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandreset64(p: *mut i64, b: i64) -> u8 { let r: u8; - llvm_asm!("btrq $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "btr [{p}], {b}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } @@ -46,10 +58,14 @@ pub unsafe fn _bittestandreset64(p: *mut i64, b: i64) -> u8 { #[unstable(feature = "simd_x86_bittest", issue = "59414")] pub unsafe fn _bittestandcomplement64(p: *mut i64, b: i64) -> u8 { let r: u8; - llvm_asm!("btcq $2, $1\n\tsetc ${0:b}" - : "=r"(r), "+*m"(p) - : "r"(b) - : "cc", "memory"); + asm!( + "btc [{p}], {b}", + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack) + ); r } diff --git a/crates/std_detect/src/detect/os/aarch64.rs b/crates/std_detect/src/detect/os/aarch64.rs index c95b688970..2f289f5807 100644 --- a/crates/std_detect/src/detect/os/aarch64.rs +++ b/crates/std_detect/src/detect/os/aarch64.rs @@ -34,7 +34,11 @@ pub(crate) fn detect_features() -> cache::Initializer { // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 let aa64isar0: u64; unsafe { - llvm_asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); + asm!( + "mrs {}, ID_AA64ISAR0_EL1", + out(reg) aa64isar0, + options(pure, nomem, preserves_flags, nostack) + ); } let aes = bits_shift(aa64isar0, 7, 4) >= 1; @@ -51,7 +55,11 @@ pub(crate) fn detect_features() -> cache::Initializer { // ID_AA64PFR0_EL1 - Processor Feature Register 0 let aa64pfr0: u64; unsafe { - llvm_asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); + asm!( + "mrs {}, ID_AA64PFR0_EL1", + out(reg) aa64pfr0, + options(pure, nomem, preserves_flags, nostack) + ); } let fp = bits_shift(aa64pfr0, 19, 16) < 0xF; @@ -74,7 +82,11 @@ pub(crate) fn detect_features() -> cache::Initializer { // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 let aa64isar1: u64; unsafe { - llvm_asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); + asm!( + "mrs {}, ID_AA64ISAR1_EL1", + out(reg) aa64isar1, + options(pure, nomem, preserves_flags, nostack) + ); } enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1); diff --git a/crates/std_detect/src/lib.rs b/crates/std_detect/src/lib.rs index 46cf8fb68d..b051be5c0a 100644 --- a/crates/std_detect/src/lib.rs +++ b/crates/std_detect/src/lib.rs @@ -15,7 +15,7 @@ #![feature(const_fn, staged_api, stdsimd, doc_cfg, allow_internal_unstable)] #![allow(clippy::shadow_reuse)] #![deny(clippy::missing_inline_in_public_items)] -#![cfg_attr(all(target_os = "freebsd", target_arch = "aarch64"), feature(llvm_asm))] +#![cfg_attr(all(target_os = "freebsd", target_arch = "aarch64"), feature(asm))] #![cfg_attr(test, allow(unused_imports))] #![cfg_attr(feature = "std_detect_file_io", feature(vec_spare_capacity))] #![no_std]