mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
Add inline asm register definitions to librustc_target
This commit is contained in:
parent
62d5784a8f
commit
989edf6dd9
155
src/librustc_target/asm/aarch64.rs
Normal file
155
src/librustc_target/asm/aarch64.rs
Normal file
@ -0,0 +1,155 @@
|
||||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
AArch64 AArch64InlineAsmRegClass {
|
||||
reg,
|
||||
vreg,
|
||||
vreg_low16,
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64InlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::reg => &['w', 'x'],
|
||||
Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str, Option<&'static str>)> {
|
||||
match self {
|
||||
Self::reg => {
|
||||
if ty.size().bits() <= 32 {
|
||||
Some(('w', "w0", None))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Self::vreg | Self::vreg_low16 => match ty.size().bits() {
|
||||
8 => Some(('b', "b0", None)),
|
||||
16 => Some(('h', "h0", None)),
|
||||
32 => Some(('s', "s0", None)),
|
||||
64 => Some(('d', "d0", None)),
|
||||
128 => Some(('q', "q0", None)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg => Some(('x', "x0")),
|
||||
Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
|
||||
Self::vreg | Self::vreg_low16 => types! {
|
||||
"fp": I8, I16, I32, I64, F32, F64,
|
||||
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
|
||||
x0: reg = ["x0", "w0"],
|
||||
x1: reg = ["x1", "w1"],
|
||||
x2: reg = ["x2", "w2"],
|
||||
x3: reg = ["x3", "w3"],
|
||||
x4: reg = ["x4", "w4"],
|
||||
x5: reg = ["x5", "w5"],
|
||||
x6: reg = ["x6", "w6"],
|
||||
x7: reg = ["x7", "w7"],
|
||||
x8: reg = ["x8", "w8"],
|
||||
x9: reg = ["x9", "w9"],
|
||||
x10: reg = ["x10", "w10"],
|
||||
x11: reg = ["x11", "w11"],
|
||||
x12: reg = ["x12", "w12"],
|
||||
x13: reg = ["x13", "w13"],
|
||||
x14: reg = ["x14", "w14"],
|
||||
x15: reg = ["x15", "w15"],
|
||||
x16: reg = ["x16", "w16"],
|
||||
x17: reg = ["x17", "w17"],
|
||||
x18: reg = ["x18", "w18"],
|
||||
x19: reg = ["x19", "w19"],
|
||||
x20: reg = ["x20", "w20"],
|
||||
x21: reg = ["x21", "w21"],
|
||||
x22: reg = ["x22", "w22"],
|
||||
x23: reg = ["x23", "w23"],
|
||||
x24: reg = ["x24", "w24"],
|
||||
x25: reg = ["x25", "w25"],
|
||||
x26: reg = ["x26", "w26"],
|
||||
x27: reg = ["x27", "w27"],
|
||||
x28: reg = ["x28", "w28"],
|
||||
x30: reg = ["x30", "w30", "lr"],
|
||||
v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
|
||||
v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
|
||||
v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
|
||||
v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"],
|
||||
v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"],
|
||||
v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"],
|
||||
v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"],
|
||||
v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"],
|
||||
v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"],
|
||||
v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"],
|
||||
v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"],
|
||||
v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"],
|
||||
v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"],
|
||||
v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"],
|
||||
v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"],
|
||||
v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"],
|
||||
v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"],
|
||||
v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"],
|
||||
v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"],
|
||||
v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"],
|
||||
v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"],
|
||||
v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"],
|
||||
v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"],
|
||||
v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"],
|
||||
v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"],
|
||||
v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"],
|
||||
v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"],
|
||||
v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"],
|
||||
v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"],
|
||||
v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
|
||||
v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
|
||||
v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
|
||||
"the frame pointer cannot be used as an operand for inline asm" =
|
||||
["x29", "fp"],
|
||||
"the stack pointer cannot be used as an operand for inline asm" =
|
||||
["sp", "wsp"],
|
||||
"the zero register cannot be used as an operand for inline asm" =
|
||||
["xzr", "wzr"],
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64InlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
let (prefix, index) = if (self as u32) < Self::v0 as u32 {
|
||||
(modifier.unwrap_or('x'), self as u32 - Self::x0 as u32)
|
||||
} else {
|
||||
(modifier.unwrap_or('v'), self as u32 - Self::v0 as u32)
|
||||
};
|
||||
assert!(index < 32);
|
||||
write!(out, "{}{}", prefix, index)
|
||||
}
|
||||
}
|
253
src/librustc_target/asm/arm.rs
Normal file
253
src/librustc_target/asm/arm.rs
Normal file
@ -0,0 +1,253 @@
|
||||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
Arm ArmInlineAsmRegClass {
|
||||
reg,
|
||||
reg_thumb,
|
||||
sreg,
|
||||
sreg_low16,
|
||||
dreg,
|
||||
dreg_low16,
|
||||
dreg_low8,
|
||||
qreg,
|
||||
qreg_low8,
|
||||
qreg_low4,
|
||||
}
|
||||
}
|
||||
|
||||
impl ArmInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => &['e', 'f'],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str, Option<&'static str>)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg | Self::reg_thumb => types! { _: I8, I16, I32, F32; },
|
||||
Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
|
||||
Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
|
||||
"vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
|
||||
},
|
||||
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
|
||||
"neon": VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
|
||||
r0: reg, reg_thumb = ["r0", "a1"],
|
||||
r1: reg, reg_thumb = ["r1", "a2"],
|
||||
r2: reg, reg_thumb = ["r2", "a3"],
|
||||
r3: reg, reg_thumb = ["r3", "a4"],
|
||||
r4: reg, reg_thumb = ["r4", "v1"],
|
||||
r5: reg, reg_thumb = ["r5", "v2"],
|
||||
r6: reg, reg_thumb = ["r6", "v3"],
|
||||
r7: reg, reg_thumb = ["r7", "v4"],
|
||||
r8: reg = ["r8", "v5"],
|
||||
r9: reg = ["r9", "v6", "rfp"],
|
||||
r10: reg = ["r10", "sl"],
|
||||
r12: reg = ["r12", "ip"],
|
||||
r14: reg = ["r14", "lr"],
|
||||
s0: sreg, sreg_low16 = ["s0"],
|
||||
s1: sreg, sreg_low16 = ["s1"],
|
||||
s2: sreg, sreg_low16 = ["s2"],
|
||||
s3: sreg, sreg_low16 = ["s3"],
|
||||
s4: sreg, sreg_low16 = ["s4"],
|
||||
s5: sreg, sreg_low16 = ["s5"],
|
||||
s6: sreg, sreg_low16 = ["s6"],
|
||||
s7: sreg, sreg_low16 = ["s7"],
|
||||
s8: sreg, sreg_low16 = ["s8"],
|
||||
s9: sreg, sreg_low16 = ["s9"],
|
||||
s10: sreg, sreg_low16 = ["s10"],
|
||||
s11: sreg, sreg_low16 = ["s11"],
|
||||
s12: sreg, sreg_low16 = ["s12"],
|
||||
s13: sreg, sreg_low16 = ["s13"],
|
||||
s14: sreg, sreg_low16 = ["s14"],
|
||||
s15: sreg, sreg_low16 = ["s15"],
|
||||
s16: sreg = ["s16"],
|
||||
s17: sreg = ["s17"],
|
||||
s18: sreg = ["s18"],
|
||||
s19: sreg = ["s19"],
|
||||
s20: sreg = ["s20"],
|
||||
s21: sreg = ["s21"],
|
||||
s22: sreg = ["s22"],
|
||||
s23: sreg = ["s23"],
|
||||
s24: sreg = ["s24"],
|
||||
s25: sreg = ["s25"],
|
||||
s26: sreg = ["s26"],
|
||||
s27: sreg = ["s27"],
|
||||
s28: sreg = ["s28"],
|
||||
s29: sreg = ["s29"],
|
||||
s30: sreg = ["s30"],
|
||||
s31: sreg = ["s31"],
|
||||
d0: dreg, dreg_low16, dreg_low8 = ["d0"],
|
||||
d1: dreg, dreg_low16, dreg_low8 = ["d1"],
|
||||
d2: dreg, dreg_low16, dreg_low8 = ["d2"],
|
||||
d3: dreg, dreg_low16, dreg_low8 = ["d3"],
|
||||
d4: dreg, dreg_low16, dreg_low8 = ["d4"],
|
||||
d5: dreg, dreg_low16, dreg_low8 = ["d5"],
|
||||
d6: dreg, dreg_low16, dreg_low8 = ["d6"],
|
||||
d7: dreg, dreg_low16, dreg_low8 = ["d7"],
|
||||
d8: dreg, dreg_low16 = ["d8"],
|
||||
d9: dreg, dreg_low16 = ["d9"],
|
||||
d10: dreg, dreg_low16 = ["d10"],
|
||||
d11: dreg, dreg_low16 = ["d11"],
|
||||
d12: dreg, dreg_low16 = ["d12"],
|
||||
d13: dreg, dreg_low16 = ["d13"],
|
||||
d14: dreg, dreg_low16 = ["d14"],
|
||||
d15: dreg, dreg_low16 = ["d15"],
|
||||
d16: dreg = ["d16"],
|
||||
d17: dreg = ["d17"],
|
||||
d18: dreg = ["d18"],
|
||||
d19: dreg = ["d19"],
|
||||
d20: dreg = ["d20"],
|
||||
d21: dreg = ["d21"],
|
||||
d22: dreg = ["d22"],
|
||||
d23: dreg = ["d23"],
|
||||
d24: dreg = ["d24"],
|
||||
d25: dreg = ["d25"],
|
||||
d26: dreg = ["d26"],
|
||||
d27: dreg = ["d27"],
|
||||
d28: dreg = ["d28"],
|
||||
d29: dreg = ["d29"],
|
||||
d30: dreg = ["d30"],
|
||||
d31: dreg = ["d31"],
|
||||
q0: qreg, qreg_low8, qreg_low4 = ["q0"],
|
||||
q1: qreg, qreg_low8, qreg_low4 = ["q1"],
|
||||
q2: qreg, qreg_low8, qreg_low4 = ["q2"],
|
||||
q3: qreg, qreg_low8, qreg_low4 = ["q3"],
|
||||
q4: qreg, qreg_low8 = ["q4"],
|
||||
q5: qreg, qreg_low8 = ["q5"],
|
||||
q6: qreg, qreg_low8 = ["q6"],
|
||||
q7: qreg, qreg_low8 = ["q7"],
|
||||
q8: qreg = ["q8"],
|
||||
q9: qreg = ["q9"],
|
||||
q10: qreg = ["q10"],
|
||||
q11: qreg = ["q11"],
|
||||
q12: qreg = ["q12"],
|
||||
q13: qreg = ["q13"],
|
||||
q14: qreg = ["q14"],
|
||||
q15: qreg = ["q15"],
|
||||
"the frame pointer cannot be used as an operand for inline asm" =
|
||||
["r11", "fp"],
|
||||
"the stack pointer cannot be used as an operand for inline asm" =
|
||||
["r13", "sp"],
|
||||
"the program pointer cannot be used as an operand for inline asm" =
|
||||
["r15", "pc"],
|
||||
}
|
||||
}
|
||||
|
||||
impl ArmInlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
// Only qreg is allowed to have modifiers. This should have been
|
||||
// validated already by now.
|
||||
if let Some(modifier) = modifier {
|
||||
let index = self as u32 - Self::q0 as u32;
|
||||
assert!(index < 16);
|
||||
let index = index * 2 + (modifier == 'f') as u32;
|
||||
write!(out, "d{}", index)
|
||||
} else {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(ArmInlineAsmReg)) {
|
||||
cb(self);
|
||||
|
||||
macro_rules! reg_conflicts {
|
||||
(
|
||||
$(
|
||||
$q:ident : $d0:ident $d1:ident : $s0:ident $s1:ident $s2:ident $s3:ident
|
||||
),*;
|
||||
$(
|
||||
$q_high:ident : $d0_high:ident $d1_high:ident
|
||||
),*;
|
||||
) => {
|
||||
match self {
|
||||
$(
|
||||
Self::$q => {
|
||||
cb(Self::$d0);
|
||||
cb(Self::$d1);
|
||||
cb(Self::$s0);
|
||||
cb(Self::$s1);
|
||||
cb(Self::$s2);
|
||||
cb(Self::$s3);
|
||||
}
|
||||
Self::$d0 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$s0);
|
||||
cb(Self::$s1);
|
||||
}
|
||||
Self::$d1 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$s2);
|
||||
cb(Self::$s3);
|
||||
}
|
||||
Self::$s0 | Self::$s1 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$d0);
|
||||
}
|
||||
Self::$s2 | Self::$s3 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$d1);
|
||||
}
|
||||
)*
|
||||
$(
|
||||
Self::$q_high => {
|
||||
cb(Self::$d0_high);
|
||||
cb(Self::$d1_high);
|
||||
}
|
||||
Self::$d0_high | Self::$d1_high => {
|
||||
cb(Self::$q_high);
|
||||
}
|
||||
)*
|
||||
_ => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
reg_conflicts! {
|
||||
q0 : d0 d1 : s0 s1 s2 s3,
|
||||
q1 : d2 d3 : s4 s5 s6 s7,
|
||||
q2 : d4 d5 : s8 s9 s10 s11,
|
||||
q3 : d6 d7 : s12 s13 s14 s15,
|
||||
q4 : d8 d9 : s16 s17 s18 s19,
|
||||
q5 : d10 d11 : s20 s21 s22 s23,
|
||||
q6 : d12 d13 : s24 s25 s26 s27,
|
||||
q7 : d14 d15 : s28 s29 s30 s31;
|
||||
q8 : d16 d17,
|
||||
q9 : d18 d19,
|
||||
q10 : d20 d21,
|
||||
q11 : d22 d23,
|
||||
q12 : d24 d25,
|
||||
q13 : d26 d27,
|
||||
q14 : d28 d29,
|
||||
q15 : d30 d31;
|
||||
}
|
||||
}
|
||||
}
|
560
src/librustc_target/asm/mod.rs
Normal file
560
src/librustc_target/asm/mod.rs
Normal file
@ -0,0 +1,560 @@
|
||||
use crate::abi::Size;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! def_reg_class {
|
||||
($arch:ident $arch_regclass:ident {
|
||||
$(
|
||||
$class:ident,
|
||||
)*
|
||||
}) => {
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $arch_regclass {
|
||||
$($class,)*
|
||||
}
|
||||
|
||||
impl $arch_regclass {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
$(Self::$class => stringify!($class),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result<Self, &'static str> {
|
||||
match name {
|
||||
$(
|
||||
stringify!($class) => Ok(Self::$class),
|
||||
)*
|
||||
_ => Err("unknown register class"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
|
||||
super::InlineAsmRegClass,
|
||||
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
|
||||
> {
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use super::InlineAsmRegClass;
|
||||
let mut map = FxHashMap::default();
|
||||
$(
|
||||
map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
|
||||
)*
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! def_regs {
|
||||
($arch:ident $arch_reg:ident $arch_regclass:ident {
|
||||
$(
|
||||
$reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
|
||||
)*
|
||||
$(
|
||||
$error:literal = [$($bad_reg:literal),+],
|
||||
)*
|
||||
}) => {
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $arch_reg {
|
||||
$($reg,)*
|
||||
}
|
||||
|
||||
impl $arch_reg {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
$(Self::$reg => $reg_name,)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reg_class(self) -> $arch_regclass {
|
||||
match self {
|
||||
$(Self::$reg => $arch_regclass::$class,)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
_arch: super::InlineAsmArch,
|
||||
mut _has_feature: impl FnMut(&str) -> bool,
|
||||
name: &str,
|
||||
) -> Result<Self, &'static str> {
|
||||
match name {
|
||||
$(
|
||||
$($alias)|* | $reg_name => {
|
||||
$($filter(_arch, &mut _has_feature)?;)?
|
||||
Ok(Self::$reg)
|
||||
}
|
||||
)*
|
||||
$(
|
||||
$($bad_reg)|* => Err($error),
|
||||
)*
|
||||
_ => Err("unknown register"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fill_reg_map(
|
||||
_arch: super::InlineAsmArch,
|
||||
mut _has_feature: impl FnMut(&str) -> bool,
|
||||
map: &mut rustc_data_structures::fx::FxHashMap<
|
||||
super::InlineAsmRegClass,
|
||||
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
|
||||
>,
|
||||
) {
|
||||
use super::{InlineAsmReg, InlineAsmRegClass};
|
||||
$(
|
||||
if $($filter(_arch, &mut _has_feature).is_ok() &&)? true {
|
||||
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
$(
|
||||
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! types {
|
||||
(
|
||||
$(_ : $($ty:expr),+;)?
|
||||
$($feature:literal: $($ty2:expr),+;)*
|
||||
) => {
|
||||
{
|
||||
use super::InlineAsmType::*;
|
||||
&[
|
||||
$($(
|
||||
($ty, None),
|
||||
)*)?
|
||||
$($(
|
||||
($ty2, Some($feature)),
|
||||
)*)*
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod aarch64;
|
||||
mod arm;
|
||||
mod riscv;
|
||||
mod x86;
|
||||
|
||||
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
|
||||
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
|
||||
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
|
||||
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum InlineAsmArch {
|
||||
X86,
|
||||
X86_64,
|
||||
Arm,
|
||||
AArch64,
|
||||
RiscV32,
|
||||
RiscV64,
|
||||
}
|
||||
|
||||
impl FromStr for InlineAsmArch {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
|
||||
match s {
|
||||
"x86" => Ok(Self::X86),
|
||||
"x86_64" => Ok(Self::X86_64),
|
||||
"arm" => Ok(Self::Arm),
|
||||
"aarch64" => Ok(Self::AArch64),
|
||||
"riscv32" => Ok(Self::RiscV32),
|
||||
"riscv64" => Ok(Self::RiscV64),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
RustcEncodable,
|
||||
RustcDecodable,
|
||||
Debug,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
HashStable_Generic
|
||||
)]
|
||||
pub enum InlineAsmReg {
|
||||
X86(X86InlineAsmReg),
|
||||
Arm(ArmInlineAsmReg),
|
||||
AArch64(AArch64InlineAsmReg),
|
||||
RiscV(RiscVInlineAsmReg),
|
||||
}
|
||||
|
||||
impl InlineAsmReg {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::X86(r) => r.name(),
|
||||
Self::Arm(r) => r.name(),
|
||||
Self::AArch64(r) => r.name(),
|
||||
Self::RiscV(r) => r.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reg_class(self) -> InlineAsmRegClass {
|
||||
match self {
|
||||
Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
|
||||
Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
|
||||
Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
|
||||
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
name: Symbol,
|
||||
) -> Result<Self, &'static str> {
|
||||
// FIXME: use direct symbol comparison for register names
|
||||
name.with(|name| {
|
||||
Ok(match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
Self::X86(X86InlineAsmReg::parse(arch, has_feature, name)?)
|
||||
}
|
||||
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, name)?),
|
||||
InlineAsmArch::AArch64 => {
|
||||
Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, name)?)
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, name)?)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
match self {
|
||||
Self::X86(r) => r.emit(out, arch, modifier),
|
||||
Self::Arm(r) => r.emit(out, arch, modifier),
|
||||
Self::AArch64(r) => r.emit(out, arch, modifier),
|
||||
Self::RiscV(r) => r.emit(out, arch, modifier),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
|
||||
match self {
|
||||
Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
|
||||
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
|
||||
Self::AArch64(_) => cb(self),
|
||||
Self::RiscV(_) => cb(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
RustcEncodable,
|
||||
RustcDecodable,
|
||||
Debug,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
HashStable_Generic
|
||||
)]
|
||||
pub enum InlineAsmRegClass {
|
||||
X86(X86InlineAsmRegClass),
|
||||
Arm(ArmInlineAsmRegClass),
|
||||
AArch64(AArch64InlineAsmRegClass),
|
||||
RiscV(RiscVInlineAsmRegClass),
|
||||
}
|
||||
|
||||
impl InlineAsmRegClass {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::X86(r) => r.name(),
|
||||
Self::Arm(r) => r.name(),
|
||||
Self::AArch64(r) => r.name(),
|
||||
Self::RiscV(r) => r.name(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggested template modifier to use for this type and an
|
||||
/// example of a register named formatted with it. Optionally also returns
|
||||
/// the name of a different register class to use instead.
|
||||
///
|
||||
/// Such suggestions are useful if a type smaller than the full register
|
||||
/// size is used and a modifier can be used to point to the subregister of
|
||||
/// the correct size.
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str, Option<&'static str>)> {
|
||||
match self {
|
||||
Self::X86(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Arm(r) => r.suggest_modifier(arch, ty),
|
||||
Self::AArch64(r) => r.suggest_modifier(arch, ty),
|
||||
Self::RiscV(r) => r.suggest_modifier(arch, ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default modifier for this register and an example of a
|
||||
/// register named formatted with it.
|
||||
///
|
||||
/// This is only needed when the register class can suggest a modifier, so
|
||||
/// that the user can be shown how to get the default behavior without a
|
||||
/// warning.
|
||||
pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::X86(r) => r.default_modifier(arch),
|
||||
Self::Arm(r) => r.default_modifier(arch),
|
||||
Self::AArch64(r) => r.default_modifier(arch),
|
||||
Self::RiscV(r) => r.default_modifier(arch),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of supported types for this register class, each with a
|
||||
/// options target feature required to use this type.
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::X86(r) => r.supported_types(arch),
|
||||
Self::Arm(r) => r.supported_types(arch),
|
||||
Self::AArch64(r) => r.supported_types(arch),
|
||||
Self::RiscV(r) => r.supported_types(arch),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
|
||||
// FIXME: use direct symbol comparison for register class names
|
||||
name.with(|name| {
|
||||
Ok(match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
|
||||
InlineAsmArch::AArch64 => {
|
||||
Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the list of template modifiers that can be used with this
|
||||
/// register class.
|
||||
pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::X86(r) => r.valid_modifiers(arch),
|
||||
Self::Arm(r) => r.valid_modifiers(arch),
|
||||
Self::AArch64(r) => r.valid_modifiers(arch),
|
||||
Self::RiscV(r) => r.valid_modifiers(arch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
RustcEncodable,
|
||||
RustcDecodable,
|
||||
Debug,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
HashStable_Generic
|
||||
)]
|
||||
pub enum InlineAsmRegOrRegClass {
|
||||
Reg(InlineAsmReg),
|
||||
RegClass(InlineAsmRegClass),
|
||||
}
|
||||
|
||||
impl InlineAsmRegOrRegClass {
|
||||
pub fn reg_class(self) -> InlineAsmRegClass {
|
||||
match self {
|
||||
Self::Reg(r) => r.reg_class(),
|
||||
Self::RegClass(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InlineAsmRegOrRegClass {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Reg(r) => write!(f, "\"{}\"", r.name()),
|
||||
Self::RegClass(r) => f.write_str(r.name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions: u8 {
|
||||
const PURE = 1 << 0;
|
||||
const NOMEM = 1 << 1;
|
||||
const READONLY = 1 << 2;
|
||||
const PRESERVES_FLAGS = 1 << 3;
|
||||
const NORETURN = 1 << 4;
|
||||
const NOSTACK = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
|
||||
pub enum InlineAsmTemplatePiece {
|
||||
String(String),
|
||||
Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
|
||||
}
|
||||
|
||||
impl fmt::Display for InlineAsmTemplatePiece {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::String(s) => {
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'{' => f.write_str("{{")?,
|
||||
'}' => f.write_str("}}")?,
|
||||
_ => write!(f, "{}", c.escape_debug())?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Placeholder { operand_idx, modifier: Some(modifier), .. } => {
|
||||
write!(f, "{{{}:{}}}", operand_idx, modifier)
|
||||
}
|
||||
Self::Placeholder { operand_idx, modifier: None, .. } => {
|
||||
write!(f, "{{{}}}", operand_idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InlineAsmTemplatePiece {
|
||||
/// Rebuilds the asm template string from its pieces.
|
||||
pub fn to_string(s: &[Self]) -> String {
|
||||
use fmt::Write;
|
||||
let mut out = String::new();
|
||||
for p in s.iter() {
|
||||
let _ = write!(out, "{}", p);
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// Set of types which can be used with a particular register class.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum InlineAsmType {
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
F32,
|
||||
F64,
|
||||
VecI8(u64),
|
||||
VecI16(u64),
|
||||
VecI32(u64),
|
||||
VecI64(u64),
|
||||
VecI128(u64),
|
||||
VecF32(u64),
|
||||
VecF64(u64),
|
||||
}
|
||||
|
||||
impl InlineAsmType {
|
||||
pub fn is_integer(self) -> bool {
|
||||
match self {
|
||||
Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self) -> Size {
|
||||
Size::from_bytes(match self {
|
||||
Self::I8 => 1,
|
||||
Self::I16 => 2,
|
||||
Self::I32 => 4,
|
||||
Self::I64 => 8,
|
||||
Self::I128 => 16,
|
||||
Self::F32 => 4,
|
||||
Self::F64 => 8,
|
||||
Self::VecI8(n) => n * 1,
|
||||
Self::VecI16(n) => n * 2,
|
||||
Self::VecI32(n) => n * 4,
|
||||
Self::VecI64(n) => n * 8,
|
||||
Self::VecI128(n) => n * 16,
|
||||
Self::VecF32(n) => n * 4,
|
||||
Self::VecF64(n) => n * 8,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InlineAsmType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Self::I8 => f.write_str("i8"),
|
||||
Self::I16 => f.write_str("i16"),
|
||||
Self::I32 => f.write_str("i32"),
|
||||
Self::I64 => f.write_str("i64"),
|
||||
Self::I128 => f.write_str("i128"),
|
||||
Self::F32 => f.write_str("f32"),
|
||||
Self::F64 => f.write_str("f64"),
|
||||
Self::VecI8(n) => write!(f, "i8x{}", n),
|
||||
Self::VecI16(n) => write!(f, "i16x{}", n),
|
||||
Self::VecI32(n) => write!(f, "i32x{}", n),
|
||||
Self::VecI64(n) => write!(f, "i64x{}", n),
|
||||
Self::VecI128(n) => write!(f, "i128x{}", n),
|
||||
Self::VecF32(n) => write!(f, "f32x{}", n),
|
||||
Self::VecF64(n) => write!(f, "f64x{}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the full set of allocatable registers for a given architecture.
|
||||
///
|
||||
/// The registers are structured as a map containing the set of allocatable
|
||||
/// registers in each register class. A particular register may be allocatable
|
||||
/// from multiple register classes, in which case it will appear multiple times
|
||||
/// in the map.
|
||||
pub fn allocatable_registers(
|
||||
arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
let mut map = x86::regclass_map();
|
||||
x86::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::Arm => {
|
||||
let mut map = arm::regclass_map();
|
||||
arm::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
let mut map = aarch64::regclass_map();
|
||||
aarch64::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
let mut map = riscv::regclass_map();
|
||||
riscv::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
140
src/librustc_target/asm/riscv.rs
Normal file
140
src/librustc_target/asm/riscv.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
RiscV RiscVInlineAsmRegClass {
|
||||
reg,
|
||||
freg,
|
||||
}
|
||||
}
|
||||
|
||||
impl RiscVInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
&[]
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str, Option<&'static str>)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg => {
|
||||
if arch == InlineAsmArch::RiscV64 {
|
||||
types! { _: I8, I16, I32, I64, F32, F64; }
|
||||
} else {
|
||||
types! { _: I8, I16, I32, F32; }
|
||||
}
|
||||
}
|
||||
Self::freg => types! { "f": F32; "d": F64; },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn not_e(
|
||||
_arch: InlineAsmArch,
|
||||
mut has_feature: impl FnMut(&str) -> bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if has_feature("e") {
|
||||
Err("register can't be used with the `e` target feature")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
RiscV RiscVInlineAsmReg RiscVInlineAsmRegClass {
|
||||
x1: reg = ["x1", "ra"],
|
||||
x5: reg = ["x5", "t0"],
|
||||
x6: reg = ["x6", "t1"],
|
||||
x7: reg = ["x7", "t2"],
|
||||
x9: reg = ["x9", "s1"],
|
||||
x10: reg = ["x10", "a0"],
|
||||
x11: reg = ["x11", "a1"],
|
||||
x12: reg = ["x12", "a2"],
|
||||
x13: reg = ["x13", "a3"],
|
||||
x14: reg = ["x14", "a4"],
|
||||
x15: reg = ["x15", "a5"],
|
||||
x16: reg = ["x16", "a6"] % not_e,
|
||||
x17: reg = ["x17", "a7"] % not_e,
|
||||
x18: reg = ["x18", "s2"] % not_e,
|
||||
x19: reg = ["x19", "s3"] % not_e,
|
||||
x20: reg = ["x20", "s4"] % not_e,
|
||||
x21: reg = ["x21", "s5"] % not_e,
|
||||
x22: reg = ["x22", "s6"] % not_e,
|
||||
x23: reg = ["x23", "s7"] % not_e,
|
||||
x24: reg = ["x24", "s8"] % not_e,
|
||||
x25: reg = ["x25", "s9"] % not_e,
|
||||
x26: reg = ["x26", "s10"] % not_e,
|
||||
x27: reg = ["x27", "s11"] % not_e,
|
||||
x28: reg = ["x28", "t3"] % not_e,
|
||||
x29: reg = ["x29", "t4"] % not_e,
|
||||
x30: reg = ["x30", "t5"] % not_e,
|
||||
x31: reg = ["x31", "t6"] % not_e,
|
||||
f0: freg = ["f0", "ft0"],
|
||||
f1: freg = ["f1", "ft1"],
|
||||
f2: freg = ["f2", "ft2"],
|
||||
f3: freg = ["f3", "ft3"],
|
||||
f4: freg = ["f4", "ft4"],
|
||||
f5: freg = ["f5", "ft5"],
|
||||
f6: freg = ["f6", "ft6"],
|
||||
f7: freg = ["f7", "ft7"],
|
||||
f8: freg = ["f8", "fs0"],
|
||||
f9: freg = ["f9", "fs1"],
|
||||
f10: freg = ["f10", "fa0"],
|
||||
f11: freg = ["f11", "fa1"],
|
||||
f12: freg = ["f12", "fa2"],
|
||||
f13: freg = ["f13", "fa3"],
|
||||
f14: freg = ["f14", "fa4"],
|
||||
f15: freg = ["f15", "fa5"],
|
||||
f16: freg = ["f16", "fa6"],
|
||||
f17: freg = ["f17", "fa7"],
|
||||
f18: freg = ["f18", "fs2"],
|
||||
f19: freg = ["f19", "fs3"],
|
||||
f20: freg = ["f20", "fs4"],
|
||||
f21: freg = ["f21", "fs5"],
|
||||
f22: freg = ["f22", "fs6"],
|
||||
f23: freg = ["f23", "fs7"],
|
||||
f24: freg = ["f24", "fs8"],
|
||||
f25: freg = ["f25", "fs9"],
|
||||
f26: freg = ["f26", "fs10"],
|
||||
f27: freg = ["f27", "fs11"],
|
||||
f28: freg = ["f28", "ft8"],
|
||||
f29: freg = ["f29", "ft9"],
|
||||
f30: freg = ["f30", "ft10"],
|
||||
f31: freg = ["f31", "ft11"],
|
||||
"the frame pointer cannot be used as an operand for inline asm" =
|
||||
["x8", "s0", "fp"],
|
||||
"the stack pointer cannot be used as an operand for inline asm" =
|
||||
["x2", "sp"],
|
||||
"the global pointer cannot be used as an operand for inline asm" =
|
||||
["x3", "gp"],
|
||||
"the thread pointer cannot be used as an operand for inline asm" =
|
||||
["x4", "tp"],
|
||||
"the zero register cannot be used as an operand for inline asm" =
|
||||
["x0", "zero"],
|
||||
}
|
||||
}
|
||||
|
||||
impl RiscVInlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
_modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
}
|
338
src/librustc_target/asm/x86.rs
Normal file
338
src/librustc_target/asm/x86.rs
Normal file
@ -0,0 +1,338 @@
|
||||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
X86 X86InlineAsmRegClass {
|
||||
reg,
|
||||
reg_abcd,
|
||||
xmm_reg,
|
||||
ymm_reg,
|
||||
zmm_reg,
|
||||
kreg,
|
||||
}
|
||||
}
|
||||
|
||||
impl X86InlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::reg => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
&['l', 'h', 'x', 'e', 'r']
|
||||
} else {
|
||||
&['x', 'e']
|
||||
}
|
||||
}
|
||||
Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
&['l', 'h', 'x', 'e', 'r']
|
||||
} else {
|
||||
&['l', 'h', 'x', 'e']
|
||||
}
|
||||
}
|
||||
Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
|
||||
Self::kreg => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str, Option<&'static str>)> {
|
||||
match self {
|
||||
Self::reg => match ty.size().bits() {
|
||||
8 => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
Some(('l', "al", None))
|
||||
} else {
|
||||
// Low byte registers require reg_abcd on x86 so we emit
|
||||
// a suggestion to use that register class instead.
|
||||
Some(('l', "al", Some("reg_abcd")))
|
||||
}
|
||||
}
|
||||
16 => Some(('x', "ax", None)),
|
||||
32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)),
|
||||
_ => None,
|
||||
},
|
||||
Self::reg_abcd => match ty.size().bits() {
|
||||
8 => Some(('l', "al", None)),
|
||||
16 => Some(('x', "ax", None)),
|
||||
32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)),
|
||||
_ => None,
|
||||
},
|
||||
Self::xmm_reg => None,
|
||||
Self::ymm_reg => {
|
||||
if ty.size().bits() <= 128 {
|
||||
Some(('x', "xmm0", None))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Self::zmm_reg => match ty.size().bits() {
|
||||
256 => Some(('y', "ymm0", None)),
|
||||
512 => None,
|
||||
_ => Some(('x', "xmm0", None)),
|
||||
},
|
||||
Self::kreg => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg | Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
Some(('r', "rax"))
|
||||
} else {
|
||||
Some(('e', "eax"))
|
||||
}
|
||||
}
|
||||
Self::xmm_reg => Some(('x', "xmm0")),
|
||||
Self::ymm_reg => Some(('y', "ymm0")),
|
||||
Self::zmm_reg => Some(('z', "zmm0")),
|
||||
Self::kreg => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg | Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
types! { _: I8, I16, I32, I64, F32, F64; }
|
||||
} else {
|
||||
types! { _: I8, I16, I32, F32; }
|
||||
}
|
||||
}
|
||||
Self::xmm_reg => types! {
|
||||
"sse": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
Self::ymm_reg => types! {
|
||||
"avx": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
|
||||
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4);
|
||||
},
|
||||
Self::zmm_reg => types! {
|
||||
"avx512f": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
|
||||
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4),
|
||||
VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8);
|
||||
},
|
||||
Self::kreg => types! {
|
||||
"avx512f": I8, I16;
|
||||
"avx512bw": I32, I64;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn x86_64_only(
|
||||
arch: InlineAsmArch,
|
||||
_has_feature: impl FnMut(&str) -> bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 => Err("register is only available on x86_64"),
|
||||
InlineAsmArch::X86_64 => Ok(()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
X86 X86InlineAsmReg X86InlineAsmRegClass {
|
||||
ax: reg, reg_abcd = ["ax", "al", "eax", "rax"],
|
||||
bx: reg, reg_abcd = ["bx", "bl", "ebx", "rbx"],
|
||||
cx: reg, reg_abcd = ["cx", "cl", "ecx", "rcx"],
|
||||
dx: reg, reg_abcd = ["dx", "dl", "edx", "rdx"],
|
||||
si: reg = ["si", "sil", "esi", "rsi"],
|
||||
di: reg = ["di", "dil", "edi", "rdi"],
|
||||
r8: reg = ["r8", "r8b", "r8w", "r8d"] % x86_64_only,
|
||||
r9: reg = ["r9", "r9b", "r9w", "r9d"] % x86_64_only,
|
||||
r10: reg = ["r10", "r10b", "r10w", "r10d"] % x86_64_only,
|
||||
r11: reg = ["r11", "r11b", "r11w", "r11d"] % x86_64_only,
|
||||
r12: reg = ["r12", "r12b", "r12w", "r12d"] % x86_64_only,
|
||||
r13: reg = ["r13", "r13b", "r13w", "r13d"] % x86_64_only,
|
||||
r14: reg = ["r14", "r14b", "r14w", "r14d"] % x86_64_only,
|
||||
r15: reg = ["r15", "r15b", "r15w", "r15d"] % x86_64_only,
|
||||
xmm0: xmm_reg = ["xmm0"],
|
||||
xmm1: xmm_reg = ["xmm1"],
|
||||
xmm2: xmm_reg = ["xmm2"],
|
||||
xmm3: xmm_reg = ["xmm3"],
|
||||
xmm4: xmm_reg = ["xmm4"],
|
||||
xmm5: xmm_reg = ["xmm5"],
|
||||
xmm6: xmm_reg = ["xmm6"],
|
||||
xmm7: xmm_reg = ["xmm7"],
|
||||
xmm8: xmm_reg = ["xmm8"] % x86_64_only,
|
||||
xmm9: xmm_reg = ["xmm9"] % x86_64_only,
|
||||
xmm10: xmm_reg = ["xmm10"] % x86_64_only,
|
||||
xmm11: xmm_reg = ["xmm11"] % x86_64_only,
|
||||
xmm12: xmm_reg = ["xmm12"] % x86_64_only,
|
||||
xmm13: xmm_reg = ["xmm13"] % x86_64_only,
|
||||
xmm14: xmm_reg = ["xmm14"] % x86_64_only,
|
||||
xmm15: xmm_reg = ["xmm15"] % x86_64_only,
|
||||
ymm0: ymm_reg = ["ymm0"],
|
||||
ymm1: ymm_reg = ["ymm1"],
|
||||
ymm2: ymm_reg = ["ymm2"],
|
||||
ymm3: ymm_reg = ["ymm3"],
|
||||
ymm4: ymm_reg = ["ymm4"],
|
||||
ymm5: ymm_reg = ["ymm5"],
|
||||
ymm6: ymm_reg = ["ymm6"],
|
||||
ymm7: ymm_reg = ["ymm7"],
|
||||
ymm8: ymm_reg = ["ymm8"] % x86_64_only,
|
||||
ymm9: ymm_reg = ["ymm9"] % x86_64_only,
|
||||
ymm10: ymm_reg = ["ymm10"] % x86_64_only,
|
||||
ymm11: ymm_reg = ["ymm11"] % x86_64_only,
|
||||
ymm12: ymm_reg = ["ymm12"] % x86_64_only,
|
||||
ymm13: ymm_reg = ["ymm13"] % x86_64_only,
|
||||
ymm14: ymm_reg = ["ymm14"] % x86_64_only,
|
||||
ymm15: ymm_reg = ["ymm15"] % x86_64_only,
|
||||
zmm0: zmm_reg = ["zmm0"],
|
||||
zmm1: zmm_reg = ["zmm1"],
|
||||
zmm2: zmm_reg = ["zmm2"],
|
||||
zmm3: zmm_reg = ["zmm3"],
|
||||
zmm4: zmm_reg = ["zmm4"],
|
||||
zmm5: zmm_reg = ["zmm5"],
|
||||
zmm6: zmm_reg = ["zmm6"],
|
||||
zmm7: zmm_reg = ["zmm7"],
|
||||
zmm8: zmm_reg = ["zmm8"] % x86_64_only,
|
||||
zmm9: zmm_reg = ["zmm9"] % x86_64_only,
|
||||
zmm10: zmm_reg = ["zmm10"] % x86_64_only,
|
||||
zmm11: zmm_reg = ["zmm11"] % x86_64_only,
|
||||
zmm12: zmm_reg = ["zmm12"] % x86_64_only,
|
||||
zmm13: zmm_reg = ["zmm13"] % x86_64_only,
|
||||
zmm14: zmm_reg = ["zmm14"] % x86_64_only,
|
||||
zmm15: zmm_reg = ["zmm15"] % x86_64_only,
|
||||
zmm16: zmm_reg = ["zmm16", "xmm16", "ymm16"] % x86_64_only,
|
||||
zmm17: zmm_reg = ["zmm17", "xmm17", "ymm17"] % x86_64_only,
|
||||
zmm18: zmm_reg = ["zmm18", "xmm18", "ymm18"] % x86_64_only,
|
||||
zmm19: zmm_reg = ["zmm19", "xmm19", "ymm19"] % x86_64_only,
|
||||
zmm20: zmm_reg = ["zmm20", "xmm20", "ymm20"] % x86_64_only,
|
||||
zmm21: zmm_reg = ["zmm21", "xmm21", "ymm21"] % x86_64_only,
|
||||
zmm22: zmm_reg = ["zmm22", "xmm22", "ymm22"] % x86_64_only,
|
||||
zmm23: zmm_reg = ["zmm23", "xmm23", "ymm23"] % x86_64_only,
|
||||
zmm24: zmm_reg = ["zmm24", "xmm24", "ymm24"] % x86_64_only,
|
||||
zmm25: zmm_reg = ["zmm25", "xmm25", "ymm25"] % x86_64_only,
|
||||
zmm26: zmm_reg = ["zmm26", "xmm26", "ymm26"] % x86_64_only,
|
||||
zmm27: zmm_reg = ["zmm27", "xmm27", "ymm27"] % x86_64_only,
|
||||
zmm28: zmm_reg = ["zmm28", "xmm28", "ymm28"] % x86_64_only,
|
||||
zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
|
||||
zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
|
||||
zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
|
||||
k1: kreg = ["k1"],
|
||||
k2: kreg = ["k2"],
|
||||
k3: kreg = ["k3"],
|
||||
k4: kreg = ["k4"],
|
||||
k5: kreg = ["k5"],
|
||||
k6: kreg = ["k6"],
|
||||
k7: kreg = ["k7"],
|
||||
"high byte registers are not currently supported as operands for inline asm" =
|
||||
["ah", "bh", "ch", "dh"],
|
||||
"the frame pointer cannot be used as an operand for inline asm" =
|
||||
["bp", "bpl", "ebp", "rbp"],
|
||||
"the stack pointer cannot be used as an operand for inline asm" =
|
||||
["sp", "spl", "esp", "rsp"],
|
||||
"the instruction pointer cannot be used as an operand for inline asm" =
|
||||
["ip", "eip", "rip"],
|
||||
"x87 registers are not currently supported as operands for inline asm" =
|
||||
["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"],
|
||||
"MMX registers are not currently supported as operands for inline asm" =
|
||||
["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"],
|
||||
"the k0 AVX mask register cannot be used as an operand for inline asm" = ["k0"],
|
||||
}
|
||||
}
|
||||
|
||||
impl X86InlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
let reg_default_modifier = match arch {
|
||||
InlineAsmArch::X86 => 'e',
|
||||
InlineAsmArch::X86_64 => 'r',
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if self as u32 <= Self::dx as u32 {
|
||||
let root = ['a', 'b', 'c', 'd'][self as usize - Self::ax as usize];
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "{}l", root),
|
||||
'h' => write!(out, "{}h", root),
|
||||
'x' => write!(out, "{}x", root),
|
||||
'e' => write!(out, "e{}x", root),
|
||||
'r' => write!(out, "r{}x", root),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::di as u32 {
|
||||
let root = ["si", "di"][self as usize - Self::si as usize];
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "{}l", root),
|
||||
'x' => write!(out, "{}", root),
|
||||
'e' => write!(out, "e{}", root),
|
||||
'r' => write!(out, "r{}", root),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::r15 as u32 {
|
||||
let index = self as u32 - Self::r8 as u32 + 8;
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "r{}b", index),
|
||||
'x' => write!(out, "r{}w", index),
|
||||
'e' => write!(out, "r{}d", index),
|
||||
'r' => write!(out, "r{}", index),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::xmm15 as u32 {
|
||||
let prefix = modifier.unwrap_or('x');
|
||||
let index = self as u32 - Self::xmm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else if self as u32 <= Self::ymm15 as u32 {
|
||||
let prefix = modifier.unwrap_or('y');
|
||||
let index = self as u32 - Self::ymm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else if self as u32 <= Self::zmm31 as u32 {
|
||||
let prefix = modifier.unwrap_or('z');
|
||||
let index = self as u32 - Self::zmm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else {
|
||||
let index = self as u32 - Self::k1 as u32 + 1;
|
||||
write!(out, "k{}", index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(X86InlineAsmReg)) {
|
||||
macro_rules! reg_conflicts {
|
||||
($($x:ident : $y:ident : $z:ident,)*) => {
|
||||
match self {
|
||||
$(
|
||||
Self::$x | Self::$y | Self::$z => {
|
||||
cb(Self::$x);
|
||||
cb(Self::$y);
|
||||
cb(Self::$z);
|
||||
}
|
||||
)*
|
||||
r => cb(r),
|
||||
}
|
||||
};
|
||||
}
|
||||
reg_conflicts! {
|
||||
xmm0 : ymm0 : zmm0,
|
||||
xmm1 : ymm1 : zmm1,
|
||||
xmm2 : ymm2 : zmm2,
|
||||
xmm3 : ymm3 : zmm3,
|
||||
xmm4 : ymm4 : zmm4,
|
||||
xmm5 : ymm5 : zmm5,
|
||||
xmm6 : ymm6 : zmm6,
|
||||
xmm7 : ymm7 : zmm7,
|
||||
xmm8 : ymm8 : zmm8,
|
||||
xmm9 : ymm9 : zmm9,
|
||||
xmm10 : ymm10 : zmm10,
|
||||
xmm11 : ymm11 : zmm11,
|
||||
xmm12 : ymm12 : zmm12,
|
||||
xmm13 : ymm13 : zmm13,
|
||||
xmm14 : ymm14 : zmm14,
|
||||
xmm15 : ymm15 : zmm15,
|
||||
}
|
||||
}
|
||||
}
|
@ -25,9 +25,10 @@ extern crate rustc_macros;
|
||||
extern crate log;
|
||||
|
||||
pub mod abi;
|
||||
pub mod asm;
|
||||
pub mod spec;
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
/// instead of implementing everything in librustc_middle.
|
||||
pub trait HashStableContext {}
|
||||
pub trait HashStableContext: rustc_span::HashStableContext {}
|
||||
|
Loading…
Reference in New Issue
Block a user