1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-24 21:42:54 +02:00
llvm-mirror/unittests/Transforms/Utils/Cloning.cpp

411 lines
13 KiB
C++
Raw Normal View History

//===- Cloning.cpp - Unit tests for the Cloner ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/LLVMContext.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
class CloneInstruction : public ::testing::Test {
protected:
virtual void SetUp() {
V = nullptr;
}
template <typename T>
T *clone(T *V1) {
Value *V2 = V1->clone();
Orig.insert(V1);
Clones.insert(V2);
return cast<T>(V2);
}
void eraseClones() {
DeleteContainerPointers(Clones);
}
virtual void TearDown() {
eraseClones();
DeleteContainerPointers(Orig);
delete V;
}
SmallPtrSet<Value *, 4> Orig; // Erase on exit
SmallPtrSet<Value *, 4> Clones; // Erase in eraseClones
LLVMContext context;
Value *V;
};
TEST_F(CloneInstruction, OverflowBits) {
V = new Argument(Type::getInt32Ty(context));
BinaryOperator *Add = BinaryOperator::Create(Instruction::Add, V, V);
BinaryOperator *Sub = BinaryOperator::Create(Instruction::Sub, V, V);
BinaryOperator *Mul = BinaryOperator::Create(Instruction::Mul, V, V);
BinaryOperator *AddClone = this->clone(Add);
BinaryOperator *SubClone = this->clone(Sub);
BinaryOperator *MulClone = this->clone(Mul);
EXPECT_FALSE(AddClone->hasNoUnsignedWrap());
EXPECT_FALSE(AddClone->hasNoSignedWrap());
EXPECT_FALSE(SubClone->hasNoUnsignedWrap());
EXPECT_FALSE(SubClone->hasNoSignedWrap());
EXPECT_FALSE(MulClone->hasNoUnsignedWrap());
EXPECT_FALSE(MulClone->hasNoSignedWrap());
eraseClones();
Add->setHasNoUnsignedWrap();
Sub->setHasNoUnsignedWrap();
Mul->setHasNoUnsignedWrap();
AddClone = this->clone(Add);
SubClone = this->clone(Sub);
MulClone = this->clone(Mul);
EXPECT_TRUE(AddClone->hasNoUnsignedWrap());
EXPECT_FALSE(AddClone->hasNoSignedWrap());
EXPECT_TRUE(SubClone->hasNoUnsignedWrap());
EXPECT_FALSE(SubClone->hasNoSignedWrap());
EXPECT_TRUE(MulClone->hasNoUnsignedWrap());
EXPECT_FALSE(MulClone->hasNoSignedWrap());
eraseClones();
Add->setHasNoSignedWrap();
Sub->setHasNoSignedWrap();
Mul->setHasNoSignedWrap();
AddClone = this->clone(Add);
SubClone = this->clone(Sub);
MulClone = this->clone(Mul);
EXPECT_TRUE(AddClone->hasNoUnsignedWrap());
EXPECT_TRUE(AddClone->hasNoSignedWrap());
EXPECT_TRUE(SubClone->hasNoUnsignedWrap());
EXPECT_TRUE(SubClone->hasNoSignedWrap());
EXPECT_TRUE(MulClone->hasNoUnsignedWrap());
EXPECT_TRUE(MulClone->hasNoSignedWrap());
eraseClones();
Add->setHasNoUnsignedWrap(false);
Sub->setHasNoUnsignedWrap(false);
Mul->setHasNoUnsignedWrap(false);
AddClone = this->clone(Add);
SubClone = this->clone(Sub);
MulClone = this->clone(Mul);
EXPECT_FALSE(AddClone->hasNoUnsignedWrap());
EXPECT_TRUE(AddClone->hasNoSignedWrap());
EXPECT_FALSE(SubClone->hasNoUnsignedWrap());
EXPECT_TRUE(SubClone->hasNoSignedWrap());
EXPECT_FALSE(MulClone->hasNoUnsignedWrap());
EXPECT_TRUE(MulClone->hasNoSignedWrap());
}
TEST_F(CloneInstruction, Inbounds) {
V = new Argument(Type::getInt32PtrTy(context));
Constant *Z = Constant::getNullValue(Type::getInt32Ty(context));
std::vector<Value *> ops;
ops.push_back(Z);
GetElementPtrInst *GEP = GetElementPtrInst::Create(V, ops);
EXPECT_FALSE(this->clone(GEP)->isInBounds());
GEP->setIsInBounds();
EXPECT_TRUE(this->clone(GEP)->isInBounds());
}
TEST_F(CloneInstruction, Exact) {
V = new Argument(Type::getInt32Ty(context));
BinaryOperator *SDiv = BinaryOperator::Create(Instruction::SDiv, V, V);
EXPECT_FALSE(this->clone(SDiv)->isExact());
SDiv->setIsExact(true);
EXPECT_TRUE(this->clone(SDiv)->isExact());
}
TEST_F(CloneInstruction, Attributes) {
Type *ArgTy1[] = { Type::getInt32PtrTy(context) };
FunctionType *FT1 = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
Function *F1 = Function::Create(FT1, Function::ExternalLinkage);
BasicBlock *BB = BasicBlock::Create(context, "", F1);
IRBuilder<> Builder(BB);
Builder.CreateRetVoid();
Function *F2 = Function::Create(FT1, Function::ExternalLinkage);
Attribute::AttrKind AK[] = { Attribute::NoCapture };
AttributeSet AS = AttributeSet::get(context, 0, AK);
Argument *A = F1->arg_begin();
A->addAttr(AS);
SmallVector<ReturnInst*, 4> Returns;
ValueToValueMapTy VMap;
VMap[A] = UndefValue::get(A->getType());
CloneFunctionInto(F2, F1, VMap, false, Returns);
EXPECT_FALSE(F2->arg_begin()->hasNoCaptureAttr());
delete F1;
delete F2;
}
TEST_F(CloneInstruction, CallingConvention) {
Type *ArgTy1[] = { Type::getInt32PtrTy(context) };
FunctionType *FT1 = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
Function *F1 = Function::Create(FT1, Function::ExternalLinkage);
F1->setCallingConv(CallingConv::Cold);
BasicBlock *BB = BasicBlock::Create(context, "", F1);
IRBuilder<> Builder(BB);
Builder.CreateRetVoid();
Function *F2 = Function::Create(FT1, Function::ExternalLinkage);
SmallVector<ReturnInst*, 4> Returns;
ValueToValueMapTy VMap;
VMap[F1->arg_begin()] = F2->arg_begin();
CloneFunctionInto(F2, F1, VMap, false, Returns);
EXPECT_EQ(CallingConv::Cold, F2->getCallingConv());
delete F1;
delete F2;
}
class CloneFunc : public ::testing::Test {
protected:
virtual void SetUp() {
SetupModule();
CreateOldFunc();
CreateNewFunc();
SetupFinder();
}
virtual void TearDown() {
delete Finder;
}
void SetupModule() {
M = new Module("", C);
}
void CreateOldFunc() {
FunctionType* FuncType = FunctionType::get(Type::getVoidTy(C), false);
OldFunc = Function::Create(FuncType, GlobalValue::PrivateLinkage, "f", M);
CreateOldFunctionBodyAndDI();
}
void CreateOldFunctionBodyAndDI() {
DIBuilder DBuilder(*M);
IRBuilder<> IBuilder(C);
// Function DI
DIFile File = DBuilder.createFile("filename.c", "/file/dir/");
DITypeArray ParamTypes = DBuilder.getOrCreateTypeArray(None);
DICompositeType FuncType = DBuilder.createSubroutineType(File, ParamTypes);
DICompileUnit CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99,
"filename.c", "/file/dir", "CloneFunc", false, "", 0);
DISubprogram Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4,
FuncType, true, true, 3, 0, false, OldFunc);
// Function body
BasicBlock* Entry = BasicBlock::Create(C, "", OldFunc);
IBuilder.SetInsertPoint(Entry);
DebugLoc Loc = DebugLoc::get(3, 2, Subprogram);
IBuilder.SetCurrentDebugLocation(Loc);
AllocaInst* Alloca = IBuilder.CreateAlloca(IntegerType::getInt32Ty(C));
IBuilder.SetCurrentDebugLocation(DebugLoc::get(4, 2, Subprogram));
Value* AllocaContent = IBuilder.getInt32(1);
Instruction* Store = IBuilder.CreateStore(AllocaContent, Alloca);
IBuilder.SetCurrentDebugLocation(DebugLoc::get(5, 2, Subprogram));
Instruction* Terminator = IBuilder.CreateRetVoid();
// Create a local variable around the alloca
DIType IntType = DBuilder.createBasicType("int", 32, 0,
dwarf::DW_ATE_signed);
Move the complex address expression out of DIVariable and into an extra argument of the llvm.dbg.declare/llvm.dbg.value intrinsics. Previously, DIVariable was a variable-length field that has an optional reference to a Metadata array consisting of a variable number of complex address expressions. In the case of OpPiece expressions this is wasting a lot of storage in IR, because when an aggregate type is, e.g., SROA'd into all of its n individual members, the IR will contain n copies of the DIVariable, all alike, only differing in the complex address reference at the end. By making the complex address into an extra argument of the dbg.value/dbg.declare intrinsics, all of the pieces can reference the same variable and the complex address expressions can be uniqued across the CU, too. Down the road, this will allow us to move other flags, such as "indirection" out of the DIVariable, too. The new intrinsics look like this: declare void @llvm.dbg.declare(metadata %storage, metadata %var, metadata %expr) declare void @llvm.dbg.value(metadata %storage, i64 %offset, metadata %var, metadata %expr) This patch adds a new LLVM-local tag to DIExpressions, so we can detect and pretty-print DIExpression metadata nodes. What this patch doesn't do: This patch does not touch the "Indirect" field in DIVariable; but moving that into the expression would be a natural next step. http://reviews.llvm.org/D4919 rdar://problem/17994491 Thanks to dblaikie and dexonsmith for reviewing this patch! Note: I accidentally committed a bogus older version of this patch previously. llvm-svn: 218787
2014-10-01 20:55:02 +02:00
DIExpression E = DBuilder.createExpression();
DIVariable Variable = DBuilder.createLocalVariable(
dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, true);
Move the complex address expression out of DIVariable and into an extra argument of the llvm.dbg.declare/llvm.dbg.value intrinsics. Previously, DIVariable was a variable-length field that has an optional reference to a Metadata array consisting of a variable number of complex address expressions. In the case of OpPiece expressions this is wasting a lot of storage in IR, because when an aggregate type is, e.g., SROA'd into all of its n individual members, the IR will contain n copies of the DIVariable, all alike, only differing in the complex address reference at the end. By making the complex address into an extra argument of the dbg.value/dbg.declare intrinsics, all of the pieces can reference the same variable and the complex address expressions can be uniqued across the CU, too. Down the road, this will allow us to move other flags, such as "indirection" out of the DIVariable, too. The new intrinsics look like this: declare void @llvm.dbg.declare(metadata %storage, metadata %var, metadata %expr) declare void @llvm.dbg.value(metadata %storage, i64 %offset, metadata %var, metadata %expr) This patch adds a new LLVM-local tag to DIExpressions, so we can detect and pretty-print DIExpression metadata nodes. What this patch doesn't do: This patch does not touch the "Indirect" field in DIVariable; but moving that into the expression would be a natural next step. http://reviews.llvm.org/D4919 rdar://problem/17994491 Thanks to dblaikie and dexonsmith for reviewing this patch! Note: I accidentally committed a bogus older version of this patch previously. llvm-svn: 218787
2014-10-01 20:55:02 +02:00
DBuilder.insertDeclare(Alloca, Variable, E, Store);
DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, Terminator);
// Finalize the debug info
DBuilder.finalize();
// Create another, empty, compile unit
DIBuilder DBuilder2(*M);
DBuilder2.createCompileUnit(dwarf::DW_LANG_C99,
"extra.c", "/file/dir", "CloneFunc", false, "", 0);
DBuilder2.finalize();
}
void CreateNewFunc() {
ValueToValueMapTy VMap;
NewFunc = CloneFunction(OldFunc, VMap, true, nullptr);
M->getFunctionList().push_back(NewFunc);
}
void SetupFinder() {
Finder = new DebugInfoFinder();
Finder->processModule(*M);
}
LLVMContext C;
Function* OldFunc;
Function* NewFunc;
Module* M;
DebugInfoFinder* Finder;
};
// Test that a new, distinct function was created.
TEST_F(CloneFunc, NewFunctionCreated) {
EXPECT_NE(OldFunc, NewFunc);
}
// Test that a new subprogram entry was added and is pointing to the new
// function, while the original subprogram still points to the old one.
TEST_F(CloneFunc, Subprogram) {
unsigned SubprogramCount = Finder->subprogram_count();
EXPECT_EQ(2U, SubprogramCount);
auto Iter = Finder->subprograms().begin();
DISubprogram Sub1(*Iter);
EXPECT_TRUE(Sub1.Verify());
Iter++;
DISubprogram Sub2(*Iter);
EXPECT_TRUE(Sub2.Verify());
EXPECT_TRUE((Sub1.getFunction() == OldFunc && Sub2.getFunction() == NewFunc)
|| (Sub1.getFunction() == NewFunc && Sub2.getFunction() == OldFunc));
}
// Test that the new subprogram entry was not added to the CU which doesn't
// contain the old subprogram entry.
TEST_F(CloneFunc, SubprogramInRightCU) {
EXPECT_EQ(2U, Finder->compile_unit_count());
auto Iter = Finder->compile_units().begin();
DICompileUnit CU1(*Iter);
EXPECT_TRUE(CU1.Verify());
Iter++;
DICompileUnit CU2(*Iter);
EXPECT_TRUE(CU2.Verify());
EXPECT_TRUE(CU1.getSubprograms().getNumElements() == 0
|| CU2.getSubprograms().getNumElements() == 0);
}
// Test that instructions in the old function still belong to it in the
// metadata, while instruction in the new function belong to the new one.
TEST_F(CloneFunc, InstructionOwnership) {
inst_iterator OldIter = inst_begin(OldFunc);
inst_iterator OldEnd = inst_end(OldFunc);
inst_iterator NewIter = inst_begin(NewFunc);
inst_iterator NewEnd = inst_end(NewFunc);
while (OldIter != OldEnd && NewIter != NewEnd) {
Instruction& OldI = *OldIter;
Instruction& NewI = *NewIter;
EXPECT_NE(&OldI, &NewI);
EXPECT_EQ(OldI.hasMetadata(), NewI.hasMetadata());
if (OldI.hasMetadata()) {
const DebugLoc& OldDL = OldI.getDebugLoc();
const DebugLoc& NewDL = NewI.getDebugLoc();
// Verify that the debug location data is the same
EXPECT_EQ(OldDL.getLine(), NewDL.getLine());
EXPECT_EQ(OldDL.getCol(), NewDL.getCol());
// But that they belong to different functions
DISubprogram OldSubprogram(OldDL.getScope(C));
DISubprogram NewSubprogram(NewDL.getScope(C));
EXPECT_TRUE(OldSubprogram.Verify());
EXPECT_TRUE(NewSubprogram.Verify());
EXPECT_EQ(OldFunc, OldSubprogram.getFunction());
EXPECT_EQ(NewFunc, NewSubprogram.getFunction());
}
++OldIter;
++NewIter;
}
EXPECT_EQ(OldEnd, OldIter);
EXPECT_EQ(NewEnd, NewIter);
}
// Test that the arguments for debug intrinsics in the new function were
// properly cloned
TEST_F(CloneFunc, DebugIntrinsics) {
inst_iterator OldIter = inst_begin(OldFunc);
inst_iterator OldEnd = inst_end(OldFunc);
inst_iterator NewIter = inst_begin(NewFunc);
inst_iterator NewEnd = inst_end(NewFunc);
while (OldIter != OldEnd && NewIter != NewEnd) {
Instruction& OldI = *OldIter;
Instruction& NewI = *NewIter;
if (DbgDeclareInst* OldIntrin = dyn_cast<DbgDeclareInst>(&OldI)) {
DbgDeclareInst* NewIntrin = dyn_cast<DbgDeclareInst>(&NewI);
EXPECT_TRUE(NewIntrin);
// Old address must belong to the old function
EXPECT_EQ(OldFunc, cast<AllocaInst>(OldIntrin->getAddress())->
getParent()->getParent());
// New address must belong to the new function
EXPECT_EQ(NewFunc, cast<AllocaInst>(NewIntrin->getAddress())->
getParent()->getParent());
// Old variable must belong to the old function
EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable())
.getContext()).getFunction());
// New variable must belong to the New function
EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable())
.getContext()).getFunction());
} else if (DbgValueInst* OldIntrin = dyn_cast<DbgValueInst>(&OldI)) {
DbgValueInst* NewIntrin = dyn_cast<DbgValueInst>(&NewI);
EXPECT_TRUE(NewIntrin);
// Old variable must belong to the old function
EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable())
.getContext()).getFunction());
// New variable must belong to the New function
EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable())
.getContext()).getFunction());
}
++OldIter;
++NewIter;
}
}
}