From 88a7961c64e2848d8f60d1e75f8113dec86df0d4 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 22 Apr 2013 14:58:02 +0000 Subject: [PATCH] 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. llvm-svn: 180019 --- docs/LangRef.rst | 20 ++++++++++---------- include/llvm/CodeGen/AsmPrinter.h | 3 ++- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 7 ++----- lib/CodeGen/MachineModuleInfo.cpp | 3 +-- lib/IR/Verifier.cpp | 23 +++++++++++++++++++++++ lib/Transforms/IPO/ConstantMerge.cpp | 5 ++--- lib/Transforms/IPO/StripSymbols.cpp | 7 +++---- lib/Transforms/Scalar/GlobalMerge.cpp | 5 ++--- test/Feature/aliases.ll | 2 ++ test/Verifier/llvm.used-invalid-init.ll | 6 ++++++ test/Verifier/llvm.used-invalid-init2.ll | 7 +++++++ test/Verifier/llvm.used-invalid-type.ll | 6 ++++++ test/Verifier/llvm.used-invalid-type2.ll | 5 +++++ test/Verifier/llvm.used-ptr-type.ll | 4 ++++ 14 files changed, 75 insertions(+), 28 deletions(-) create mode 100644 test/Verifier/llvm.used-invalid-init.ll create mode 100644 test/Verifier/llvm.used-invalid-init2.ll create mode 100644 test/Verifier/llvm.used-invalid-type.ll create mode 100644 test/Verifier/llvm.used-invalid-type2.ll create mode 100644 test/Verifier/llvm.used-ptr-type.ll diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 7dafbb98779..382314e166b 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -2868,9 +2868,9 @@ All globals of this sort should have a section specified as The '``llvm.used``' Global Variable ----------------------------------- -The ``@llvm.used`` global is an array with i8\* element type which has -:ref:`appending linkage `. This array contains a list of -pointers to global variables and functions which may optionally have a +The ``@llvm.used`` global is an array which has + :ref:`appending linkage `. This array contains a list of +pointers to global variables, functions and aliases which may optionally have a pointer cast formed of bitcast or getelementptr. For example, a legal use of it is: @@ -2884,13 +2884,13 @@ use of it is: i8* bitcast (i32* @Y to i8*) ], section "llvm.metadata" -If a global variable appears in the ``@llvm.used`` list, then the -compiler, assembler, and linker are required to treat the symbol as if -there is a reference to the global that it cannot see. For example, if a -variable has internal linkage and no references other than that from the -``@llvm.used`` list, it cannot be deleted. This is commonly used to -represent references from inline asms and other things the compiler -cannot "see", and corresponds to "``attribute((used))``" in GNU C. +If a symbol appears in the ``@llvm.used`` list, then the compiler, assembler, +and linker are required to treat the symbol as if there is a reference to the +symbol that it cannot see. For example, if a variable has internal linkage and +no references other than that from the ``@llvm.used`` list, it cannot be +deleted. This is commonly used to represent references from inline asms and +other things the compiler cannot "see", and corresponds to +"``attribute((used))``" in GNU C. On some targets, the code generator must emit a directive to the assembler or object file to prevent the assembler and linker from diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index e0a6e3f4027..f2b0f9be961 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -25,6 +25,7 @@ namespace llvm { class BlockAddress; class GCStrategy; class Constant; + class ConstantArray; class GCMetadataPrinter; class GlobalValue; class GlobalVariable; @@ -480,7 +481,7 @@ namespace llvm { void EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, unsigned uid) const; - void EmitLLVMUsedList(const Constant *List); + void EmitLLVMUsedList(const ConstantArray *InitList); void EmitXXStructorList(const Constant *List, bool isCtor); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy *C); }; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 2d13db2c9c9..9187c6c2bec 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1213,7 +1213,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { if (GV->getName() == "llvm.used") { if (MAI->hasNoDeadStrip()) // No need to emit this at all. - EmitLLVMUsedList(GV->getInitializer()); + EmitLLVMUsedList(cast(GV->getInitializer())); return true; } @@ -1256,11 +1256,8 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { /// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each /// global in the specified llvm.used list for which emitUsedDirectiveFor /// 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*'. - const ConstantArray *InitList = dyn_cast(List); - if (InitList == 0) return; - for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { const GlobalValue *GV = dyn_cast(InitList->getOperand(i)->stripPointerCasts()); diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 0ea9ae0fcc8..8af9d053b12 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -326,8 +326,7 @@ void MachineModuleInfo::AnalyzeModule(const Module &M) { if (!GV || !GV->hasInitializer()) return; // Should be an array of 'i8*'. - const ConstantArray *InitList = dyn_cast(GV->getInitializer()); - if (InitList == 0) return; + const ConstantArray *InitList = cast(GV->getInitializer()); for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (const Function *F = diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 69cb5dc3817..f7aa79cca39 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -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(GVType)) { + PointerType *PTy = dyn_cast(ATy->getElementType()); + Assert1(PTy, "wrong type for intrinsic global variable", &GV); + if (GV.hasInitializer()) { + Constant *Init = GV.getInitializer(); + ConstantArray *InitArray = dyn_cast(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(V) || isa(V), + "invalid llvm.used member", V); + } + } + } + } + visitGlobalValue(GV); } diff --git a/lib/Transforms/IPO/ConstantMerge.cpp b/lib/Transforms/IPO/ConstantMerge.cpp index 8336d3ad347..b63495b9685 100644 --- a/lib/Transforms/IPO/ConstantMerge.cpp +++ b/lib/Transforms/IPO/ConstantMerge.cpp @@ -66,9 +66,8 @@ ModulePass *llvm::createConstantMergePass() { return new ConstantMerge(); } static void FindUsedValues(GlobalVariable *LLVMUsed, SmallPtrSet &UsedValues) { if (LLVMUsed == 0) return; - ConstantArray *Inits = dyn_cast(LLVMUsed->getInitializer()); - if (Inits == 0) return; - + ConstantArray *Inits = cast(LLVMUsed->getInitializer()); + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) if (GlobalValue *GV = dyn_cast(Inits->getOperand(i)->stripPointerCasts())) diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 5f8681ff454..3396f7929e6 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -195,10 +195,9 @@ static void findUsedValues(GlobalVariable *LLVMUsed, SmallPtrSet &UsedValues) { if (LLVMUsed == 0) return; UsedValues.insert(LLVMUsed); - - ConstantArray *Inits = dyn_cast(LLVMUsed->getInitializer()); - if (Inits == 0) return; - + + ConstantArray *Inits = cast(LLVMUsed->getInitializer()); + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) if (GlobalValue *GV = dyn_cast(Inits->getOperand(i)->stripPointerCasts())) diff --git a/lib/Transforms/Scalar/GlobalMerge.cpp b/lib/Transforms/Scalar/GlobalMerge.cpp index 5d02c68a7a4..4796eb2953a 100644 --- a/lib/Transforms/Scalar/GlobalMerge.cpp +++ b/lib/Transforms/Scalar/GlobalMerge.cpp @@ -200,9 +200,8 @@ void GlobalMerge::collectUsedGlobalVariables(Module &M) { if (!GV || !GV->hasInitializer()) return; // Should be an array of 'i8*'. - const ConstantArray *InitList = dyn_cast(GV->getInitializer()); - if (InitList == 0) return; - + const ConstantArray *InitList = cast(GV->getInitializer()); + for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (const GlobalVariable *G = dyn_cast(InitList->getOperand(i)->stripPointerCasts())) diff --git a/test/Feature/aliases.ll b/test/Feature/aliases.ll index d44dff4c43c..139381215ee 100644 --- a/test/Feature/aliases.ll +++ b/test/Feature/aliases.ll @@ -2,6 +2,8 @@ ; RUN: llvm-as %t1.ll -o - | llvm-dis > %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 @foo1 = alias i32* @bar @foo2 = alias i32* @bar diff --git a/test/Verifier/llvm.used-invalid-init.ll b/test/Verifier/llvm.used-invalid-init.ll new file mode 100644 index 00000000000..b0887c994e7 --- /dev/null +++ b/test/Verifier/llvm.used-invalid-init.ll @@ -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 diff --git a/test/Verifier/llvm.used-invalid-init2.ll b/test/Verifier/llvm.used-invalid-init2.ll new file mode 100644 index 00000000000..ee8a970bf10 --- /dev/null +++ b/test/Verifier/llvm.used-invalid-init2.ll @@ -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 diff --git a/test/Verifier/llvm.used-invalid-type.ll b/test/Verifier/llvm.used-invalid-type.ll new file mode 100644 index 00000000000..2de5c86fce3 --- /dev/null +++ b/test/Verifier/llvm.used-invalid-type.ll @@ -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 diff --git a/test/Verifier/llvm.used-invalid-type2.ll b/test/Verifier/llvm.used-invalid-type2.ll new file mode 100644 index 00000000000..bff3f2d153a --- /dev/null +++ b/test/Verifier/llvm.used-invalid-type2.ll @@ -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 diff --git a/test/Verifier/llvm.used-ptr-type.ll b/test/Verifier/llvm.used-ptr-type.ll new file mode 100644 index 00000000000..adfb1691d34 --- /dev/null +++ b/test/Verifier/llvm.used-ptr-type.ll @@ -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"