Index: llvm/lib/IR/ModuleSummaryIndex.cpp =================================================================== --- llvm/lib/IR/ModuleSummaryIndex.cpp +++ llvm/lib/IR/ModuleSummaryIndex.cpp @@ -197,7 +197,7 @@ bool ModuleSummaryIndex::canImportGlobalVar(GlobalValueSummary *S, bool AnalyzeRefs) const { auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) { - return !isReadOnly(GVS) && GVS->refs().size(); + return !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size(); }; auto *GVS = cast(S->getBaseObject()); Index: llvm/lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionImport.cpp +++ llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -319,9 +319,10 @@ NumImportedGlobalVarsThinLink++; MarkExported(VI, RefSummary.get()); // Promote referenced functions and variables - for (const auto &VI : RefSummary->refs()) - for (const auto &RefFn : VI.getSummaryList()) - MarkExported(VI, RefFn.get()); + if (!Index.isWriteOnly(cast(RefSummary.get()))) + for (const auto &VI : RefSummary->refs()) + for (const auto &RefFn : VI.getSummaryList()) + MarkExported(VI, RefFn.get()); break; } } Index: llvm/lib/Transforms/Utils/FunctionImportUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/FunctionImportUtils.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/InstIterator.h" using namespace llvm; @@ -252,8 +253,15 @@ auto* GVS = dyn_cast_or_null( ImportIndex.findSummaryInModule(VI, M.getModuleIdentifier())); // At this stage "maybe" is "definitely" - if (GVS && (ImportIndex.isReadOnly(GVS) || ImportIndex.isWriteOnly(GVS))) + if (GVS && + (ImportIndex.isReadOnly(GVS) || ImportIndex.isWriteOnly(GVS))) { V->addAttribute("thinlto-internalize"); + if (ImportIndex.isWriteOnly(GVS)) { + auto *VTy = V->getValueType(); + if (VTy->isStructTy() || VTy->isArrayTy()) + V->setInitializer(ConstantAggregateZero::get(VTy)); + } + } } } Index: llvm/test/ThinLTO/X86/Inputs/writeonly-with-refs.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/Inputs/writeonly-with-refs.ll @@ -0,0 +1,17 @@ +; ModuleID = 'foo.o' +source_filename = "foo.cpp" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.S = type { i32 } +%struct.Q = type { %struct.S* } + +@_ZL3Obj = internal constant %struct.S { i32 42 }, align 4 +@outer = dso_local local_unnamed_addr global %struct.Q { %struct.S* @_ZL3Obj }, align 8 + +; Function Attrs: nofree norecurse nounwind uwtable writeonly +define dso_local void @_Z3foov() local_unnamed_addr { +entry: + store %struct.S* null, %struct.S** getelementptr inbounds (%struct.Q, %struct.Q* @outer, i64 0, i32 0), align 8 + ret void +} Index: llvm/test/ThinLTO/X86/writeonly-with-refs.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/writeonly-with-refs.ll @@ -0,0 +1,26 @@ +; RUN: opt -thinlto-bc %s -o %t1 +; RUN: opt -thinlto-bc %p/Inputs/writeonly-with-refs.ll -o %t2 +; RUN: llvm-lto2 run -save-temps %t1 %t2 -o %t-out \ +; RUN: -r=%t1,main,plx \ +; RUN: -r=%t1,_Z3foov,l \ +; RUN: -r=%t2,_Z3foov,pl \ +; RUN: -r=%t2,outer,pl + +; @outer should have been internalized and converted to zeroinitilizer. +; RUN: llvm-dis %t-out.1.5.precodegen.bc -o - | FileCheck %s +; RUN: llvm-dis %t-out.2.5.precodegen.bc -o - | FileCheck %s + +; CHECK: @outer = internal unnamed_addr global %struct.Q zeroinitializer + +source_filename = "main.cpp" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: norecurse uwtable +define dso_local i32 @main() local_unnamed_addr { +entry: + tail call void @_Z3foov() + ret i32 0 +} + +declare dso_local void @_Z3foov() local_unnamed_addr