Gil Dogon wrote:
I have two questions :
1. Is that the right way to go, or is there a simpler/more standard way to have frontend support for new architecture intrinsics ?
Gil, it's really easy to add builtins to the llvm-gcc frontend and have them auto-magically converted to the llvm intrinsic versions. The main problem with this is that you end up with a non-standard front end that you have to somehow distribute to the people who need it. There may be funny licensing problems, etc... I don't really know.
Here's a quick how-to based on adding an intrinsic which we want to look like:
void* llvm.my.foo(void**, void*)
1) Get the llvm-gcc source from svn.
2) Edit the file gcc/builtins.def
The comments at the top are helpful, read them.
a) Add a macro that looks something like
#undef DEF_MY_BUILTIN
#define DEF_MY_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_MD, TYPE, TYPE, \
false, false, true, ATTRS, false, true)
You can figure out what this means based on the comments in the
builtins.def file. Essentially the important magic is the
BUILT_IN_MD flag trickles through and gets your llvm intrinsic
generated automatically. Also, all of your builtins will be
prefixed with __builtin_ --- you could change this if you wanted.
b) Add an include directive at the bottom of the file,
"#include my-builtins.def"
This isn't strictly necessary, you could just add your builtins
directly to the builtins.def file, but it helps keep them
separate.
3) Edit the gcc/Makefile.in file (not necessary if you skipped b above)
a) Find the BUILTINS_DEF line and add your "my-builtins.def" file.
4) Create and edit gcc/my-builtins.def
The file gcc/builtin-types.def lists the macros you can use to
declare the function types for your macros, and
gcc/builtin-attrs.def lists the attributes, though I've only ever
used ATTR_NOTHROW_LIST.
a) Use the macro you defined earlier to generate your builtins, in
our example case it is
DEF_MY_BUILTIN (BUILT_IN_MY_FOO, "my_foo", \
BT_FN_PTR_PTRPTR_PTR, ATTR_NOTHROW_LIST)
This is straightforward, the first parameter is an ID for your
builtin within gcc -- it just needs to be unique. The second is
the "name" of your builtin, which will be prepended with
"__builtin_" based on our definition of DEF_MY_BUILTIN. The third
is the function type from gcc/builtin-types.def, (here a function
taking a pointer to a pointer, and a pointer, and returning a
pointer). The fourth is the function attributes which I don't
really know anything about.
b) In our case here, the correct function type didn't exist, so an
additional step is to edit gcc/builtin-types.def. I would add the
following in the section where the 2-parameter types are defined.
DEF_FUNCTION_TYPE_2 (BT_FN_PTR_PTRPTR_PTR, BT_PTR, BT_PTR_PTR, BT_PTR)
That's all you need to change within llvm-gcc (I think, I didn't
bug-test the instructions, but I'm pretty sure it will work.
5) Get llvm source from svn
6) Edit include/llvm/Intrinsics.td
You can either add your intrinsics directly, or just add an
include to your own file. Here I'm adding them directly.
a) Add a definition of your intrinsic. In our case, it looks like
def int_my_foo : Intrinsic<[llvm_ptr_ty],
[llvm_ptrptr_ty, llvm_ptr_ty]>,
GCCBuiltin<"__builtin_my_foo">;
Clearly the fun here is the GCCBuiltin tag which is what gets
everything to /just work/.
7) Build llvm.
8) Configure llvm-gcc with your modified llvm binary directory as it's
llvm directory.
9) Build llvm-gcc.
10) Configure llvm with the llvm-gcc directory.
11) Rebuild llvm.
And voila, users can now use your gcc builtin as
"void* addr = __builtin_my_foo(&bar, bar)" and compilation will naturally generate a llvm.my.foo for it.
One caveat is that I've never actually done this with parameters that have address types, but ints, voids, and longs work fine. There's a routine in llvm-gcc inside of "gcc/llvm-convert.cpp" called TreeToLLVM::EmitBuiltinCall that does the actual conversion, you may need to do some work in that area. My guess is that it will /just work/ though.
Hope this helps. There may be other ways to do this using gcc asm tags and such, but I know that this works and gets parameters in the right place, etc.
Let me know if there are any bugs in the instructions.
Luke