Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -1658,11 +1658,26 @@ Intrinsic::ID ID = F->getIntrinsicID(); StringRef Name = F->getName(); - if (Name == - Intrinsic::getName(ID, ArgTys, F->getParent(), F->getFunctionType())) + std::string WantedName = + Intrinsic::getName(ID, ArgTys, F->getParent(), F->getFunctionType()); + if (Name == WantedName) return None; - auto NewDecl = Intrinsic::getDeclaration(F->getParent(), ID, ArgTys); + GlobalValue *ExistingF = F->getParent()->getNamedValue(WantedName); + + Function *NewDecl = nullptr; + if (ExistingF) { + if (cast(ExistingF)->getFunctionType() == F->getFunctionType()) { + NewDecl = cast(ExistingF); + } else { + // The name already exists, but has the wrong prototype. Make place for + // the new one by renaming the old version. + ExistingF->setName(Name + ".renamed"); + } + } + + if (!NewDecl) + NewDecl = Intrinsic::getDeclaration(F->getParent(), ID, ArgTys); NewDecl->setCallingConv(F->getCallingConv()); assert(NewDecl->getFunctionType() == F->getFunctionType() && "Shouldn't change the signature"); Index: llvm/test/tools/llvm-link/Inputs/remangle1.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/Inputs/remangle1.ll @@ -0,0 +1,10 @@ +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%aaa = type <{ %aab, i32, [4 x i8] }> +%aab = type { i64 } +%fum = type { %aac, i8, [7 x i8] } +%aac = type { [8 x i8] } + +declare void @bar01(%aaa*) +declare void @bar02(%fum*) Index: llvm/test/tools/llvm-link/Inputs/remangle2.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/Inputs/remangle2.ll @@ -0,0 +1,27 @@ +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%fum = type { %aab, i8, [7 x i8] } +%aab = type { %aba } +%aba = type { [8 x i8] } +%fum.1 = type { %abb, i8, [7 x i8] } +%abb = type { %abc } +%abc = type { [4 x i8] } + +declare void @foo(%fum*) + +declare %fum.1** @"llvm.ssa.copy.p0p0s_fum.1s"(%fum.1**) + +declare %fum** @"llvm.ssa.copy.p0p0s_fums"(%fum**) + +define void @foo1(%fum** %a, %fum.1 ** %b) { + %b.copy = call %fum.1** @"llvm.ssa.copy.p0p0s_fum.1s"(%fum.1** %b) + %a.copy = call %fum** @"llvm.ssa.copy.p0p0s_fums"(%fum** %a) + ret void +} + +define void @foo2(%fum.1 ** %b, %fum** %a) { + %a.copy = call %fum** @"llvm.ssa.copy.p0p0s_fums"(%fum** %a) + %b.copy = call %fum.1** @"llvm.ssa.copy.p0p0s_fum.1s"(%fum.1** %b) + ret void +} Index: llvm/test/tools/llvm-link/remangle.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-link/remangle.ll @@ -0,0 +1,27 @@ +# RUN: llvm-as %S/Inputs/remangle1.ll -o %t.remangle1.bc +# RUN: llvm-as %S/Inputs/remangle2.ll -o %t.remangle2.bc +# RUN: llvm-link %t.remangle1.bc %t.remangle2.bc -o %t.remangle.linked.bc +# RUN: llvm-dis %t.remangle.linked.bc -o - | FileCheck %s + +; CHECK-DAG: %fum.1 = type { %aab.0, i8, [7 x i8] } +; CHECK-DAG: %aab.0 = type { %aba } +; CHECK-DAG: %aba = type { [8 x i8] } +; CHECK-DAG: %fum.1.2 = type { %abb, i8, [7 x i8] } +; CHECK-DAG: %abb = type { %abc } +; CHECK-DAG: %abc = type { [4 x i8] } + +; CHECK-LABEL: define void @foo1(%fum.1** %a, %fum.1.2** %b) { +; CHECK-NEXT: %b.copy = call %fum.1.2** @llvm.ssa.copy.p0p0s_fum.1.2s(%fum.1.2** %b) +; CHECK-NEXT: %a.copy = call %fum.1** @llvm.ssa.copy.p0p0s_fum.1s(%fum.1** %a) +; CHECK-NEXT: ret void + +; CHECK: declare %fum.1.2** @llvm.ssa.copy.p0p0s_fum.1.2s(%fum.1.2** returned) + +; CHECK: declare %fum.1** @llvm.ssa.copy.p0p0s_fum.1s(%fum.1** returned) + +; CHECK-LABEL: define void @foo2(%fum.1.2** %b, %fum.1** %a) { +; CHECK-NEXT: %a.copy = call %fum.1** @llvm.ssa.copy.p0p0s_fum.1s(%fum.1** %a) +; CHECK-NEXT: %b.copy = call %fum.1.2** @llvm.ssa.copy.p0p0s_fum.1.2s(%fum.1.2** %b) +; CHECK-NEXT: ret void + +