Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using WebAssembly in LLVM

NOTE: the content is out-of-date. All development is moved to the https://github.com/yurydelendik/wasmception

Using WebAssembly in LLVM

Compiling

# locations, e.g.
export WORKDIR=~/llvmwasm; mkdir -p $WORKDIR
export INSTALLDIR=$WORKDIR

# checkout LLVM
cd $WORKDIR
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

# checkout clang
cd $WORKDIR/llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang

# checkout lld
svn co http://llvm.org/svn/llvm-project/lld/trunk lld

# build folder (~14 min; ~1 hour /wo -j)
mkdir $WORKDIR/llvm-build
cd $WORKDIR/llvm-build
# For Debug build:
# cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Debug $WORKDIR/llvm
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm 
make -j 8

# install llvm
make install

Example

Let's create "fib.c" and compile it, first to LLVM bitcode, then to WebAssembly-like file. (Notice -O2 or above near clang to avoid failure during llc run.)

$INSTALLDIR/bin/clang -emit-llvm --target=wasm32 -Oz fib.c -c -o fib.bc
$INSTALLDIR/bin/llc -asm-verbose=false -o fib.s fib.bc

See output at fib.s.

Convert to WebAssebly s-expressions (needs binaryen s2wasm tool):

$BINARYENDIR/bin/s2wasm fib.s > fib.wast

See output at fib.wast.

References

#/bin/bash
llvm_root=~/llvmwasm/llvm-build/bin
binaryen_root=~/llvmwasm/binaryen/bin
cfile=$1
bcfile=${cfile%.*}.bc
sfile=${cfile%.*}.s
wastfile=${cfile%.*}.wast
$llvm_root/clang -emit-llvm --target=wasm32 -Oz "$cfile" -c -o "$bcfile"
if [ $? != 0 ];then
exit 1
fi
$llvm_root/llc -asm-verbose=false -o "$sfile" "$bcfile"
if [ $? != 0 ];then
exit 2
fi
$binaryen_root/s2wasm "$sfile" > "$wastfile"
if [ $? != 0 ];then
exit 3
fi
int fib(int n) {
int i, t, a = 0, b = 1;
for (i = 0; i < n; i++) {
t = a + b; a = b; b = t;
}
return b;
}
.text
.file "fib.bc"
.globl fib
.type fib,@function
fib:
.param i32
.result i32
block $BB0_3
i32.const 1
set_local @9, pop
i32.const 0
set_local @13, pop
i32.const -1
set_local @12, pop
@0
set_local @6, pop
@9
set_local @14, pop
BB0_1:
loop $BB0_3
add @12, @9
set_local @12, pop
sge @12, @6
set_local @11, pop
brif $BB0_3, @11
add @14, @13
set_local @5, pop
@14
set_local @13, pop
@5
set_local @14, pop
br $BB0_1
BB0_3:
return @14
func_end0:
.size fib, func_end0-fib
(module
(import $print_i32 "stdio" "print" (param i32))
(import $print_f32 "stdio" "print" (param f32))
(import $print_i64 "stdio" "print" (param i64))
(import $print_f64 "stdio" "print" (param f64))
(func $fib
(param i32)
(result i32)
(block $BB0_3
(set_local @9 (i32.const 1))
(set_local @13 (i32.const 0))
(set_local @12 (i32.const -1))
(set_local @6 (@0))
(set_local @14 (@9))
(loop $BB0_1
(set_local @12 (add @12 @9))
(set_local @11 (sge @12 @6))
(brif $BB0_3 @11)
(set_local @5 (add @14 @13))
(set_local @13 (@14))
(set_local @14 (@5))
(br $BB0_1)
)
)
(return @14)
)
(memory 0 0
(segment 0
""
)
)
)
ROOT_DIR=$(shell pwd)
LLVM_WORKDIR=$(ROOT_DIR)/src/llvm
LLVM_BUILDDIR=$(ROOT_DIR)/build/llvm
BINARYEN_WORKDIR=$(ROOT_DIR)/src/binaryen
BINARYEN_BUILDDIR=$(ROOT_DIR)/build/binaryen
INSTALLDIR=$(ROOT_DIR)/bin
build: build-llvm build-binaryen
clean: clean-llvm clean-binaryen
rm -rf $(INSTALLDIR)
install: install-llvm install-binaryen
$(LLVM_WORKDIR)/.svn:
rm -rf $(LLVM_WORKDIR)
mkdir -p $(LLVM_WORKDIR)
svn co http://llvm.org/svn/llvm-project/llvm/trunk $(LLVM_WORKDIR)
svn co http://llvm.org/svn/llvm-project/cfe/trunk $(LLVM_WORKDIR)/tools/clang
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk $(LLVM_WORKDIR)/projects/compiler-rt
$(LLVM_BUILDDIR)/Makefile: $(LLVM_WORKDIR)/.svn
mkdir -p $(LLVM_BUILDDIR)
cd $(LLVM_BUILDDIR); cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$(INSTALLDIR) -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DLLVM_TARGETS_TO_BUILD= -DCMAKE_BUILD_TYPE=Release $(LLVM_WORKDIR)
build-llvm: $(LLVM_BUILDDIR)/Makefile
$(MAKE) -C $(LLVM_BUILDDIR) -j 8 clang llc llvm-lib
clean-llvm:
rm -rf $(LLVM_WORKDIR)
rm -rf $(LLVM_BUILDDIR)
install-llvm:
mkdir -p $(INSTALLDIR)
$(MAKE) -C $(LLVM_BUILDDIR) install-clang install-llc install-llvm-lib
$(BINARYEN_WORKDIR)/.git:
rm -rf $(BINARYEN_WORKDIR)
mkdir -p $(BINARYEN_WORKDIR)
git clone https://github.com/WebAssembly/binaryen $(BINARYEN_WORKDIR)
$(BINARYEN_BUILDDIR)/Makefile: $(BINARYEN_WORKDIR)/.git
mkdir -p $(BINARYEN_BUILDDIR)
cd $(BINARYEN_BUILDDIR); cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$(INSTALLDIR) -DCMAKE_BUILD_TYPE=Release $(BINARYEN_WORKDIR)
build-binaryen: $(BINARYEN_BUILDDIR)/Makefile
$(MAKE) -C $(BINARYEN_BUILDDIR) -j 8 wasm-as wasm-dis s2wasm
clean-binaryen:
rm -rf $(BINARYEN_WORKDIR)
rm -rf $(BINARYEN_BUILDDIR)
install-binaryen:
mkdir -p $(INSTALLDIR)
cp $(addprefix $(BINARYEN_BUILDDIR)/bin/, wasm-as wasm-dis s2wasm) $(INSTALLDIR)
.PHONY: build clean install build-llvm clean-llvm install-llvm build-binaryen clean-binaryen install-binaryen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment