Stream: rust-toolchain

Topic: inline wasm in Rust?


view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:00):

Hi! did https://github.com/rustwasm/team/issues/24 get anywhere? the issue was closed, but i haven't been able to find if/where the follow-up discussion happened

For my use cases, this would have been nice, but not strictly necessary. I expect it will eventually become higher priority for someone.

view this post on Zulip Alex Crichton (Mar 30 2021 at 14:05):

It did not, but I think asm! nowadays on nightly rust may have some support

view this post on Zulip Alex Crichton (Mar 30 2021 at 14:05):

I suspect it's quite limited though

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:37):

hah indeed, there are tests in rustc that shows the proper syntax (the trick is to use "local" instead of "reg", and local.set/get to write/read them)

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:37):

#[no_mangle]
pub fn inline() -> u32 {
    let x = 13;
    let y = 37;
    let mut z = 0;
    unsafe {
        asm!(
            "local.get {x}",
            "local.get {y}",
            "i32.add",
            "local.set {z}",
            x = in(local) x,
            y = in(local) y,
            z = out(local) z,
        );
    }
    z
}

view this post on Zulip Alex Crichton (Mar 30 2021 at 14:49):

I have no idea how any of that works in llvm

view this post on Zulip Yury Delendik (Mar 30 2021 at 14:51):

I used .S web assembly in the past, works well

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:51):

is the inline assembly sent as strings straight to llvm? the syntax errors in inline asm suggest so, but i'm unsure

view this post on Zulip Yury Delendik (Mar 30 2021 at 14:52):

is inline assembly a requirement?

view this post on Zulip Alex Crichton (Mar 30 2021 at 14:52):

afaik yes, it goes straight to LLVM's assembler

view this post on Zulip Alex Crichton (Mar 30 2021 at 14:53):

which afaik has not a ton of documentation

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:53):

i was playing with reading from a second memory, which i do now by having a custom preprocessing pass using an updated walrus, and it works fine

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:54):

(rustc's execution model in wasm makes it so that we still need to copy everything we read out from this second memory to the main memory, so it's not as interesting as i expected)

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 14:55):

but i was wondering if this could be done without preprocessing, and i just realized today that there was inline assembly support for wasm

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 15:03):

@Alex Crichton @fitzgen (he/him) are you interested in PRs for walrus to rely on a more recent wasmparser?

view this post on Zulip Alex Crichton (Mar 30 2021 at 15:04):

sure!

view this post on Zulip Till Schneidereit (Mar 30 2021 at 15:37):

Would this give us a way to introduce collections, or at least Vec-like buffers, whose backing store is in a different Memory, by implementing all operations that get/set contained values with inline wasm referring to the other Memory?

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 15:47):

Yep, I do have a proof of concept implementing an io::Read impl that can read from the second memory. That's using the walrus preprocessing, inline asm would be more straightforward tho, but they'd result in equivalent wasm code being created.

view this post on Zulip Till Schneidereit (Mar 30 2021 at 16:25):

very cool!

(rustc's execution model in wasm makes it so that we still need to copy everything we read out from this second memory to the main memory, so it's not as interesting as i expected)

Can you say more about this? I'd expect to be able to load values and store them in a local in the current stack frame, but it seems like that's not the case?

view this post on Zulip Benjamin Bouvier (Mar 30 2021 at 16:43):

Sure! My point was rather about non-primitive data structures, which need to be reconstructed in the first memory to be useful. E.g. one can't just read a Vec which elements are only backed by the second memory; the main Rust program only knows about its own memory, and will assume that pointers into the heap are referring to the first memory. That stands for "native" stdlib Vec at least. For a custom, user-land defined Vec, we could teach it to allocate in the second memory instead, and read from/write into it. The header may still live on the primary memory (stack or heap), though. Does that make sense? (and please correct me if this is wrong; I'd expect this to work like that)

view this post on Zulip Till Schneidereit (Mar 30 2021 at 16:50):

it does make sense, yes. And yes, that's what I had envisioned.

We actually had extensive discussions about this all the way back at TPAC in Lyon, and concluded that it'd be hard to support this for Vec. (This was in the context of GC, but I think largely applies to multi-memory, too.)

I could imagine there still being a lot of value in supporting good abstractions for this in custom data structures, perhaps implementing traits that also have implementations for std equivalents

view this post on Zulip Benjamin Bouvier (Apr 01 2021 at 16:45):

I guess a more general question is, what can be directly accessed from Rust code? and where could i find this information? I know I can declare extern "C" functions and they become imports, but what else can we explicitly do? Can we directly manipulate wasm globals from Rust code? or function tables? (and so on for every wasm concept)

view this post on Zulip Alex Crichton (Apr 01 2021 at 16:47):

afaik there's not really much documentation on this, but we're generally constrained by LLVM right now -- and this basically means that you can't manipulate or even declare arbitrary tables/globals/memories

view this post on Zulip Benjamin Bouvier (Apr 01 2021 at 16:50):

ah, that makes sense, thanks! So it makes these wasm preprocessing transforms (as done above with walrus for using a second memory) more interesting...

view this post on Zulip Benjamin Bouvier (Apr 01 2021 at 16:51):

It seems that I can put a static mut X: u32 = 0 declaration within an extern "C" block, but that doesn't export a wasm global, though

view this post on Zulip Benjamin Bouvier (Apr 01 2021 at 16:55):

Interesting: it does actually export a wasm global that contains an offset into the linear memory where the Rust static is stored


Last updated: Oct 23 2024 at 20:03 UTC