Luke Dalessandro wrote:
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
#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,
This isn't strictly necessary, you could just add your builtins
directly to the builtins.def file, but it helps keep them
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
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", \
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],
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
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.
Well Luke , First I just wanted to thank you for your effort , even though I am not likely to follow what you suggested, It seems very detailed, and maybe
even it can be added to the LLVM documentation (I think that currently there is no document about llvm-gcc hacking) and help future compiler writers .. .
I decide to avoid this approach mainly because of the problem that you've mentioned above. Adding source level llvm-gcc frontend to
our distribution is too much of a headache right now, and also increases build time dramatically, so I'd like to avoid it.
What I did was a rather quick-and-dirty hack which I know is non-standard, but nevertheless quite painless and straightforward :
A. I define my proprietary intrinsics in an include file something like
int __VMPINTR__something(....) ;
B. I define a corresponding int_vmp_something in llvms Intrinsics.td .
C. I changed Function::getIntrinsicID by adding the following :
where VMP_intrinsic function code recognizes my proprietary '__VMPINTR__' style intrinsic names.
I know also that for Chris or other LLVM tblgen masters it could be quite easy to make this VMP_intrinsic function code
tblgened , but I will be content to manually edit it as I go along .(I do not expect to have that many of them) ...