Skip to content

Commit 6645da3

Browse files
committed
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`
2 parents 4cbda82 + d9f237c commit 6645da3

File tree

8 files changed

+231
-4
lines changed

8 files changed

+231
-4
lines changed

compiler/rustc_codegen_llvm/src/asm.rs

+4
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
261261
InlineAsmArch::Hexagon => {}
262262
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
263263
InlineAsmArch::SpirV => {}
264+
InlineAsmArch::Wasm32 => {}
264265
}
265266
}
266267
if !options.contains(InlineAsmOptions::NOMEM) {
@@ -519,6 +520,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
519520
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
520521
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
521522
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
523+
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
522524
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
523525
bug!("LLVM backend does not support SPIR-V")
524526
}
@@ -584,6 +586,7 @@ fn modifier_to_llvm(
584586
_ => unreachable!(),
585587
},
586588
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
589+
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
587590
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
588591
bug!("LLVM backend does not support SPIR-V")
589592
}
@@ -626,6 +629,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
626629
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
627630
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
628631
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
632+
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
629633
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
630634
bug!("LLVM backend does not support SPIR-V")
631635
}

compiler/rustc_llvm/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ pub fn initialize_available_targets() {
167167
LLVMInitializeWebAssemblyTargetInfo,
168168
LLVMInitializeWebAssemblyTarget,
169169
LLVMInitializeWebAssemblyTargetMC,
170-
LLVMInitializeWebAssemblyAsmPrinter
170+
LLVMInitializeWebAssemblyAsmPrinter,
171+
LLVMInitializeWebAssemblyAsmParser
171172
);
172173
}

compiler/rustc_target/src/asm/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ mod mips;
156156
mod nvptx;
157157
mod riscv;
158158
mod spirv;
159+
mod wasm;
159160
mod x86;
160161

161162
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
@@ -165,6 +166,7 @@ pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
165166
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
166167
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
167168
pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
169+
pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
168170
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
169171

170172
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
@@ -180,6 +182,7 @@ pub enum InlineAsmArch {
180182
Mips,
181183
Mips64,
182184
SpirV,
185+
Wasm32,
183186
}
184187

185188
impl FromStr for InlineAsmArch {
@@ -198,6 +201,7 @@ impl FromStr for InlineAsmArch {
198201
"mips" => Ok(Self::Mips),
199202
"mips64" => Ok(Self::Mips64),
200203
"spirv" => Ok(Self::SpirV),
204+
"wasm32" => Ok(Self::Wasm32),
201205
_ => Err(()),
202206
}
203207
}
@@ -213,6 +217,7 @@ pub enum InlineAsmReg {
213217
Hexagon(HexagonInlineAsmReg),
214218
Mips(MipsInlineAsmReg),
215219
SpirV(SpirVInlineAsmReg),
220+
Wasm(WasmInlineAsmReg),
216221
}
217222

218223
impl InlineAsmReg {
@@ -272,6 +277,9 @@ impl InlineAsmReg {
272277
InlineAsmArch::SpirV => {
273278
Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
274279
}
280+
InlineAsmArch::Wasm32 => {
281+
Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
282+
}
275283
})
276284
}
277285

@@ -315,6 +323,7 @@ pub enum InlineAsmRegClass {
315323
Hexagon(HexagonInlineAsmRegClass),
316324
Mips(MipsInlineAsmRegClass),
317325
SpirV(SpirVInlineAsmRegClass),
326+
Wasm(WasmInlineAsmRegClass),
318327
}
319328

320329
impl InlineAsmRegClass {
@@ -328,6 +337,7 @@ impl InlineAsmRegClass {
328337
Self::Hexagon(r) => r.name(),
329338
Self::Mips(r) => r.name(),
330339
Self::SpirV(r) => r.name(),
340+
Self::Wasm(r) => r.name(),
331341
}
332342
}
333343

@@ -344,6 +354,7 @@ impl InlineAsmRegClass {
344354
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
345355
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
346356
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
357+
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
347358
}
348359
}
349360

@@ -367,6 +378,7 @@ impl InlineAsmRegClass {
367378
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
368379
Self::Mips(r) => r.suggest_modifier(arch, ty),
369380
Self::SpirV(r) => r.suggest_modifier(arch, ty),
381+
Self::Wasm(r) => r.suggest_modifier(arch, ty),
370382
}
371383
}
372384

@@ -386,6 +398,7 @@ impl InlineAsmRegClass {
386398
Self::Hexagon(r) => r.default_modifier(arch),
387399
Self::Mips(r) => r.default_modifier(arch),
388400
Self::SpirV(r) => r.default_modifier(arch),
401+
Self::Wasm(r) => r.default_modifier(arch),
389402
}
390403
}
391404

@@ -404,6 +417,7 @@ impl InlineAsmRegClass {
404417
Self::Hexagon(r) => r.supported_types(arch),
405418
Self::Mips(r) => r.supported_types(arch),
406419
Self::SpirV(r) => r.supported_types(arch),
420+
Self::Wasm(r) => r.supported_types(arch),
407421
}
408422
}
409423

@@ -429,6 +443,7 @@ impl InlineAsmRegClass {
429443
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
430444
}
431445
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
446+
InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
432447
})
433448
})
434449
}
@@ -445,6 +460,7 @@ impl InlineAsmRegClass {
445460
Self::Hexagon(r) => r.valid_modifiers(arch),
446461
Self::Mips(r) => r.valid_modifiers(arch),
447462
Self::SpirV(r) => r.valid_modifiers(arch),
463+
Self::Wasm(r) => r.valid_modifiers(arch),
448464
}
449465
}
450466
}
@@ -592,5 +608,10 @@ pub fn allocatable_registers(
592608
spirv::fill_reg_map(arch, has_feature, target, &mut map);
593609
map
594610
}
611+
InlineAsmArch::Wasm32 => {
612+
let mut map = wasm::regclass_map();
613+
wasm::fill_reg_map(arch, has_feature, target, &mut map);
614+
map
615+
}
595616
}
596617
}

compiler/rustc_target/src/asm/wasm.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::{InlineAsmArch, InlineAsmType};
2+
use rustc_macros::HashStable_Generic;
3+
4+
def_reg_class! {
5+
Wasm WasmInlineAsmRegClass {
6+
local,
7+
}
8+
}
9+
10+
impl WasmInlineAsmRegClass {
11+
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
12+
&[]
13+
}
14+
15+
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
16+
None
17+
}
18+
19+
pub fn suggest_modifier(
20+
self,
21+
_arch: InlineAsmArch,
22+
_ty: InlineAsmType,
23+
) -> Option<(char, &'static str)> {
24+
None
25+
}
26+
27+
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
28+
None
29+
}
30+
31+
pub fn supported_types(
32+
self,
33+
_arch: InlineAsmArch,
34+
) -> &'static [(InlineAsmType, Option<&'static str>)] {
35+
match self {
36+
Self::local => {
37+
types! { _: I8, I16, I32, I64, F32, F64; }
38+
}
39+
}
40+
}
41+
}
42+
43+
def_regs! {
44+
// WebAssembly doesn't have registers.
45+
Wasm WasmInlineAsmReg WasmInlineAsmRegClass {}
46+
}

src/doc/unstable-book/src/library-features/asm.md

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Inline assembly is currently supported on the following architectures:
2828
- NVPTX
2929
- Hexagon
3030
- MIPS32r2 and MIPS64r2
31+
- wasm32
3132

3233
## Basic usage
3334

@@ -521,6 +522,7 @@ Here is the list of currently supported register classes:
521522
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
522523
| RISC-V | `freg` | `f[0-31]` | `f` |
523524
| Hexagon | `reg` | `r[0-28]` | `r` |
525+
| wasm32 | `local` | None\* | `r` |
524526

525527
> **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.
526528
>
@@ -529,6 +531,8 @@ Here is the list of currently supported register classes:
529531
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
530532
>
531533
> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
534+
>
535+
> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
532536
533537
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
534538

@@ -562,6 +566,7 @@ Each register class has constraints on which value types they can be used with.
562566
| RISC-V | `freg` | `f` | `f32` |
563567
| RISC-V | `freg` | `d` | `f64` |
564568
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
569+
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
565570

566571
> **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).
567572

src/test/assembly/asm/wasm-types.rs

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// no-system-llvm
2+
// assembly-output: emit-asm
3+
// compile-flags: --target wasm32-unknown-unknown
4+
// compile-flags: --crate-type cdylib
5+
// needs-llvm-components: webassembly
6+
7+
#![feature(no_core, lang_items, rustc_attrs)]
8+
#![no_core]
9+
10+
#[rustc_builtin_macro]
11+
macro_rules! asm {
12+
() => {};
13+
}
14+
#[rustc_builtin_macro]
15+
macro_rules! concat {
16+
() => {};
17+
}
18+
19+
#[lang = "sized"]
20+
trait Sized {}
21+
#[lang = "copy"]
22+
trait Copy {}
23+
24+
type ptr = *mut u8;
25+
26+
impl Copy for i8 {}
27+
impl Copy for i16 {}
28+
impl Copy for i32 {}
29+
impl Copy for f32 {}
30+
impl Copy for i64 {}
31+
impl Copy for f64 {}
32+
impl Copy for ptr {}
33+
34+
extern "C" {
35+
fn extern_func();
36+
static extern_static: u8;
37+
}
38+
39+
// CHECK-LABEL: sym_fn:
40+
// CHECK: #APP
41+
// CHECK: call extern_func
42+
// CHECK: #NO_APP
43+
#[no_mangle]
44+
pub unsafe fn sym_fn() {
45+
asm!("call {}", sym extern_func);
46+
}
47+
48+
// CHECK-LABEL: sym_static
49+
// CHECK: #APP
50+
// CHECK: i32.const 42
51+
// CHECK: i32.store extern_static
52+
// CHECK: #NO_APP
53+
#[no_mangle]
54+
pub unsafe fn sym_static() {
55+
asm!("
56+
i32.const 42
57+
i32.store {}
58+
", sym extern_static);
59+
}
60+
61+
macro_rules! check {
62+
($func:ident $ty:ident $instr:literal) => {
63+
#[no_mangle]
64+
pub unsafe fn $func(x: $ty) -> $ty {
65+
let y;
66+
asm!(concat!("local.get {}\n", $instr, "\nlocal.set {}"), in(local) x, out(local) y);
67+
y
68+
}
69+
};
70+
}
71+
72+
// CHECK-LABEL: i8_i32:
73+
// CHECK: #APP
74+
// CHECK: local.get {{[0-9]}}
75+
// CHECK: i32.clz
76+
// CHECK: local.set {{[0-9]}}
77+
// CHECK: #NO_APP
78+
check!(i8_i32 i8 "i32.clz");
79+
80+
// CHECK-LABEL: i16_i32:
81+
// CHECK: #APP
82+
// CHECK: local.get {{[0-9]}}
83+
// CHECK: i32.clz
84+
// CHECK: local.set {{[0-9]}}
85+
// CHECK: #NO_APP
86+
check!(i16_i32 i16 "i32.clz");
87+
88+
// CHECK-LABEL: i32_i32:
89+
// CHECK: #APP
90+
// CHECK: local.get {{[0-9]}}
91+
// CHECK: i32.clz
92+
// CHECK: local.set {{[0-9]}}
93+
// CHECK: #NO_APP
94+
check!(i32_i32 i32 "i32.clz");
95+
96+
// CHECK-LABEL: i8_i64
97+
// CHECK: #APP
98+
// CHECK: local.get {{[0-9]}}
99+
// CHECK: i64.clz
100+
// CHECK: local.set {{[0-9]}}
101+
// CHECK: #NO_APP
102+
check!(i8_i64 i8 "i64.clz");
103+
104+
// CHECK-LABEL: i16_i64
105+
// CHECK: #APP
106+
// CHECK: local.get {{[0-9]}}
107+
// CHECK: i64.clz
108+
// CHECK: local.set {{[0-9]}}
109+
// CHECK: #NO_APP
110+
check!(i16_i64 i16 "i64.clz");
111+
112+
// CHECK-LABEL: i32_i64
113+
// CHECK: #APP
114+
// CHECK: local.get {{[0-9]}}
115+
// CHECK: i64.clz
116+
// CHECK: local.set {{[0-9]}}
117+
// CHECK: #NO_APP
118+
check!(i32_i64 i32 "i64.clz");
119+
120+
// CHECK-LABEL: i64_i64
121+
// CHECK: #APP
122+
// CHECK: local.get {{[0-9]}}
123+
// CHECK: i64.clz
124+
// CHECK: local.set {{[0-9]}}
125+
// CHECK: #NO_APP
126+
check!(i64_i64 i64 "i64.clz");
127+
128+
// CHECK-LABEL: f32_f32
129+
// CHECK: #APP
130+
// CHECK: local.get {{[0-9]}}
131+
// CHECK: f32.abs
132+
// CHECK: local.set {{[0-9]}}
133+
// CHECK: #NO_APP
134+
check!(f32_f32 f32 "f32.abs");
135+
136+
// CHECK-LABEL: f64_f64
137+
// CHECK: #APP
138+
// CHECK: local.get {{[0-9]}}
139+
// CHECK: f64.abs
140+
// CHECK: local.set {{[0-9]}}
141+
// CHECK: #NO_APP
142+
check!(f64_f64 f64 "f64.abs");
143+
144+
// CHECK-LABEL: i32_ptr
145+
// CHECK: #APP
146+
// CHECK: local.get {{[0-9]}}
147+
// CHECK: i32.eqz
148+
// CHECK: local.set {{[0-9]}}
149+
// CHECK: #NO_APP
150+
check!(i32_ptr ptr "i32.eqz");

0 commit comments

Comments
 (0)