[LLVMdev] Use list preservation when using Instruction::clone
Tyler Denniston
tyler at csail.mit.edu
Thu Oct 2 18:07:23 PDT 2014
The attachment of the tarball didn't work, so I've pasted the pass
code and the human-readable test bitcode. Hopefully the line breaks
stay sane.
// File Test.cpp
#include "llvm/Pass.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <set>
using namespace llvm;
class TestPass : public ModulePass {
public:
static char ID;
TestPass() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
for (Module::iterator fit = M.begin(), fite = M.end(); fit !=
fite; ++fit) {
Function *F = fit;
Function *CloneF = createFunctionClone(F, M);
std::set<Instruction *> Is = getInstructions(F);
evaluateFunction(CloneF, M);
validateFunctionBody(F, Is);
CloneF->eraseFromParent();
}
return false;
}
private:
// Return all instructions in the given Function.
std::set<Instruction *> getInstructions(Function *F) {
std::set<Instruction *> Is;
for (Function::iterator bbit = F->begin(), bbite = F->end(); bbit
!= bbite; ++bbit) {
BasicBlock *BB = bbit;
for (BasicBlock::iterator it = BB->begin(), ite = BB->end(); it
!= ite; ++it) {
Instruction *I = it;
Is.insert(I);
}
}
return Is;
}
// Assert that the given Function's instructions is equal to the given set.
void validateFunctionBody(Function *F, const std::set<Instruction *> &Is) {
std::set<Instruction *> CurrIs = getInstructions(F);
std::set<Instruction *>::iterator a = CurrIs.begin(), b = Is.begin();
// Compare the two sets.
while (a != CurrIs.end()) {
if (b == Is.end() || *a != *b) assert(false);
++a; ++b;
}
}
// JIT and evaluate the given function.
void evaluateFunction(Function *F, Module &M) {
std::string errStr;
InitializeNativeTarget();
ExecutionEngine *EE = ExecutionEngine::create(&M, false, &errStr);
if (EE == NULL) {
errs() << "Could not create execution engine: " << errStr << "\n";
assert(false);
}
std::vector<GenericValue> args;
for (unsigned i = 0; i < F->arg_size(); i++) {
GenericValue gv;
gv.IntVal = APInt(32, 0);
args.push_back(gv);
}
// Execute the function
GenericValue v = EE->runFunction(F, args);
}
// Return a clone of the given function.
Function *createFunctionClone(Function *F, Module &M) {
ValueToValueMapTy argVmap;
SmallVector<ReturnInst *, 8> returns;
Function *CloneF = Function::Create(F->getFunctionType(),
GlobalVariable::ExternalLinkage, "", &M);
Function::arg_iterator DestI = CloneF->arg_begin();
for (Function::const_arg_iterator J = F->arg_begin(); J !=
F->arg_end(); ++J) {
DestI->setName(J->getName());
argVmap[J] = DestI++;
}
CloneFunctionInto(CloneF, F, argVmap, true, returns);
return CloneF;
}
};
char TestPass::ID = 0;
static RegisterPass<TestPass> X("test", "Bug test pass", false, false);
// File bug.ll
define internal i32 @openregion(i32 %i1, i32 %i2, i32 %j1, i32 %j2) #0 {
entry:
%retval = alloca i32, align 4
%i1.addr = alloca i32, align 4
%i2.addr = alloca i32, align 4
%j1.addr = alloca i32, align 4
%j2.addr = alloca i32, align 4
%x = alloca i32, align 4
%y = alloca i32, align 4
store i32 %i1, i32* %i1.addr, align 4
store i32 %i2, i32* %i2.addr, align 4
store i32 %j1, i32* %j1.addr, align 4
store i32 %j2, i32* %j2.addr, align 4
%0 = load i32* %i1.addr, align 4
%1 = load i32* %i2.addr, align 4
%cmp = icmp sgt i32 %0, %1
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
%2 = load i32* %i2.addr, align 4
%3 = load i32* %i1.addr, align 4
%4 = load i32* %j1.addr, align 4
%5 = load i32* %j2.addr, align 4
%call = call i32 @openregion(i32 %2, i32 %3, i32 %4, i32 %5)
store i32 %call, i32* %retval
br label %return
if.end: ; preds = %entry
%6 = load i32* %j1.addr, align 4
%7 = load i32* %j2.addr, align 4
%cmp1 = icmp sgt i32 %6, %7
br i1 %cmp1, label %if.then2, label %if.end4
if.then2: ; preds = %if.end
%8 = load i32* %i1.addr, align 4
%9 = load i32* %i2.addr, align 4
%10 = load i32* %j2.addr, align 4
%11 = load i32* %j1.addr, align 4
%call3 = call i32 @openregion(i32 %8, i32 %9, i32 %10, i32 %11)
store i32 %call3, i32* %retval
br label %return
if.end4: ; preds = %if.end
%12 = load i32* %i1.addr, align 4
store i32 %12, i32* %x, align 4
br label %for.cond
for.cond: ; preds =
%for.inc14, %if.end4
%13 = load i32* %x, align 4
%14 = load i32* %i2.addr, align 4
%cmp5 = icmp sle i32 %13, %14
br i1 %cmp5, label %for.body, label %for.end16
for.body: ; preds = %for.cond
%15 = load i32* %j1.addr, align 4
store i32 %15, i32* %y, align 4
br label %for.cond6
for.cond6: ; preds = %for.inc,
%for.body
%16 = load i32* %y, align 4
%17 = load i32* %j2.addr, align 4
%cmp7 = icmp sle i32 %16, %17
br i1 %cmp7, label %for.body8, label %for.end
for.body8: ; preds = %for.cond6
%18 = load i32* %x, align 4
%mul = mul nsw i32 %18, 20
%add = add nsw i32 21, %mul
%19 = load i32* %y, align 4
%add9 = add nsw i32 %add, %19
%idxprom = sext i32 %add9 to i64
%20 = add nsw i8 0, 0
%conv = zext i8 %20 to i32
%cmp10 = icmp ne i32 %conv, 0
br i1 %cmp10, label %if.then12, label %if.end13
if.then12: ; preds = %for.body8
store i32 0, i32* %retval
br label %return
if.end13: ; preds = %for.body8
br label %for.inc
for.inc: ; preds = %if.end13
%21 = load i32* %y, align 4
%inc = add nsw i32 %21, 1
store i32 %inc, i32* %y, align 4
br label %for.cond6
for.end: ; preds = %for.cond6
br label %for.inc14
for.inc14: ; preds = %for.end
%22 = load i32* %x, align 4
%inc15 = add nsw i32 %22, 1
store i32 %inc15, i32* %x, align 4
br label %for.cond
for.end16: ; preds = %for.cond
store i32 1, i32* %retval
br label %return
return: ; preds =
%for.end16, %if.then12, %if.then2, %if.then
%23 = load i32* %retval
ret i32 %23
}
Quoting Tyler Denniston <tyler at csail.mit.edu>:
> Ok, it took me a little while to isolate this into a test case, but I
> have one, in the attached tarball. Please run the attached pass on the
> attached bitcode (LLVM 3.4).
>
> The bug I'm seeing is summarized as follows:
>
> 1. Save a list of all of the function F's instructions.
> 2. Create a clone of the function F.
> 3. JIT and execute the cloned function.
> 4. Assert that the body of F has not changed.
>
> The bug is the assertion in (4) failing. If you run the test case, you
> should see a crash with this message:
>
> Assertion failed: (false), function validateFunctionBody, file
> Test.cpp, line 50.
>
> The reason I started this thread asking about use lists is I think
> this has to do with instructions in the cloned function listing
> instructions in the original function as Uses, and thus when the JIT
> erases some instructions in the cloned function, the originals are
> deleted as dead code. That's just a hypothesis, anyway, I'm not sure
> it's correct.
>
> I don't think this seems like intended behavior, but perhaps with this
> additional information about the behavior I'm seeing, someone can shed
> some light on this for me.
>
> Tyler
>
> Quoting Jingyue Wu <jingyue at google.com>:
>
>> Hi Tyler,
>>
>> Doesn't look right. Would you mind attaching the test?
>>
>> Btw, instead of creating an empty function and CloneFunctionInto, can you
>> just CloneFunction?
>>
>> Jingyue
>>
>> On Thu Oct 02 2014 at 2:47:51 PM Tyler Denniston <tyler at csail.mit.edu>
>> wrote:
>>
>>> I'm trying to create a clone of a function using Function::Create()
>>> and CloneFunctionInto. However, I'm running into an issue. I believe
>>> that the instructions in the function clone still have Use edges to
>>> values in the original function. This is a problem for my purposes.
>>>
>>> For example, consider an original function F. I create a new function
>>> G belonging to the same module and call CloneFunctionInto(G, F) to
>>> copy over the function body. Now, consider a phi node p in F, and an
>>> instruction I in F which uses p. The problem is, the cloned phi node
>>> p' in G still lists I as a user.
>>>
>>> Is this intended behavior? And if so, is there a way I can remove
>>> these Use edges in my cloned function?
>>>
>>> Thanks,
>>>
>>> Tyler
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>>
More information about the llvm-dev
mailing list