Index: include/llvm/Transforms/IPO/FunctionImport.h =================================================================== --- include/llvm/Transforms/IPO/FunctionImport.h +++ include/llvm/Transforms/IPO/FunctionImport.h @@ -122,8 +122,9 @@ const DenseSet &GUIDPreservedSymbols, function_ref isPrevailing); -/// Converts value \p GV to declaration. -void convertToDeclaration(GlobalValue &GV); +/// Converts value \p GV to declaration, or replaces with a declaration if +/// it is an alias. Returns true if converted, false if replaced. +bool convertToDeclaration(GlobalValue &GV); /// Compute the set of summaries needed for a ThinLTO backend compilation of /// \p ModulePath. Index: lib/LTO/LTOBackend.cpp =================================================================== --- lib/LTO/LTOBackend.cpp +++ lib/LTO/LTOBackend.cpp @@ -401,18 +401,13 @@ static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals, const ModuleSummaryIndex &Index) { - auto MaybeDrop = [&](GlobalValue &GV) { + std::vector ReplacedGlobals; + for (auto &GV : Mod.global_values()) if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID())) - if (!Index.isGlobalValueLive(GVS)) - convertToDeclaration(GV); - }; + if (!Index.isGlobalValueLive(GVS) && !convertToDeclaration(GV)) + ReplacedGlobals.push_back(&GV); - // Process functions and global now. - // FIXME: add support for aliases (needs support in convertToDeclaration). - for (auto &GV : Mod) - MaybeDrop(GV); - for (auto &GV : Mod.globals()) - MaybeDrop(GV); + for (GlobalValue *GV : ReplacedGlobals) GV->eraseFromParent(); } Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -613,7 +613,7 @@ return std::error_code(); } -void llvm::convertToDeclaration(GlobalValue &GV) { +bool llvm::convertToDeclaration(GlobalValue &GV) { DEBUG(dbgs() << "Converting to a declaration: `" << GV.getName() << "\n"); if (Function *F = dyn_cast(&GV)) { F->deleteBody(); @@ -624,14 +624,24 @@ V->setLinkage(GlobalValue::ExternalLinkage); V->clearMetadata(); V->setComdat(nullptr); - } else - // For now we don't resolve or drop aliases. Once we do we'll - // need to add support here for creating either a function or - // variable declaration, and return the new GlobalValue* for - // the caller to use. - // Support of dropping aliases is required for correct dead code - // elimination performed in thin LTO backends (see 'dropDeadSymbols'). - llvm_unreachable("Expected function or variable"); + } else { + GlobalValue *NewGV; + if (GV.getValueType()->isFunctionTy()) + NewGV = + Function::Create(cast(GV.getValueType()), + GlobalValue::ExternalLinkage, "", GV.getParent()); + else + NewGV = + new GlobalVariable(*GV.getParent(), GV.getValueType(), + /*isConstant*/ false, GlobalValue::ExternalLinkage, + /*init*/ nullptr, "", + /*insertbefore*/ nullptr, GV.getThreadLocalMode(), + GV.getType()->getAddressSpace()); + NewGV->takeName(&GV); + GV.replaceAllUsesWith(NewGV); + return false; + } + return true; } /// Fixup WeakForLinker linkages in \p TheModule based on summary analysis. @@ -666,9 +676,13 @@ // interposable property and possibly get inlined. Simply drop // the definition in that case. if (GlobalValue::isAvailableExternallyLinkage(NewLinkage) && - GlobalValue::isInterposableLinkage(GV.getLinkage())) - convertToDeclaration(GV); - else { + GlobalValue::isInterposableLinkage(GV.getLinkage())) { + auto Converted = convertToDeclaration(GV); + // FIXME: Change this to collect replaced GVs and later erase + // them from the parent module once thinLTOResolveWeakForLinkerGUID is + // changed to enable this for aliases. + assert(Converted && "Expected GV to be converted"); + } else { DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from " << GV.getLinkage() << " to " << NewLinkage << "\n"); GV.setLinkage(NewLinkage); Index: test/LTO/Resolution/X86/not-prevailing-alias.ll =================================================================== --- /dev/null +++ test/LTO/Resolution/X86/not-prevailing-alias.ll @@ -0,0 +1,43 @@ +; Test to ensure that dead alias are dropped by converting to a declaration +; RUN: opt -module-summary %s -o %t1.bc +; RUN: llvm-lto2 run %t1.bc -r %t1.bc,barAlias,x \ +; RUN: -r %t1.bc,bar,x -r %t1.bc,zed,px \ +; RUN: -r %t1.bc,var,x -r %t1.bc,varAlias,x \ +; RUN: -o %t2.o -save-temps + +; Check that bar and barAlias were dropped to declarations +; RUN: llvm-dis %t2.o.1.1.promote.bc -o - | FileCheck %s --check-prefix=DROP +; DROP-DAG: declare void @bar() +; DROP-DAG: declare void @barAlias() +; DROP-DAG: @var = external global i32 +; DROP-DAG: @varAlias = external global i32 + +; Check that 'barAlias' and 'varAlias' were not inlined. +; RUN: llvm-objdump -d %t2.o.1 | FileCheck %s +; CHECK: zed: +; CHECK-NEXT: {{.*}} pushq +; CHECK-NEXT: {{.*}} callq 0 +; CHECK-NEXT: movq (%rip), %rax + +; Check that 'barAlias' and 'varAlias' produced as undefined. +; RUN: llvm-readelf --symbols %t2.o.1 | FileCheck %s --check-prefix=SYMBOLS +; SYMBOLS: NOTYPE GLOBAL DEFAULT UND barAlias +; SYMBOLS: NOTYPE GLOBAL DEFAULT UND varAlias +; SYMBOLS: FUNC GLOBAL DEFAULT 2 zed + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@barAlias = alias void(), void()* @bar +define void @bar() { + ret void +} + +@var = global i32 99 +@varAlias = alias i32, i32* @var + +define i32 @zed() { + call void @barAlias() + %1 = load i32, i32* @varAlias, align 4 + ret i32 %1 +}