about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Cain <bcain@quicinc.com>2020-06-09 15:08:28 -0500
committerBrian Cain <bcain@quicinc.com>2020-06-16 08:58:13 -0500
commit7a9f29d30587f4492bfc4af491d2e7b4d9b930e9 (patch)
tree7ed8d2f57364ea630e8a34cb3a36bc2bff7bd50a
parentbb8674837a9cc5225020e07fc3f164762bb4c11c (diff)
downloadrust-7a9f29d30587f4492bfc4af491d2e7b4d9b930e9.tar.gz
rust-7a9f29d30587f4492bfc4af491d2e7b4d9b930e9.zip
Add initial asm!() support for hexagon
GPRs only
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md13
-rw-r--r--src/librustc_codegen_llvm/asm.rs4
-rw-r--r--src/librustc_target/asm/hexagon.rs93
-rw-r--r--src/librustc_target/asm/mod.rs27
-rw-r--r--src/test/assembly/asm/hexagon-types.rs130
5 files changed, 264 insertions, 3 deletions
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index ea560a6d709..f4220dcd7c1 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -374,7 +374,7 @@ options := "options(" option *["," option] [","] ")"
 asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
 ```
 
-The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
+The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
 
 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
 
@@ -386,7 +386,7 @@ As with format strings, named arguments must appear after positional arguments.
 
 The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
 
-The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
+The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
 
 [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
 
@@ -473,6 +473,7 @@ Here is the list of currently supported register classes:
 | NVPTX | `reg64` | None\* | `l` |
 | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
 | RISC-V | `freg` | `f[0-31]` | `f` |
+| Hexagon | `reg` | `r[0-28]` | `r` |
 
 > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
 >
@@ -507,6 +508,7 @@ Each register class has constraints on which value types they can be used with.
 | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | RISC-V | `freg` | `f` | `f32` |
 | RISC-V | `freg` | `d` | `f64` |
+| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
 
 > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
 
@@ -563,13 +565,16 @@ Some registers have multiple names. These are all treated by the compiler as ide
 | RISC-V | `f[10-17]` | `fa[0-7]` |
 | RISC-V | `f[18-27]` | `fs[2-11]` |
 | RISC-V | `f[28-31]` | `ft[8-11]` |
+| Hexagon | `r29` | `sp` |
+| Hexagon | `r30` | `fr` |
+| Hexagon | `r31` | `lr` |
 
 Some registers cannot be used for input or output operands:
 
 | Architecture | Unsupported register | Reason |
 | ------------ | -------------------- | ------ |
 | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
-| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. |
+| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
 | x86 | `k0` | This is a constant zero register which can't be modified. |
 | x86 | `ip` | This is the program counter, not a real register. |
 | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
@@ -578,6 +583,7 @@ Some registers cannot be used for input or output operands:
 | ARM | `pc` | This is the program counter, not a real register. |
 | RISC-V | `x0` | This is a constant zero register which can't be modified. |
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
+| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
 
 ## Template modifiers
 
@@ -623,6 +629,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
 | NVPTX | `reg64` | None | `rd0` | None |
 | RISC-V | `reg` | None | `x1` | None |
 | RISC-V | `freg` | None | `f0` | None |
+| Hexagon | `reg` | None | `r0` | None |
 
 > Notes:
 > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 9d4a30f23a2..2f9e49591c3 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -255,6 +255,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 }
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
                 InlineAsmArch::Nvptx64 => {}
+                InlineAsmArch::Hexagon => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -427,6 +428,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
             InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
+            InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
@@ -472,6 +474,7 @@ fn modifier_to_llvm(
                 modifier
             }
         }
+        InlineAsmRegClass::Hexagon(_) => None,
         InlineAsmRegClass::Nvptx(_) => None,
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
         | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
@@ -523,6 +526,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
             cx.type_vector(cx.type_i64(), 2)
         }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
diff --git a/src/librustc_target/asm/hexagon.rs b/src/librustc_target/asm/hexagon.rs
new file mode 100644
index 00000000000..d41941d0b4c
--- /dev/null
+++ b/src/librustc_target/asm/hexagon.rs
@@ -0,0 +1,93 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+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<&'static str>)] {
+        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"],
+        r19: reg = ["r19"],
+        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 = ["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/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs
index a18a4dbd3e2..834d7c6d381 100644
--- a/src/librustc_target/asm/mod.rs
+++ b/src/librustc_target/asm/mod.rs
@@ -148,12 +148,14 @@ macro_rules! types {
 
 mod aarch64;
 mod arm;
+mod hexagon;
 mod nvptx;
 mod riscv;
 mod x86;
 
 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
@@ -167,6 +169,7 @@ pub enum InlineAsmArch {
     RiscV32,
     RiscV64,
     Nvptx64,
+    Hexagon,
 }
 
 impl FromStr for InlineAsmArch {
@@ -181,6 +184,7 @@ impl FromStr for InlineAsmArch {
             "riscv32" => Ok(Self::RiscV32),
             "riscv64" => Ok(Self::RiscV64),
             "nvptx64" => Ok(Self::Nvptx64),
+            "hexagon" => Ok(Self::Hexagon),
             _ => Err(()),
         }
     }
@@ -203,6 +207,7 @@ pub enum InlineAsmReg {
     AArch64(AArch64InlineAsmReg),
     RiscV(RiscVInlineAsmReg),
     Nvptx(NvptxInlineAsmReg),
+    Hexagon(HexagonInlineAsmReg),
 }
 
 impl InlineAsmReg {
@@ -212,6 +217,7 @@ impl InlineAsmReg {
             Self::Arm(r) => r.name(),
             Self::AArch64(r) => r.name(),
             Self::RiscV(r) => r.name(),
+            Self::Hexagon(r) => r.name(),
         }
     }
 
@@ -221,6 +227,7 @@ impl InlineAsmReg {
             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::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
         }
     }
 
@@ -246,6 +253,9 @@ impl InlineAsmReg {
             InlineAsmArch::Nvptx64 => {
                 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
             }
+            InlineAsmArch::Hexagon => {
+                Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?)
+            }
         })
     }
 
@@ -262,6 +272,7 @@ impl InlineAsmReg {
             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::Hexagon(r) => r.emit(out, arch, modifier),
         }
     }
 
@@ -271,6 +282,7 @@ impl InlineAsmReg {
             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
             Self::AArch64(_) => cb(self),
             Self::RiscV(_) => cb(self),
+            Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
         }
     }
 }
@@ -292,6 +304,7 @@ pub enum InlineAsmRegClass {
     AArch64(AArch64InlineAsmRegClass),
     RiscV(RiscVInlineAsmRegClass),
     Nvptx(NvptxInlineAsmRegClass),
+    Hexagon(HexagonInlineAsmRegClass),
 }
 
 impl InlineAsmRegClass {
@@ -302,6 +315,7 @@ impl InlineAsmRegClass {
             Self::AArch64(r) => r.name(),
             Self::RiscV(r) => r.name(),
             Self::Nvptx(r) => r.name(),
+            Self::Hexagon(r) => r.name(),
         }
     }
 
@@ -315,6 +329,7 @@ impl InlineAsmRegClass {
             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::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
         }
     }
 
@@ -335,6 +350,7 @@ impl InlineAsmRegClass {
             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::Hexagon(r) => r.suggest_modifier(arch, ty),
         }
     }
 
@@ -351,6 +367,7 @@ impl InlineAsmRegClass {
             Self::AArch64(r) => r.default_modifier(arch),
             Self::RiscV(r) => r.default_modifier(arch),
             Self::Nvptx(r) => r.default_modifier(arch),
+            Self::Hexagon(r) => r.default_modifier(arch),
         }
     }
 
@@ -366,6 +383,7 @@ impl InlineAsmRegClass {
             Self::AArch64(r) => r.supported_types(arch),
             Self::RiscV(r) => r.supported_types(arch),
             Self::Nvptx(r) => r.supported_types(arch),
+            Self::Hexagon(r) => r.supported_types(arch),
         }
     }
 
@@ -384,6 +402,9 @@ impl InlineAsmRegClass {
                     Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
                 }
                 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
+                InlineAsmArch::Hexagon => {
+                    Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
+                }
             })
         })
     }
@@ -397,6 +418,7 @@ impl InlineAsmRegClass {
             Self::AArch64(r) => r.valid_modifiers(arch),
             Self::RiscV(r) => r.valid_modifiers(arch),
             Self::Nvptx(r) => r.valid_modifiers(arch),
+            Self::Hexagon(r) => r.valid_modifiers(arch),
         }
     }
 }
@@ -541,5 +563,10 @@ pub fn allocatable_registers(
             nvptx::fill_reg_map(arch, has_feature, &mut map);
             map
         }
+        InlineAsmArch::Hexagon => {
+            let mut map = hexagon::regclass_map();
+            hexagon::fill_reg_map(arch, has_feature, &mut map);
+            map
+        }
     }
 }
diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs
new file mode 100644
index 00000000000..ba2d8a363cd
--- /dev/null
+++ b/src/test/assembly/asm/hexagon-types.rs
@@ -0,0 +1,130 @@
+// no-system-llvm
+// assembly-output: emit-asm
+// compile-flags: --target hexagon-unknown-linux-musl
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const i32;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for f32 {}
+impl Copy for ptr {}
+extern "C" {
+    fn extern_func();
+    static extern_static: u8;
+}
+
+macro_rules! check {
+    ($func:ident $ty:ident $class:ident) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            // Hack to avoid function merging
+            extern "Rust" {
+                fn dont_merge(s: &str);
+            }
+            dont_merge(stringify!($func));
+
+            let y;
+            asm!("{} = {}", out($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+// CHECK-LABEL: sym_static:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_static
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_static() {
+    // Hack to avoid function merging
+    extern "Rust" {
+        fn dont_merge(s: &str);
+    }
+    dont_merge(stringify!($func));
+
+    asm!("r0 = #{}", sym extern_static);
+}
+
+// CHECK-LABEL: sym_fn:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_func
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    // Hack to avoid function merging
+    extern "Rust" {
+        fn dont_merge(s: &str);
+    }
+    dont_merge(stringify!($func));
+
+    asm!("r0 = #{}", sym extern_func);
+}
+
+// This is a test for multi-instruction packets,
+// which require the escaped braces.
+//
+// CHECK-LABEL: packet:
+// CHECK: InlineAsm Start
+// CHECK: {
+// CHECK:   r{{[0-9]+}} = r0
+// CHECK:   memw(r1) = r{{[0-9]+}}
+// CHECK: }
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn packet() {
+    let val = 1024;
+    asm!("{{
+        {} = r0
+        memw(r1) = {}
+    }}", out(reg) _, in(reg) &val);
+}
+
+// CHECK-LABEL: ptr:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_ptr ptr reg);
+
+// CHECK-LABEL: reg_f32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_f32 f32 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i8:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i16 i16 reg);