Skip to content

WASM: Runtime Library #1413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Tracked by #1485
Shaikh-Ubaid opened this issue Jan 9, 2023 · 11 comments
Open
Tracked by #1485

WASM: Runtime Library #1413

Shaikh-Ubaid opened this issue Jan 9, 2023 · 11 comments
Labels

Comments

@Shaikh-Ubaid
Copy link
Collaborator

The runtime library functions that need access to libc are currently not supported in the wasm backend (and therefore also not yet supported in the wasm_x64 and wasm_x86 backends). It seems WASI or something similar could be used. This issue to plan/discuss about supporting the runtime library functions in the wasm backend.

@certik
Copy link
Contributor

certik commented Jan 9, 2023

What are the possible ways forward?

One option is to use wasi-libc: https://github.com/WebAssembly/wasi-libc. This option I think would mean to compile the C runtime library using the wasi-sdk toolchain (I think), and then somehow make the compiled wasm work with our wasm output.

Another option is to take the frontend language (Fortran or Python) runtime library, that calls into C, and then implement those C functions somehow.


We also have several applications of wasm:

  • Running in the browser (https://dev.lfortran.org/)
  • Compiling to x86 binaries that run locally
  • Running using wasmtime locally

We should ensure that our solution works well for all three use cases.

@czgdp1807
Copy link
Collaborator

Another option is to take the frontend language (Fortran or Python) runtime library, that calls into C, and then implement those C functions somehow.

This feels hackish to me. IMO, wasi-libc is a better direction to take. Might be difficult but feels more robust.

@czgdp1807
Copy link
Collaborator

Another option is to take the frontend language (Fortran or Python) runtime library, that calls into C, and then implement those C functions somehow.

This feels hackish to me. IMO, wasi-libc is a better direction to take. Might be difficult but feels more robust. Is there anything that prevents us from using wasi-libc?

@certik
Copy link
Contributor

certik commented Jan 10, 2023

Nothing is preventing us as far as I know.

@czgdp1807
Copy link
Collaborator

Then we should try with wasi-libc first. If it works then good, otherwise we can go for second option. Its experimental, so we should try early to know any potential blockers with both the options. Supporting this would make WASM backend much more useful and invite a lot of users.

@Shaikh-Ubaid
Copy link
Collaborator Author

I will share my thoughts on this soon.

@certik
Copy link
Contributor

certik commented Jan 11, 2023

The pure Fortran (and Python) library works with wasm, so the only remaining file to tackle is src/libasr/runtime/lfortran_intrinsics.c. In this file we currently have a lot of functions that do not have to be there:

  • All math functions will be eventually handled by Port intrinsics to use IntrinsicFunction lfortran/lfortran#1045, they will become pure surface language implementation
  • String manipulation utilities can be all written in the surface language using pointers
  • Bit manipulation routines should be handled by introducing the proper operations in ASR as IntegerBitSomething and implemented directly by the backend
  • Unsigned integer handling should be done somehow directly via ASR and the backend (details to be designed)
  • Random numbers: we should have our own eventually
  • Command line argument handling utilities: I think these can also be handled in the surface language eventually

That leaves the following functions:

  • Printing (eventually we will move it out into the surface language as well some some ASR support in the backend)
  • Heap management: wrappers for memset, malloc, realloc, calloc and free. Eventually we can have our own as well; for now we'll use libc --- I think these are only needed in the backend, so each backend can handle these directly; we can also consider moving to ASR
  • CPU time: clock(). Probably we can consider creating an ASR node for this
  • File IO: fopen, fread, fclose: these should probably be handled directly via ASR (details to be designed)

Given this, it seems to me that we do not need the C runtime library at all, it is just a temporary measure to get things going.

For the WASM backend specifically, I would almost not bother, and rather work on moving more things into the surface language and ASR, one by one.

@certik
Copy link
Contributor

certik commented Mar 14, 2023

We now use IntrinsicFunction (might need to sync ASR with LFortran). Just a few functions are ported, but sin already works.

There are two ways.

1

In the WASM backend you can implement IntrinsicFunction by changing this:

    var imports = {
        wasi_snapshot_preview1: {
            /* wasi functions */
            fd_write: fd_write,
            proc_exit: proc_exit,
        },
        js: {
            /* custom functions */
            cpu_time: cpu_time,
            show_img: show_image,
            show_img_color: show_image_color
        },
    };

Into:

    var imports = {
        wasi_snapshot_preview1: {
            /* wasi functions */
            fd_write: fd_write,
            proc_exit: proc_exit,
        },
        lcompilers: {
            /* custom functions */
            cpu_time: cpu_time,
            show_img: show_image,
            show_img_color: show_image_color,
            sin: ...,
            cos: ...,
        },
    };

2

Improve the ASR->ASR pass and instead of calling implementation in C, call pure Fortran implementation. Most likely we will implement this in ASR itself, then it is usable for LPython also. See lfortran/lfortran#1435.

@Shaikh-Ubaid
Copy link
Collaborator Author

At present the wasm binary generated by lpython/lfortran works with both node and wasmtime. It seems using the first approach shared in #1413 (comment), we can support the missing math functions by supplying them in the imports object. This way it could work with node. I am unsure if we could similarly support the math functions using wasmtime (we should investigate if it there is any way to supply custom functions via imports object using wasmtime.)

@certik
Copy link
Contributor

certik commented Mar 21, 2023

Regarding 1), I think we can use wasmtime run with:

        --preload <NAME=MODULE_PATH>
            Load the given WebAssembly module before the main module

and provide the implementation of our imports in C, compile with clang to wasm and preload the module. Something like that might work and might be quite simple to maintain.

@certik
Copy link
Contributor

certik commented Oct 3, 2023

I think here is how we need to move forward: we need to port ALL of our runtime library to ASR, based on the plan above (#1413 (comment)).

  • For generic functions like "all" and "sum" that have to work with any user type, we implement them directly in C++, constructing the actual function at runtime via our ASR builder. We already do that.
  • For functions like sin/cos that have just 2 implementations (single and double precision) the best way is to keep them in the surface language (either Python or Fortran) and use LCompilers to translate to ASR and either generate C++ code that constructs the ASR, or even keep it in the surface language and precompile it (that's what LFortran does today for some stuff) and automatically translate to the other language (say if the source is in Fortran, generate Python code automatically and vice versa), and we need to hook it in in libasr somehow. The technical details can be solved, there are several possible ways forward.
  • malloc has to be implemented most likely in the frontend langauge, we have to implement our own allocator.
  • Anything that truly has to access the host has to be a dedicated ASR node that the backend then implements directly. There are only few of such things. The rest we implement directly in ASR and lower directly via our backends.

That will make pure Fortran or pure LPython code work completely via WASM, and our WASM->x64 backend will generate a standalone binary that will just work. If we need to link with C, then we just generate an .o, and in wasm we "import" such functions, and we leave it to the user to link it correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants