Skip to content

Instantly share code, notes, and snippets.

@yurydelendik
Last active February 23, 2024 05:08
Show Gist options
  • Save yurydelendik/4eeff8248aeb14ce763e to your computer and use it in GitHub Desktop.
Save yurydelendik/4eeff8248aeb14ce763e to your computer and use it in GitHub Desktop.
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
@fospring
Copy link

@yurydelendik
When I use command:

s2wasm fib.s > fib.wast

Console output:

[[function element:]]:
==========
.functype	fib (i32) -> (i32)
	.local  	i32, i32, i32, i32
	i
==========
Abort trap: 6

And the fib.wast file is empty.
Can you tell me why?
My plateform is Mac(Darwin Kernel Version 17.7.0,macOS 10.13.6)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment