summaryrefslogtreecommitdiff
path: root/unittests/Linker/LinkModulesTest.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
commitdd58ef019b700900793a1eb48b52123db01b654e (patch)
treefcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /unittests/Linker/LinkModulesTest.cpp
parent2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff)
Notes
Diffstat (limited to 'unittests/Linker/LinkModulesTest.cpp')
-rw-r--r--unittests/Linker/LinkModulesTest.cpp127
1 files changed, 119 insertions, 8 deletions
diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp
index 45f1308d3bd9..322a44f8aafe 100644
--- a/unittests/Linker/LinkModulesTest.cpp
+++ b/unittests/Linker/LinkModulesTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
@@ -15,6 +16,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm-c/Core.h"
#include "llvm-c/Linker.h"
#include "gtest/gtest.h"
@@ -70,12 +72,16 @@ protected:
BasicBlock *ExitBB;
};
+static void expectNoDiags(const DiagnosticInfo &DI, void *C) {
+ EXPECT_TRUE(false);
+}
+
TEST_F(LinkModuleTest, BlockAddress) {
IRBuilder<> Builder(EntryBB);
std::vector<Value *> GEPIndices;
GEPIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0));
- GEPIndices.push_back(F->arg_begin());
+ GEPIndices.push_back(&*F->arg_begin());
Value *GEP = Builder.CreateGEP(AT, GV, GEPIndices, "switch.gep");
Value *Load = Builder.CreateLoad(GEP, "switch.load");
@@ -92,10 +98,8 @@ TEST_F(LinkModuleTest, BlockAddress) {
Builder.CreateRet(ConstantPointerNull::get(Type::getInt8PtrTy(Ctx)));
Module *LinkedModule = new Module("MyModuleLinked", Ctx);
- Linker::LinkModules(LinkedModule, M.get());
-
- // Delete the original module.
- M.reset();
+ Ctx.setDiagnosticHandler(expectNoDiags);
+ Linker::linkModules(*LinkedModule, std::move(M));
// Check that the global "@switch.bas" is well-formed.
const GlobalVariable *LinkedGV = LinkedModule->getNamedGlobal("switch.bas");
@@ -168,13 +172,15 @@ static Module *getInternal(LLVMContext &Ctx) {
TEST_F(LinkModuleTest, EmptyModule) {
std::unique_ptr<Module> InternalM(getInternal(Ctx));
std::unique_ptr<Module> EmptyM(new Module("EmptyModule1", Ctx));
- Linker::LinkModules(EmptyM.get(), InternalM.get());
+ Ctx.setDiagnosticHandler(expectNoDiags);
+ Linker::linkModules(*EmptyM, std::move(InternalM));
}
TEST_F(LinkModuleTest, EmptyModule2) {
std::unique_ptr<Module> InternalM(getInternal(Ctx));
std::unique_ptr<Module> EmptyM(new Module("EmptyModule1", Ctx));
- Linker::LinkModules(InternalM.get(), EmptyM.get());
+ Ctx.setDiagnosticHandler(expectNoDiags);
+ Linker::linkModules(*InternalM, std::move(EmptyM));
}
TEST_F(LinkModuleTest, TypeMerge) {
@@ -189,7 +195,8 @@ TEST_F(LinkModuleTest, TypeMerge) {
"@t2 = weak global %t zeroinitializer\n";
std::unique_ptr<Module> M2 = parseAssemblyString(M2Str, Err, C);
- Linker::LinkModules(M1.get(), M2.get(), [](const llvm::DiagnosticInfo &){});
+ Ctx.setDiagnosticHandler(expectNoDiags);
+ Linker::linkModules(*M1, std::move(M2));
EXPECT_EQ(M1->getNamedGlobal("t1")->getType(),
M1->getNamedGlobal("t2")->getType());
@@ -219,4 +226,108 @@ TEST_F(LinkModuleTest, CAPIFailure) {
LLVMDisposeMessage(errout);
}
+TEST_F(LinkModuleTest, NewCAPISuccess) {
+ std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));
+ std::unique_ptr<Module> SourceM(getExternal(Ctx, "bar"));
+ LLVMBool Result =
+ LLVMLinkModules2(wrap(DestM.get()), wrap(SourceM.release()));
+ EXPECT_EQ(0, Result);
+ // "bar" is present in destination module
+ EXPECT_NE(nullptr, DestM->getFunction("bar"));
+}
+
+static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {
+ auto *Err = reinterpret_cast<std::string *>(C);
+ char *CErr = LLVMGetDiagInfoDescription(DI);
+ *Err = CErr;
+ LLVMDisposeMessage(CErr);
+}
+
+TEST_F(LinkModuleTest, NewCAPIFailure) {
+ // Symbol clash between two modules
+ LLVMContext Ctx;
+ std::string Err;
+ LLVMContextSetDiagnosticHandler(wrap(&Ctx), diagnosticHandler, &Err);
+
+ std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));
+ std::unique_ptr<Module> SourceM(getExternal(Ctx, "foo"));
+ LLVMBool Result =
+ LLVMLinkModules2(wrap(DestM.get()), wrap(SourceM.release()));
+ EXPECT_EQ(1, Result);
+ EXPECT_EQ("Linking globals named 'foo': symbol multiply defined!", Err);
+}
+
+TEST_F(LinkModuleTest, MoveDistinctMDs) {
+ LLVMContext C;
+ SMDiagnostic Err;
+
+ const char *SrcStr = "define void @foo() !attach !0 {\n"
+ "entry:\n"
+ " call void @llvm.md(metadata !1)\n"
+ " ret void, !attach !2\n"
+ "}\n"
+ "declare void @llvm.md(metadata)\n"
+ "!named = !{!3, !4}\n"
+ "!0 = distinct !{}\n"
+ "!1 = distinct !{}\n"
+ "!2 = distinct !{}\n"
+ "!3 = distinct !{}\n"
+ "!4 = !{!3}\n";
+
+ std::unique_ptr<Module> Src = parseAssemblyString(SrcStr, Err, C);
+ assert(Src);
+ ASSERT_TRUE(Src.get());
+
+ // Get the addresses of the Metadata before merging.
+ Function *F = &*Src->begin();
+ ASSERT_EQ("foo", F->getName());
+ BasicBlock *BB = &F->getEntryBlock();
+ auto *CI = cast<CallInst>(&BB->front());
+ auto *RI = cast<ReturnInst>(BB->getTerminator());
+ NamedMDNode *NMD = &*Src->named_metadata_begin();
+
+ MDNode *M0 = F->getMetadata("attach");
+ MDNode *M1 =
+ cast<MDNode>(cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());
+ MDNode *M2 = RI->getMetadata("attach");
+ MDNode *M3 = NMD->getOperand(0);
+ MDNode *M4 = NMD->getOperand(1);
+
+ // Confirm a few things about the IR.
+ EXPECT_TRUE(M0->isDistinct());
+ EXPECT_TRUE(M1->isDistinct());
+ EXPECT_TRUE(M2->isDistinct());
+ EXPECT_TRUE(M3->isDistinct());
+ EXPECT_TRUE(M4->isUniqued());
+ EXPECT_EQ(M3, M4->getOperand(0));
+
+ // Link into destination module.
+ auto Dst = llvm::make_unique<Module>("Linked", C);
+ ASSERT_TRUE(Dst.get());
+ Ctx.setDiagnosticHandler(expectNoDiags);
+ Linker::linkModules(*Dst, std::move(Src));
+
+ // Check that distinct metadata was moved, not cloned. Even !4, the uniqued
+ // node, should effectively be moved, since its only operand hasn't changed.
+ F = &*Dst->begin();
+ BB = &F->getEntryBlock();
+ CI = cast<CallInst>(&BB->front());
+ RI = cast<ReturnInst>(BB->getTerminator());
+ NMD = &*Dst->named_metadata_begin();
+
+ EXPECT_EQ(M0, F->getMetadata("attach"));
+ EXPECT_EQ(M1, cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());
+ EXPECT_EQ(M2, RI->getMetadata("attach"));
+ EXPECT_EQ(M3, NMD->getOperand(0));
+ EXPECT_EQ(M4, NMD->getOperand(1));
+
+ // Confirm a few things about the IR. This shouldn't have changed.
+ EXPECT_TRUE(M0->isDistinct());
+ EXPECT_TRUE(M1->isDistinct());
+ EXPECT_TRUE(M2->isDistinct());
+ EXPECT_TRUE(M3->isDistinct());
+ EXPECT_TRUE(M4->isUniqued());
+ EXPECT_EQ(M3, M4->getOperand(0));
+}
+
} // end anonymous namespace