1
Fork 0

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`
This commit is contained in:
bors 2020-12-01 20:23:06 +00:00
commit 6645da366e
8 changed files with 231 additions and 4 deletions

View file

@ -261,6 +261,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
InlineAsmArch::Hexagon => {} InlineAsmArch::Hexagon => {}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::SpirV => {} InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 => {}
} }
} }
if !options.contains(InlineAsmOptions::NOMEM) { 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::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk", InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
} }
@ -584,6 +586,7 @@ fn modifier_to_llvm(
_ => unreachable!(), _ => unreachable!(),
}, },
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") 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::ymm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
} }

View file

@ -167,6 +167,7 @@ pub fn initialize_available_targets() {
LLVMInitializeWebAssemblyTargetInfo, LLVMInitializeWebAssemblyTargetInfo,
LLVMInitializeWebAssemblyTarget, LLVMInitializeWebAssemblyTarget,
LLVMInitializeWebAssemblyTargetMC, LLVMInitializeWebAssemblyTargetMC,
LLVMInitializeWebAssemblyAsmPrinter LLVMInitializeWebAssemblyAsmPrinter,
LLVMInitializeWebAssemblyAsmParser
); );
} }

View file

@ -156,6 +156,7 @@ mod mips;
mod nvptx; mod nvptx;
mod riscv; mod riscv;
mod spirv; mod spirv;
mod wasm;
mod x86; mod x86;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
@ -165,6 +166,7 @@ pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
@ -180,6 +182,7 @@ pub enum InlineAsmArch {
Mips, Mips,
Mips64, Mips64,
SpirV, SpirV,
Wasm32,
} }
impl FromStr for InlineAsmArch { impl FromStr for InlineAsmArch {
@ -198,6 +201,7 @@ impl FromStr for InlineAsmArch {
"mips" => Ok(Self::Mips), "mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64), "mips64" => Ok(Self::Mips64),
"spirv" => Ok(Self::SpirV), "spirv" => Ok(Self::SpirV),
"wasm32" => Ok(Self::Wasm32),
_ => Err(()), _ => Err(()),
} }
} }
@ -213,6 +217,7 @@ pub enum InlineAsmReg {
Hexagon(HexagonInlineAsmReg), Hexagon(HexagonInlineAsmReg),
Mips(MipsInlineAsmReg), Mips(MipsInlineAsmReg),
SpirV(SpirVInlineAsmReg), SpirV(SpirVInlineAsmReg),
Wasm(WasmInlineAsmReg),
} }
impl InlineAsmReg { impl InlineAsmReg {
@ -272,6 +277,9 @@ impl InlineAsmReg {
InlineAsmArch::SpirV => { InlineAsmArch::SpirV => {
Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?) 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), Hexagon(HexagonInlineAsmRegClass),
Mips(MipsInlineAsmRegClass), Mips(MipsInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass),
Wasm(WasmInlineAsmRegClass),
} }
impl InlineAsmRegClass { impl InlineAsmRegClass {
@ -328,6 +337,7 @@ impl InlineAsmRegClass {
Self::Hexagon(r) => r.name(), Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(), Self::Mips(r) => r.name(),
Self::SpirV(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::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), 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::Hexagon(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::SpirV(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::Hexagon(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch),
Self::SpirV(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::Hexagon(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch),
Self::SpirV(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)?) Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
} }
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::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::Hexagon(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch),
Self::SpirV(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); spirv::fill_reg_map(arch, has_feature, target, &mut map);
map map
} }
InlineAsmArch::Wasm32 => {
let mut map = wasm::regclass_map();
wasm::fill_reg_map(arch, has_feature, target, &mut map);
map
}
} }
} }

View file

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

View file

@ -28,6 +28,7 @@ Inline assembly is currently supported on the following architectures:
- NVPTX - NVPTX
- Hexagon - Hexagon
- MIPS32r2 and MIPS64r2 - MIPS32r2 and MIPS64r2
- wasm32
## Basic usage ## 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 | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
| RISC-V | `freg` | `f[0-31]` | `f` | | RISC-V | `freg` | `f[0-31]` | `f` |
| Hexagon | `reg` | `r[0-28]` | `r` | | 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. > **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 #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 #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). 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` | `f` | `f32` |
| RISC-V | `freg` | `d` | `f64` | | RISC-V | `freg` | `d` | `f64` |
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | | 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). > **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).

@ -1 +1 @@
Subproject commit ee1617457899ef2eb55dcf7ee2758b4340b6533f Subproject commit 7ade8dc4b84142abd3e6d1fb8a0f4111b0bbd571

View file

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

View file

@ -1,5 +1,5 @@
// compile-flags: --target wasm32-unknown-unknown // compile-flags: --target sparc-unknown-linux-gnu
// needs-llvm-components: webassembly // needs-llvm-components: sparc
#![feature(no_core, lang_items, rustc_attrs)] #![feature(no_core, lang_items, rustc_attrs)]
#![no_core] #![no_core]