Clarify that llvm.used can contain aliases.

Also add a check for llvm.used in the verifier and simplify clients now that
they can assume they have a ConstantArray.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180019 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola 2013-04-22 14:58:02 +00:00
parent 2c55362848
commit cde25b435a
14 changed files with 75 additions and 28 deletions

View File

@ -2868,9 +2868,9 @@ All globals of this sort should have a section specified as
The '``llvm.used``' Global Variable The '``llvm.used``' Global Variable
----------------------------------- -----------------------------------
The ``@llvm.used`` global is an array with i8\* element type which has The ``@llvm.used`` global is an array which has
:ref:`appending linkage <linkage_appending>`. This array contains a list of :ref:`appending linkage <linkage_appending>`. This array contains a list of
pointers to global variables and functions which may optionally have a pointers to global variables, functions and aliases which may optionally have a
pointer cast formed of bitcast or getelementptr. For example, a legal pointer cast formed of bitcast or getelementptr. For example, a legal
use of it is: use of it is:
@ -2884,13 +2884,13 @@ use of it is:
i8* bitcast (i32* @Y to i8*) i8* bitcast (i32* @Y to i8*)
], section "llvm.metadata" ], section "llvm.metadata"
If a global variable appears in the ``@llvm.used`` list, then the If a symbol appears in the ``@llvm.used`` list, then the compiler, assembler,
compiler, assembler, and linker are required to treat the symbol as if and linker are required to treat the symbol as if there is a reference to the
there is a reference to the global that it cannot see. For example, if a symbol that it cannot see. For example, if a variable has internal linkage and
variable has internal linkage and no references other than that from the no references other than that from the ``@llvm.used`` list, it cannot be
``@llvm.used`` list, it cannot be deleted. This is commonly used to deleted. This is commonly used to represent references from inline asms and
represent references from inline asms and other things the compiler other things the compiler cannot "see", and corresponds to
cannot "see", and corresponds to "``attribute((used))``" in GNU C. "``attribute((used))``" in GNU C.
On some targets, the code generator must emit a directive to the On some targets, the code generator must emit a directive to the
assembler or object file to prevent the assembler and linker from assembler or object file to prevent the assembler and linker from

View File

@ -25,6 +25,7 @@ namespace llvm {
class BlockAddress; class BlockAddress;
class GCStrategy; class GCStrategy;
class Constant; class Constant;
class ConstantArray;
class GCMetadataPrinter; class GCMetadataPrinter;
class GlobalValue; class GlobalValue;
class GlobalVariable; class GlobalVariable;
@ -480,7 +481,7 @@ namespace llvm {
void EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, void EmitJumpTableEntry(const MachineJumpTableInfo *MJTI,
const MachineBasicBlock *MBB, const MachineBasicBlock *MBB,
unsigned uid) const; unsigned uid) const;
void EmitLLVMUsedList(const Constant *List); void EmitLLVMUsedList(const ConstantArray *InitList);
void EmitXXStructorList(const Constant *List, bool isCtor); void EmitXXStructorList(const Constant *List, bool isCtor);
GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy *C); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy *C);
}; };

View File

@ -1213,7 +1213,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI,
bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) {
if (GV->getName() == "llvm.used") { if (GV->getName() == "llvm.used") {
if (MAI->hasNoDeadStrip()) // No need to emit this at all. if (MAI->hasNoDeadStrip()) // No need to emit this at all.
EmitLLVMUsedList(GV->getInitializer()); EmitLLVMUsedList(cast<ConstantArray>(GV->getInitializer()));
return true; return true;
} }
@ -1256,11 +1256,8 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) {
/// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each /// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each
/// global in the specified llvm.used list for which emitUsedDirectiveFor /// global in the specified llvm.used list for which emitUsedDirectiveFor
/// is true, as being used with this directive. /// is true, as being used with this directive.
void AsmPrinter::EmitLLVMUsedList(const Constant *List) { void AsmPrinter::EmitLLVMUsedList(const ConstantArray *InitList) {
// Should be an array of 'i8*'. // Should be an array of 'i8*'.
const ConstantArray *InitList = dyn_cast<ConstantArray>(List);
if (InitList == 0) return;
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
const GlobalValue *GV = const GlobalValue *GV =
dyn_cast<GlobalValue>(InitList->getOperand(i)->stripPointerCasts()); dyn_cast<GlobalValue>(InitList->getOperand(i)->stripPointerCasts());

View File

@ -326,8 +326,7 @@ void MachineModuleInfo::AnalyzeModule(const Module &M) {
if (!GV || !GV->hasInitializer()) return; if (!GV || !GV->hasInitializer()) return;
// Should be an array of 'i8*'. // Should be an array of 'i8*'.
const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); const ConstantArray *InitList = cast<ConstantArray>(GV->getInitializer());
if (InitList == 0) return;
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i)
if (const Function *F = if (const Function *F =

View File

@ -449,6 +449,29 @@ void Verifier::visitGlobalVariable(GlobalVariable &GV) {
} }
} }
if (GV.hasName() && (GV.getName() == "llvm.used")) {
Assert1(!GV.hasInitializer() || GV.hasAppendingLinkage(),
"invalid linkage for intrinsic global variable", &GV);
Type *GVType = GV.getType()->getElementType();
if (ArrayType *ATy = dyn_cast<ArrayType>(GVType)) {
PointerType *PTy = dyn_cast<PointerType>(ATy->getElementType());
Assert1(PTy, "wrong type for intrinsic global variable", &GV);
if (GV.hasInitializer()) {
Constant *Init = GV.getInitializer();
ConstantArray *InitArray = dyn_cast<ConstantArray>(Init);
Assert1(InitArray, "wrong initalizer for intrinsic global variable",
Init);
for (unsigned i = 0, e = InitArray->getNumOperands(); i != e; ++i) {
Value *V = Init->getOperand(i)->stripPointerCasts();
// stripPointerCasts strips aliases, so we only need to check for
// variables and functions.
Assert1(isa<GlobalVariable>(V) || isa<Function>(V),
"invalid llvm.used member", V);
}
}
}
}
visitGlobalValue(GV); visitGlobalValue(GV);
} }

View File

@ -66,9 +66,8 @@ ModulePass *llvm::createConstantMergePass() { return new ConstantMerge(); }
static void FindUsedValues(GlobalVariable *LLVMUsed, static void FindUsedValues(GlobalVariable *LLVMUsed,
SmallPtrSet<const GlobalValue*, 8> &UsedValues) { SmallPtrSet<const GlobalValue*, 8> &UsedValues) {
if (LLVMUsed == 0) return; if (LLVMUsed == 0) return;
ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer()); ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
if (Inits == 0) return;
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
if (GlobalValue *GV = if (GlobalValue *GV =
dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))

View File

@ -195,10 +195,9 @@ static void findUsedValues(GlobalVariable *LLVMUsed,
SmallPtrSet<const GlobalValue*, 8> &UsedValues) { SmallPtrSet<const GlobalValue*, 8> &UsedValues) {
if (LLVMUsed == 0) return; if (LLVMUsed == 0) return;
UsedValues.insert(LLVMUsed); UsedValues.insert(LLVMUsed);
ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer()); ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
if (Inits == 0) return;
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
if (GlobalValue *GV = if (GlobalValue *GV =
dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))

View File

@ -200,9 +200,8 @@ void GlobalMerge::collectUsedGlobalVariables(Module &M) {
if (!GV || !GV->hasInitializer()) return; if (!GV || !GV->hasInitializer()) return;
// Should be an array of 'i8*'. // Should be an array of 'i8*'.
const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); const ConstantArray *InitList = cast<ConstantArray>(GV->getInitializer());
if (InitList == 0) return;
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i)
if (const GlobalVariable *G = if (const GlobalVariable *G =
dyn_cast<GlobalVariable>(InitList->getOperand(i)->stripPointerCasts())) dyn_cast<GlobalVariable>(InitList->getOperand(i)->stripPointerCasts()))

View File

@ -2,6 +2,8 @@
; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll ; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll
; RUN: diff %t1.ll %t2.ll ; RUN: diff %t1.ll %t2.ll
@llvm.used = appending global [1 x i8*] [i8* bitcast (i32* @foo1 to i8*)], section "llvm.metadata"
@bar = external global i32 @bar = external global i32
@foo1 = alias i32* @bar @foo1 = alias i32* @bar
@foo2 = alias i32* @bar @foo2 = alias i32* @bar

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@llvm.used = appending global [1 x i8*] zeroinitializer, section "llvm.metadata"
; CHECK: wrong initalizer for intrinsic global variable
; CHECK-NEXT: [1 x i8*] zeroinitializer

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@a = global i8 42
@llvm.used = appending global [2 x i8*] [i8* @a, i8* null], section "llvm.metadata"
; CHECK: invalid llvm.used member
; CHECK-NEXT: i8* null

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@llvm.used = appending global [1 x i32] [i32 0], section "llvm.metadata"
; CHECK: wrong type for intrinsic global variable
; CHECK-NEXT: [1 x i32]* @llvm.used

View File

@ -0,0 +1,5 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@llvm.used = appending global i32 0, section "llvm.metadata"
; CHECK: Only global arrays can have appending linkage!
; CHEKC-NEXT: i32* @llvm.used

View File

@ -0,0 +1,4 @@
; RUN: llvm-as < %s -o /dev/null
@a = global i32 42
@llvm.used = appending global [1 x i32*] [i32* @a], section "llvm.metadata"