Adding Intrinsics for custom processor (frotend, problem)

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

#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

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 .. :slight_smile: .

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 :

unsigned vmpi=VMP_intrinsic(Name,Len);
if(vmpi)
return vmpi;

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) ...