Convert all uses of llvm_asm! to asm! (#1052)

This commit is contained in:
Amanieu d'Antras 2021-03-17 01:44:35 +00:00 committed by GitHub
parent 7accc82569
commit a1e151e838
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 161 additions and 140 deletions

View file

@ -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)
)
}
}

View file

@ -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<const IMM4: i32>() {
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

View file

@ -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));
}
}
};

View file

@ -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:
/// 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<const VAL: i32>() {
static_assert_imm16!(VAL);
asm!("brk {}", const VAL);
}
/// Inserts a breakpoint instruction.
///
/// * `BKPT` when compiling as T32,
/// * `BRK` when compiling as A32 or A64.
/// `VAL` is a compile-time constant integer in range `[0, 255]`.
///
/// # Safety
///
/// 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<const VAL: i32>() {
static_assert_imm8!(VAL);
asm!("bkpt #{}", const VAL);
}

View file

@ -12,7 +12,6 @@
platform_intrinsics,
repr_simd,
simd_ffi,
llvm_asm,
proc_macro_hygiene,
stmt_expr_attributes,
core_intrinsics,

View file

@ -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) => {

View file

@ -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
}

View file

@ -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.

View file

@ -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)]

View file

@ -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
}

View file

@ -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);

View file

@ -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]