about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-12-01 20:23:06 +0000
committerbors <bors@rust-lang.org>2020-12-01 20:23:06 +0000
commit6645da366eed0c61258a04265bea513e94df7ea6 (patch)
tree86b957f685e4f26a11c4cee82f67957625e1e5c6
parent4cbda829c00af2c3ac362c979fa97ea90be0be7d (diff)
parentd9f237caa6a90fd6581124a3627af55e9c2a0f22 (diff)
downloadrust-6645da366eed0c61258a04265bea513e94df7ea6.tar.gz
rust-6645da366eed0c61258a04265bea513e94df7ea6.zip
Auto merge of #78684 - devsnek:inline-asm-wasm, r=Amanieu
Add wasm32 support to inline asm

There is some contention around inline asm and wasm, and I really only made this to figure out the process of hacking on rustc, but I figured as long as the code existed, it was worth uploading.

cc `@Amanieu`
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs4
-rw-r--r--compiler/rustc_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_target/src/asm/mod.rs21
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs46
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md5
m---------src/llvm-project0
-rw-r--r--src/test/assembly/asm/wasm-types.rs150
-rw-r--r--src/test/ui/asm/bad-arch.rs4
8 files changed, 230 insertions, 3 deletions
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index b5d279eeb6f..8801211d51b 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -261,6 +261,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 InlineAsmArch::Hexagon => {}
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
                 InlineAsmArch::SpirV => {}
+                InlineAsmArch::Wasm32 => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -519,6 +520,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
             | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
+            InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
             InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
                 bug!("LLVM backend does not support SPIR-V")
             }
@@ -584,6 +586,7 @@ fn modifier_to_llvm(
             _ => unreachable!(),
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
@@ -626,6 +629,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index a381290d46f..b2ffa271f62 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -167,6 +167,7 @@ pub fn initialize_available_targets() {
         LLVMInitializeWebAssemblyTargetInfo,
         LLVMInitializeWebAssemblyTarget,
         LLVMInitializeWebAssemblyTargetMC,
-        LLVMInitializeWebAssemblyAsmPrinter
+        LLVMInitializeWebAssemblyAsmPrinter,
+        LLVMInitializeWebAssemblyAsmParser
     );
 }
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 5ebd6c4a234..aff1ff92d31 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -156,6 +156,7 @@ mod mips;
 mod nvptx;
 mod riscv;
 mod spirv;
+mod wasm;
 mod x86;
 
 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
@@ -165,6 +166,7 @@ pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
+pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
 
 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
@@ -180,6 +182,7 @@ pub enum InlineAsmArch {
     Mips,
     Mips64,
     SpirV,
+    Wasm32,
 }
 
 impl FromStr for InlineAsmArch {
@@ -198,6 +201,7 @@ impl FromStr for InlineAsmArch {
             "mips" => Ok(Self::Mips),
             "mips64" => Ok(Self::Mips64),
             "spirv" => Ok(Self::SpirV),
+            "wasm32" => Ok(Self::Wasm32),
             _ => Err(()),
         }
     }
@@ -213,6 +217,7 @@ pub enum InlineAsmReg {
     Hexagon(HexagonInlineAsmReg),
     Mips(MipsInlineAsmReg),
     SpirV(SpirVInlineAsmReg),
+    Wasm(WasmInlineAsmReg),
 }
 
 impl InlineAsmReg {
@@ -272,6 +277,9 @@ impl InlineAsmReg {
             InlineAsmArch::SpirV => {
                 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
+            InlineAsmArch::Wasm32 => {
+                Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
+            }
         })
     }
 
@@ -315,6 +323,7 @@ pub enum InlineAsmRegClass {
     Hexagon(HexagonInlineAsmRegClass),
     Mips(MipsInlineAsmRegClass),
     SpirV(SpirVInlineAsmRegClass),
+    Wasm(WasmInlineAsmRegClass),
 }
 
 impl InlineAsmRegClass {
@@ -328,6 +337,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.name(),
             Self::Mips(r) => r.name(),
             Self::SpirV(r) => r.name(),
+            Self::Wasm(r) => r.name(),
         }
     }
 
@@ -344,6 +354,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
+            Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
         }
     }
 
@@ -367,6 +378,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
             Self::Mips(r) => r.suggest_modifier(arch, ty),
             Self::SpirV(r) => r.suggest_modifier(arch, ty),
+            Self::Wasm(r) => r.suggest_modifier(arch, ty),
         }
     }
 
@@ -386,6 +398,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.default_modifier(arch),
             Self::Mips(r) => r.default_modifier(arch),
             Self::SpirV(r) => r.default_modifier(arch),
+            Self::Wasm(r) => r.default_modifier(arch),
         }
     }
 
@@ -404,6 +417,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.supported_types(arch),
             Self::Mips(r) => r.supported_types(arch),
             Self::SpirV(r) => r.supported_types(arch),
+            Self::Wasm(r) => r.supported_types(arch),
         }
     }
 
@@ -429,6 +443,7 @@ impl InlineAsmRegClass {
                     Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
                 }
                 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
+                InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
             })
         })
     }
@@ -445,6 +460,7 @@ impl InlineAsmRegClass {
             Self::Hexagon(r) => r.valid_modifiers(arch),
             Self::Mips(r) => r.valid_modifiers(arch),
             Self::SpirV(r) => r.valid_modifiers(arch),
+            Self::Wasm(r) => r.valid_modifiers(arch),
         }
     }
 }
@@ -592,5 +608,10 @@ pub fn allocatable_registers(
             spirv::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
+        InlineAsmArch::Wasm32 => {
+            let mut map = wasm::regclass_map();
+            wasm::fill_reg_map(arch, has_feature, target, &mut map);
+            map
+        }
     }
 }
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
new file mode 100644
index 00000000000..1b33f8f9632
--- /dev/null
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -0,0 +1,46 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+
+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<&'static str>)] {
+        match self {
+            Self::local => {
+                types! { _: I8, I16, I32, I64, F32, F64; }
+            }
+        }
+    }
+}
+
+def_regs! {
+    // WebAssembly doesn't have registers.
+    Wasm WasmInlineAsmReg WasmInlineAsmRegClass {}
+}
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 6e4e1f78b96..ccdd8628699 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -28,6 +28,7 @@ Inline assembly is currently supported on the following architectures:
 - NVPTX
 - Hexagon
 - MIPS32r2 and MIPS64r2
+- wasm32
 
 ## Basic usage
 
@@ -521,6 +522,7 @@ Here is the list of currently supported register classes:
 | 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` |
+| wasm32 | `local` | None\* | `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.
 >
@@ -529,6 +531,8 @@ Here is the list of currently supported register classes:
 > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
 >
 > Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
+>
+> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
 
 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
 
@@ -562,6 +566,7 @@ Each register class has constraints on which value types they can be used with.
 | RISC-V | `freg` | `f` | `f32` |
 | RISC-V | `freg` | `d` | `f64` |
 | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
+| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
 
 > **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).
 
diff --git a/src/llvm-project b/src/llvm-project
-Subproject ee1617457899ef2eb55dcf7ee2758b4340b6533
+Subproject 7ade8dc4b84142abd3e6d1fb8a0f4111b0bbd57
diff --git a/src/test/assembly/asm/wasm-types.rs b/src/test/assembly/asm/wasm-types.rs
new file mode 100644
index 00000000000..94ca526222a
--- /dev/null
+++ b/src/test/assembly/asm/wasm-types.rs
@@ -0,0 +1,150 @@
+// no-system-llvm
+// assembly-output: emit-asm
+// compile-flags: --target wasm32-unknown-unknown
+// compile-flags: --crate-type cdylib
+// needs-llvm-components: webassembly
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *mut u8;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for f32 {}
+impl Copy for i64 {}
+impl Copy for f64 {}
+impl Copy for ptr {}
+
+extern "C" {
+    fn extern_func();
+    static extern_static: u8;
+}
+
+// CHECK-LABEL: sym_fn:
+// CHECK: #APP
+// CHECK: call extern_func
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: sym_static
+// CHECK: #APP
+// CHECK: i32.const 42
+// CHECK: i32.store extern_static
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_static() {
+    asm!("
+        i32.const 42
+        i32.store {}
+    ", sym extern_static);
+}
+
+macro_rules! check {
+    ($func:ident $ty:ident $instr:literal) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!(concat!("local.get {}\n", $instr, "\nlocal.set {}"), in(local) x, out(local) y);
+            y
+        }
+    };
+}
+
+// CHECK-LABEL: i8_i32:
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i32.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i8_i32 i8 "i32.clz");
+
+// CHECK-LABEL: i16_i32:
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i32.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i16_i32 i16 "i32.clz");
+
+// CHECK-LABEL: i32_i32:
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i32.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i32_i32 i32 "i32.clz");
+
+// CHECK-LABEL: i8_i64
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i64.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i8_i64 i8 "i64.clz");
+
+// CHECK-LABEL: i16_i64
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i64.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i16_i64 i16 "i64.clz");
+
+// CHECK-LABEL: i32_i64
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i64.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i32_i64 i32 "i64.clz");
+
+// CHECK-LABEL: i64_i64
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i64.clz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i64_i64 i64 "i64.clz");
+
+// CHECK-LABEL: f32_f32
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: f32.abs
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(f32_f32 f32 "f32.abs");
+
+// CHECK-LABEL: f64_f64
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: f64.abs
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(f64_f64 f64 "f64.abs");
+
+// CHECK-LABEL: i32_ptr
+// CHECK: #APP
+// CHECK: local.get {{[0-9]}}
+// CHECK: i32.eqz
+// CHECK: local.set {{[0-9]}}
+// CHECK: #NO_APP
+check!(i32_ptr ptr "i32.eqz");
diff --git a/src/test/ui/asm/bad-arch.rs b/src/test/ui/asm/bad-arch.rs
index 1d21ae8df24..763b5fe5cca 100644
--- a/src/test/ui/asm/bad-arch.rs
+++ b/src/test/ui/asm/bad-arch.rs
@@ -1,5 +1,5 @@
-// compile-flags: --target wasm32-unknown-unknown
-// needs-llvm-components: webassembly
+// compile-flags: --target sparc-unknown-linux-gnu
+// needs-llvm-components: sparc
 
 #![feature(no_core, lang_items, rustc_attrs)]
 #![no_core]