Compile your WebAssembly programs into SPIR-V shaders

Overview

Crates.io docs.rs GitHub

wasm2spirv - Compile your WebAssembly programs into SPIR-V shaders

Warning

wasm2spirv is still in early development, and not production ready.

This repository contains the code for both, the CLI and library for wasm2spirv. wasm2spirv allows you to compile any WebAssembly program into a SPIR-V shader

Features

  • Compiles your WebAssembly programs into SPIR-V
  • Can transpile into other various shading languages
  • Supports validation and optimization of the resulting SPIR-V
  • Can be compiled to WebAssembly itself
    • You won't be able to use spirv-tools, spirv_cross or tree-sitter in WebAssembly
    • CLI will have to be compiled to WASI

Caveats

  • Still in early development
    • Unexpected bugs and crashes are to be expected
    • Still working through the WebAssembly MVP
  • WebAssembly programs with memory allocations will not work
    • You can customize whether the memory.grow instruction errors the compilation (hard errors) or always returns -1 (soft errors)
  • You'll have to manually provide quite some extra information
    • This is because SPIR-V has a lot of constructs compared to the simplicity of WebAssembly.
    • wasm2spirv can do some inferrence based on the WebAssembly program itself, but it's usually better to specify most the information on the configuration.
    • The plan for the future is to be able to store the config information inside the WebAssembly program itself.

Compilation Targets

Target Windows Linux macOS WebAssembly
SPIR-V
GLSL ☑️ (spvc-glsl/naga-glsl) ☑️ (spvc-glsl/naga-glsl) ☑️ (spvc-glsl/naga-glsl) ☑️ (naga-glsl)
HLSL ☑️ (spvc-hlsl/naga-hlsl) ☑️ (spvc-hlsl/naga-hlsl) ☑️ (spvc-hlsl/naga-hlsl) ☑️ (naga-hlsl)
Metal (MSL) ☑️ (spvc-msl/naga-msl) ☑️ (spvc-msl/naga-msl) ☑️ (spvc-msl/naga-msl) ☑️ (naga-msl)
WGSL ☑️ (naga-wgsl) ☑️ (naga-wgsl) ☑️ (naga-wgsl) ☑️ (naga-wgsl)
DXIL
OpenCL C
Cuda
Validation ☑️ (spvt-validate/naga-validate) ☑️ (spvt-validate/naga-validate) ☑️ (spvt-validate/naga-validate) ☑️ (naga-validate)
  • Supported
  • ☑️ Supported, but requires cargo feature(s)
  • Unsupported

Note
The CLI programs built by the releases use the Khronos compilers/validators whenever possible, faling back to naga compilers/validators if the Khronos are not available or are not supported on that platform.

Examples

You can find a few examples on the "examples" directory, with their Zig file, translated WebAssembly Text, and compilation configuration file.

Saxpy example

Zig program

export fn main(n: usize, alpha: f32, x: [*]const f32, y: [*]f32) void {
    var i = gl_GlobalInvocationID(0);
    const size = gl_NumWorkGroups(0);

    while (i < n) {
        y[i] += alpha * x[i];
        i += size;
    }
}

extern "spir_global" fn gl_GlobalInvocationID(u32) usize;
extern "spir_global" fn gl_NumWorkGroups(u32) usize;

WebAssembly text

(module
  (type (;0;) (func (param i32) (result i32)))
  (type (;1;) (func (param i32 f32 i32 i32)))
  (import "spir_global" "gl_GlobalInvocationID" (func (;0;) (type 0)))
  (import "spir_global" "gl_NumWorkGroups" (func (;1;) (type 0)))
  (func (;2;) (type 1) (param i32 f32 i32 i32)
    (local i32 i32 i32 i32 i32)
    i32.const 0
    call 0
    local.tee 4
    i32.const 2
    i32.shl
    local.set 5
    i32.const 0
    call 1
    local.tee 6
    i32.const 2
    i32.shl
    local.set 7
    block  ;; label = @1
      loop  ;; label = @2
        local.get 4
        local.get 0
        i32.ge_u
        br_if 1 (;@1;)
        local.get 3
        local.get 5
        i32.add
        local.tee 8
        local.get 8
        f32.load
        local.get 2
        local.get 5
        i32.add
        f32.load
        local.get 1
        f32.mul
        f32.add
        f32.store
        local.get 5
        local.get 7
        i32.add
        local.set 5
        local.get 4
        local.get 6
        i32.add
        local.set 4
        br 0 (;@2;)
      end
    end)
  (memory (;0;) 16)
  (global (;0;) (mut i32) (i32.const 1048576))
  (export "memory" (memory 0))
  (export "main" (func 2)))

Configuration file (in JSON)

{
  "platform": {
    "vulkan": "1.1"
  },
  "version": "1.3",
  "addressing_model": "logical",
  "memory_model": "GLSL450",
  "capabilities": { "dynamic": ["VariablePointers"] },
  "extensions": ["VH_KHR_variable_pointers"],
  "functions": {
    "2": {
      "execution_model": "GLCompute",
      "execution_modes": [{
        "local_size": [1, 1, 1]
      }],
      "params": {
        "0": {
          "type": "i32",
          "kind": {
            "descriptor_set": {
              "storage_class": "StorageBuffer",
              "set": 0,
              "binding": 0
            }
          }
        },

        "1": {
          "type": "f32",
          "kind": {
            "descriptor_set": {
              "storage_class": "StorageBuffer",
              "set": 0,
              "binding": 1
            }
          }
        },

        "2": {
          "type": {
            "size": "fat",
            "storage_class": "StorageBuffer",
            "pointee": "f32"
          },
          "kind": {
            "descriptor_set": {
              "storage_class": "StorageBuffer",
              "set": 0,
              "binding": 2
            }
          }
        },

        "3": {
          "type": {
            "size": "fat",
            "storage_class": "StorageBuffer",
            "pointee": "f32"
          },
          "kind": {
            "descriptor_set": {
              "storage_class": "StorageBuffer",
              "set": 0,
              "binding": 3
            }
          }
        }
      }
    }
  }
}

SPIR-V result

; SPIR-V
; Version: 1.3
; Generator: rspirv
; Bound: 73
OpCapability VariablePointers
OpCapability Shader
OpExtension "VH_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "main" %6 %7
OpExecutionMode %3 LocalSize 1 1 1
OpDecorate %6 BuiltIn GlobalInvocationId
OpDecorate %7 BuiltIn NumWorkgroups
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
OpMemberDecorate %14 0 Offset 0
OpDecorate %14 Block
OpDecorate %16 DescriptorSet 0
OpDecorate %16 Binding 1
OpDecorate %17 ArrayStride 4
OpMemberDecorate %18 0 Offset 0
OpDecorate %18 Block
OpDecorate %20 DescriptorSet 0
OpDecorate %20 Binding 2
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 3
%1 = OpTypeInt 32 0
%2 = OpConstant  %1  1048576
%4 = OpTypeVector %1 3
%5 = OpTypePointer Input %4
%6 = OpVariable  %5  Input
%7 = OpVariable  %5  Input
%8 = OpTypeVoid
%9 = OpTypeFunction %8
%10 = OpTypeStruct %1
%11 = OpTypePointer StorageBuffer %10
%12 = OpVariable  %11  StorageBuffer
%13 = OpTypeFloat 32
%14 = OpTypeStruct %13
%15 = OpTypePointer StorageBuffer %14
%16 = OpVariable  %15  StorageBuffer
%17 = OpTypeRuntimeArray %13
%18 = OpTypeStruct %17
%19 = OpTypePointer StorageBuffer %18
%20 = OpVariable  %19  StorageBuffer
%21 = OpVariable  %19  StorageBuffer
%23 = OpTypePointer Function %1
%28 = OpConstant  %1  2
%39 = OpTypeBool
%41 = OpConstant  %1  0
%42 = OpTypePointer StorageBuffer %1
%46 = OpTypePointer Function %19
%50 = OpTypePointer StorageBuffer %13
%51 = OpConstant  %1  4
%3 = OpFunction  %8  None %9
%22 = OpLabel
%48 = OpVariable  %23  Function %41
%47 = OpVariable  %46  Function
%33 = OpVariable  %23  Function
%30 = OpVariable  %23  Function
%27 = OpVariable  %23  Function
%24 = OpVariable  %23  Function
%25 = OpLoad  %4  %6
%26 = OpCompositeExtract  %1  %25 0
OpStore %24 %26
%29 = OpShiftLeftLogical  %1  %26 %28
OpStore %27 %29
%31 = OpLoad  %4  %7
%32 = OpCompositeExtract  %1  %31 0
OpStore %30 %32
%34 = OpShiftLeftLogical  %1  %32 %28
OpStore %33 %34
OpBranch %35
%35 = OpLabel
OpBranch %36
%36 = OpLabel
%40 = OpLoad  %1  %24
%43 = OpAccessChain  %42  %12 %41
%44 = OpLoad  %1  %43
%45 = OpUGreaterThanEqual  %39  %40 %44
OpLoopMerge %37 %38 None
OpBranchConditional %45 %37 %38
%38 = OpLabel
OpStore %47 %21
%49 = OpLoad  %1  %27
OpStore %48 %49
%52 = OpUDiv  %1  %49 %51
%53 = OpAccessChain  %50  %21 %41 %52
%54 = OpLoad  %19  %47
%55 = OpLoad  %1  %48
%56 = OpUDiv  %1  %55 %51
%57 = OpAccessChain  %50  %54 %41 %56
%58 = OpLoad  %13  %57 Aligned 4
%59 = OpLoad  %1  %27
%60 = OpUDiv  %1  %59 %51
%61 = OpAccessChain  %50  %20 %41 %60
%62 = OpLoad  %13  %61 Aligned 4
%63 = OpAccessChain  %50  %16 %41
%64 = OpLoad  %13  %63
%65 = OpFMul  %13  %62 %64
%66 = OpFAdd  %13  %58 %65
OpStore %53 %66 Aligned 4
%67 = OpLoad  %1  %27
%68 = OpLoad  %1  %33
%69 = OpIAdd  %1  %67 %68
OpStore %27 %69
%70 = OpLoad  %1  %24
%71 = OpLoad  %1  %30
%72 = OpIAdd  %1  %70 %71
OpStore %24 %72
OpBranch %36
%37 = OpLabel
OpReturn
OpFunctionEnd

Metal translation

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

struct _10
{
    uint _m0;
};

struct _14
{
    float _m0;
};

struct _18
{
    float _m0[1];
};

kernel void main0(device _10& _12 [[buffer(0)]], device _14& _16 [[buffer(1)]], device _18& _20 [[buffer(2)]], device _18& _21 [[buffer(3)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_NumWorkGroups [[threadgroups_per_grid]])
{
    uint _48 = 0u;
    uint _29 = gl_GlobalInvocationID.x << 2u;
    uint _34 = gl_NumWorkGroups.x << 2u;
    device _18* _47;
    for (uint _24 = gl_GlobalInvocationID.x, _27 = _29, _30 = gl_NumWorkGroups.x, _33 = _34; !(_24 >= _12._m0); )
    {
        _47 = &_21;
        _48 = _27;
        _21._m0[_27 / 4u] = _47->_m0[_48 / 4u] + (_20._m0[_27 / 4u] * _16._m0);
        _27 += _33;
        _24 += _30;
        continue;
    }
}

Installation

To add wasm2spirv as a library for your Rust project, run this command on you'r project's root directory.
cargo add wasm2spirv

To install the latest version of the wasm2spirv CLI, run this command.
cargo install wasm2spirv

Cargo features

  • spirv-tools enables optimization and validation.
  • spirv_cross enables cross-compilation to GLSL, HLSL and MSL.
  • tree-sitter enables syntax highlighting on the CLI.
  • naga enables cross-compilation for GLSL, HLSL, MSL and WGSL.

Related projects

  • SPIRV-LLVM is an official Khronos tool to compile LLVM IR into SPIR-V.
  • Wasmer is a WebAssembly runtime that runs WebAssembly programs on the host machine.
  • Bytecoder can translate JVM code into JavaScript, WebAssembly and OpenCL.
  • Naga is a translator from, and to, various shading languages and IRs.
Comments
  • Bump wasmparser from 0.108.0 to 0.109.0

    Bump wasmparser from 0.108.0 to 0.109.0

    Bumps wasmparser from 0.108.0 to 0.109.0.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
  • Full rework/refactor for pointer values

    Full rework/refactor for pointer values

    The previous implementation was inherently flawed, and required quite extra carefulness from the developer to ensure everything was done correctly.

    This new implementation aims to fix this issues

    opened by Aandreba 0
  • Add extra logical instructions and float comparisons

    Add extra logical instructions and float comparisons

    Added support for this integer instructions:

    • Popcnt
    • Clz (Count leading zeros)
    • Ctz (Count trailing zeros)

    Added support for this float instructions:

    • Abs (Absolute value)
    • Ceil
    • Truncate
    • Floor
    • Nearest
    • Sqrt (Square root)
    • Copysign
    • Min
    • Max

    And partial support for this instructions:

    • Rotl (Rotate left)
      • Only works with OpenCL extended is, panics otherwise
    • Rotr (Rotate right)
      • Only parsing works, translation panics
    opened by Aandreba 0
  • Added WebAssembly CLI build on release & support naga compilers

    Added WebAssembly CLI build on release & support naga compilers

    I thought it would be fitting that the wasm to spirv compiler could run it's CLI with WebAssembly, so I made it possible. To do so, I also implemented support for the Naga compiler, which can compile to GLSL, HLSL, MSL & WGSL and can be compiled to WebAssebly (unlike spirv-tools & spirv_cross).

    opened by Aandreba 0
  • Bump serde from 1.0.174 to 1.0.175

    Bump serde from 1.0.174 to 1.0.175

    Bumps serde from 1.0.174 to 1.0.175.

    Release notes

    Sourced from serde's releases.

    v1.0.175

    • Restore missing LICENSE files in serde_derive crate (#2527, thanks @​ankane)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump clap from 4.3.17 to 4.3.19

    Bump clap from 4.3.17 to 4.3.19

    Bumps clap from 4.3.17 to 4.3.19.

    Release notes

    Sourced from clap's releases.

    v4.3.19

    [4.3.19] - 2023-07-21

    Fixes

    • (parse) Respect value_terminator even in the presence of later multiple-value positional arguments

    v4.3.18

    [4.3.18] - 2023-07-21

    Fixes

    • (parse) Suggest -- in fewer places where it won't work
    Changelog

    Sourced from clap's changelog.

    [4.3.19] - 2023-07-21

    Fixes

    • (parse) Respect value_terminator even in the presence of later multiple-value positional arguments

    [4.3.18] - 2023-07-21

    Fixes

    • (parse) Suggest -- in fewer places where it won't work
    Commits
    • ae5549d chore: Release
    • 4b30a2c docs: Update changelog
    • 5540d20 Merge pull request #5037 from epage/term
    • 8bee728 fix(parser): Value terminator has higher precedence than later multiple values
    • bdf205b test(parser): Show one value terminator bug
    • 727ca29 Merge pull request #5034 from epage/update
    • 9856d67 chore: Release
    • a6267b7 docs: Update changelog
    • e822341 Merge pull request #5033 from epage/escape
    • 0137a8b chore(complete): Update completest
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Improved control flow, dynamic detection of structured ifs and loops

    Improved control flow, dynamic detection of structured ifs and loops

    Previously, conditional branches were always marked as loop merges, but this is obviously wrong, since it doesn't account for ifs (selection merges). This has been improved, though more tests have to be done to ensure this is 100% correct

    enhancement 
    opened by Aandreba 0
  • Add workflow to automatically generate CLI builds when a new release is created

    Add workflow to automatically generate CLI builds when a new release is created

    This new workflow will generate CLI builds for the following targets and upload them as assets to the release that triggered the workflow.

    Currently targeted platforms

    • 64-bit x86 Windows (x86_64-pc-windows-msvc)
    • 64-bit x86 Linux (x86_64-unknown-linux-gnu)
    • Apple Silicon macOS (aarch64-apple-darwin)
    • 64-bit x86 macOS (x86_64-apple-darwin)
    opened by Aandreba 0
Releases(v0.1.0)
Owner
Alex Andreba
Alex Andreba
Rust to SPIR-V compiler

Rlsl - Rust Like Shading Language Deprecated in favor of rust-gpu What is Rlsl? Rlsl can compile a subset of Rust to SPIR-V. You can read more about t

Maik Klein 551 Dec 18, 2022
🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧

?? rust-gpu Rust as a first-class language and ecosystem for GPU graphics & compute shaders Current Status ?? Note: This project is still heavily in d

Embark 5.5k Jan 9, 2023
Toy library for neural networks in Rust using Vulkan compute shaders

descent Toy library for neural networks in Rust using Vulkan compute shaders. Features Multi-dimensional arrays backed by Vulkan device memory Use Rus

Simon Brown 71 Dec 16, 2022
Compile-time creation of neural networks with Rust

GAMMA Compile-time creation of neural networks with Rust Description This is for now just a showcase project of what can be done with const generics i

Aitor Ruano 354 Jan 1, 2023
Compile-time creation of neural networks

Mushin: Compile-time creation of neural networks Mushin is a Japanese term used in martial arts that refers to the state of mind obtained by practice.

Aitor Ruano 354 Jan 1, 2023
Turn your webcam into a face-detector with Rust, onnxruntime and actix_web!

InferCam ONNX Turn your webcam into a face detector with Rust, onnxruntime and the lightweight ultraface network. Overview Images are captured from th

null 4 May 10, 2022
A Python CLI tool that finds all third-party packages imported into your Python project

python-third-party-imports This is a Python CLI tool built with Rust that finds all third-party packages imported into your Python project. Install Yo

Maksudul Haque 24 Feb 1, 2023
WebAssembly component model implementation for any backend.

wasm_component_layer wasm_component_layer is a runtime agnostic implementation of the WebAssembly component model. It supports loading and linking WAS

Douglas Dwyer 11 Aug 28, 2023
m2cgen (Model 2 Code Generator) - is a lightweight library which provides an easy way to transpile trained statistical models into a native code

Transform ML models into a native code (Java, C, Python, Go, JavaScript, Visual Basic, C#, R, PowerShell, PHP, Dart, Haskell, Ruby, F#, Rust) with zero dependencies

Bayes' Witnesses 2.3k Dec 31, 2022
How to: Run Rust code on your NVIDIA GPU

Status This documentation about an unstable feature is UNMAINTAINED and was written over a year ago. Things may have drastically changed since then; r

null 343 Dec 22, 2022
Talk with your machine in this minimalistic Rust crate!

Speak Speak is a simple, easy to use Natural Language Processor (NLP) written in Rust. Why use Speak? Speak uses a custom engine, and to setup you jus

Alex 15 Oct 11, 2022
A fast and cross-platform Signed Distance Function (SDF) viewer, easily integrated with your SDF library.

SDF Viewer (demo below) A fast and cross-platform Signed Distance Function (SDF) viewer, easily integrated with your SDF library. A Signed Distance Fu

null 39 Dec 21, 2022
Your one stop CLI for ONNX model analysis.

Your one stop CLI for ONNX model analysis. Featuring graph visualization, FLOP counts, memory metrics and more! ⚡️ Quick start First, download and ins

Christopher Fleetwood 20 Dec 30, 2022
Believe in AI democratization. llama for nodejs backed by llama-rs, work locally on your laptop CPU. support llama/alpaca model.

llama-node Large Language Model LLaMA on node.js This project is in an early stage, the API for nodejs may change in the future, use it with caution.

Genkagaku.GPT 145 Apr 10, 2023
An NVIDIA SMI'esk GPU Monitoring tool for your terminal.

NVTOP An NVIDIA SMI'esk GPU Monitoring tool for your terminal. art by stable-diffusion + Maz Contents: usage prerequisites installation why troublesho

Jer 17 Oct 14, 2023
🔭 interactively explore `onnx` networks in your CLI.

nnli Interactively explore onnx networks in your CLI. Get nnli ?? From Cargo cargo install nnli From Github git clone https://github.com/drbh/nnli.git

drbh 18 Nov 27, 2023
Rust (MIR) → SPIR-V (Shader) compiler

inspirv-rust UPDATE 2: Next design iteration would probably be based on HIR instead of MIR. See more details here. In the meantime, you might want to

Markus Siglreithmaier 53 Oct 11, 2022
Rust to SPIR-V compiler

Rlsl - Rust Like Shading Language Deprecated in favor of rust-gpu What is Rlsl? Rlsl can compile a subset of Rust to SPIR-V. You can read more about t

Maik Klein 551 Dec 18, 2022
A rollup plugin that compile Rust code into WebAssembly modules

rollup-plugin-rust tl;dr -- see examples This is a rollup plugin that loads Rust code so it can be interop with Javascript base project. Currently, th

Fahmi Akbar Wildana 37 Aug 1, 2022
Contains the source code to compile the drop'in language into WebAssembly files

drop'in compiler This repository contains the source code to compile the drop'in language into WebAssembly files. This source code is in an experiment

Blue Forest 2 Dec 17, 2022