Skip to content

Commit fce7fdc

Browse files
committed
SIL: serialization of initializers of global variables.
This is needed for cross-module optimization: it enables constant folding of global let variables which are defined in another module.
1 parent fc3e68a commit fce7fdc

File tree

6 files changed

+145
-15
lines changed

6 files changed

+145
-15
lines changed

include/swift/SIL/SILGlobalVariable.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class SILGlobalVariable
3737
: public llvm::ilist_node<SILGlobalVariable>,
3838
public SILAllocated<SILGlobalVariable>
3939
{
40+
public:
41+
using const_iterator = SILBasicBlock::const_iterator;
42+
4043
private:
4144
friend class SILModule;
4245
friend class SILBuilder;
@@ -157,6 +160,9 @@ class SILGlobalVariable
157160
return dyn_cast_or_null<ObjectInst>(getStaticInitializerValue()) != nullptr;
158161
}
159162

163+
const_iterator begin() const { return StaticInitializerBlock.begin(); }
164+
const_iterator end() const { return StaticInitializerBlock.end(); }
165+
160166
/// Returns true if \p I is a valid instruction to be contained in the
161167
/// static initializer.
162168
static bool isValidStaticInitializerInst(const SILInstruction *I,

lib/Serialization/DeserializeSIL.cpp

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -799,9 +799,10 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
799799
// occurred and this is a declaration. Work around that for now.
800800
if (!CurrentBB)
801801
return fn;
802+
Builder.setInsertionPoint(CurrentBB);
802803

803804
// Handle a SILInstruction record.
804-
if (readSILInstruction(fn, CurrentBB, Builder, kind, scratch)) {
805+
if (readSILInstruction(fn, Builder, kind, scratch)) {
805806
LLVM_DEBUG(llvm::dbgs() << "readSILInstruction returns error.\n");
806807
MF->fatal();
807808
}
@@ -1031,16 +1032,12 @@ SILDeserializer::readKeyPathComponent(ArrayRef<uint64_t> ListOfValues,
10311032
llvm_unreachable("invalid key path component kind encoding");
10321033
}
10331034

1034-
bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
1035+
bool SILDeserializer::readSILInstruction(SILFunction *Fn,
10351036
SILBuilder &Builder,
10361037
unsigned RecordKind,
10371038
SmallVectorImpl<uint64_t> &scratch) {
1038-
// Return error if Basic Block is null.
1039-
if (!BB)
1040-
return true;
1041-
1042-
Builder.setInsertionPoint(BB);
1043-
Builder.setCurrentDebugScope(Fn->getDebugScope());
1039+
if (Fn)
1040+
Builder.setCurrentDebugScope(Fn->getDebugScope());
10441041
unsigned RawOpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0,
10451042
Attr = 0, Attr2 = 0, Attr3 = 0, Attr4 = 0, NumSubs = 0,
10461043
NumConformances = 0, IsNonThrowingApply = 0;
@@ -2096,7 +2093,22 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
20962093
break;
20972094
}
20982095
case SILInstructionKind::ObjectInst: {
2099-
llvm_unreachable("Serialization of global initializers not supported");
2096+
assert(RecordKind == SIL_ONE_TYPE_VALUES &&
2097+
"Layout should be OneTypeValues.");
2098+
unsigned NumVals = ListOfValues.size();
2099+
assert(NumVals >= 1 && "Not enough values");
2100+
unsigned numBaseElements = ListOfValues[0];
2101+
SILType ClassTy =
2102+
getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
2103+
SmallVector<SILValue, 4> elements;
2104+
for (unsigned i = 1; i < NumVals; i += 2) {
2105+
SILType elementType = getSILType(MF->getType(ListOfValues[i + 1]),
2106+
SILValueCategory::Object, Fn);
2107+
SILValue elementVal = getLocalValue(ListOfValues[i], elementType);
2108+
elements.push_back(elementVal);
2109+
}
2110+
ResultVal = Builder.createObject(Loc, ClassTy, elements, numBaseElements);
2111+
break;
21002112
}
21012113
case SILInstructionKind::BranchInst: {
21022114
SmallVector<SILValue, 4> Args;
@@ -2927,7 +2939,60 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) {
29272939
globalVarOrOffset = v;
29282940
v->setDeclaration(IsDeclaration);
29292941

2930-
if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), v);
2942+
if (Callback)
2943+
Callback->didDeserialize(MF->getAssociatedModule(), v);
2944+
2945+
scratch.clear();
2946+
maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
2947+
if (!maybeEntry)
2948+
MF->fatal(maybeEntry.takeError());
2949+
entry = maybeEntry.get();
2950+
if (entry.Kind == llvm::BitstreamEntry::EndBlock)
2951+
return v;
2952+
2953+
maybeKind = SILCursor.readRecord(entry.ID, scratch, &blobData);
2954+
if (!maybeKind)
2955+
MF->fatal(maybeKind.takeError());
2956+
kind = maybeKind.get();
2957+
2958+
SILBuilder Builder(v);
2959+
2960+
llvm::DenseMap<uint32_t, ValueBase*> SavedLocalValues;
2961+
llvm::DenseMap<uint32_t, ValueBase*> SavedForwardLocalValues;
2962+
serialization::ValueID SavedLastValueID = 1;
2963+
2964+
SavedLocalValues.swap(LocalValues);
2965+
SavedForwardLocalValues.swap(ForwardLocalValues);
2966+
std::swap(SavedLastValueID, LastValueID);
2967+
2968+
while (kind != SIL_FUNCTION && kind != SIL_VTABLE && kind != SIL_GLOBALVAR &&
2969+
kind != SIL_WITNESS_TABLE && kind != SIL_DIFFERENTIABILITY_WITNESS) {
2970+
if (readSILInstruction(nullptr, Builder, kind, scratch)) {
2971+
LLVM_DEBUG(llvm::dbgs() << "readSILInstruction returns error.\n");
2972+
MF->fatal();
2973+
}
2974+
2975+
// Fetch the next record.
2976+
scratch.clear();
2977+
llvm::Expected<llvm::BitstreamEntry> maybeEntry =
2978+
SILCursor.advance(AF_DontPopBlockAtEnd);
2979+
if (!maybeEntry)
2980+
MF->fatal(maybeEntry.takeError());
2981+
llvm::BitstreamEntry entry = maybeEntry.get();
2982+
2983+
// EndBlock means the end of this SILFunction.
2984+
if (entry.Kind == llvm::BitstreamEntry::EndBlock)
2985+
break;
2986+
maybeKind = SILCursor.readRecord(entry.ID, scratch);
2987+
if (!maybeKind)
2988+
MF->fatal(maybeKind.takeError());
2989+
kind = maybeKind.get();
2990+
}
2991+
2992+
SavedLocalValues.swap(LocalValues);
2993+
SavedForwardLocalValues.swap(ForwardLocalValues);
2994+
std::swap(SavedLastValueID, LastValueID);
2995+
29312996
return v;
29322997
}
29332998

lib/Serialization/DeserializeSIL.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ namespace swift {
9898
SILBasicBlock *readSILBasicBlock(SILFunction *Fn,
9999
SILBasicBlock *Prev,
100100
SmallVectorImpl<uint64_t> &scratch);
101-
/// Read a SIL instruction within a given SIL basic block.
102-
bool readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
101+
/// Read a SIL instruction.
102+
bool readSILInstruction(SILFunction *Fn,
103103
SILBuilder &Builder,
104104
unsigned RecordKind,
105105
SmallVectorImpl<uint64_t> &scratch);

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t SWIFTMODULE_VERSION_MINOR = 560; // SILVTable flag for non-overridden entries
58+
const uint16_t SWIFTMODULE_VERSION_MINOR = 561; // Initializers of globals.
5959

6060
/// A standard hash seed used for all string hashes in a serialized module.
6161
///

lib/Serialization/SerializeSIL.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,8 +734,26 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
734734
PrettyStackTraceSILNode stackTrace("Serializing", &SI);
735735

736736
switch (SI.getKind()) {
737-
case SILInstructionKind::ObjectInst:
738-
llvm_unreachable("static initializers of sil_global are not serialized");
737+
case SILInstructionKind::ObjectInst: {
738+
const ObjectInst *OI = cast<ObjectInst>(&SI);
739+
unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code];
740+
SmallVector<ValueID, 4> Args;
741+
Args.push_back((unsigned)OI->getBaseElements().size());
742+
for (const Operand &op : OI->getAllOperands()) {
743+
SILValue OpVal = op.get();
744+
Args.push_back(addValueRef(OpVal));
745+
SILType OpType = OpVal->getType();
746+
assert(OpType.isObject());
747+
Args.push_back(S.addTypeRef(OpType.getASTType()));
748+
}
749+
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode,
750+
(unsigned)SI.getKind(),
751+
S.addTypeRef(
752+
OI->getType().getASTType()),
753+
(unsigned)OI->getType().getCategory(),
754+
Args);
755+
break;
756+
}
739757

740758
case SILInstructionKind::DebugValueInst:
741759
case SILInstructionKind::DebugValueAddrInst:
@@ -2349,6 +2367,19 @@ void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) {
23492367
(unsigned)!g.isDefinition(),
23502368
(unsigned)g.isLet(),
23512369
TyID, dID);
2370+
2371+
ValueIDs.clear();
2372+
InstID = 0;
2373+
unsigned ValueID = 2;
2374+
for (const SILInstruction &initInst : g) {
2375+
for (auto result : initInst.getResults()) {
2376+
ValueIDs[result] = ValueID++;
2377+
}
2378+
}
2379+
2380+
for (const SILInstruction &initInst : g) {
2381+
writeSILInstruction(initInst);
2382+
}
23522383
}
23532384

23542385
void SILSerializer::writeSILVTable(const SILVTable &vt) {

test/SIL/Serialization/globals.sil

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
sil_stage canonical
66

77
import Swift
8+
import Builtin
89

910
// CHECK-NOT: sil_global hidden @hidden_global_unused
1011
sil_global hidden @hidden_global_unused : $Int
@@ -15,6 +16,17 @@ sil_global @public_global_unused : $Int
1516
// CHECK: sil_global @public_global_used
1617
sil_global @public_global_used : $Int
1718

19+
// CHECK: sil_global [serialized] @initialized_global_object : $Int64 = {
20+
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 27
21+
// CHECK-NEXT: %1 = integer_literal $Builtin.Int64, 28
22+
// CHECK-NEXT: %initval = object $GlobalObject (%0 : $Builtin.Int64, [tail_elems] %1 : $Builtin.Int64, %1 : $Builtin.Int64)
23+
// CHECK-NEXT: }
24+
sil_global [serialized] @initialized_global_object : $Int64 = {
25+
%0 = integer_literal $Builtin.Int64, 27
26+
%1 = integer_literal $Builtin.Int64, 28
27+
%initval = object $GlobalObject (%0 : $Builtin.Int64, [tail_elems] %1 : $Builtin.Int64, %1 : $Builtin.Int64)
28+
}
29+
1830
// CHECK: sil_global [serialized] @serialized_global
1931
sil_global [serialized] @serialized_global : $Int
2032

@@ -24,3 +36,19 @@ bb0:
2436
%2 = tuple ()
2537
return %2 : $()
2638
}
39+
40+
// CHECK: sil_global [serialized] @initialized_global_int : $Int64 = {
41+
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 27
42+
// CHECK-NEXT: %initval = struct $Int64 (%0 : $Builtin.Int64)
43+
// CHECK-NEXT: }
44+
sil_global [serialized] @initialized_global_int : $Int64 = {
45+
%0 = integer_literal $Builtin.Int64, 27
46+
%initval = struct $Int64 (%0 : $Builtin.Int64)
47+
}
48+
49+
class GlobalObject {
50+
@_hasStorage let e: Builtin.Int64
51+
52+
}
53+
54+

0 commit comments

Comments
 (0)