Index: llvm/trunk/include/llvm/IR/Intrinsics.h =================================================================== --- llvm/trunk/include/llvm/IR/Intrinsics.h +++ llvm/trunk/include/llvm/IR/Intrinsics.h @@ -18,6 +18,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include namespace llvm { @@ -143,6 +144,10 @@ bool matchIntrinsicType(Type *Ty, ArrayRef &Infos, SmallVectorImpl &ArgTys); + // Checks if the intrinsic name matches with its signature and if not + // returns the declaration with the same signature and remangled name. + llvm::Optional remangleIntrinsicFunction(Function *F); + } // End Intrinsic namespace } // End llvm namespace Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -18,12 +18,14 @@ #include "llvm/AsmParser/SlotMapping.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" @@ -210,6 +212,17 @@ for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ) UpgradeCallsToIntrinsic(&*FI++); // must be post-increment, as we remove + // Some types could be renamed during loading if several modules are + // loaded in the same LLVMContext (LTO scenario). In this case we should + // remangle intrinsics names as well. + for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ) { + Function *F = &*FI++; + if (auto Remangled = Intrinsic::remangleIntrinsicFunction(F)) { + F->replaceAllUsesWith(Remangled.getValue()); + F->eraseFromParent(); + } + } + UpgradeDebugInfo(*M); UpgradeModuleFlags(*M); Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -15,6 +15,7 @@ #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/AutoUpgrade.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -230,8 +231,10 @@ // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. - typedef DenseMap UpgradedIntrinsicMap; - UpgradedIntrinsicMap UpgradedIntrinsics; + typedef DenseMap UpdatedIntrinsicMap; + UpdatedIntrinsicMap UpgradedIntrinsics; + // Intrinsics which were remangled because of types rename + UpdatedIntrinsicMap RemangledIntrinsics; // Map the bitcode's custom MDKind ID to the Module's MDKind ID. DenseMap MDKindMap; @@ -3425,6 +3428,11 @@ Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; + else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) + // Some types could be renamed during loading if several modules are + // loaded in the same LLVMContext (LTO scenario). In this case we should + // remangle intrinsics names as well. + RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. @@ -5601,6 +5609,13 @@ } } + // Update calls to the remangled intrinsics + for (auto &I : RemangledIntrinsics) + for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); + UI != UE;) + // Don't expect any other users than call sites + CallSite(*UI++).setCalledFunction(I.second); + // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = FunctionsWithSPs.lookup(F)) F->setSubprogram(SP); @@ -5654,6 +5669,12 @@ I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); + // Do the same for remangled intrinsics + for (auto &I : RemangledIntrinsics) { + I.first->replaceAllUsesWith(I.second); + I.first->eraseFromParent(); + } + RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); Index: llvm/trunk/lib/IR/Function.cpp =================================================================== --- llvm/trunk/lib/IR/Function.cpp +++ llvm/trunk/lib/IR/Function.cpp @@ -1060,6 +1060,37 @@ llvm_unreachable("unhandled"); } +Optional Intrinsic::remangleIntrinsicFunction(Function *F) { + Intrinsic::ID ID = F->getIntrinsicID(); + if (!ID) + return None; + + // Accumulate an array of overloaded types for the given intrinsic + SmallVector ArgTys; + { + SmallVector Table; + getIntrinsicInfoTableEntries(ID, Table); + ArrayRef TableRef = Table; + FunctionType *FTy = F->getFunctionType(); + + // If we encounter any problems matching the signature with the descriptor + // just give up remangling. It's up to verifier to report the discrepancy. + if (Intrinsic::matchIntrinsicType(FTy->getReturnType(), TableRef, ArgTys)) + return None; + for (auto Ty : FTy->params()) + if (Intrinsic::matchIntrinsicType(Ty, TableRef, ArgTys)) + return None; + } + + StringRef Name = F->getName(); + if (Name == Intrinsic::getName(ID, ArgTys)) + return None; + + auto NewDecl = Intrinsic::getDeclaration(F->getParent(), ID, ArgTys); + NewDecl->setCallingConv(F->getCallingConv()); + return NewDecl; +} + /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it. bool Function::hasAddressTaken(const User* *PutOffender) const { Index: llvm/trunk/lib/Linker/IRMover.cpp =================================================================== --- llvm/trunk/lib/Linker/IRMover.cpp +++ llvm/trunk/lib/Linker/IRMover.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/TypeFinder.h" #include "llvm/Support/Error.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -901,6 +902,14 @@ if (ShouldLink || !ForAlias) forceRenaming(NewGV, SGV->getName()); } + + // Overloaded intrinsics have overloaded types names as part of their + // names. If we renamed overloaded types we should rename the intrinsic + // as well. + if (Function *F = dyn_cast(NewGV)) + if (auto Remangled = Intrinsic::remangleIntrinsicFunction(F)) + NewGV = Remangled.getValue(); + if (ShouldLink || ForAlias) { if (const Comdat *SC = SGV->getComdat()) { if (auto *GO = dyn_cast(NewGV)) { Index: llvm/trunk/test/LTO/X86/Inputs/remangle_intrinsics.ll =================================================================== --- llvm/trunk/test/LTO/X86/Inputs/remangle_intrinsics.ll +++ llvm/trunk/test/LTO/X86/Inputs/remangle_intrinsics.ll @@ -0,0 +1,8 @@ +%struct.rtx_def = type { i16, i16 } + +define void @bar(%struct.rtx_def* %a, i8 %b, i32 %c) { + call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true) + ret void +} + +declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1) Index: llvm/trunk/test/LTO/X86/remangle_intrinsics.ll =================================================================== --- llvm/trunk/test/LTO/X86/remangle_intrinsics.ll +++ llvm/trunk/test/LTO/X86/remangle_intrinsics.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s > %t1 +; RUN: llvm-as < %p/Inputs/remangle_intrinsics.ll > %t2 +; RUN: llvm-lto %t1 %t2 | FileCheck %s + +; We have "struct.rtx_def" type in both modules being LTOed. Both modules use +; an overloaded intrinsic which has this type in its signature/name. When +; modules are loaded one of the types is renamed to "struct.rtx_def.0". +; The intrinsic which uses this type should be remangled/renamed as well. +; If we didn't do that verifier would complain. + +; CHECK: Wrote native object file + +%struct.rtx_def = type { i16 } + +define void @foo(%struct.rtx_def* %a, i8 %b, i32 %c) { + call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true) + ret void +} + +declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1) Index: llvm/trunk/unittests/Linker/LinkModulesTest.cpp =================================================================== --- llvm/trunk/unittests/Linker/LinkModulesTest.cpp +++ llvm/trunk/unittests/Linker/LinkModulesTest.cpp @@ -306,4 +306,58 @@ EXPECT_EQ(M3, M4->getOperand(0)); } +TEST_F(LinkModuleTest, RemangleIntrinsics) { + LLVMContext C; + SMDiagnostic Err; + + // We load two modules inside the same context C. In both modules there is a + // "struct.rtx_def" type. In the module loaded the second (Bar) this type will + // be renamed to "struct.rtx_def.0". Check that the intrinsics which have this + // type in the signature are properly remangled. + const char *FooStr = + "%struct.rtx_def = type { i16 }\n" + "define void @foo(%struct.rtx_def* %a, i8 %b, i32 %c) {\n" + " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n" + " ret void\n" + "}\n" + "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n"; + + const char *BarStr = + "%struct.rtx_def = type { i16 }\n" + "define void @bar(%struct.rtx_def* %a, i8 %b, i32 %c) {\n" + " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n" + " ret void\n" + "}\n" + "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n"; + + std::unique_ptr Foo = parseAssemblyString(FooStr, Err, C); + assert(Foo); + ASSERT_TRUE(Foo.get()); + // Foo is loaded first, so the type and the intrinsic have theis original + // names. + ASSERT_TRUE(Foo->getFunction("llvm.memset.p0struct.rtx_def.i32")); + ASSERT_FALSE(Foo->getFunction("llvm.memset.p0struct.rtx_def.0.i32")); + + std::unique_ptr Bar = parseAssemblyString(BarStr, Err, C); + assert(Bar); + ASSERT_TRUE(Bar.get()); + // Bar is loaded after Foo, so the type is renamed to struct.rtx_def.0. Check + // that the intrinsic is also renamed. + ASSERT_FALSE(Bar->getFunction("llvm.memset.p0struct.rtx_def.i32")); + ASSERT_TRUE(Bar->getFunction("llvm.memset.p0struct.rtx_def.0.i32")); + + // Link two modules together. + auto Dst = llvm::make_unique("Linked", C); + ASSERT_TRUE(Dst.get()); + Ctx.setDiagnosticHandler(expectNoDiags); + bool Failed = Linker::linkModules(*Foo, std::move(Bar)); + ASSERT_FALSE(Failed); + + // "struct.rtx_def" from Foo and "struct.rtx_def.0" from Bar are isomorphic + // types, so they must be uniquified by linker. Check that they use the same + // intrinsic definition. + Function *F = Foo->getFunction("llvm.memset.p0struct.rtx_def.i32"); + ASSERT_EQ(F->getNumUses(), (unsigned)2); +} + } // end anonymous namespace