Strategy to compile for LLVM IR

Hi,

We have a compiler for the Faust language (faust.grame.fr) that currently compiles a C++ class which implements a DSP plug-in with several methods.

Our strategy to compile LLVM IR instead is the following:

- use the current Faust ==> C++ compiler to compile a "empty" plug-in that we use as a template C++ class.

- compile this template C++ class using "llvm-g++ -emit-llvm -c " to get a bytecode file template.bc

- use "llvm2cpp template.bc" to get a template.bc.cpp of C++ code the Faust ==> LLVM IR new backend will have to execute to produce the correct bytecode.

- take this template.bc.cpp code as the "constant" part of the Faust ==> LLVM IR backend and add everything needed to produce the "variable" part (that one corresponding to what the real Faust plug-in will do)

This method should work but is a bit complex, since we have to look at the template.bc.cpp code, find the "entry points" (Function* or BadsicBlock* objects) we will have to enrich with additional code.

Is there any more common and simple method to achieve the same result? or any other advice?

Thanks

Stephane Letz

We have a compiler for the Faust language (faust.grame.fr) that
currently compiles a C++ class which implements a DSP plug-in with
several methods.

ok

Our strategy to compile LLVM IR instead is the following:

- use the current Faust ==> C++ compiler to compile a "empty" plug-in
that we use as a template C++ class.

- compile this template C++ class using "llvm-g++ -emit-llvm -c "
to get a bytecode file template.bc

Ok.

- use "llvm2cpp template.bc" to get a template.bc.cpp of C++ code
the Faust ==> LLVM IR new backend will have to execute to produce
the correct bytecode.

- take this template.bc.cpp code as the "constant" part of the Faust
==> LLVM IR backend and add everything needed to produce the
"variable" part (that one corresponding to what the real Faust plug-
in will do)

Is there any more common and simple method to achieve the same
result? or any other advice?

Here's a better way. Consider a simple C template like this:

void the_template(int X, int Y) {
   if (X == 123)
     hole1(Y, X*Y);

   int *Ptr;
   for (...)
     hole2(Ptr);
}

The template can do whatever you want obviously. I assume that there are various pieces that need to be filled in, e.g. the body of a loop. In you C template code, just put simple function calls to external functions (named hole1/hole2 in this example).

At runtime, load the IR for the code above (either from the .bc file, or statically linked into your app with llvm2cpp). Then do the following:

1. Create new internal LLVM functions that will be used to fill in the
    holes in the template.
2. Clone the template code, specializing it based on globals or arguments,
    or whatever else you want.
3. Iterate through the cloned code looking for calls to hole*. Change the
    callinst to call into the new LLVM function you created with #1.
4. After you iterate through and update the calls, use the InlineFunction
    routine in llvm/Transforms/Utils/Cloning.h to inline the calls to the
    static functions you built in #1.

The end result is happy specialized code, but in a nice and maintainable form.

-Chris

We have a compiler for the Faust language (faust.grame.fr) that
currently compiles a C++ class which implements a DSP plug-in with
several methods.

BTW, since you are fast becoming a guru in code specialization with LLVM, it would be really nice if you could write a little document that captures some of this wisdom for the next person :slight_smile:

-Chris

Our strategy to compile LLVM IR instead is the following:

- use the current Faust ==> C++ compiler to compile a "empty" plug-in
that we use as a template C++ class.

- compile this template C++ class using "llvm-g++ -emit-llvm -c "
to get a bytecode file template.bc

- use "llvm2cpp template.bc" to get a template.bc.cpp of C++ code
the Faust ==> LLVM IR new backend will have to execute to produce
the correct bytecode.

- take this template.bc.cpp code as the "constant" part of the Faust
==> LLVM IR backend and add everything needed to produce the
"variable" part (that one corresponding to what the real Faust plug-
in will do)

This method should work but is a bit complex, since we have to look
at the template.bc.cpp code, find the "entry points" (Function* or
BadsicBlock* objects) we will have to enrich with additional code.

Is there any more common and simple method to achieve the same
result? or any other advice?

Thanks

Stephane Letz

_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris