Link symbols with different visibilities according to the rules in the

System V Application Binary Interface. This lets us use
-fvisibility-inlines-hidden with LTO.
Fixes PR11697.

llvm-svn: 147624
This commit is contained in:
Rafael Espindola 2012-01-05 23:02:01 +00:00
parent 5267211899
commit 23f8d64b58
3 changed files with 127 additions and 24 deletions

View File

@ -17,6 +17,7 @@
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Transforms/Utils/Cloning.h"
@ -379,7 +380,9 @@ namespace {
/// getLinkageResult - This analyzes the two global values and determines
/// what the result will look like in the destination module.
bool getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
GlobalValue::LinkageTypes &LT, bool &LinkFromSrc);
GlobalValue::LinkageTypes &LT,
GlobalValue::VisibilityTypes &Vis,
bool &LinkFromSrc);
/// getLinkedToGlobal - Given a global in the source module, return the
/// global in the destination module that is being linked to, if any.
@ -451,15 +454,27 @@ static void CopyGVAttributes(GlobalValue *DestGV, const GlobalValue *SrcGV) {
forceRenaming(DestGV, SrcGV->getName());
}
static bool isLessConstraining(GlobalValue::VisibilityTypes a,
GlobalValue::VisibilityTypes b) {
if (a == GlobalValue::HiddenVisibility)
return false;
if (b == GlobalValue::HiddenVisibility)
return true;
if (a == GlobalValue::ProtectedVisibility)
return false;
if (b == GlobalValue::ProtectedVisibility)
return true;
return false;
}
/// getLinkageResult - This analyzes the two global values and determines what
/// the result will look like in the destination module. In particular, it
/// computes the resultant linkage type, computes whether the global in the
/// source should be copied over to the destination (replacing the existing
/// one), and computes whether this linkage is an error or not. It also performs
/// visibility checks: we cannot link together two symbols with different
/// visibilities.
/// computes the resultant linkage type and visibility, computes whether the
/// global in the source should be copied over to the destination (replacing
/// the existing one), and computes whether this linkage is an error or not.
bool ModuleLinker::getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
GlobalValue::LinkageTypes &LT,
GlobalValue::LinkageTypes &LT,
GlobalValue::VisibilityTypes &Vis,
bool &LinkFromSrc) {
assert(Dest && "Must have two globals being queried");
assert(!Src->hasLocalLinkage() &&
@ -521,13 +536,10 @@ bool ModuleLinker::getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
"': symbol multiply defined!");
}
// Check visibility
if (Src->getVisibility() != Dest->getVisibility() &&
!SrcIsDeclaration && !DestIsDeclaration &&
!Src->hasAvailableExternallyLinkage() &&
!Dest->hasAvailableExternallyLinkage())
return emitError("Linking globals named '" + Src->getName() +
"': symbols have different visibilities!");
// Compute the visibility. We follow the rules in the System V Application
// Binary Interface.
Vis = isLessConstraining(Src->getVisibility(), Dest->getVisibility()) ?
Dest->getVisibility() : Src->getVisibility();
return false;
}
@ -665,6 +677,7 @@ bool ModuleLinker::linkAppendingVarProto(GlobalVariable *DstGV,
/// merge them into the dest module.
bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
GlobalValue *DGV = getLinkedToGlobal(SGV);
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
if (DGV) {
// Concatenation of appending linkage variables is magic and handled later.
@ -674,9 +687,11 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
// Determine whether linkage of these two globals follows the source
// module's definition or the destination module's definition.
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
bool LinkFromSrc = false;
if (getLinkageResult(DGV, SGV, NewLinkage, LinkFromSrc))
if (getLinkageResult(DGV, SGV, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
// If we're not linking from the source, then keep the definition that we
// have.
@ -686,9 +701,10 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
if (DGVar->isDeclaration() && SGV->isConstant() && !DGVar->isConstant())
DGVar->setConstant(true);
// Set calculated linkage.
// Set calculated linkage and visibility.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
// Make sure to remember this mapping.
ValueMap[SGV] = ConstantExpr::getBitCast(DGV,TypeMap.get(SGV->getType()));
@ -711,6 +727,8 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
SGV->getType()->getAddressSpace());
// Propagate alignment, visibility and section info.
CopyGVAttributes(NewDGV, SGV);
if (NewVisibility)
NewDGV->setVisibility(*NewVisibility);
if (DGV) {
DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDGV, DGV->getType()));
@ -726,17 +744,21 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
/// destination module if needed, setting up mapping information.
bool ModuleLinker::linkFunctionProto(Function *SF) {
GlobalValue *DGV = getLinkedToGlobal(SF);
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
if (DGV) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
bool LinkFromSrc = false;
if (getLinkageResult(DGV, SF, NewLinkage, LinkFromSrc))
GlobalValue::VisibilityTypes NV;
if (getLinkageResult(DGV, SF, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
if (!LinkFromSrc) {
// Set calculated linkage
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
// Make sure to remember this mapping.
ValueMap[SF] = ConstantExpr::getBitCast(DGV, TypeMap.get(SF->getType()));
@ -753,6 +775,8 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
Function *NewDF = Function::Create(TypeMap.get(SF->getFunctionType()),
SF->getLinkage(), SF->getName(), DstM);
CopyGVAttributes(NewDF, SF);
if (NewVisibility)
NewDF->setVisibility(*NewVisibility);
if (DGV) {
// Any uses of DF need to change to NewDF, with cast.
@ -775,17 +799,21 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
/// source module.
bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
GlobalValue *DGV = getLinkedToGlobal(SGA);
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
if (DGV) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
bool LinkFromSrc = false;
if (getLinkageResult(DGV, SGA, NewLinkage, LinkFromSrc))
if (getLinkageResult(DGV, SGA, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
if (!LinkFromSrc) {
// Set calculated linkage.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
// Make sure to remember this mapping.
ValueMap[SGA] = ConstantExpr::getBitCast(DGV,TypeMap.get(SGA->getType()));
@ -802,6 +830,8 @@ bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
SGA->getLinkage(), SGA->getName(),
/*aliasee*/0, DstM);
CopyGVAttributes(NewDA, SGA);
if (NewVisibility)
NewDA->setVisibility(*NewVisibility);
if (DGV) {
// Any uses of DGV need to change to NewDA, with cast.

View File

@ -0,0 +1,46 @@
; RUN: llvm-link %s %p/visibility2.ll -S | FileCheck %s
; RUN: llvm-link %p/visibility2.ll %s -S | FileCheck %s
; The values in this file are strong, the ones in visibility2.ll are weak,
; but we should still get the visibility from them.
; Variables
; CHECK: @v1 = hidden global i32 0
@v1 = global i32 0
; CHECK: @v2 = protected global i32 0
@v2 = global i32 0
; CHECK: @v3 = hidden global i32 0
@v3 = protected global i32 0
; Aliases
; CHECK: @a1 = hidden alias i32* @v1
@a1 = alias i32* @v1
; CHECK: @a2 = protected alias i32* @v2
@a2 = alias i32* @v2
; CHECK: @a3 = hidden alias i32* @v3
@a3 = protected alias i32* @v3
; Functions
; CHECK: define hidden void @f1()
define void @f1() {
entry:
ret void
}
; CHECK: define protected void @f2()
define void @f2() {
entry:
ret void
}
; CHECK: define hidden void @f3()
define protected void @f3() {
entry:
ret void
}

View File

@ -0,0 +1,27 @@
; This file is used by visibility1.ll, so it doesn't actually do anything itself
;
; RUN: true
; Variables
@v1 = weak hidden global i32 0
@v2 = weak protected global i32 0
@v3 = weak hidden global i32 0
; Aliases
@a1 = hidden alias weak i32* @v1
@a2 = protected alias weak i32* @v2
@a3 = hidden alias weak i32* @v3
; Functions
define weak hidden void @f1() {
entry:
ret void
}
define weak protected void @f2() {
entry:
ret void
}
define weak hidden void @f3() {
entry:
ret void
}