brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · c98cdc2 Raw
365 lines · cpp
1//===- llvm/unittest/Linker/LinkModulesTest.cpp - IRBuilder tests ---------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm-c/Core.h"10#include "llvm-c/Linker.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/IR/BasicBlock.h"14#include "llvm/IR/DataLayout.h"15#include "llvm/IR/Function.h"16#include "llvm/IR/IRBuilder.h"17#include "llvm/IR/Module.h"18#include "llvm/Linker/Linker.h"19#include "llvm/Support/SourceMgr.h"20#include "gtest/gtest.h"21 22using namespace llvm;23 24namespace {25 26class LinkModuleTest : public testing::Test {27protected:28  void SetUp() override {29    M.reset(new Module("MyModule", Ctx));30    FunctionType *FTy =31        FunctionType::get(PointerType::getUnqual(Ctx), Type::getInt32Ty(Ctx),32                          false /*=isVarArg*/);33    F = Function::Create(FTy, Function::ExternalLinkage, "ba_func", M.get());34    F->setCallingConv(CallingConv::C);35 36    EntryBB = BasicBlock::Create(Ctx, "entry", F);37    SwitchCase1BB = BasicBlock::Create(Ctx, "switch.case.1", F);38    SwitchCase2BB = BasicBlock::Create(Ctx, "switch.case.2", F);39    ExitBB = BasicBlock::Create(Ctx, "exit", F);40 41    AT = ArrayType::get(PointerType::getUnqual(Ctx), 3);42 43    GV =44        new GlobalVariable(*M, AT, false /*=isConstant*/,45                           GlobalValue::InternalLinkage, nullptr, "switch.bas");46 47    // Global Initializer48    std::vector<Constant *> Init;49    Constant *SwitchCase1BA = BlockAddress::get(SwitchCase1BB);50    Init.push_back(SwitchCase1BA);51 52    Constant *SwitchCase2BA = BlockAddress::get(SwitchCase2BB);53    Init.push_back(SwitchCase2BA);54 55    ConstantInt *One = ConstantInt::get(Type::getInt32Ty(Ctx), 1);56    Constant *OnePtr =57        ConstantExpr::getIntToPtr(One, PointerType::getUnqual(Ctx));58    Init.push_back(OnePtr);59 60    GV->setInitializer(ConstantArray::get(AT, Init));61  }62 63  void TearDown() override { M.reset(); }64 65  LLVMContext Ctx;66  std::unique_ptr<Module> M;67  Function *F;68  ArrayType *AT;69  GlobalVariable *GV;70  BasicBlock *EntryBB;71  BasicBlock *SwitchCase1BB;72  BasicBlock *SwitchCase2BB;73  BasicBlock *ExitBB;74};75 76static void expectNoDiags(const DiagnosticInfo *DI, void *C) {77  llvm_unreachable("expectNoDiags called!");78}79 80TEST_F(LinkModuleTest, BlockAddress) {81  IRBuilder<> Builder(EntryBB);82 83  std::vector<Value *> GEPIndices;84  GEPIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0));85  GEPIndices.push_back(&*F->arg_begin());86 87  Value *GEP = Builder.CreateGEP(AT, GV, GEPIndices, "switch.gep");88  Value *Load = Builder.CreateLoad(AT->getElementType(), GEP, "switch.load");89 90  Builder.CreateRet(Load);91 92  Builder.SetInsertPoint(SwitchCase1BB);93  Builder.CreateBr(ExitBB);94 95  Builder.SetInsertPoint(SwitchCase2BB);96  Builder.CreateBr(ExitBB);97 98  Builder.SetInsertPoint(ExitBB);99  Builder.CreateRet(ConstantPointerNull::get(PointerType::getUnqual(Ctx)));100 101  Module *LinkedModule = new Module("MyModuleLinked", Ctx);102  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);103  Linker::linkModules(*LinkedModule, std::move(M));104 105  // Check that the global "@switch.bas" is well-formed.106  const GlobalVariable *LinkedGV = LinkedModule->getNamedGlobal("switch.bas");107  const Constant *Init = LinkedGV->getInitializer();108 109  // @switch.bas = internal global [3 x i8*]110  //   [i8* blockaddress(@ba_func, %switch.case.1),111  //    i8* blockaddress(@ba_func, %switch.case.2),112  //    i8* inttoptr (i32 1 to i8*)]113 114  ArrayType *AT = ArrayType::get(PointerType::getUnqual(Ctx), 3);115  EXPECT_EQ(AT, Init->getType());116 117  Value *Elem = Init->getOperand(0);118  ASSERT_TRUE(isa<BlockAddress>(Elem));119  EXPECT_EQ(cast<BlockAddress>(Elem)->getFunction(),120            LinkedModule->getFunction("ba_func"));121  EXPECT_EQ(cast<BlockAddress>(Elem)->getBasicBlock()->getParent(),122            LinkedModule->getFunction("ba_func"));123 124  Elem = Init->getOperand(1);125  ASSERT_TRUE(isa<BlockAddress>(Elem));126  EXPECT_EQ(cast<BlockAddress>(Elem)->getFunction(),127            LinkedModule->getFunction("ba_func"));128  EXPECT_EQ(cast<BlockAddress>(Elem)->getBasicBlock()->getParent(),129            LinkedModule->getFunction("ba_func"));130 131  delete LinkedModule;132}133 134static Module *getExternal(LLVMContext &Ctx, StringRef FuncName) {135  // Create a module with an empty externally-linked function136  Module *M = new Module("ExternalModule", Ctx);137  FunctionType *FTy = FunctionType::get(138      Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx), false /*=isVarArgs*/);139 140  Function *F =141      Function::Create(FTy, Function::ExternalLinkage, FuncName, M);142  F->setCallingConv(CallingConv::C);143 144  BasicBlock *BB = BasicBlock::Create(Ctx, "", F);145  IRBuilder<> Builder(BB);146  Builder.CreateRetVoid();147  return M;148}149 150static Module *getInternal(LLVMContext &Ctx) {151  Module *InternalM = new Module("InternalModule", Ctx);152  FunctionType *FTy = FunctionType::get(153      Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx), false /*=isVarArgs*/);154 155  Function *F =156      Function::Create(FTy, Function::InternalLinkage, "bar", InternalM);157  F->setCallingConv(CallingConv::C);158 159  BasicBlock *BB = BasicBlock::Create(Ctx, "", F);160  IRBuilder<> Builder(BB);161  Builder.CreateRetVoid();162 163  StructType *STy = StructType::create(Ctx, PointerType::get(Ctx, 0));164 165  GlobalVariable *GV =166      new GlobalVariable(*InternalM, STy, false /*=isConstant*/,167                         GlobalValue::InternalLinkage, nullptr, "g");168 169  GV->setInitializer(ConstantStruct::get(STy, F));170  return InternalM;171}172 173TEST_F(LinkModuleTest, EmptyModule) {174  std::unique_ptr<Module> InternalM(getInternal(Ctx));175  std::unique_ptr<Module> EmptyM(new Module("EmptyModule1", Ctx));176  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);177  Linker::linkModules(*EmptyM, std::move(InternalM));178}179 180TEST_F(LinkModuleTest, EmptyModule2) {181  std::unique_ptr<Module> InternalM(getInternal(Ctx));182  std::unique_ptr<Module> EmptyM(new Module("EmptyModule1", Ctx));183  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);184  Linker::linkModules(*InternalM, std::move(EmptyM));185}186 187TEST_F(LinkModuleTest, TypeMerge) {188  LLVMContext C;189  SMDiagnostic Err;190 191  const char *M1Str = "%t = type {i32}\n"192                      "@t1 = weak global %t zeroinitializer\n";193  std::unique_ptr<Module> M1 = parseAssemblyString(M1Str, Err, C);194 195  const char *M2Str = "%t = type {i32}\n"196                      "@t2 = weak global %t zeroinitializer\n";197  std::unique_ptr<Module> M2 = parseAssemblyString(M2Str, Err, C);198 199  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);200  Linker::linkModules(*M1, std::move(M2));201 202  EXPECT_EQ(M1->getNamedGlobal("t1")->getType(),203            M1->getNamedGlobal("t2")->getType());204}205 206TEST_F(LinkModuleTest, NewCAPISuccess) {207  std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));208  std::unique_ptr<Module> SourceM(getExternal(Ctx, "bar"));209  LLVMBool Result =210      LLVMLinkModules2(wrap(DestM.get()), wrap(SourceM.release()));211  EXPECT_EQ(0, Result);212  // "bar" is present in destination module213  EXPECT_NE(nullptr, DestM->getFunction("bar"));214}215 216static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {217  auto *Err = reinterpret_cast<std::string *>(C);218  char *CErr = LLVMGetDiagInfoDescription(DI);219  *Err = CErr;220  LLVMDisposeMessage(CErr);221}222 223TEST_F(LinkModuleTest, NewCAPIFailure) {224  // Symbol clash between two modules225  LLVMContext Ctx;226  std::string Err;227  LLVMContextSetDiagnosticHandler(wrap(&Ctx), diagnosticHandler, &Err);228 229  std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));230  std::unique_ptr<Module> SourceM(getExternal(Ctx, "foo"));231  LLVMBool Result =232      LLVMLinkModules2(wrap(DestM.get()), wrap(SourceM.release()));233  EXPECT_EQ(1, Result);234  EXPECT_EQ("Linking globals named 'foo': symbol multiply defined!", Err);235}236 237TEST_F(LinkModuleTest, MoveDistinctMDs) {238  LLVMContext C;239  SMDiagnostic Err;240 241  const char *SrcStr = "define void @foo() !attach !0 {\n"242                       "entry:\n"243                       "  call void @llvm.md(metadata !1)\n"244                       "  ret void, !attach !2\n"245                       "}\n"246                       "declare void @llvm.md(metadata)\n"247                       "!named = !{!3, !4}\n"248                       "!0 = distinct !{}\n"249                       "!1 = distinct !{}\n"250                       "!2 = distinct !{}\n"251                       "!3 = distinct !{}\n"252                       "!4 = !{!3}\n";253 254  std::unique_ptr<Module> Src = parseAssemblyString(SrcStr, Err, C);255  assert(Src);256  ASSERT_TRUE(Src.get());257 258  // Get the addresses of the Metadata before merging.259  Function *F = &*Src->begin();260  ASSERT_EQ("foo", F->getName());261  BasicBlock *BB = &F->getEntryBlock();262  auto *CI = cast<CallInst>(&BB->front());263  auto *RI = cast<ReturnInst>(BB->getTerminator());264  NamedMDNode *NMD = &*Src->named_metadata_begin();265 266  MDNode *M0 = F->getMetadata("attach");267  MDNode *M1 =268      cast<MDNode>(cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());269  MDNode *M2 = RI->getMetadata("attach");270  MDNode *M3 = NMD->getOperand(0);271  MDNode *M4 = NMD->getOperand(1);272 273  // Confirm a few things about the IR.274  EXPECT_TRUE(M0->isDistinct());275  EXPECT_TRUE(M1->isDistinct());276  EXPECT_TRUE(M2->isDistinct());277  EXPECT_TRUE(M3->isDistinct());278  EXPECT_TRUE(M4->isUniqued());279  EXPECT_EQ(M3, M4->getOperand(0));280 281  // Link into destination module.282  auto Dst = std::make_unique<Module>("Linked", C);283  ASSERT_TRUE(Dst.get());284  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);285  Linker::linkModules(*Dst, std::move(Src));286 287  // Check that distinct metadata was moved, not cloned.  Even !4, the uniqued288  // node, should effectively be moved, since its only operand hasn't changed.289  F = &*Dst->begin();290  BB = &F->getEntryBlock();291  CI = cast<CallInst>(&BB->front());292  RI = cast<ReturnInst>(BB->getTerminator());293  NMD = &*Dst->named_metadata_begin();294 295  EXPECT_EQ(M0, F->getMetadata("attach"));296  EXPECT_EQ(M1, cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());297  EXPECT_EQ(M2, RI->getMetadata("attach"));298  EXPECT_EQ(M3, NMD->getOperand(0));299  EXPECT_EQ(M4, NMD->getOperand(1));300 301  // Confirm a few things about the IR.  This shouldn't have changed.302  EXPECT_TRUE(M0->isDistinct());303  EXPECT_TRUE(M1->isDistinct());304  EXPECT_TRUE(M2->isDistinct());305  EXPECT_TRUE(M3->isDistinct());306  EXPECT_TRUE(M4->isUniqued());307  EXPECT_EQ(M3, M4->getOperand(0));308}309 310TEST_F(LinkModuleTest, RemangleIntrinsics) {311  LLVMContext C;312  SMDiagnostic Err;313 314  // We load two modules inside the same context C. In both modules there is a315  // "struct.rtx_def" type. In the module loaded the second (Bar) this type will316  // be renamed to "struct.rtx_def.0". Check that the intrinsics which have this317  // type in the signature are properly remangled.318  const char *FooStr =319    "%struct.rtx_def = type { i16 }\n"320    "define void @foo(%struct.rtx_def %a) {\n"321    "  call %struct.rtx_def @llvm.ssa.copy.s_struct.rtx_defs(%struct.rtx_def %a)\n"322    "  ret void\n"323    "}\n"324    "declare %struct.rtx_def @llvm.ssa.copy.s_struct.rtx_defs(%struct.rtx_def)\n";325 326  const char *BarStr =327    "%struct.rtx_def = type { i16 }\n"328    "define void @bar(%struct.rtx_def %a) {\n"329    "  call %struct.rtx_def @llvm.ssa.copy.s_struct.rtx_defs(%struct.rtx_def %a)\n"330    "  ret void\n"331    "}\n"332    "declare %struct.rtx_def @llvm.ssa.copy.s_struct.rtx_defs(%struct.rtx_def)\n";333 334  std::unique_ptr<Module> Foo = parseAssemblyString(FooStr, Err, C);335  assert(Foo);336  ASSERT_TRUE(Foo.get());337  // Foo is loaded first, so the type and the intrinsic have theis original338  // names.339  ASSERT_TRUE(Foo->getFunction("llvm.ssa.copy.s_struct.rtx_defs"));340  ASSERT_FALSE(Foo->getFunction("llvm.ssa.copy.s_struct.rtx_defs.0"));341 342  std::unique_ptr<Module> Bar = parseAssemblyString(BarStr, Err, C);343  assert(Bar);344  ASSERT_TRUE(Bar.get());345  // Bar is loaded after Foo, so the type is renamed to struct.rtx_def.0. Check346  // that the intrinsic is also renamed.347  ASSERT_FALSE(Bar->getFunction("llvm.ssa.copy.s_struct.rtx_defs"));348  ASSERT_TRUE(Bar->getFunction("llvm.ssa.copy.s_struct.rtx_def.0s"));349 350  // Link two modules together.351  auto Dst = std::make_unique<Module>("Linked", C);352  ASSERT_TRUE(Dst.get());353  Ctx.setDiagnosticHandlerCallBack(expectNoDiags);354  bool Failed = Linker::linkModules(*Foo, std::move(Bar));355  ASSERT_FALSE(Failed);356 357  // "struct.rtx_def" from Foo and "struct.rtx_def.0" from Bar are isomorphic358  // types, so they must be uniquified by linker. Check that they use the same359  // intrinsic definition.360  Function *F = Foo->getFunction("llvm.ssa.copy.s_struct.rtx_defs");361  ASSERT_TRUE(F->hasNUses(2));362}363 364} // end anonymous namespace365