summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_target/src/asm
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_target/src/asm')
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs200
-rw-r--r--compiler/rustc_target/src/asm/arm.rs340
-rw-r--r--compiler/rustc_target/src/asm/avr.rs197
-rw-r--r--compiler/rustc_target/src/asm/bpf.rs118
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs95
-rw-r--r--compiler/rustc_target/src/asm/mips.rs135
-rw-r--r--compiler/rustc_target/src/asm/mod.rs976
-rw-r--r--compiler/rustc_target/src/asm/msp430.rs81
-rw-r--r--compiler/rustc_target/src/asm/nvptx.rs50
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs204
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs185
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs107
-rw-r--r--compiler/rustc_target/src/asm/spirv.rs47
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs47
-rw-r--r--compiler/rustc_target/src/asm/x86.rs492
15 files changed, 3274 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
new file mode 100644
index 000000000..62a0f9fb0
--- /dev/null
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -0,0 +1,200 @@
+use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::{RelocModel, Target};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ AArch64 AArch64InlineAsmRegClass {
+ reg,
+ vreg,
+ vreg_low16,
+ preg,
+ }
+}
+
+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'],
+ Self::preg => &[],
+ }
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ match self {
+ Self::reg => match ty.size().bits() {
+ 64 => None,
+ _ => Some(('w', "w0")),
+ },
+ Self::vreg | Self::vreg_low16 => match ty.size().bits() {
+ 8 => Some(('b', "b0")),
+ 16 => Some(('h', "h0")),
+ 32 => Some(('s', "s0")),
+ 64 => Some(('d', "d0")),
+ 128 => Some(('q', "q0")),
+ _ => None,
+ },
+ Self::preg => 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")),
+ Self::preg => None,
+ }
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
+ Self::vreg | Self::vreg_low16 => types! {
+ neon: 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);
+ },
+ Self::preg => &[],
+ }
+ }
+}
+
+pub fn target_reserves_x18(target: &Target) -> bool {
+ target.os == "android" || target.os == "fuchsia" || target.is_like_osx || target.is_like_windows
+}
+
+fn reserved_x18(
+ _arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ _target_features: &FxHashSet<Symbol>,
+ target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ if target_reserves_x18(target) {
+ Err("x18 is a reserved register on this target")
+ } else {
+ Ok(())
+ }
+}
+
+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"] % reserved_x18,
+ 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", "wlr"],
+ v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"],
+ v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"],
+ v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2", "z2"],
+ v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3", "z3"],
+ v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4", "z4"],
+ v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5", "z5"],
+ v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6", "z6"],
+ v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7", "z7"],
+ v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8", "z8"],
+ v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9", "z9"],
+ v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10", "z10"],
+ v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11", "z11"],
+ v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12", "z12"],
+ v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"],
+ v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"],
+ v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"],
+ v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"],
+ v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"],
+ v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"],
+ v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"],
+ v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"],
+ v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"],
+ v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"],
+ v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"],
+ v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"],
+ v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"],
+ v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"],
+ v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"],
+ v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"],
+ v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"],
+ v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"],
+ v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"],
+ p0: preg = ["p0"],
+ p1: preg = ["p1"],
+ p2: preg = ["p2"],
+ p3: preg = ["p3"],
+ p4: preg = ["p4"],
+ p5: preg = ["p5"],
+ p6: preg = ["p6"],
+ p7: preg = ["p7"],
+ p8: preg = ["p8"],
+ p9: preg = ["p9"],
+ p10: preg = ["p10"],
+ p11: preg = ["p11"],
+ p12: preg = ["p12"],
+ p13: preg = ["p13"],
+ p14: preg = ["p14"],
+ p15: preg = ["p15"],
+ ffr: preg = ["ffr"],
+ #error = ["x19", "w19"] =>
+ "x19 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["x29", "w29", "fp", "wfp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["sp", "wsp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["xzr", "wzr"] =>
+ "the zero register cannot be used as an operand for inline asm",
+ }
+}
+
+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)
+ }
+}
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
new file mode 100644
index 000000000..0db3eb6fc
--- /dev/null
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -0,0 +1,340 @@
+use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::{RelocModel, Target};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
+use std::fmt;
+
+def_reg_class! {
+ Arm ArmInlineAsmRegClass {
+ reg,
+ 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_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, F32; },
+ Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
+ Self::dreg_low16 | Self::dreg_low8 => types! {
+ vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
+ },
+ Self::dreg => types! {
+ d32: 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);
+ },
+ }
+ }
+}
+
+// This uses the same logic as useR7AsFramePointer in LLVM
+fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> bool {
+ target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
+}
+
+fn frame_pointer_r11(
+ arch: InlineAsmArch,
+ reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ target: &Target,
+ is_clobber: bool,
+) -> Result<(), &'static str> {
+ not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
+
+ if !frame_pointer_is_r7(target_features, target) {
+ Err("the frame pointer (r11) cannot be used as an operand for inline asm")
+ } else {
+ Ok(())
+ }
+}
+
+fn frame_pointer_r7(
+ _arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ if frame_pointer_is_r7(target_features, target) {
+ Err("the frame pointer (r7) cannot be used as an operand for inline asm")
+ } else {
+ Ok(())
+ }
+}
+
+fn not_thumb1(
+ _arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ is_clobber: bool,
+) -> Result<(), &'static str> {
+ if !is_clobber
+ && target_features.contains(&sym::thumb_mode)
+ && !target_features.contains(&sym::thumb2)
+ {
+ Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
+ } else {
+ Ok(())
+ }
+}
+
+fn reserved_r9(
+ arch: InlineAsmArch,
+ reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ target: &Target,
+ is_clobber: bool,
+) -> Result<(), &'static str> {
+ not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
+
+ match reloc_model {
+ RelocModel::Rwpi | RelocModel::RopiRwpi => {
+ Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
+ }
+ _ => Ok(()),
+ }
+}
+
+def_regs! {
+ Arm ArmInlineAsmReg ArmInlineAsmRegClass {
+ r0: reg = ["r0", "a1"],
+ r1: reg = ["r1", "a2"],
+ r2: reg = ["r2", "a3"],
+ r3: reg = ["r3", "a4"],
+ r4: reg = ["r4", "v1"],
+ r5: reg = ["r5", "v2"],
+ r7: reg = ["r7", "v4"] % frame_pointer_r7,
+ r8: reg = ["r8", "v5"] % not_thumb1,
+ r9: reg = ["r9", "v6", "rfp"] % reserved_r9,
+ r10: reg = ["r10", "sl"] % not_thumb1,
+ r11: reg = ["r11", "fp"] % frame_pointer_r11,
+ r12: reg = ["r12", "ip"] % not_thumb1,
+ r14: reg = ["r14", "lr"] % not_thumb1,
+ 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"],
+ #error = ["r6", "v3"] =>
+ "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["r13", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r15", "pc"] =>
+ "the program pointer cannot be used as an operand for inline asm",
+ }
+}
+
+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);
+ }
+ )*
+ _ => {},
+ }
+ };
+ }
+
+ // ARM's floating-point register file is interesting in that it can be
+ // viewed as 16 128-bit registers, 32 64-bit registers or 32 32-bit
+ // registers. Because these views overlap, the registers of different
+ // widths will conflict (e.g. d0 overlaps with s0 and s1, and q1
+ // overlaps with d2 and d3).
+ //
+ // See section E1.3.1 of the ARM Architecture Reference Manual for
+ // ARMv8-A for more details.
+ 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;
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
new file mode 100644
index 000000000..9a96a61f5
--- /dev/null
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -0,0 +1,197 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Avr AvrInlineAsmRegClass {
+ reg,
+ reg_upper,
+ reg_pair,
+ reg_iw,
+ reg_ptr,
+ }
+}
+
+impl AvrInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ match self {
+ Self::reg_pair | Self::reg_iw | Self::reg_ptr => &['h', 'l'],
+ _ => &[],
+ }
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8; },
+ Self::reg_upper => types! { _: I8; },
+ Self::reg_pair => types! { _: I16; },
+ Self::reg_iw => types! { _: I16; },
+ Self::reg_ptr => types! { _: I16; },
+ }
+ }
+}
+
+def_regs! {
+ Avr AvrInlineAsmReg AvrInlineAsmRegClass {
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+ r16: reg, reg_upper = ["r16"],
+ r17: reg, reg_upper = ["r17"],
+ r18: reg, reg_upper = ["r18"],
+ r19: reg, reg_upper = ["r19"],
+ r20: reg, reg_upper = ["r20"],
+ r21: reg, reg_upper = ["r21"],
+ r22: reg, reg_upper = ["r22"],
+ r23: reg, reg_upper = ["r23"],
+ r24: reg, reg_upper = ["r24"],
+ r25: reg, reg_upper = ["r25"],
+ r26: reg, reg_upper = ["r26", "XL"],
+ r27: reg, reg_upper = ["r27", "XH"],
+ r30: reg, reg_upper = ["r30", "ZL"],
+ r31: reg, reg_upper = ["r31", "ZH"],
+
+ r3r2: reg_pair = ["r3r2"],
+ r5r4: reg_pair = ["r5r4"],
+ r7r6: reg_pair = ["r7r6"],
+ r9r8: reg_pair = ["r9r8"],
+ r11r10: reg_pair = ["r11r10"],
+ r13r12: reg_pair = ["r13r12"],
+ r15r14: reg_pair = ["r15r14"],
+ r17r16: reg_pair = ["r17r16"],
+ r19r18: reg_pair = ["r19r18"],
+ r21r20: reg_pair = ["r21r20"],
+ r23r22: reg_pair = ["r23r22"],
+
+ r25r24: reg_iw, reg_pair = ["r25r24"],
+
+ X: reg_ptr, reg_iw, reg_pair = ["r27r26", "X"],
+ Z: reg_ptr, reg_iw, reg_pair = ["r31r30", "Z"],
+
+ #error = ["Y", "YL", "YH"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["SP", "SPL", "SPH"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r0", "r1", "r1r0"] =>
+ "r0 and r1 are not available due to an issue in LLVM",
+ }
+}
+
+macro_rules! emit_pairs {
+ (
+ $self:ident $modifier:ident,
+ $($pair:ident $name:literal $hi:literal $lo:literal,)*
+ ) => {
+ match ($self, $modifier) {
+ $(
+ (AvrInlineAsmReg::$pair, Some('h')) => $hi,
+ (AvrInlineAsmReg::$pair, Some('l')) => $lo,
+ (AvrInlineAsmReg::$pair, _) => $name,
+ )*
+ _ => $self.name(),
+ }
+ };
+}
+
+impl AvrInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ modifier: Option<char>,
+ ) -> fmt::Result {
+ let name = emit_pairs! {
+ self modifier,
+ Z "Z" "ZH" "ZL",
+ X "X" "XH" "XL",
+ r25r24 "r25:r24" "r25" "r24",
+ r23r22 "r23:r22" "r23" "r22",
+ r21r20 "r21:r20" "r21" "r20",
+ r19r18 "r19:r18" "r19" "r18",
+ r17r16 "r17:r16" "r17" "r16",
+ r15r14 "r15:r14" "r15" "r14",
+ r13r12 "r13:r12" "r13" "r12",
+ r11r10 "r11:r10" "r11" "r10",
+ r9r8 "r9:r8" "r9" "r8",
+ r7r6 "r7:r6" "r7" "r6",
+ r5r4 "r5:r4" "r5" "r4",
+ r3r2 "r3:r2" "r3" "r2",
+ };
+ out.write_str(name)
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(AvrInlineAsmReg)) {
+ cb(self);
+
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $pair:ident : $hi:ident $lo:ident,
+ )*
+ ) => {
+ match self {
+ $(
+ Self::$pair => {
+ cb(Self::$hi);
+ cb(Self::$lo);
+ }
+ Self::$hi => {
+ cb(Self::$pair);
+ }
+ Self::$lo => {
+ cb(Self::$pair);
+ }
+ )*
+ }
+ };
+ }
+
+ reg_conflicts! {
+ Z : r31 r30,
+ X : r27 r26,
+ r25r24 : r25 r24,
+ r23r22 : r23 r22,
+ r21r20 : r21 r20,
+ r19r18 : r19 r18,
+ r17r16 : r17 r16,
+ r15r14 : r15 r14,
+ r13r12 : r13 r12,
+ r11r10 : r11 r10,
+ r9r8 : r9 r8,
+ r7r6 : r7 r6,
+ r5r4 : r5 r4,
+ r3r2 : r3 r2,
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
new file mode 100644
index 000000000..3b03766a0
--- /dev/null
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -0,0 +1,118 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Bpf BpfInlineAsmRegClass {
+ reg,
+ wreg,
+ }
+}
+
+impl BpfInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, I64; },
+ Self::wreg => types! { alu32: I8, I16, I32; },
+ }
+ }
+}
+
+def_regs! {
+ Bpf BpfInlineAsmReg BpfInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ w0: wreg = ["w0"],
+ w1: wreg = ["w1"],
+ w2: wreg = ["w2"],
+ w3: wreg = ["w3"],
+ w4: wreg = ["w4"],
+ w5: wreg = ["w5"],
+ w6: wreg = ["w6"],
+ w7: wreg = ["w7"],
+ w8: wreg = ["w8"],
+ w9: wreg = ["w9"],
+
+ #error = ["r10", "w10"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ }
+}
+
+impl BpfInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(BpfInlineAsmReg)) {
+ cb(self);
+
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $r:ident : $w:ident
+ ),*
+ ) => {
+ match self {
+ $(
+ Self::$r => {
+ cb(Self::$w);
+ }
+ Self::$w => {
+ cb(Self::$r);
+ }
+ )*
+ }
+ };
+ }
+
+ reg_conflicts! {
+ r0 : w0,
+ r1 : w1,
+ r2 : w2,
+ r3 : w3,
+ r4 : w4,
+ r5 : w5,
+ r6 : w6,
+ r7 : w7,
+ r8 : w8,
+ r9 : w9
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
new file mode 100644
index 000000000..d20270ac9
--- /dev/null
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -0,0 +1,95 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Hexagon HexagonInlineAsmRegClass {
+ reg,
+ }
+}
+
+impl HexagonInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, F32; },
+ }
+ }
+}
+
+def_regs! {
+ Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+ r16: reg = ["r16"],
+ r17: reg = ["r17"],
+ r18: reg = ["r18"],
+ r20: reg = ["r20"],
+ r21: reg = ["r21"],
+ r22: reg = ["r22"],
+ r23: reg = ["r23"],
+ r24: reg = ["r24"],
+ r25: reg = ["r25"],
+ r26: reg = ["r26"],
+ r27: reg = ["r27"],
+ r28: reg = ["r28"],
+ #error = ["r19"] =>
+ "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["r29", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r30", "fr"] =>
+ "the frame register cannot be used as an operand for inline asm",
+ #error = ["r31", "lr"] =>
+ "the link register cannot be used as an operand for inline asm",
+ }
+}
+
+impl HexagonInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+
+ pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
+}
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
new file mode 100644
index 000000000..4e7c2eb1b
--- /dev/null
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -0,0 +1,135 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Mips MipsInlineAsmRegClass {
+ reg,
+ freg,
+ }
+}
+
+impl MipsInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match (self, arch) {
+ (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
+ (Self::reg, _) => types! { _: I8, I16, I32, F32; },
+ (Self::freg, _) => types! { _: F32, F64; },
+ }
+ }
+}
+
+// The reserved registers are somewhat taken from
+// <https://github.com/llvm/llvm-project/blob/deb8f8bcf31540c657716ea5242183b0792702a1/llvm/lib/Target/Mips/MipsRegisterInfo.cpp#L150>.
+def_regs! {
+ Mips MipsInlineAsmReg MipsInlineAsmRegClass {
+ r2: reg = ["$2"],
+ r3: reg = ["$3"],
+ r4: reg = ["$4"],
+ r5: reg = ["$5"],
+ r6: reg = ["$6"],
+ r7: reg = ["$7"],
+ // FIXME: Reserve $t0, $t1 if in mips16 mode.
+ r8: reg = ["$8"],
+ r9: reg = ["$9"],
+ r10: reg = ["$10"],
+ r11: reg = ["$11"],
+ r12: reg = ["$12"],
+ r13: reg = ["$13"],
+ r14: reg = ["$14"],
+ r15: reg = ["$15"],
+ r16: reg = ["$16"],
+ r17: reg = ["$17"],
+ r18: reg = ["$18"],
+ r19: reg = ["$19"],
+ r20: reg = ["$20"],
+ r21: reg = ["$21"],
+ r22: reg = ["$22"],
+ r23: reg = ["$23"],
+ r24: reg = ["$24"],
+ r25: reg = ["$25"],
+ f0: freg = ["$f0"],
+ f1: freg = ["$f1"],
+ f2: freg = ["$f2"],
+ f3: freg = ["$f3"],
+ f4: freg = ["$f4"],
+ f5: freg = ["$f5"],
+ f6: freg = ["$f6"],
+ f7: freg = ["$f7"],
+ f8: freg = ["$f8"],
+ f9: freg = ["$f9"],
+ f10: freg = ["$f10"],
+ f11: freg = ["$f11"],
+ f12: freg = ["$f12"],
+ f13: freg = ["$f13"],
+ f14: freg = ["$f14"],
+ f15: freg = ["$f15"],
+ f16: freg = ["$f16"],
+ f17: freg = ["$f17"],
+ f18: freg = ["$f18"],
+ f19: freg = ["$f19"],
+ f20: freg = ["$f20"],
+ f21: freg = ["$f21"],
+ f22: freg = ["$f22"],
+ f23: freg = ["$f23"],
+ f24: freg = ["$f24"],
+ f25: freg = ["$f25"],
+ f26: freg = ["$f26"],
+ f27: freg = ["$f27"],
+ f28: freg = ["$f28"],
+ f29: freg = ["$f29"],
+ f30: freg = ["$f30"],
+ f31: freg = ["$f31"],
+ #error = ["$0"] =>
+ "constant zero cannot be used as an operand for inline asm",
+ #error = ["$1"] =>
+ "reserved for assembler (Assembler Temp)",
+ #error = ["$26"] =>
+ "OS-reserved register cannot be used as an operand for inline asm",
+ #error = ["$27"] =>
+ "OS-reserved register cannot be used as an operand for inline asm",
+ #error = ["$28"] =>
+ "the global pointer cannot be used as an operand for inline asm",
+ #error = ["$29"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["$30"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["$31"] =>
+ "the return address register cannot be used as an operand for inline asm",
+ }
+}
+
+impl MipsInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
new file mode 100644
index 000000000..65d2cd64b
--- /dev/null
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -0,0 +1,976 @@
+use crate::spec::Target;
+use crate::{abi::Size, spec::RelocModel};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+use std::str::FromStr;
+
+macro_rules! def_reg_class {
+ ($arch:ident $arch_regclass:ident {
+ $(
+ $class:ident,
+ )*
+ }) => {
+ #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
+ #[allow(non_camel_case_types)]
+ pub enum $arch_regclass {
+ $($class,)*
+ }
+
+ impl $arch_regclass {
+ pub fn name(self) -> rustc_span::Symbol {
+ match self {
+ $(Self::$class => rustc_span::symbol::sym::$class,)*
+ }
+ }
+
+ pub fn parse(name: rustc_span::Symbol) -> Result<Self, &'static str> {
+ match name {
+ $(
+ rustc_span::sym::$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_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 = [$($bad_reg:literal),+] => $error:literal,
+ )*
+ }) => {
+ #[allow(unreachable_code)]
+ #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, 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(name: &str) -> Result<Self, &'static str> {
+ match name {
+ $(
+ $($alias)|* | $reg_name => Ok(Self::$reg),
+ )*
+ $(
+ $($bad_reg)|* => Err($error),
+ )*
+ _ => Err("unknown register"),
+ }
+ }
+
+ pub fn validate(self,
+ _arch: super::InlineAsmArch,
+ _reloc_model: crate::spec::RelocModel,
+ _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
+ _target: &crate::spec::Target,
+ _is_clobber: bool,
+ ) -> Result<(), &'static str> {
+ match self {
+ $(
+ Self::$reg => {
+ $($filter(
+ _arch,
+ _reloc_model,
+ _target_features,
+ _target,
+ _is_clobber
+ )?;)?
+ Ok(())
+ }
+ )*
+ }
+ }
+ }
+
+ pub(super) fn fill_reg_map(
+ _arch: super::InlineAsmArch,
+ _reloc_model: crate::spec::RelocModel,
+ _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
+ _target: &crate::spec::Target,
+ _map: &mut rustc_data_structures::fx::FxHashMap<
+ super::InlineAsmRegClass,
+ rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
+ >,
+ ) {
+ #[allow(unused_imports)]
+ use super::{InlineAsmReg, InlineAsmRegClass};
+ $(
+ if $($filter(_arch, _reloc_model, _target_features, _target, false).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_rules! types {
+ (
+ $(_ : $($ty:expr),+;)?
+ $($feature:ident: $($ty2:expr),+;)*
+ ) => {
+ {
+ use super::InlineAsmType::*;
+ &[
+ $($(
+ ($ty, None),
+ )*)?
+ $($(
+ ($ty2, Some(rustc_span::sym::$feature)),
+ )*)*
+ ]
+ }
+ };
+}
+
+mod aarch64;
+mod arm;
+mod avr;
+mod bpf;
+mod hexagon;
+mod mips;
+mod msp430;
+mod nvptx;
+mod powerpc;
+mod riscv;
+mod s390x;
+mod spirv;
+mod wasm;
+mod x86;
+
+pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
+pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
+pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
+pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
+pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
+pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
+pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
+pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
+pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
+pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
+pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
+pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
+pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
+pub enum InlineAsmArch {
+ X86,
+ X86_64,
+ Arm,
+ AArch64,
+ RiscV32,
+ RiscV64,
+ Nvptx64,
+ Hexagon,
+ Mips,
+ Mips64,
+ PowerPC,
+ PowerPC64,
+ S390x,
+ SpirV,
+ Wasm32,
+ Wasm64,
+ Bpf,
+ Avr,
+ Msp430,
+}
+
+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),
+ "nvptx64" => Ok(Self::Nvptx64),
+ "powerpc" => Ok(Self::PowerPC),
+ "powerpc64" => Ok(Self::PowerPC64),
+ "hexagon" => Ok(Self::Hexagon),
+ "mips" => Ok(Self::Mips),
+ "mips64" => Ok(Self::Mips64),
+ "s390x" => Ok(Self::S390x),
+ "spirv" => Ok(Self::SpirV),
+ "wasm32" => Ok(Self::Wasm32),
+ "wasm64" => Ok(Self::Wasm64),
+ "bpf" => Ok(Self::Bpf),
+ "avr" => Ok(Self::Avr),
+ "msp430" => Ok(Self::Msp430),
+ _ => Err(()),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum InlineAsmReg {
+ X86(X86InlineAsmReg),
+ Arm(ArmInlineAsmReg),
+ AArch64(AArch64InlineAsmReg),
+ RiscV(RiscVInlineAsmReg),
+ Nvptx(NvptxInlineAsmReg),
+ PowerPC(PowerPCInlineAsmReg),
+ Hexagon(HexagonInlineAsmReg),
+ Mips(MipsInlineAsmReg),
+ S390x(S390xInlineAsmReg),
+ SpirV(SpirVInlineAsmReg),
+ Wasm(WasmInlineAsmReg),
+ Bpf(BpfInlineAsmReg),
+ Avr(AvrInlineAsmReg),
+ Msp430(Msp430InlineAsmReg),
+ // Placeholder for invalid register constraints for the current target
+ Err,
+}
+
+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(),
+ Self::PowerPC(r) => r.name(),
+ Self::Hexagon(r) => r.name(),
+ Self::Mips(r) => r.name(),
+ Self::S390x(r) => r.name(),
+ Self::Bpf(r) => r.name(),
+ Self::Avr(r) => r.name(),
+ Self::Msp430(r) => r.name(),
+ Self::Err => "<reg>",
+ }
+ }
+
+ 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()),
+ Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
+ Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
+ Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
+ Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
+ Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
+ Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
+ Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
+ Self::Err => InlineAsmRegClass::Err,
+ }
+ }
+
+ pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
+ // FIXME: use direct symbol comparison for register names
+ // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
+ let name = name.as_str();
+ Ok(match arch {
+ InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
+ InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
+ InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+ Self::RiscV(RiscVInlineAsmReg::parse(name)?)
+ }
+ InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
+ InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
+ Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
+ }
+ InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
+ InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+ Self::Mips(MipsInlineAsmReg::parse(name)?)
+ }
+ InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
+ InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
+ Self::Wasm(WasmInlineAsmReg::parse(name)?)
+ }
+ InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
+ InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
+ InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
+ })
+ }
+
+ pub fn validate(
+ self,
+ arch: InlineAsmArch,
+ reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ target: &Target,
+ is_clobber: bool,
+ ) -> Result<(), &'static str> {
+ match self {
+ Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::Err => unreachable!(),
+ }
+ }
+
+ // NOTE: This function isn't used at the moment, but is needed to support
+ // falling back to an external assembler.
+ 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),
+ Self::PowerPC(r) => r.emit(out, arch, modifier),
+ Self::Hexagon(r) => r.emit(out, arch, modifier),
+ Self::Mips(r) => r.emit(out, arch, modifier),
+ Self::S390x(r) => r.emit(out, arch, modifier),
+ Self::Bpf(r) => r.emit(out, arch, modifier),
+ Self::Avr(r) => r.emit(out, arch, modifier),
+ Self::Msp430(r) => r.emit(out, arch, modifier),
+ Self::Err => unreachable!("Use of InlineAsmReg::Err"),
+ }
+ }
+
+ 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),
+ Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
+ Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
+ Self::Mips(_) => cb(self),
+ Self::S390x(_) => cb(self),
+ Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
+ Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
+ Self::Msp430(_) => cb(self),
+ Self::Err => unreachable!("Use of InlineAsmReg::Err"),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum InlineAsmRegClass {
+ X86(X86InlineAsmRegClass),
+ Arm(ArmInlineAsmRegClass),
+ AArch64(AArch64InlineAsmRegClass),
+ RiscV(RiscVInlineAsmRegClass),
+ Nvptx(NvptxInlineAsmRegClass),
+ PowerPC(PowerPCInlineAsmRegClass),
+ Hexagon(HexagonInlineAsmRegClass),
+ Mips(MipsInlineAsmRegClass),
+ S390x(S390xInlineAsmRegClass),
+ SpirV(SpirVInlineAsmRegClass),
+ Wasm(WasmInlineAsmRegClass),
+ Bpf(BpfInlineAsmRegClass),
+ Avr(AvrInlineAsmRegClass),
+ Msp430(Msp430InlineAsmRegClass),
+ // Placeholder for invalid register constraints for the current target
+ Err,
+}
+
+impl InlineAsmRegClass {
+ pub fn name(self) -> Symbol {
+ match self {
+ Self::X86(r) => r.name(),
+ Self::Arm(r) => r.name(),
+ Self::AArch64(r) => r.name(),
+ Self::RiscV(r) => r.name(),
+ Self::Nvptx(r) => r.name(),
+ Self::PowerPC(r) => r.name(),
+ Self::Hexagon(r) => r.name(),
+ Self::Mips(r) => r.name(),
+ Self::S390x(r) => r.name(),
+ Self::SpirV(r) => r.name(),
+ Self::Wasm(r) => r.name(),
+ Self::Bpf(r) => r.name(),
+ Self::Avr(r) => r.name(),
+ Self::Msp430(r) => r.name(),
+ Self::Err => rustc_span::symbol::sym::reg,
+ }
+ }
+
+ /// Returns a suggested register class to use for this type. This is called
+ /// when `supported_types` fails to give a better error
+ /// message to the user.
+ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
+ match self {
+ Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
+ Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
+ Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
+ Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
+ Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
+ Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
+ Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
+ Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
+ Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
+ Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
+ Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
+ Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
+ Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
+ Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
+ Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
+ }
+ }
+
+ /// Returns a suggested template modifier to use for this type and an
+ /// example of a register named formatted with it.
+ ///
+ /// 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)> {
+ 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),
+ Self::Nvptx(r) => r.suggest_modifier(arch, ty),
+ Self::PowerPC(r) => r.suggest_modifier(arch, ty),
+ Self::Hexagon(r) => r.suggest_modifier(arch, ty),
+ Self::Mips(r) => r.suggest_modifier(arch, ty),
+ Self::S390x(r) => r.suggest_modifier(arch, ty),
+ Self::SpirV(r) => r.suggest_modifier(arch, ty),
+ Self::Wasm(r) => r.suggest_modifier(arch, ty),
+ Self::Bpf(r) => r.suggest_modifier(arch, ty),
+ Self::Avr(r) => r.suggest_modifier(arch, ty),
+ Self::Msp430(r) => r.suggest_modifier(arch, ty),
+ Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
+ }
+ }
+
+ /// 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),
+ Self::Nvptx(r) => r.default_modifier(arch),
+ Self::PowerPC(r) => r.default_modifier(arch),
+ Self::Hexagon(r) => r.default_modifier(arch),
+ Self::Mips(r) => r.default_modifier(arch),
+ Self::S390x(r) => r.default_modifier(arch),
+ Self::SpirV(r) => r.default_modifier(arch),
+ Self::Wasm(r) => r.default_modifier(arch),
+ Self::Bpf(r) => r.default_modifier(arch),
+ Self::Avr(r) => r.default_modifier(arch),
+ Self::Msp430(r) => r.default_modifier(arch),
+ Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
+ }
+ }
+
+ /// Returns a list of supported types for this register class, each with an
+ /// options target feature required to use this type.
+ pub fn supported_types(
+ self,
+ arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+ 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),
+ Self::Nvptx(r) => r.supported_types(arch),
+ Self::PowerPC(r) => r.supported_types(arch),
+ Self::Hexagon(r) => r.supported_types(arch),
+ Self::Mips(r) => r.supported_types(arch),
+ Self::S390x(r) => r.supported_types(arch),
+ Self::SpirV(r) => r.supported_types(arch),
+ Self::Wasm(r) => r.supported_types(arch),
+ Self::Bpf(r) => r.supported_types(arch),
+ Self::Avr(r) => r.supported_types(arch),
+ Self::Msp430(r) => r.supported_types(arch),
+ Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
+ }
+ }
+
+ pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
+ Ok(match arch {
+ InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
+ Self::X86(X86InlineAsmRegClass::parse(name)?)
+ }
+ InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+ Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
+ }
+ InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
+ Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
+ }
+ InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+ Self::Mips(MipsInlineAsmRegClass::parse(name)?)
+ }
+ InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
+ Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
+ }
+ InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(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),
+ Self::Nvptx(r) => r.valid_modifiers(arch),
+ Self::PowerPC(r) => r.valid_modifiers(arch),
+ Self::Hexagon(r) => r.valid_modifiers(arch),
+ Self::Mips(r) => r.valid_modifiers(arch),
+ Self::S390x(r) => r.valid_modifiers(arch),
+ Self::SpirV(r) => r.valid_modifiers(arch),
+ Self::Wasm(r) => r.valid_modifiers(arch),
+ Self::Bpf(r) => r.valid_modifiers(arch),
+ Self::Avr(r) => r.valid_modifiers(arch),
+ Self::Msp430(r) => r.valid_modifiers(arch),
+ Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
+ }
+ }
+
+ /// Returns whether registers in this class can only be used as clobbers
+ /// and not as inputs/outputs.
+ pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
+ self.supported_types(arch).is_empty()
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+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) => write!(f, "{}", r.name()),
+ }
+ }
+}
+
+/// 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 {
+ matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
+ }
+
+ 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.
+// NOTE: This function isn't used at the moment, but is needed to support
+// falling back to an external assembler.
+pub fn allocatable_registers(
+ arch: InlineAsmArch,
+ reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ target: &crate::spec::Target,
+) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
+ match arch {
+ InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
+ let mut map = x86::regclass_map();
+ x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Arm => {
+ let mut map = arm::regclass_map();
+ arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::AArch64 => {
+ let mut map = aarch64::regclass_map();
+ aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+ let mut map = riscv::regclass_map();
+ riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Nvptx64 => {
+ let mut map = nvptx::regclass_map();
+ nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
+ let mut map = powerpc::regclass_map();
+ powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Hexagon => {
+ let mut map = hexagon::regclass_map();
+ hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+ let mut map = mips::regclass_map();
+ mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::S390x => {
+ let mut map = s390x::regclass_map();
+ s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::SpirV => {
+ let mut map = spirv::regclass_map();
+ spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
+ let mut map = wasm::regclass_map();
+ wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Bpf => {
+ let mut map = bpf::regclass_map();
+ bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Avr => {
+ let mut map = avr::regclass_map();
+ avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Msp430 => {
+ let mut map = msp430::regclass_map();
+ msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum InlineAsmClobberAbi {
+ X86,
+ X86_64Win,
+ X86_64SysV,
+ Arm,
+ AArch64,
+ AArch64NoX18,
+ RiscV,
+}
+
+impl InlineAsmClobberAbi {
+ /// Parses a clobber ABI for the given target, or returns a list of supported
+ /// clobber ABIs for the target.
+ pub fn parse(
+ arch: InlineAsmArch,
+ target: &Target,
+ name: Symbol,
+ ) -> Result<Self, &'static [&'static str]> {
+ let name = name.as_str();
+ match arch {
+ InlineAsmArch::X86 => match name {
+ "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
+ Ok(InlineAsmClobberAbi::X86)
+ }
+ _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
+ },
+ InlineAsmArch::X86_64 => match name {
+ "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
+ "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
+ "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
+ "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
+ _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
+ },
+ InlineAsmArch::Arm => match name {
+ "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
+ _ => Err(&["C", "system", "efiapi", "aapcs"]),
+ },
+ InlineAsmArch::AArch64 => match name {
+ "C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
+ InlineAsmClobberAbi::AArch64NoX18
+ } else {
+ InlineAsmClobberAbi::AArch64
+ }),
+ _ => Err(&["C", "system", "efiapi"]),
+ },
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
+ "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
+ _ => Err(&["C", "system", "efiapi"]),
+ },
+ _ => Err(&[]),
+ }
+ }
+
+ /// Returns the set of registers which are clobbered by this ABI.
+ pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
+ macro_rules! clobbered_regs {
+ ($arch:ident $arch_reg:ident {
+ $(
+ $reg:ident,
+ )*
+ }) => {
+ &[
+ $(InlineAsmReg::$arch($arch_reg::$reg),)*
+ ]
+ };
+ }
+ match self {
+ InlineAsmClobberAbi::X86 => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ ax, cx, dx,
+
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+
+ k0, k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ }
+ },
+ InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ ax, cx, dx, si, di, r8, r9, r10, r11,
+
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
+ zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
+ zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
+
+ k0, k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
+ }
+ },
+ InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ // rdi and rsi are callee-saved on windows
+ ax, cx, dx, r8, r9, r10, r11,
+
+ // xmm6-xmm15 are callee-saved on windows, but we need to
+ // mark them as clobbered anyways because the upper portions
+ // of ymm6-ymm15 are volatile.
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
+ zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
+ zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
+
+ k0, k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
+ }
+ },
+ InlineAsmClobberAbi::AArch64 => clobbered_regs! {
+ AArch64 AArch64InlineAsmReg {
+ x0, x1, x2, x3, x4, x5, x6, x7,
+ x8, x9, x10, x11, x12, x13, x14, x15,
+ x16, x17, x18, x30,
+
+ // Technically the low 64 bits of v8-v15 are preserved, but
+ // we have no way of expressing this using clobbers.
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+
+ p0, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11, p12, p13, p14, p15,
+ ffr,
+
+ }
+ },
+ InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
+ AArch64 AArch64InlineAsmReg {
+ x0, x1, x2, x3, x4, x5, x6, x7,
+ x8, x9, x10, x11, x12, x13, x14, x15,
+ x16, x17, x30,
+
+ // Technically the low 64 bits of v8-v15 are preserved, but
+ // we have no way of expressing this using clobbers.
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+
+ p0, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11, p12, p13, p14, p15,
+ ffr,
+
+ }
+ },
+ InlineAsmClobberAbi::Arm => clobbered_regs! {
+ Arm ArmInlineAsmReg {
+ // r9 is either platform-reserved or callee-saved. Either
+ // way we don't need to clobber it.
+ r0, r1, r2, r3, r12, r14,
+
+ // The finest-grained register variant is used here so that
+ // partial uses of larger registers are properly handled.
+ s0, s1, s2, s3, s4, s5, s6, s7,
+ s8, s9, s10, s11, s12, s13, s14, s15,
+ // s16-s31 are callee-saved
+ d16, d17, d18, d19, d20, d21, d22, d23,
+ d24, d25, d26, d27, d28, d29, d30, d31,
+ }
+ },
+ InlineAsmClobberAbi::RiscV => clobbered_regs! {
+ RiscV RiscVInlineAsmReg {
+ // ra
+ x1,
+ // t0-t2
+ x5, x6, x7,
+ // a0-a7
+ x10, x11, x12, x13, x14, x15, x16, x17,
+ // t3-t6
+ x28, x29, x30, x31,
+ // ft0-ft7
+ f0, f1, f2, f3, f4, f5, f6, f7,
+ // fa0-fa7
+ f10, f11, f12, f13, f14, f15, f16, f17,
+ // ft8-ft11
+ f28, f29, f30, f31,
+
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+ }
+ },
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
new file mode 100644
index 000000000..a27d6390a
--- /dev/null
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -0,0 +1,81 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Msp430 Msp430InlineAsmRegClass {
+ reg,
+ }
+}
+
+impl Msp430InlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match (self, arch) {
+ (Self::reg, _) => types! { _: I8, I16; },
+ }
+ }
+}
+
+// The reserved registers are taken from:
+// https://github.com/llvm/llvm-project/blob/36cb29cbbe1b22dcd298ad65e1fabe899b7d7249/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp#L73.
+def_regs! {
+ Msp430 Msp430InlineAsmReg Msp430InlineAsmRegClass {
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+
+ #error = ["r0", "pc"] =>
+ "the program counter cannot be used as an operand for inline asm",
+ #error = ["r1", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r2", "sr"] =>
+ "the status register cannot be used as an operand for inline asm",
+ #error = ["r3", "cg"] =>
+ "the constant generator cannot be used as an operand for inline asm",
+ #error = ["r4", "fp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ }
+}
+
+impl Msp430InlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
new file mode 100644
index 000000000..8e1e91e7c
--- /dev/null
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -0,0 +1,50 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+
+def_reg_class! {
+ Nvptx NvptxInlineAsmRegClass {
+ reg16,
+ reg32,
+ reg64,
+ }
+}
+
+impl NvptxInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg16 => types! { _: I8, I16; },
+ Self::reg32 => types! { _: I8, I16, I32, F32; },
+ Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; },
+ }
+ }
+}
+
+def_regs! {
+ // Registers in PTX are declared in the assembly.
+ // There are no predefined registers that one can use.
+ Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {}
+}
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
new file mode 100644
index 000000000..d3ccb3035
--- /dev/null
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -0,0 +1,204 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ PowerPC PowerPCInlineAsmRegClass {
+ reg,
+ reg_nonzero,
+ freg,
+ cr,
+ xer,
+ }
+}
+
+impl PowerPCInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg | Self::reg_nonzero => {
+ if arch == InlineAsmArch::PowerPC {
+ types! { _: I8, I16, I32; }
+ } else {
+ types! { _: I8, I16, I32, I64; }
+ }
+ }
+ Self::freg => types! { _: F32, F64; },
+ Self::cr | Self::xer => &[],
+ }
+ }
+}
+
+def_regs! {
+ PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
+ r0: reg = ["r0", "0"],
+ r3: reg, reg_nonzero = ["r3", "3"],
+ r4: reg, reg_nonzero = ["r4", "4"],
+ r5: reg, reg_nonzero = ["r5", "5"],
+ r6: reg, reg_nonzero = ["r6", "6"],
+ r7: reg, reg_nonzero = ["r7", "7"],
+ r8: reg, reg_nonzero = ["r8", "8"],
+ r9: reg, reg_nonzero = ["r9", "9"],
+ r10: reg, reg_nonzero = ["r10", "10"],
+ r11: reg, reg_nonzero = ["r11", "11"],
+ r12: reg, reg_nonzero = ["r12", "12"],
+ r14: reg, reg_nonzero = ["r14", "14"],
+ r15: reg, reg_nonzero = ["r15", "15"],
+ r16: reg, reg_nonzero = ["r16", "16"],
+ r17: reg, reg_nonzero = ["r17", "17"],
+ r18: reg, reg_nonzero = ["r18", "18"],
+ r19: reg, reg_nonzero = ["r19", "19"],
+ r20: reg, reg_nonzero = ["r20", "20"],
+ r21: reg, reg_nonzero = ["r21", "21"],
+ r22: reg, reg_nonzero = ["r22", "22"],
+ r23: reg, reg_nonzero = ["r23", "23"],
+ r24: reg, reg_nonzero = ["r24", "24"],
+ r25: reg, reg_nonzero = ["r25", "25"],
+ r26: reg, reg_nonzero = ["r26", "26"],
+ r27: reg, reg_nonzero = ["r27", "27"],
+ r28: reg, reg_nonzero = ["r28", "28"],
+ f0: freg = ["f0", "fr0"],
+ f1: freg = ["f1", "fr1"],
+ f2: freg = ["f2", "fr2"],
+ f3: freg = ["f3", "fr3"],
+ f4: freg = ["f4", "fr4"],
+ f5: freg = ["f5", "fr5"],
+ f6: freg = ["f6", "fr6"],
+ f7: freg = ["f7", "fr7"],
+ f8: freg = ["f8", "fr8"],
+ f9: freg = ["f9", "fr9"],
+ f10: freg = ["f10", "fr10"],
+ f11: freg = ["f11", "fr11"],
+ f12: freg = ["f12", "fr12"],
+ f13: freg = ["f13", "fr13"],
+ f14: freg = ["f14", "fr14"],
+ f15: freg = ["f15", "fr15"],
+ f16: freg = ["f16", "fr16"],
+ f17: freg = ["f17", "fr17"],
+ f18: freg = ["f18", "fr18"],
+ f19: freg = ["f19", "fr19"],
+ f20: freg = ["f20", "fr20"],
+ f21: freg = ["f21", "fr21"],
+ f22: freg = ["f22", "fr22"],
+ f23: freg = ["f23", "fr23"],
+ f24: freg = ["f24", "fr24"],
+ f25: freg = ["f25", "fr25"],
+ f26: freg = ["f26", "fr26"],
+ f27: freg = ["f27", "fr27"],
+ f28: freg = ["f28", "fr28"],
+ f29: freg = ["f29", "fr29"],
+ f30: freg = ["f30", "fr30"],
+ f31: freg = ["f31", "fr31"],
+ cr: cr = ["cr"],
+ cr0: cr = ["cr0"],
+ cr1: cr = ["cr1"],
+ cr2: cr = ["cr2"],
+ cr3: cr = ["cr3"],
+ cr4: cr = ["cr4"],
+ cr5: cr = ["cr5"],
+ cr6: cr = ["cr6"],
+ cr7: cr = ["cr7"],
+ xer: xer = ["xer"],
+ #error = ["r1", "1", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r2", "2"] =>
+ "r2 is a system reserved register and cannot be used as an operand for inline asm",
+ #error = ["r13", "13"] =>
+ "r13 is a system reserved register and cannot be used as an operand for inline asm",
+ #error = ["r29", "29"] =>
+ "r29 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["r30", "30"] =>
+ "r30 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["r31", "31", "fp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["lr"] =>
+ "the link register cannot be used as an operand for inline asm",
+ #error = ["ctr"] =>
+ "the counter register cannot be used as an operand for inline asm",
+ #error = ["vrsave"] =>
+ "the vrsave register cannot be used as an operand for inline asm",
+ }
+}
+
+impl PowerPCInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ macro_rules! do_emit {
+ (
+ $($(($reg:ident, $value:literal)),*;)*
+ ) => {
+ out.write_str(match self {
+ $($(Self::$reg => $value,)*)*
+ })
+ };
+ }
+ // Strip off the leading prefix.
+ do_emit! {
+ (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
+ (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15");
+ (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
+ (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28");
+ (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
+ (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
+ (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
+ (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
+ (cr, "cr");
+ (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
+ (xer, "xer");
+ }
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) {
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $full:ident : $($field:ident)*
+ ),*;
+ ) => {
+ match self {
+ $(
+ Self::$full => {
+ cb(Self::$full);
+ $(cb(Self::$field);)*
+ }
+ $(Self::$field)|* => {
+ cb(Self::$full);
+ cb(self);
+ }
+ )*
+ r => cb(r),
+ }
+ };
+ }
+ reg_conflicts! {
+ cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
new file mode 100644
index 000000000..e41bdc9a5
--- /dev/null
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -0,0 +1,185 @@
+use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::{RelocModel, Target};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
+use std::fmt;
+
+def_reg_class! {
+ RiscV RiscVInlineAsmRegClass {
+ reg,
+ freg,
+ vreg,
+ }
+}
+
+impl RiscVInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ 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; },
+ Self::vreg => &[],
+ }
+ }
+}
+
+fn not_e(
+ _arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ if target_features.contains(&sym::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"],
+ 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"],
+ v0: vreg = ["v0"],
+ v1: vreg = ["v1"],
+ v2: vreg = ["v2"],
+ v3: vreg = ["v3"],
+ v4: vreg = ["v4"],
+ v5: vreg = ["v5"],
+ v6: vreg = ["v6"],
+ v7: vreg = ["v7"],
+ v8: vreg = ["v8"],
+ v9: vreg = ["v9"],
+ v10: vreg = ["v10"],
+ v11: vreg = ["v11"],
+ v12: vreg = ["v12"],
+ v13: vreg = ["v13"],
+ v14: vreg = ["v14"],
+ v15: vreg = ["v15"],
+ v16: vreg = ["v16"],
+ v17: vreg = ["v17"],
+ v18: vreg = ["v18"],
+ v19: vreg = ["v19"],
+ v20: vreg = ["v20"],
+ v21: vreg = ["v21"],
+ v22: vreg = ["v22"],
+ v23: vreg = ["v23"],
+ v24: vreg = ["v24"],
+ v25: vreg = ["v25"],
+ v26: vreg = ["v26"],
+ v27: vreg = ["v27"],
+ v28: vreg = ["v28"],
+ v29: vreg = ["v29"],
+ v30: vreg = ["v30"],
+ v31: vreg = ["v31"],
+ #error = ["x9", "s1"] =>
+ "s1 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["x8", "s0", "fp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["x2", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["x3", "gp"] =>
+ "the global pointer cannot be used as an operand for inline asm",
+ #error = ["x4", "tp"] =>
+ "the thread pointer cannot be used as an operand for inline asm" ,
+ #error = ["x0", "zero"] =>
+ "the zero register cannot be used as an operand for inline asm",
+ }
+}
+
+impl RiscVInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
new file mode 100644
index 000000000..0a50064f5
--- /dev/null
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -0,0 +1,107 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ S390x S390xInlineAsmRegClass {
+ reg,
+ freg,
+ }
+}
+
+impl S390xInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match (self, arch) {
+ (Self::reg, _) => types! { _: I8, I16, I32, I64; },
+ (Self::freg, _) => types! { _: F32, F64; },
+ }
+ }
+}
+
+def_regs! {
+ S390x S390xInlineAsmReg S390xInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ f0: freg = ["f0"],
+ f1: freg = ["f1"],
+ f2: freg = ["f2"],
+ f3: freg = ["f3"],
+ f4: freg = ["f4"],
+ f5: freg = ["f5"],
+ f6: freg = ["f6"],
+ f7: freg = ["f7"],
+ f8: freg = ["f8"],
+ f9: freg = ["f9"],
+ f10: freg = ["f10"],
+ f11: freg = ["f11"],
+ f12: freg = ["f12"],
+ f13: freg = ["f13"],
+ f14: freg = ["f14"],
+ f15: freg = ["f15"],
+ #error = ["r11"] =>
+ "The frame pointer cannot be used as an operand for inline asm",
+ #error = ["r15"] =>
+ "The stack pointer cannot be used as an operand for inline asm",
+ #error = [
+ "c0", "c1", "c2", "c3",
+ "c4", "c5", "c6", "c7",
+ "c8", "c9", "c10", "c11",
+ "c12", "c13", "c14", "c15"
+ ] =>
+ "control registers are reserved by the kernel and cannot be used as operands for inline asm",
+ #error = [
+ "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7",
+ "a8", "a9", "a10", "a11",
+ "a12", "a13", "a14", "a15"
+ ] =>
+ "access registers are not supported and cannot be used as operands for inline asm",
+ }
+}
+
+impl S390xInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ write!(out, "%{}", self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
new file mode 100644
index 000000000..31073da10
--- /dev/null
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -0,0 +1,47 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+
+def_reg_class! {
+ SpirV SpirVInlineAsmRegClass {
+ reg,
+ }
+}
+
+impl SpirVInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::reg => {
+ types! { _: I8, I16, I32, I64, F32, F64; }
+ }
+ }
+ }
+}
+
+def_regs! {
+ // SPIR-V is SSA-based, it does not have registers.
+ SpirV SpirVInlineAsmReg SpirVInlineAsmRegClass {}
+}
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
new file mode 100644
index 000000000..f095b7c6e
--- /dev/null
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -0,0 +1,47 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+
+def_reg_class! {
+ Wasm WasmInlineAsmRegClass {
+ local,
+ }
+}
+
+impl WasmInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'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<Symbol>)] {
+ match self {
+ Self::local => {
+ types! { _: I8, I16, I32, I64, F32, F64; }
+ }
+ }
+ }
+}
+
+def_regs! {
+ // WebAssembly doesn't have registers.
+ Wasm WasmInlineAsmReg WasmInlineAsmRegClass {}
+}
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
new file mode 100644
index 000000000..238c36509
--- /dev/null
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -0,0 +1,492 @@
+use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::{RelocModel, Target};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ X86 X86InlineAsmRegClass {
+ reg,
+ reg_abcd,
+ reg_byte,
+ xmm_reg,
+ ymm_reg,
+ zmm_reg,
+ kreg,
+ kreg0,
+ mmx_reg,
+ x87_reg,
+ tmm_reg,
+ }
+}
+
+impl X86InlineAsmRegClass {
+ pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
+ match self {
+ Self::reg => {
+ if arch == InlineAsmArch::X86_64 {
+ &['l', '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::reg_byte => &[],
+ Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
+ Self::kreg | Self::kreg0 => &[],
+ Self::mmx_reg | Self::x87_reg => &[],
+ Self::tmm_reg => &[],
+ }
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
+ match self {
+ Self::reg | Self::reg_abcd if ty.size().bits() == 8 => Some(Self::reg_byte),
+ _ => None,
+ }
+ }
+
+ pub fn suggest_modifier(
+ self,
+ arch: InlineAsmArch,
+ ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ match self {
+ Self::reg => match ty.size().bits() {
+ 16 => Some(('x', "ax")),
+ 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+ _ => None,
+ },
+ Self::reg_abcd => match ty.size().bits() {
+ 16 => Some(('x', "ax")),
+ 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+ _ => None,
+ },
+ Self::reg_byte => None,
+ Self::xmm_reg => None,
+ Self::ymm_reg => match ty.size().bits() {
+ 256 => None,
+ _ => Some(('x', "xmm0")),
+ },
+ Self::zmm_reg => match ty.size().bits() {
+ 512 => None,
+ 256 => Some(('y', "ymm0")),
+ _ => Some(('x', "xmm0")),
+ },
+ Self::kreg | Self::kreg0 => None,
+ Self::mmx_reg | Self::x87_reg => None,
+ Self::tmm_reg => 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::reg_byte => None,
+ Self::xmm_reg => Some(('x', "xmm0")),
+ Self::ymm_reg => Some(('y', "ymm0")),
+ Self::zmm_reg => Some(('z', "zmm0")),
+ Self::kreg | Self::kreg0 => None,
+ Self::mmx_reg | Self::x87_reg => None,
+ Self::tmm_reg => None,
+ }
+ }
+
+ pub fn supported_types(
+ self,
+ arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+ match self {
+ Self::reg | Self::reg_abcd => {
+ if arch == InlineAsmArch::X86_64 {
+ types! { _: I16, I32, I64, F32, F64; }
+ } else {
+ types! { _: I16, I32, F32; }
+ }
+ }
+ Self::reg_byte => types! { _: I8; },
+ 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;
+ },
+ Self::kreg0 => &[],
+ Self::mmx_reg | Self::x87_reg => &[],
+ Self::tmm_reg => &[],
+ }
+ }
+}
+
+fn x86_64_only(
+ arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ _target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86 => Err("register is only available on x86_64"),
+ InlineAsmArch::X86_64 => Ok(()),
+ _ => unreachable!(),
+ }
+}
+
+fn high_byte(
+ arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ _target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
+ _ => Ok(()),
+ }
+}
+
+fn rbx_reserved(
+ arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ _target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86 => Ok(()),
+ InlineAsmArch::X86_64 => {
+ Err("rbx is used internally by LLVM and cannot be used as an operand for inline asm")
+ }
+ _ => unreachable!(),
+ }
+}
+
+fn esi_reserved(
+ arch: InlineAsmArch,
+ _reloc_model: RelocModel,
+ _target_features: &FxHashSet<Symbol>,
+ _target: &Target,
+ _is_clobber: bool,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86 => {
+ Err("esi is used internally by LLVM and cannot be used as an operand for inline asm")
+ }
+ InlineAsmArch::X86_64 => Ok(()),
+ _ => unreachable!(),
+ }
+}
+
+def_regs! {
+ X86 X86InlineAsmReg X86InlineAsmRegClass {
+ ax: reg, reg_abcd = ["ax", "eax", "rax"],
+ bx: reg, reg_abcd = ["bx", "ebx", "rbx"] % rbx_reserved,
+ cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
+ dx: reg, reg_abcd = ["dx", "edx", "rdx"],
+ si: reg = ["si", "esi", "rsi"] % esi_reserved,
+ di: reg = ["di", "edi", "rdi"],
+ r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
+ r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
+ r10: reg = ["r10", "r10w", "r10d"] % x86_64_only,
+ r11: reg = ["r11", "r11w", "r11d"] % x86_64_only,
+ r12: reg = ["r12", "r12w", "r12d"] % x86_64_only,
+ r13: reg = ["r13", "r13w", "r13d"] % x86_64_only,
+ r14: reg = ["r14", "r14w", "r14d"] % x86_64_only,
+ r15: reg = ["r15", "r15w", "r15d"] % x86_64_only,
+ al: reg_byte = ["al"],
+ ah: reg_byte = ["ah"] % high_byte,
+ bl: reg_byte = ["bl"],
+ bh: reg_byte = ["bh"] % high_byte,
+ cl: reg_byte = ["cl"],
+ ch: reg_byte = ["ch"] % high_byte,
+ dl: reg_byte = ["dl"],
+ dh: reg_byte = ["dh"] % high_byte,
+ sil: reg_byte = ["sil"] % x86_64_only,
+ dil: reg_byte = ["dil"] % x86_64_only,
+ r8b: reg_byte = ["r8b"] % x86_64_only,
+ r9b: reg_byte = ["r9b"] % x86_64_only,
+ r10b: reg_byte = ["r10b"] % x86_64_only,
+ r11b: reg_byte = ["r11b"] % x86_64_only,
+ r12b: reg_byte = ["r12b"] % x86_64_only,
+ r13b: reg_byte = ["r13b"] % x86_64_only,
+ r14b: reg_byte = ["r14b"] % x86_64_only,
+ r15b: reg_byte = ["r15b"] % 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,
+ k0: kreg0 = ["k0"],
+ k1: kreg = ["k1"],
+ k2: kreg = ["k2"],
+ k3: kreg = ["k3"],
+ k4: kreg = ["k4"],
+ k5: kreg = ["k5"],
+ k6: kreg = ["k6"],
+ k7: kreg = ["k7"],
+ mm0: mmx_reg = ["mm0"],
+ mm1: mmx_reg = ["mm1"],
+ mm2: mmx_reg = ["mm2"],
+ mm3: mmx_reg = ["mm3"],
+ mm4: mmx_reg = ["mm4"],
+ mm5: mmx_reg = ["mm5"],
+ mm6: mmx_reg = ["mm6"],
+ mm7: mmx_reg = ["mm7"],
+ st0: x87_reg = ["st(0)", "st"],
+ st1: x87_reg = ["st(1)"],
+ st2: x87_reg = ["st(2)"],
+ st3: x87_reg = ["st(3)"],
+ st4: x87_reg = ["st(4)"],
+ st5: x87_reg = ["st(5)"],
+ st6: x87_reg = ["st(6)"],
+ st7: x87_reg = ["st(7)"],
+ tmm0: tmm_reg = ["tmm0"] % x86_64_only,
+ tmm1: tmm_reg = ["tmm1"] % x86_64_only,
+ tmm2: tmm_reg = ["tmm2"] % x86_64_only,
+ tmm3: tmm_reg = ["tmm3"] % x86_64_only,
+ tmm4: tmm_reg = ["tmm4"] % x86_64_only,
+ tmm5: tmm_reg = ["tmm5"] % x86_64_only,
+ tmm6: tmm_reg = ["tmm6"] % x86_64_only,
+ tmm7: tmm_reg = ["tmm7"] % x86_64_only,
+ #error = ["bp", "bpl", "ebp", "rbp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["sp", "spl", "esp", "rsp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["ip", "eip", "rip"] =>
+ "the instruction pointer cannot be used as an operand for inline asm",
+ }
+}
+
+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 = self.name();
+ 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 root = self.name();
+ match modifier.unwrap_or(reg_default_modifier) {
+ 'l' => write!(out, "{}b", root),
+ 'x' => write!(out, "{}w", root),
+ 'e' => write!(out, "{}d", root),
+ 'r' => out.write_str(root),
+ _ => unreachable!(),
+ }
+ } else if self as u32 <= Self::r15b as u32 {
+ out.write_str(self.name())
+ } 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 {
+ out.write_str(self.name())
+ }
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(X86InlineAsmReg)) {
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $w:ident : $l:ident $h:ident
+ ),*;
+ $(
+ $w2:ident : $l2:ident
+ ),*;
+ $(
+ $x:ident : $y:ident : $z:ident
+ ),*;
+ ) => {
+ match self {
+ $(
+ Self::$w => {
+ cb(Self::$w);
+ cb(Self::$l);
+ cb(Self::$h);
+ }
+ Self::$l => {
+ cb(Self::$w);
+ cb(Self::$l);
+ }
+ Self::$h => {
+ cb(Self::$w);
+ cb(Self::$h);
+ }
+ )*
+ $(
+ Self::$w2 | Self::$l2 => {
+ cb(Self::$w2);
+ cb(Self::$l2);
+ }
+ )*
+ $(
+ Self::$x | Self::$y | Self::$z => {
+ cb(Self::$x);
+ cb(Self::$y);
+ cb(Self::$z);
+ }
+ )*
+ r => cb(r),
+ }
+ };
+ }
+
+ // XMM*, YMM* and ZMM* are all different views of the same register.
+ //
+ // See section 15.5 of the combined Intel® 64 and IA-32 Architectures
+ // Software Developer’s Manual for more details.
+ //
+ // We don't need to specify conflicts for [x,y,z]mm[16-31] since these
+ // registers are only available with AVX-512, so we just specify them
+ // as aliases directly.
+ reg_conflicts! {
+ ax : al ah,
+ bx : bl bh,
+ cx : cl ch,
+ dx : dl dh;
+ si : sil,
+ di : dil,
+ r8 : r8b,
+ r9 : r9b,
+ r10 : r10b,
+ r11 : r11b,
+ r12 : r12b,
+ r13 : r13b,
+ r14 : r14b,
+ r15 : r15b;
+ 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;
+ }
+ }
+}