[llvm-commits] [llvm] r160664 - in /llvm/trunk: lib/Transforms/IPO/GlobalOpt.cpp test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll
David Dean
david_dean at apple.com
Tue Jul 24 09:05:14 PDT 2012
Nick, this seems to be breaking self-hosting on darwin:
While deleting: %"class.std::basic_string"* %temp.lvalue
Use still stuck around after Def is destroyed: call void @_ZNSsD1Ev(%"class.std::basic_string"* %temp.lvalue)
Use still stuck around after Def is destroyed: call void @_ZNK4llvm9StringRefcvSsEv(%"class.std::basic_string"* sret %temp.lvalue, %"class.llvm::StringRef"* %coerce)
Assertion failed: (use_empty() && "Uses remain when a value is destroyed!"), function ~Value, file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-nobootstrap-RA/llvm/lib/VMCore/Value.cpp, line 75.
0 clang 0x000000010159a472 llvm::SmallVectorImpl<char>::swap(llvm::SmallVectorImpl<char>&) + 14450
1 clang 0x000000010159a954 llvm::SmallVectorImpl<char>::swap(llvm::SmallVectorImpl<char>&) + 15700
2 libsystem_c.dylib 0x00007fff9135fcfa _sigtramp + 26
3 libsystem_c.dylib 0x0000000000000002 _sigtramp + 18446603338079929122
4 clang 0x000000010159a6b6 llvm::SmallVectorImpl<char>::swap(llvm::SmallVectorImpl<char>&) + 15030
5 clang 0x000000010159a691 llvm::SmallVectorImpl<char>::swap(llvm::SmallVectorImpl<char>&) + 14993
6 clang 0x000000010154d44d llvm::enable_if<llvm::hashing::detail::is_hashable_data<llvm::Type* const>, llvm::hash_code>::type llvm::hashing::detail::hash_combine_range_impl<llvm::Type* const>(llvm::Type* const*, llvm::Type* const*) + 7101
7 clang 0x000000010151b20e std::_Rb_tree<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType>, std::pair<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType> const, llvm::InlineAsm*>, std::_Select1st<std::pair<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType> const, llvm::InlineAsm*> >, std::less<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType> >, std::allocator<std::pair<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType> const, llvm::InlineAsm*> > >::_M_insert_unique(std::pair<std::pair<llvm::PointerType*, llvm::InlineAsmKeyType> const, llvm::InlineAsm*> const&) + 21246
8 clang 0x0000000100ad9e54 std::vector<llvm::Function*, std::allocator<llvm::Function*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::Function**, std::vector<llvm::Function*, std::allocator<llvm::Function*> > >, llvm::Function* const&) + 20532
9 clang 0x0000000100ad7506 std::vector<llvm::Function*, std::allocator<llvm::Function*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::Function**, std::vector<llvm::Function*, std::allocator<llvm::Function*> > >, llvm::Function* const&) + 9958
10 clang 0x0000000100ad5c26 std::vector<llvm::Function*, std::allocator<llvm::Function*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::Function**, std::vector<llvm::Function*, std::allocator<llvm::Function*> > >, llvm::Function* const&) + 3590
11 clang 0x000000010153d646 std::vector<llvm::StructType*, std::allocator<llvm::StructType*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::StructType**, std::vector<llvm::StructType*, std::allocator<llvm::StructType*> > >, llvm::StructType* const&) + 31510
12 clang 0x000000010153dc09 std::vector<llvm::StructType*, std::allocator<llvm::StructType*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::StructType**, std::vector<llvm::StructType*, std::allocator<llvm::StructType*> > >, llvm::StructType* const&) + 32985
13 clang 0x000000010153dded std::vector<llvm::StructType*, std::allocator<llvm::StructType*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<llvm::StructType**, std::vector<llvm::StructType*, std::allocator<llvm::StructType*> > >, llvm::StructType* const&) + 33469
14 clang 0x000000010016256a std::vector<clang::serialization::ModuleFile*, std::allocator<clang::serialization::ModuleFile*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<clang::serialization::ModuleFile**, std::vector<clang::serialization::ModuleFile*, std::allocator<clang::serialization::ModuleFile*> > >, clang::serialization::ModuleFile* const&) + 7738
15 clang 0x0000000100244dca llvm::ParseIR(llvm::MemoryBuffer*, llvm::SMDiagnostic&, llvm::LLVMContext&) + 2010
16 clang 0x000000010027b9b4 std::vector<std::pair<llvm::WeakVH, llvm::Constant*>, std::allocator<std::pair<llvm::WeakVH, llvm::Constant*> > >::_M_insert_aux(__gnu_cxx::__normal_iterator<std::pair<llvm::WeakVH, llvm::Constant*>*, std::vector<std::pair<llvm::WeakVH, llvm::Constant*>, std::allocator<std::pair<llvm::WeakVH, llvm::Constant*> > > >, std::pair<llvm::WeakVH, llvm::Constant*> const&) + 53524
17 clang 0x0000000100243a00 std::vector<clang::CXXRecordDecl const*, std::allocator<clang::CXXRecordDecl const*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<clang::CXXRecordDecl const**, std::vector<clang::CXXRecordDecl const*, std::allocator<clang::CXXRecordDecl const*> > >, clang::CXXRecordDecl const* const&) + 6224
18 clang 0x000000010004f0b8 llvm::SmallVectorImpl<clang::FileEntry const*>::operator=(llvm::SmallVectorImpl<clang::FileEntry const*> const&) + 10184
19 clang 0x0000000100024d5f std::vector<clang::CompilerInstance*, std::allocator<clang::CompilerInstance*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<clang::CompilerInstance**, std::vector<clang::CompilerInstance*, std::allocator<clang::CompilerInstance*> > >, clang::CompilerInstance* const&) + 16623
20 clang 0x000000010000b40a std::_Rb_tree<std::string, std::string, std::_Identity<std::string>, std::less<std::string>, std::allocator<std::string> >::_M_insert_unique(std::string const&) + 3978
21 clang 0x0000000100000e1a
22 clang 0x0000000100007e6c std::vector<std::string, std::allocator<std::string> >::_M_insert_aux(__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string, std::allocator<std::string> > >, std::string const&) + 4124
23 clang 0x0000000100000b34
24 clang 0x000000000000004f
Stack dump:
0. Program arguments: /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/host-compiler/bin/clang -cc1 -triple x86_64-apple-macosx10.7.0 -emit-obj -disable-free -main-file-name PrettyStackTrace.cpp -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 127.2.1 -coverage-file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support/Release+Asserts/PrettyStackTrace.o -resource-dir /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/host-compiler/bin/../lib/clang/3.2 -dependency-file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support/Release+Asserts/PrettyStackTrace.d.tmp -MP -MT /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support/Release+Asserts/PrettyStackTrace.o -MT /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support/Release+Asserts/PrettyStackTrace.d -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/include -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/llvm/include -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/llvm/lib/Support -fmodule-cache-path /var/folders/c0/p42p46x90pz38sc3mpntqhh80000gp/T/clang-module-cache -O3 -Woverloaded-virtual -Wcast-qual -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcovered-switch-default -fconst-strings -fdeprecated-macro -fdebug-compilation-dir /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.7.0 -fobjc-dispatch-method=mixed -fobjc-default-synthesize-properties -fno-common -fdiagnostics-show-option -o /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/clang-build/lib/Support/Release+Asserts/PrettyStackTrace.o -x c++ /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/llvm/lib/Support/PrettyStackTrace.cpp
1. <eof> parser at end of file
2. Per-module optimization passes
3. Running pass 'Global Variable Optimizer' on module '/Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-RA/llvm/lib/Support/PrettyStackTrace.cpp'.
clang: error: unable to execute command: Illegal instruction: 4
clang: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 3.2 (trunk 160664)
I've attached the preprocessed source and run script to reproduce.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PrettyStackTrace-sPG1th.cpp
Type: application/octet-stream
Size: 2261012 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120724/a1c1193e/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PrettyStackTrace-sPG1th.sh
Type: application/octet-stream
Size: 1133 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120724/a1c1193e/attachment-0001.obj>
-------------- next part --------------
On 24 Jul 2012, at 12:21 AM, Nick Lewycky <nicholas at mxc.ca> wrote:
> Author: nicholas
> Date: Tue Jul 24 02:21:08 2012
> New Revision: 160664
>
> URL: http://llvm.org/viewvc/llvm-project?rev=160664&view=rev
> Log:
> Teach globalopt to not nuke all stores to globals. Keep them around of they
> might be deliberate "one time" leaks, so that leak checkers can find them.
> This is a reapply of r160602 with the fix that this time I'm committing the
> code I thought I was committing last time; the I->eraseFromParent() goes
> *after* the break out of the loop.
>
> Added:
> llvm/trunk/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll
> Modified:
> llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> llvm/trunk/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll
>
> Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=160664&r1=160663&r2=160664&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Tue Jul 24 02:21:08 2012
> @@ -296,6 +296,165 @@
> return false;
> }
>
> +/// isLeakCheckerRoot - Is this global variable possibly used by a leak checker
> +/// as a root? If so, we might not really want to eliminate the stores to it.
> +static bool isLeakCheckerRoot(GlobalVariable *GV) {
> + // A global variable is a root if it is a pointer, or could plausibly contain
> + // a pointer. There are two challenges; one is that we could have a struct
> + // the has an inner member which is a pointer. We recurse through the type to
> + // detect these (up to a point). The other is that we may actually be a union
> + // of a pointer and another type, and so our LLVM type is an integer which
> + // gets converted into a pointer, or our type is an [i8 x #] with a pointer
> + // potentially contained here.
> +
> + if (GV->hasPrivateLinkage())
> + return false;
> +
> + SmallVector<Type *, 4> Types;
> + Types.push_back(cast<PointerType>(GV->getType())->getElementType());
> +
> + unsigned Limit = 20;
> + do {
> + Type *Ty = Types.pop_back_val();
> + switch (Ty->getTypeID()) {
> + default: break;
> + case Type::PointerTyID: return true;
> + case Type::ArrayTyID:
> + case Type::VectorTyID: {
> + SequentialType *STy = cast<SequentialType>(Ty);
> + Types.push_back(STy->getElementType());
> + break;
> + }
> + case Type::StructTyID: {
> + StructType *STy = cast<StructType>(Ty);
> + if (STy->isOpaque()) return true;
> + for (StructType::element_iterator I = STy->element_begin(),
> + E = STy->element_end(); I != E; ++I) {
> + Type *InnerTy = *I;
> + if (isa<PointerType>(InnerTy)) return true;
> + if (isa<CompositeType>(InnerTy))
> + Types.push_back(InnerTy);
> + }
> + break;
> + }
> + }
> + if (--Limit == 0) return true;
> + } while (!Types.empty());
> + return false;
> +}
> +
> +/// Given a value that is stored to a global but never read, determine whether
> +/// it's safe to remove the store and the chain of computation that feeds the
> +/// store.
> +static bool IsSafeComputationToRemove(Value *V) {
> + do {
> + if (isa<Constant>(V))
> + return true;
> + if (!V->hasOneUse())
> + return false;
> + if (isa<LoadInst>(V) || isa<Argument>(V) || isa<GlobalValue>(V))
> + return false;
> + if (isAllocationFn(V))
> + return true;
> +
> + Instruction *I = cast<Instruction>(V);
> + if (I->mayHaveSideEffects())
> + return false;
> + if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I)) {
> + if (!GEP->hasAllConstantIndices())
> + return false;
> + } else if (I->getNumOperands() != 1) {
> + return false;
> + }
> +
> + V = I->getOperand(0);
> + } while (1);
> +}
> +
> +/// CleanupPointerRootUsers - This GV is a pointer root. Loop over all users
> +/// of the global and clean up any that obviously don't assign the global a
> +/// value that isn't dynamically allocated.
> +///
> +static bool CleanupPointerRootUsers(GlobalVariable *GV) {
> + // A brief explanation of leak checkers. The goal is to find bugs where
> + // pointers are forgotten, causing an accumulating growth in memory
> + // usage over time. The common strategy for leak checkers is to whitelist the
> + // memory pointed to by globals at exit. This is popular because it also
> + // solves another problem where the main thread of a C++ program may shut down
> + // before other threads that are still expecting to use those globals. To
> + // handle that case, we expect the program may create a singleton and never
> + // destroy it.
> +
> + bool Changed = false;
> +
> + // If Dead[n].first is the only use of a malloc result, we can delete its
> + // chain of computation and the store to the global in Dead[n].second.
> + SmallVector<std::pair<Instruction *, Instruction *>, 32> Dead;
> +
> + // Constants can't be pointers to dynamically allocated memory.
> + for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end();
> + UI != E;) {
> + User *U = *UI++;
> + if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
> + Value *V = SI->getValueOperand();
> + if (isa<Constant>(V)) {
> + Changed = true;
> + SI->eraseFromParent();
> + } else if (Instruction *I = dyn_cast<Instruction>(V)) {
> + if (I->hasOneUse())
> + Dead.push_back(std::make_pair(I, SI));
> + }
> + } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
> + if (isa<Constant>(MSI->getValue())) {
> + Changed = true;
> + MSI->eraseFromParent();
> + } else if (Instruction *I = dyn_cast<Instruction>(MSI->getValue())) {
> + if (I->hasOneUse())
> + Dead.push_back(std::make_pair(I, MSI));
> + }
> + } else if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(U)) {
> + GlobalVariable *MemSrc = dyn_cast<GlobalVariable>(MTI->getSource());
> + if (MemSrc && MemSrc->isConstant()) {
> + Changed = true;
> + MTI->eraseFromParent();
> + } else if (Instruction *I = dyn_cast<Instruction>(MemSrc)) {
> + if (I->hasOneUse())
> + Dead.push_back(std::make_pair(I, MTI));
> + }
> + } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
> + if (CE->use_empty()) {
> + CE->destroyConstant();
> + Changed = true;
> + }
> + } else if (Constant *C = dyn_cast<Constant>(U)) {
> + if (SafeToDestroyConstant(C)) {
> + C->destroyConstant();
> + // This could have invalidated UI, start over from scratch.
> + Dead.clear();
> + CleanupPointerRootUsers(GV);
> + return true;
> + }
> + }
> + }
> +
> + for (int i = 0, e = Dead.size(); i != e; ++i) {
> + if (IsSafeComputationToRemove(Dead[i].first)) {
> + Dead[i].second->eraseFromParent();
> + Instruction *I = Dead[i].first;
> + do {
> + Instruction *J = dyn_cast<Instruction>(I->getOperand(0));
> + if (!J)
> + break;
> + I->eraseFromParent();
> + I = J;
> + } while (!isAllocationFn(I));
> + I->eraseFromParent();
> + }
> + }
> +
> + return Changed;
> +}
> +
> /// CleanupConstantGlobalUsers - We just marked GV constant. Loop over all
> /// users of the global, cleaning up the obvious ones. This is largely just a
> /// quick scan over the use list to clean up the easy and obvious cruft. This
> @@ -812,13 +971,18 @@
> // If we nuked all of the loads, then none of the stores are needed either,
> // nor is the global.
> if (AllNonStoreUsesGone) {
> - DEBUG(dbgs() << " *** GLOBAL NOW DEAD!\n");
> - CleanupConstantGlobalUsers(GV, 0, TD, TLI);
> + if (isLeakCheckerRoot(GV)) {
> + Changed |= CleanupPointerRootUsers(GV);
> + } else {
> + Changed = true;
> + CleanupConstantGlobalUsers(GV, 0, TD, TLI);
> + }
> if (GV->use_empty()) {
> + DEBUG(dbgs() << " *** GLOBAL NOW DEAD!\n");
> + Changed = true;
> GV->eraseFromParent();
> ++NumDeleted;
> }
> - Changed = true;
> }
> return Changed;
> }
> @@ -1794,10 +1958,15 @@
> if (!GS.isLoaded) {
> DEBUG(dbgs() << "GLOBAL NEVER LOADED: " << *GV);
>
> - // Delete any stores we can find to the global. We may not be able to
> - // make it completely dead though.
> - bool Changed = CleanupConstantGlobalUsers(GV, GV->getInitializer(),
> - TD, TLI);
> + bool Changed;
> + if (isLeakCheckerRoot(GV)) {
> + // Delete any constant stores to the global.
> + Changed = CleanupPointerRootUsers(GV);
> + } else {
> + // Delete any stores we can find to the global. We may not be able to
> + // make it completely dead though.
> + Changed = CleanupConstantGlobalUsers(GV, GV->getInitializer(), TD, TLI);
> + }
>
> // If the global is dead now, delete it.
> if (GV->use_empty()) {
> @@ -1845,7 +2014,7 @@
>
> if (GV->use_empty()) {
> DEBUG(dbgs() << " *** Substituting initializer allowed us to "
> - << "simplify all users and delete global!\n");
> + << "simplify all users and delete global!\n");
> GV->eraseFromParent();
> ++NumDeleted;
> } else {
>
> Modified: llvm/trunk/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll?rev=160664&r1=160663&r2=160664&view=diff
> ==============================================================================
> --- llvm/trunk/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll (original)
> +++ llvm/trunk/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll Tue Jul 24 02:21:08 2012
> @@ -17,7 +17,7 @@
> %2 = sext i32 %1 to i64 ; <i64> [#uses=1]
> %3 = mul i64 %2, ptrtoint (%struct.strchartype* getelementptr (%struct.strchartype* null, i64 1) to i64) ; <i64> [#uses=1]
> %4 = tail call i8* @malloc(i64 %3) ; <i8*> [#uses=1]
> -; CHECK: call i8* @malloc(i64
> +; CHECK-NOT: call i8* @malloc(i64
> %5 = bitcast i8* %4 to %struct.strchartype* ; <%struct.strchartype*> [#uses=1]
> store %struct.strchartype* %5, %struct.strchartype** @chartypes, align 8
> ret void
>
> Added: llvm/trunk/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll?rev=160664&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll (added)
> +++ llvm/trunk/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll Tue Jul 24 02:21:08 2012
> @@ -0,0 +1,19 @@
> +; RUN: opt -globalopt -S -o - < %s | FileCheck %s
> +
> + at test1 = internal global i8* null
> +
> +define void @test1a() {
> +; CHECK: @test1a
> +; CHECK-NOT: store
> +; CHECK-NEXT: ret void
> + store i8* null, i8** @test1
> + ret void
> +}
> +
> +define void @test1b(i8* %p) {
> +; CHECK: @test1b
> +; CHECK-NEXT: store
> +; CHECK-NEXT: ret void
> + store i8* %p, i8** @test1
> + ret void
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
-David
More information about the llvm-commits
mailing list