Skip to content

Commit 10cadee

Browse files
committed
[ThinLTO] Always import constants
This patch imports constant variables even when they can't be internalized (which results in promotion). This offers some extra constant folding opportunities. Differential revision: https://reviews.llvm.org/D70404
1 parent 3f3017e commit 10cadee

19 files changed

+188
-36
lines changed

llvm/include/llvm/IR/ModuleSummaryIndex.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -757,14 +757,29 @@ class GlobalVarSummary : public GlobalValueSummary {
757757

758758
public:
759759
struct GVarFlags {
760-
GVarFlags(bool ReadOnly, bool WriteOnly)
761-
: MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly) {}
762-
763-
// In permodule summaries both MaybeReadOnly and MaybeWriteOnly
764-
// bits are set, because attribute propagation occurs later on
765-
// thin link phase.
760+
GVarFlags(bool ReadOnly, bool WriteOnly, bool Constant)
761+
: MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly),
762+
Constant(Constant) {}
763+
764+
// If true indicates that this global variable might be accessed
765+
// purely by non-volatile load instructions. This in turn means
766+
// it can be internalized in source and destination modules during
767+
// thin LTO import because it neither modified nor its address
768+
// is taken.
766769
unsigned MaybeReadOnly : 1;
770+
// If true indicates that variable is possibly only written to, so
771+
// its value isn't loaded and its address isn't taken anywhere.
772+
// False, when 'Constant' attribute is set.
767773
unsigned MaybeWriteOnly : 1;
774+
// Indicates that value is a compile-time constant. Global variable
775+
// can be 'Constant' while not being 'ReadOnly' on several occasions:
776+
// - it is volatile, (e.g mapped device address)
777+
// - its address is taken, meaning that unlike 'ReadOnly' vars we can't
778+
// internalize it.
779+
// Constant variables are always imported thus giving compiler an
780+
// opportunity to make some extra optimizations. Readonly constants
781+
// are also internalized.
782+
unsigned Constant : 1;
768783
} VarFlags;
769784

770785
GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags,
@@ -782,6 +797,7 @@ class GlobalVarSummary : public GlobalValueSummary {
782797
void setWriteOnly(bool WO) { VarFlags.MaybeWriteOnly = WO; }
783798
bool maybeReadOnly() const { return VarFlags.MaybeReadOnly; }
784799
bool maybeWriteOnly() const { return VarFlags.MaybeWriteOnly; }
800+
bool isConstant() const { return VarFlags.Constant; }
785801

786802
void setVTableFuncs(VTableFuncList Funcs) {
787803
assert(!VTableFuncs);

llvm/lib/Analysis/ModuleSummaryAnalysis.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,9 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
599599
bool CanBeInternalized =
600600
!V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
601601
!V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass();
602-
GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, CanBeInternalized);
602+
bool Constant = V.isConstant();
603+
GlobalVarSummary::GVarFlags VarFlags(
604+
CanBeInternalized, Constant ? false : CanBeInternalized, Constant);
603605
auto GVarSummary = std::make_unique<GlobalVarSummary>(Flags, VarFlags,
604606
RefEdges.takeVector());
605607
if (NonRenamableLocal)
@@ -718,7 +720,9 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
718720
} else {
719721
std::unique_ptr<GlobalVarSummary> Summary =
720722
std::make_unique<GlobalVarSummary>(
721-
GVFlags, GlobalVarSummary::GVarFlags(false, false),
723+
GVFlags,
724+
GlobalVarSummary::GVarFlags(
725+
false, false, cast<GlobalVariable>(GV)->isConstant()),
722726
ArrayRef<ValueInfo>{});
723727
Index.addGlobalValueSummary(*GV, std::move(Summary));
724728
}

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8155,7 +8155,8 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
81558155
/*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
81568156
/*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
81578157
GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false,
8158-
/* WriteOnly */ false);
8158+
/* WriteOnly */ false,
8159+
/* Constant */ false);
81598160
std::vector<ValueInfo> Refs;
81608161
VTableFuncList VTableFuncs;
81618162
if (ParseToken(lltok::colon, "expected ':' here") ||
@@ -8827,7 +8828,8 @@ bool LLParser::ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags) {
88278828

88288829
/// GVarFlags
88298830
/// ::= 'varFlags' ':' '(' 'readonly' ':' Flag
8830-
/// ',' 'writeonly' ':' Flag ')'
8831+
/// ',' 'writeonly' ':' Flag
8832+
/// ',' 'constant' ':' Flag ')'
88318833
bool LLParser::ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) {
88328834
assert(Lex.getKind() == lltok::kw_varFlags);
88338835
Lex.Lex();
@@ -8856,6 +8858,11 @@ bool LLParser::ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) {
88568858
return true;
88578859
GVarFlags.MaybeWriteOnly = Flag;
88588860
break;
8861+
case lltok::kw_constant:
8862+
if (ParseRest(Flag))
8863+
return true;
8864+
GVarFlags.Constant = Flag;
8865+
break;
88598866
default:
88608867
return Error(Lex.getLoc(), "expected gvar flag type");
88618868
}

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,8 @@ static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags,
986986
// Decode the flags for GlobalVariable in the summary
987987
static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) {
988988
return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false,
989-
(RawFlags & 0x2) ? true : false);
989+
(RawFlags & 0x2) ? true : false,
990+
(RawFlags & 0x4) ? true : false);
990991
}
991992

992993
static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
@@ -5965,7 +5966,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
59655966
uint64_t RawFlags = Record[1];
59665967
unsigned RefArrayStart = 2;
59675968
GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false,
5968-
/* WriteOnly */ false);
5969+
/* WriteOnly */ false,
5970+
/* Constant */ false);
59695971
auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
59705972
if (Version >= 5) {
59715973
GVF = getDecodedGVarFlags(Record[2]);
@@ -6101,7 +6103,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
61016103
uint64_t RawFlags = Record[2];
61026104
unsigned RefArrayStart = 3;
61036105
GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false,
6104-
/* WriteOnly */ false);
6106+
/* WriteOnly */ false,
6107+
/* Constant */ false);
61056108
auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
61066109
if (Version >= 5) {
61076110
GVF = getDecodedGVarFlags(Record[3]);

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,8 @@ static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) {
10281028
}
10291029

10301030
static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) {
1031-
uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1);
1031+
uint64_t RawFlags =
1032+
Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1) | (Flags.Constant << 2);
10321033
return RawFlags;
10331034
}
10341035

llvm/lib/IR/AsmWriter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2901,7 +2901,8 @@ void AssemblyWriter::printAliasSummary(const AliasSummary *AS) {
29012901

29022902
void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) {
29032903
Out << ", varFlags: (readonly: " << GS->VarFlags.MaybeReadOnly << ", "
2904-
<< "writeonly: " << GS->VarFlags.MaybeWriteOnly << ")";
2904+
<< "writeonly: " << GS->VarFlags.MaybeWriteOnly << ", "
2905+
<< "constant: " << GS->VarFlags.Constant << ")";
29052906

29062907
auto VTableFuncs = GS->vTableFuncs();
29072908
if (!VTableFuncs.empty()) {

llvm/lib/IR/ModuleSummaryIndex.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ bool ModuleSummaryIndex::canImportGlobalVar(GlobalValueSummary *S,
221221
// c) Link error (external declaration with internal definition).
222222
// However we do not promote objects referenced by writeonly GV
223223
// initializer by means of converting it to 'zeroinitializer'
224-
return !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size();
224+
return !GVS->isConstant() && !isReadOnly(GVS) && !isWriteOnly(GVS) &&
225+
GVS->refs().size();
225226
};
226227
auto *GVS = cast<GlobalVarSummary>(S->getBaseObject());
227228

@@ -405,6 +406,12 @@ static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
405406
return false;
406407
}
407408

409+
static bool hasConstantFlag(const GlobalValueSummary *S) {
410+
if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
411+
return GVS->isConstant();
412+
return false;
413+
}
414+
408415
void ModuleSummaryIndex::exportToDot(
409416
raw_ostream &OS,
410417
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) const {
@@ -482,6 +489,8 @@ void ModuleSummaryIndex::exportToDot(
482489
A.addComment("immutable");
483490
if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
484491
A.addComment("writeOnly");
492+
if (Flags.Live && hasConstantFlag(SummaryIt.second))
493+
A.addComment("constant");
485494
}
486495
if (Flags.DSOLocal)
487496
A.addComment("dsoLocal");

llvm/test/Assembler/thinlto-summary.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@
7676
; CHECK: ^8 = gv: (guid: 7, summaries: (function: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1)))
7777
; CHECK: ^9 = gv: (guid: 8, summaries: (function: (module: ^0, flags: (linkage: weak_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 1), insts: 1)))
7878
; CHECK: ^10 = gv: (guid: 9, summaries: (function: (module: ^0, flags: (linkage: weak, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1)))
79-
; CHECK: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0))))
80-
; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^4))))
81-
; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0))))
82-
; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0))))
79+
; CHECK: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0))))
80+
; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0), refs: (^4))))
81+
; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0, constant: 0))))
82+
; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0))))
8383
; CHECK: ^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0))))
8484
; CHECK: ^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 1))))
8585
; CHECK: ^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 1, noRecurse: 0, returnDoesNotAlias: 1, noInline: 0, alwaysInline: 0), calls: ((callee: ^15)))))

llvm/test/Assembler/thinlto-vtable-summary.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ declare i32 @_ZN1C1fEi(%struct.C*, i32)
2929

3030
^0 = module: (path: "<stdin>", hash: (0, 0, 0, 0, 0))
3131
^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257
32-
^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367
32+
^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367
3333
^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394
34-
^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
34+
^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
3535
^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556
3636
^6 = typeidCompatibleVTable: (name: "_ZTS1A", summary: ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778
3737
^7 = typeidCompatibleVTable: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid = 6203814149063363976

llvm/test/Bitcode/thinlto-function-summary-refgraph.ll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ target triple = "x86_64-unknown-linux-gnu"
7373

7474
@bar = global void (...)* bitcast (void ()* @func to void (...)*), align 8
7575

76-
@globalvar = global i32 0, align 4
76+
@globalvar = constant i32 0, align 4
7777

7878
declare void @func() #0
7979
declare i32 @func2(...) #1
@@ -154,11 +154,12 @@ entry:
154154
; DIS-DAG: = gv: (name: "foo") ; guid = 6699318081062747564
155155
; DIS-DAG: = gv: (name: "func") ; guid = 7289175272376759421
156156
; DIS-DAG: = gv: (name: "func3") ; guid = 11517462787082255043
157-
; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid = 12887606300320728018
157+
; Check that default value of writeonly attribute is zero for constant variables
158+
; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0, constant: 1)))) ; guid = 12887606300320728018
158159
; DIS-DAG: = gv: (name: "func2") ; guid = 14069196320850861797
159160
; DIS-DAG: = gv: (name: "llvm.ctpop.i8") ; guid = 15254915475081819833
160161
; DIS-DAG: = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 9, calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 15822663052811949562
161-
; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1), refs: (^{{.*}})))) ; guid = 16434608426314478903
162+
; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0), refs: (^{{.*}})))) ; guid = 16434608426314478903
162163
; Don't try to match the exact GUID. Since it is private, the file path
163164
; will get hashed, and that will be test dependent.
164165
; DIS-DAG: = gv: (name: "Y", summaries: (function: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 14, calls: ((callee: ^{{.*}}))))) ; guid =

llvm/test/ThinLTO/X86/Inputs/dot-dumper.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
22
target triple = "x86_64-unknown-linux-gnu"
33

44
@A = local_unnamed_addr global i32 10, align 4
5-
@B = local_unnamed_addr global i32 20, align 4
5+
@B = local_unnamed_addr constant i32 20, align 4
66

77
; Function Attrs: norecurse nounwind readonly uwtable
88
define i32 @foo() local_unnamed_addr #0 {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64-unknown-linux-gnu"
3+
4+
%struct.S = type { i32, i32, i32* }
5+
%struct.Q = type { %struct.S* }
6+
7+
@val = dso_local global i32 42, align 4
8+
@_ZL3Obj = internal constant %struct.S { i32 4, i32 8, i32* @val }, align 8
9+
@outer = dso_local local_unnamed_addr global %struct.Q { %struct.S* @_ZL3Obj }, align 8
10+
11+
define dso_local nonnull %struct.S* @_Z6getObjv() local_unnamed_addr {
12+
entry:
13+
store %struct.S* null, %struct.S** getelementptr inbounds (%struct.Q, %struct.Q* @outer, i64 0, i32 0), align 8
14+
ret %struct.S* @_ZL3Obj
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
source_filename = "bar.c"
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
@foo = external dso_local local_unnamed_addr constant i32, align 4
6+
define dso_local i32 @_Z3barv() local_unnamed_addr {
7+
entry:
8+
%0 = load i32, i32* @foo, align 4
9+
ret i32 %0
10+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
source_filename = "foo.c"
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
@foo = dso_local local_unnamed_addr constant i32 21, align 4

llvm/test/ThinLTO/X86/dot-dumper.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
; COMBINED-NEXT: node [style=filled,fillcolor=lightblue];
5353
; COMBINED-NEXT: M1_[[FOO:[0-9]+]] [shape="record",label="foo|extern (inst: 4, ffl: 000010)}"]; // function
5454
; COMBINED-NEXT: M1_[[A:[0-9]+]] [shape="Mrecord",label="A|extern}"]; // variable, immutable
55-
; COMBINED-NEXT: M1_[[B:[0-9]+]] [shape="Mrecord",label="B|extern}"]; // variable, immutable
55+
; COMBINED-NEXT: M1_[[B:[0-9]+]] [shape="Mrecord",label="B|extern}"]; // variable, immutable, constant
5656
; COMBINED-NEXT: M1_{{[0-9]+}} [shape="record",label="bar|extern (inst: 1, ffl: 000000)}",fillcolor="red"]; // function, dead
5757
; COMBINED-NEXT: // Edges:
5858
; COMBINED-NEXT: M1_[[FOO]] -> M1_[[B]] [style=dashed,color=forestgreen]; // const-ref
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; Check that we promote constant object in the source module and import it
2+
; even when it is referenced in some other GV initializer and/or is used
3+
; by store instructions.
4+
; RUN: opt -thinlto-bc %s -o %t1.bc
5+
; RUN: opt -thinlto-bc %p/Inputs/import-constant.ll -o %t2.bc
6+
; RUN: llvm-lto2 run -save-temps %t1.bc %t2.bc -o %t-out \
7+
; RUN: -r=%t1.bc,main,plx \
8+
; RUN: -r=%t1.bc,_Z6getObjv,l \
9+
; RUN: -r=%t2.bc,_Z6getObjv,pl \
10+
; RUN: -r=%t2.bc,val,pl \
11+
; RUN: -r=%t2.bc,outer,pl
12+
; RUN: llvm-dis %t-out.2.1.promote.bc -o - | FileCheck %s --check-prefix=PROMOTE
13+
; RUN: llvm-dis %t-out.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
14+
; RUN: llvm-dis %t-out.1.4.opt.bc -o - | FileCheck %s --check-prefix=OPT
15+
16+
; Check that variable has been promoted in the source module
17+
; PROMOTE: @_ZL3Obj.llvm.{{.*}} = hidden constant %struct.S { i32 4, i32 8, i32* @val }
18+
19+
; @outer is a write-only variable, so it's been converted to zeroinitializer.
20+
; IMPORT: @outer = internal local_unnamed_addr global %struct.Q zeroinitializer
21+
; IMPORT-NEXT: @_ZL3Obj.llvm.{{.*}} = available_externally hidden constant %struct.S { i32 4, i32 8, i32* @val }
22+
; IMPORT-NEXT: @val = external dso_local global i32
23+
24+
; OPT: @outer = internal unnamed_addr global %struct.Q zeroinitializer
25+
26+
; OPT: define dso_local i32 @main()
27+
; OPT-NEXT: entry:
28+
; OPT-NEXT: store %struct.S* null, %struct.S** getelementptr inbounds (%struct.Q, %struct.Q* @outer, i64 0, i32 0)
29+
; OPT-NEXT: ret i32 12
30+
31+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
32+
target triple = "x86_64-unknown-linux-gnu"
33+
34+
%struct.S = type { i32, i32, i32* }
35+
36+
define dso_local i32 @main() local_unnamed_addr {
37+
entry:
38+
%call = tail call %struct.S* @_Z6getObjv()
39+
%d = getelementptr inbounds %struct.S, %struct.S* %call, i64 0, i32 0
40+
%0 = load i32, i32* %d, align 8
41+
%v = getelementptr inbounds %struct.S, %struct.S* %call, i64 0, i32 1
42+
%1 = load i32, i32* %v, align 4
43+
%add = add nsw i32 %1, %0
44+
ret i32 %add
45+
}
46+
47+
declare dso_local %struct.S* @_Z6getObjv() local_unnamed_addr

0 commit comments

Comments
 (0)