[LTO] Fix commons handling

Previously the prevailing information was not honored, and commons
symbols could override a strong definition. This patch fixes it and
propose the following semantic for commons: the client should mark
as prevailing the commons that it expects the LTO implementation to
merge (i.e. take the maximum size and alignment).
It implies that commons are allowed to have multiple prevailing
definitions.

Differential Revision: https://reviews.llvm.org/D24545

llvm-svn: 281538
This commit is contained in:
Mehdi Amini 2016-09-14 21:05:04 +00:00
parent 1c71f902d0
commit 5f7f123920
5 changed files with 50 additions and 8 deletions

View File

@ -315,6 +315,8 @@ private:
struct CommonResolution {
uint64_t Size = 0;
unsigned Align = 0;
/// Record if at least one instance of the common was marked as prevailing
bool Prevailing = false;
};
std::map<std::string, CommonResolution> Commons;

View File

@ -352,13 +352,14 @@ Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
break;
}
}
// Common resolution: collect the maximum size/alignment.
// FIXME: right now we ignore the prevailing information, it is not clear
// what is the "right" behavior here.
// Common resolution: collect the maximum size/alignment over all commons.
// We also record if we see an instance of a common as prevailing, so that
// if none is prevailing we can ignore it later.
if (Sym.getFlags() & object::BasicSymbolRef::SF_Common) {
auto &CommonRes = RegularLTO.Commons[Sym.getIRName()];
CommonRes.Size = std::max(CommonRes.Size, Sym.getCommonSize());
CommonRes.Align = std::max(CommonRes.Align, Sym.getCommonAlignment());
CommonRes.Prevailing |= Res.Prevailing;
}
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
@ -421,6 +422,9 @@ Error LTO::runRegularLTO(AddOutputFn AddOutput) {
// all the prevailing when adding the inputs, and we apply it here.
const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout();
for (auto &I : RegularLTO.Commons) {
if (!I.second.Prevailing)
// Don't do anything if no instance of this common was prevailing.
continue;
GlobalVariable *OldGV = RegularLTO.CombinedModule->getNamedGlobal(I.first);
if (OldGV && DL.getTypeAllocSize(OldGV->getValueType()) == I.second.Size) {
// Don't create a new global if the type is already correct, just make

View File

@ -0,0 +1,4 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@x = global i32 42, align 4

View File

@ -0,0 +1,12 @@
; RUN: llvm-as -o %t1.bc %s
; RUN: llvm-as -o %t2.bc %p/Inputs/commons.ll
; RUN: llvm-lto2 %t1.bc -r=%t1.bc,x,l %t2.bc -r=%t2.bc,x,pl -o %t.out -save-temps
; RUN: llvm-dis -o - %t.out.0.0.preopt.bc | FileCheck %s
; A strong definition should override the common
; CHECK: @x = global i32 42, align 4
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@x = common global i16 0, align 2

View File

@ -19,7 +19,6 @@
; RUN: -r %t2.bc,bar,px
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s --check-prefix=LARGE-PREVAILED
; Client marked the "small with large alignment" one as prevailing
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
; RUN: -r %t1.bc,v,px \
@ -53,16 +52,37 @@
; RUN: -r %t2.bc,bar,px
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s --check-prefix=NONE-PREVAILED2
; Client marked both as prevailing
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \
; RUN: -r %t1.bc,v,px \
; RUN: -r %t2.bc,v,px \
; RUN: -r %t1.bc,foo,px \
; RUN: -r %t2.bc,bar,px
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s --check-prefix=BOTH-PREVAILED1
; Same as before, but reversing the order of the inputs
; RUN: llvm-lto2 %t2.bc %t1.bc -o %t.o -save-temps \
; RUN: -r %t1.bc,v,px \
; RUN: -r %t2.bc,v,px \
; RUN: -r %t1.bc,foo,px \
; RUN: -r %t2.bc,bar,px
; RUN: llvm-dis < %t.o.0.0.preopt.bc | FileCheck %s --check-prefix=BOTH-PREVAILED2
target triple = "x86_64-apple-macosx10.11.0"
@v = common global i8 0, align 8
; LARGE-PREVAILED: @v = common global i16 0, align 8
; SMALL-PREVAILED: @v = common global [2 x i8] zeroinitializer, align 8
; In this case the first was kept as external, but we created a new merged
; common due to the second requiring a larger size:
; NONE-PREVAILED1: @v = common global [2 x i8] zeroinitializer, align 8
; NONE-PREVAILED2: @v = external global i16, align 8
; BOTH-PREVAILED1: @v = common global i16 0, align 8
; BOTH-PREVAILED2: common global [2 x i8] zeroinitializer, align 8
; In this case the first is kept as external
; NONE-PREVAILED1: @v = external global i8, align 8
; NONE-PREVAILED2: @v = external global i16, align 4
define i8 *@foo() {
ret i8 *@v