LLVM backend for Faust
Note: Below is a slightly edited version of Stephane Letz' original Faust2 page (wayback link) that used to be available at www.grame.fr. Most of this information is severely outdated now. The current git version of Faust can now be found at https://github.com/grame-cncm/faust, use the faust2 branch of that repo instead:
git clone https://github.com/grame-cncm/faust.git cd faust git checkout faust2
Older (historic) releases continue to be available on Faust's old SourceForge project at https://sourceforge.net/projects/faudiostream/, if you still need these for some reason.
Old Instructions (Outdated!)
FAUST is a compiled language for real-time audio signal processing. The name FAUST stands for Functional AUdio STream. Its programming model combines two approaches : functional programming and block diagram composition. You can think of FAUST as a structured block diagram language with a textual syntax.
LLVM (Low Level Virtual Machine) is a very interesting open-source project that provides a set of tools to develop compilers and related technologies. It provides a SSA based Internal Representation format, ObjectiveC/C/C++ front end, JIT, and various backends.
A new backend for Faust that directly produces LLVM IR (instead of the C++ class Faust currently produces) has been developed. With a (yet to come) library version of the Faust compiler, it will allow developers to embed Faust + LLVM JIT to dynamically define, compile on the fly and execute Faust plug-ins. LLVM IR and tools also allows some nice bytecode manipulations like "partial evaluation/specialization" (also called "runtime optimization" by the LLVM guys) that we also currently investigate.
The source code of can be downloaded from the Faust2 branch of the Faust git repository at the SourceForge site:
Read-only access :
git clone git://git.code.sf.net/p/faudiostream/code faudiostream
Developer (Read-Write access) :
git clone ssh://USER@git.code.sf.net/p/faudiostream/code faudiostream
Now to get the "faust2" branch where the new FIR (Faust Intermediate Representation) based backend model is developed:
cd faudiostream git checkout -b faust2 origin/faust2 make && sudo make install
Using LLVM bitcode
The new -lang parameter has to be used to produce LLVM bitcode, like for example:
faust -lang llvm examples/noise.dsp -o noise.bc
You may look at the textual version of the LLVM bitcode if no output file is specified:
faust -lang llvm examples/noise.dsp
Integrating the produced bitcode with an architecture is a bit different compared to what was usually done with C or C++ produced code. Basically one will need to compile the LLVM bitcode on one side, the adapted architecture file on the other side and link them together. Look at the architecture/llvm-jack-gtk.cpp file as an example of Faust LLVM bitcode with Jack/GTK architecture file integration. In this case, the C++ wrapper defined a class llvmdsp : public dsp that will use the API exported in the LLVM bitcode file (functions like new_llvm, delete_llvm, getNumInputs_llvm, getNumOutputs_llvm, compute_llvm, etc.). The Faust compiler produce the best LLVM bitcode it can, but does not (yet) apply any optimization passes by itself. LLVM has quite powerfull optimizations passes to be done on LLVM IR which can be tested and applied using the LLVM opt tool:
opt -O3 noise.bc -o noise.bc
The optimized LLVM bitcode file can be compiled using LLVM llc tool to produce an assembly file like:
llc -O3 noise.bc -o noise.s
Then assembly file and architecture file are linked together to produce the final application:
llvm-g++ architecture/llvm-jack-gtk.cpp noise.s `pkg-config --cflags --libs jack gtk+-2.0` -o noise
An alternative is to prepare a generic Faust LLVM bitcode loader that will be able to load and JIT any Faust generated LLVM bitcode file. Go to the "examples" folder and type "make llvm-loader" to compile the llvm-jack-gtk-loader. You can then use it to load the previously generated noise.bc bitcode file:
Compiling in Work Stealing Scheduler (-sch) mode
When compiled with -sch option, the generated LLVM bitcode will contain calls to the WSS API functions, to be compiled separately and linked to the final appplication. So:
faust -lang llvm -sch examples/noise.dsp -o noise.bc
opt -O3 noise.bc -o noise.bc llc -O3 noise.bc -o noise.s llvm-g++ architecture/llvm-jack-gtk.cpp architecture/scheduler.cpp noise.s `pkg-config --cflags --libs jack gtk+-2.0` -o noise
Using the llvm-jack-gtk-loader, generic LLVM bitcode loading cannot be done directly, since it does not contain the object code for WSS API functions. One solution is to compile the "scheduler.cpp" file to bitcode and link it with the Faust generated bitcode. The jackgtkllvm target in "examples" already does that and produce a "foo_sch.bc" kind of file for each example. Then
./llvm-jack-gtk-loader jackgtkdirllvm/noise_sch.bc will do the job.