clone function

Hi,

I am trying to use the CloneFunction from llvm/Transforms/Utils/Cloning.h and I don’t understand how the ValueToValueMapTy argument should be initialized. For instance, let say I want to clone this function (to add an argument):

define void @function(i32 %i) #0 {
entry:
%i.addr = alloca i32, align 4
store i32 %i, i32* %i.addr, align 4
ret void
}

to another function which should, after the CloneFunction, be like:

define void @cloned_function(i32 %i, i8* %ptr) #0 {
entry:
%i.addr = alloca i32, align 4
store i32 %i, i32* %i.addr, align 4
ret void
}

To do so, I first declared the clone_function with its arguments into the module then I should call CloneFunction like:

Function *function = M.getFunction(“function”);

Function cloned_function = M.getFunction(“cloned_function”);
cloned_function = CloneFunction(
function,
VM,
false /
or true? didn’t get the difference */
);

The question is how should I setup VM so that the job is correctly done? I assumed I had to link arguments from function to their equivalent in cloned_function but I don’t see why VM should contain pair<Value*, WeakVH> instead of pair<Value*, Value*>…

Thank you for the help,

Pierre

Hi,

I am trying to use the CloneFunction from llvm/Transforms/Utils/Cloning.h and I don’t understand how the ValueToValueMapTy argument should be initialized. For instance, let say I want to clone this function (to add an argument):

define void @function(i32 %i) #0 {
entry:
%i.addr = alloca i32, align 4
store i32 %i, i32* %i.addr, align 4
ret void
}

to another function which should, after the CloneFunction, be like:

define void @cloned_function(i32 %i, i8* %ptr) #0 {
entry:
%i.addr = alloca i32, align 4
store i32 %i, i32* %i.addr, align 4
ret void
}

To do so, I first declared the clone_function with its arguments into the module then I should call CloneFunction like:

Function *function = M.getFunction(“function”);

Function *cloned_function = M.getFunction("cloned_function”);

This last statement is dead code, you overwrite the cloned_function on the next line.

cloned_function = CloneFunction(
function,
VM,
false /* or true? didn’t get the difference */
);

Current LLVM has this prototype:

Function *CloneFunction(Function *F, ValueToValueMapTy &VMap,
ClonedCodeInfo *CodeInfo = nullptr);

Notice that the last argument is not a boolean (You may be using a different version of LLVM?).
Also, the API takes a function and returns another one. I’m not sure what you expect by first declaring another function with its arguments: it won’t be magically picked as a “destination” for the clone.

You have to design this as a two-part process:

  1. Clone the function (if you need to keep the original around)
  2. Change the function signature. For this there is no helper (that I know of), you may look at how it is done in the DeadArgElimination pass.

Apparently you can do part of the transformation during the clone, first creating your new function and mapping the old argument to the new ones, but you’ll still have to splice the function body from the created clone to your new function. I’m not sure if it really buys you anything over RAUW it after the fact though.

Hi,

I am trying to use the CloneFunction from llvm/Transforms/Utils/Cloning.h
and I don't understand how the ValueToValueMapTy argument should be
initialized. For instance, let say I want to clone this function (to add an
argument):

define void @function(i32 %i) #0 {
entry:
  %i.addr = alloca i32, align 4
  store i32 %i, i32* %i.addr, align 4
  ret void
}

to another function which should, after the CloneFunction, be like:

define void @cloned_function(i32 %i, i8* %ptr) #0 {
entry:
  %i.addr = alloca i32, align 4
  store i32 %i, i32* %i.addr, align 4
  ret void
}

To do so, I first declared the clone_function with its arguments into the
module then I should call CloneFunction like:

Function *function = M.getFunction("function");
Function *cloned_function = M.getFunction("cloned_function”);

This last statement is dead code, you overwrite the cloned_function on the
next line.

cloned_function = CloneFunction(
    function,
    VM,
    false /* or true? didn't get the difference */
  );

Current LLVM has this prototype:

Function *CloneFunction(Function *F, ValueToValueMapTy &VMap,
                        ClonedCodeInfo *CodeInfo = nullptr);

Notice that the last argument is not a boolean (You may be using a
different version of LLVM?).

Also, the API takes a function and returns another one. I’m not sure what

you expect by first declaring another function with its arguments: it won’t
be magically picked as a “destination” for the clone.

Yup sorry, just that I tried to use CloneFunctionInto first which takes
both the function to clone and the other. I just read the code this morning
and CloneFunction is not doing what I want, it deletes arguments passed
though the VMap. I just thought quickly that as there where only 3
arguments it would be easier for someone to explain...

The one I want to use is the CloneFunctionInto. It seems it does remap the
argument passed to the function so that instructions in the new body
doesn't point to Values in other function body. That's why it is usefull to
declare the function with its arguments: it generates independant arguments
with their own address (which differs with the one to clone). So it is
definitely not CloneFunction that I should have put the question on but
CloneFunctionInto, my bad.

For CloneFunction I followed the signature here (
http://llvm.org/docs/doxygen/html/namespacellvm.html#a5596246c2350cb74f31ffa7695d5923c)
but it seems not to be the version I have in my source files actually...

You have to design this as a two-part process:

1) Clone the function (if you need to keep the original around)
2) Change the function signature. For this there is no helper (that I know
of), you may look at how it is done in the DeadArgElimination pass.

Yes that's the hard part. And you can't clone the function if there is
arguments. The instructions using these arguments will have Values refering
to another function body which triggers errors like:

Referring to an argument in another function!
  store i8* %ptr, i8** %ptr.addr, align 8

for a function taking i8* %ptr as argument. But I think CloneFunctionInto
allows you to do this kind of argument expansion (because that's the only
thing after all: adding an argument to the function).

Not sure what you mean by "you can’t clone the function if there is arguments”, CloneFunction is supposed to handle this.

If you end up with this by only calling CloneFunction, that’s a bug. It is supposed to handle this perfectly.

Yes, CloneFunction is setting up the call for CloneFunctionInto, if you look at the implementation you should be able to copy it, and with some adaptation call CallFunctionInto.

Note: If you just want to add an argument and don’t need to preserve the old function, cloning it is an expensive solution…

Hi again,

I finally managed to find the solution looking at CloneFunctionInto
implementation.

Not sure what you mean by "you can't clone the function if there is
arguments”, CloneFunction is supposed to handle this.

I meant that you can't directly splice the function body from a function
with arguments (at least if those argument are used in the function body).
Because that's what I tried first as an "hand-made" solution, then I had to
do the arguments mapping I thought this should probably exist somewhere in
LLVM API...

The instructions using these arguments will have Values refering to
another function body which triggers errors like:

Referring to an argument in another function!
  store i8* %ptr, i8** %ptr.addr, align 8

for a function taking i8* %ptr as argument.

If you end up with this by *only* calling CloneFunction, that’s a bug. It
is supposed to handle this perfectly.

Nope, that happen when arguments weren't remapped. I didn't managed to use
CloneFunction because I didn't get how to build the ValueToValueMapTy
argument (given by "typedef ValueMap< const Value*, WeakVH

llvm::ValueToValueMapTy").

At last when I looked to the implementation they used it as a
std::map<Value*, Value*>... I'm still confused on that point. Well at least
it does make sense to remap the argument with a map like that. And that was
my initial question by the way.

But I think CloneFunctionInto allows you to do this kind of argument
expansion

Yes, CloneFunction is setting up the call for CloneFunctionInto, if you
look at the implementation you should be able to copy it, and with some
adaptation call CallFunctionInto.

(because that's the only thing after all: adding an argument to the
function).

Note: If you just want to *add* an argument and don’t need to preserve the
old function, cloning it is an expensive solution…

Well I think I don't need to keep the original function around, but how
should I do so ? This doesn't look like trivial because every CallInst to
the original function has to be modified too to match the new signature. Or
doing it with optional arguments ? Never tried those.

But anyway I guess the answer to my original question was just "you can put
some std::map<Value*, Value*> for the VMap argument" ^^.

Thanks for your time, I hope it's the last time I need to ask for help!