Skip to content

Commit 4ffe726

Browse files
committed
Merge branch 'master' of github.com:swiftwasm/swift into maxd/master-merge
# Conflicts: # test/lit.cfg
2 parents b80daa1 + 451fd09 commit 4ffe726

20 files changed

+387
-70
lines changed

cmake/modules/AddSwiftUnittests.cmake

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ function(add_swift_unittest test_dirname)
5757
_ENABLE_EXTENDED_ALIGNED_STORAGE)
5858
endif()
5959

60-
if(SWIFT_USE_LINKER)
61-
set_property(TARGET "${test_dirname}" APPEND_STRING PROPERTY
62-
LINK_FLAGS " -fuse-ld=${SWIFT_USE_LINKER}")
60+
if(NOT SWIFT_COMPILER_IS_MSVC_LIKE)
61+
if(SWIFT_USE_LINKER)
62+
target_link_options(${test_dirname} PRIVATE
63+
-fuse-ld=${SWIFT_USE_LINKER}$<$<STREQUAL:${CMAKE_HOST_SYSTEM_NAME},Windows>:.exe>)
64+
endif()
6365
endif()
6466

6567
if(SWIFT_ANALYZE_CODE_COVERAGE)

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/SIL/IR/SILPrinter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2701,7 +2701,9 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const {
27012701
printClangQualifiedNameCommentIfPresent(OS, getClangDecl());
27022702

27032703
OS << "sil_global ";
2704-
printLinkage(OS, getLinkage(), isDefinition());
2704+
// Passing true for 'isDefinition' lets print the (external) linkage if it's
2705+
// not a definition.
2706+
printLinkage(OS, getLinkage(), /*isDefinition*/ true);
27052707

27062708
if (isSerialized())
27072709
OS << "[serialized] ";

lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@
2323
#include "swift/SILOptimizer/PassManager/Passes.h"
2424
#include "swift/SILOptimizer/PassManager/Transforms.h"
2525
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
26+
#include "swift/SILOptimizer/Utils/SILInliner.h"
2627
#include "llvm/Support/CommandLine.h"
2728
#include "llvm/Support/Debug.h"
2829

2930
using namespace swift;
3031

32+
/// Functions up to this (abstract) size are serialized, even if they are not
33+
/// generic.
34+
static llvm::cl::opt<int> CMOFunctionSizeLimit("cmo-function-size-limit",
35+
llvm::cl::init(20));
36+
3137
namespace {
3238

3339
/// Scans a whole module and marks functions and types as inlinable or usable
@@ -54,6 +60,8 @@ class CrossModuleSerializationSetup {
5460

5561
bool canSerialize(SILFunction *F, bool lookIntoThunks);
5662

63+
bool canSerialize(SILInstruction *inst, bool lookIntoThunks);
64+
5765
void setUpForSerialization(SILFunction *F);
5866

5967
void prepareInstructionForSerialization(SILInstruction *inst);
@@ -193,18 +201,31 @@ static llvm::cl::opt<bool> SerializeEverything(
193201

194202
/// Decide whether to serialize a function.
195203
static bool shouldSerialize(SILFunction *F) {
196-
// The basic heursitic: serialize all generic functions, because it makes a
197-
// huge difference if generic functions can be specialized or not.
198-
if (!F->getLoweredFunctionType()->isPolymorphic() && !SerializeEverything)
199-
return false;
200-
201204
// Check if we already handled this function before.
202205
if (F->isSerialized() == IsSerialized)
203206
return false;
204207

205208
if (F->hasSemanticsAttr("optimize.no.crossmodule"))
206209
return false;
207210

211+
if (SerializeEverything)
212+
return true;
213+
214+
// The basic heursitic: serialize all generic functions, because it makes a
215+
// huge difference if generic functions can be specialized or not.
216+
if (F->getLoweredFunctionType()->isPolymorphic())
217+
return true;
218+
219+
// Also serialize "small" non-generic functions.
220+
int size = 0;
221+
for (SILBasicBlock &block : *F) {
222+
for (SILInstruction &inst : block) {
223+
size += (int)instructionInlineCost(inst);
224+
if (size >= CMOFunctionSizeLimit)
225+
return false;
226+
}
227+
}
228+
208229
return true;
209230
}
210231

@@ -227,6 +248,11 @@ prepareInstructionForSerialization(SILInstruction *inst) {
227248
handleReferencedFunction(callee);
228249
return;
229250
}
251+
if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
252+
GAI->getReferencedGlobal()->setSerialized(IsSerialized);
253+
GAI->getReferencedGlobal()->setLinkage(SILLinkage::Public);
254+
return;
255+
}
230256
if (auto *MI = dyn_cast<MethodInst>(inst)) {
231257
handleReferencedMethod(MI->getMember());
232258
return;
@@ -285,26 +311,42 @@ bool CrossModuleSerializationSetup::canSerialize(SILFunction *F,
285311
// First step: check if serializing F is even possible.
286312
for (SILBasicBlock &block : *F) {
287313
for (SILInstruction &inst : block) {
288-
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(&inst)) {
289-
SILFunction *callee = FRI->getReferencedFunctionOrNull();
290-
if (!canUseFromInline(callee, lookIntoThunks))
291-
return false;
292-
} else if (auto *KPI = dyn_cast<KeyPathInst>(&inst)) {
293-
bool canUse = true;
294-
KPI->getPattern()->visitReferencedFunctionsAndMethods(
295-
[&](SILFunction *func) {
296-
if (!canUseFromInline(func, lookIntoThunks))
297-
canUse = false;
298-
},
299-
[](SILDeclRef method) { });
300-
if (!canUse)
301-
return false;
302-
}
314+
if (!canSerialize(&inst, lookIntoThunks))
315+
return false;
303316
}
304317
}
305318
return true;
306319
}
307320

321+
bool CrossModuleSerializationSetup::canSerialize(SILInstruction *inst,
322+
bool lookIntoThunks) {
323+
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(inst)) {
324+
SILFunction *callee = FRI->getReferencedFunctionOrNull();
325+
return canUseFromInline(callee, lookIntoThunks);
326+
}
327+
if (auto *KPI = dyn_cast<KeyPathInst>(inst)) {
328+
bool canUse = true;
329+
KPI->getPattern()->visitReferencedFunctionsAndMethods(
330+
[&](SILFunction *func) {
331+
if (!canUseFromInline(func, lookIntoThunks))
332+
canUse = false;
333+
},
334+
[&](SILDeclRef method) {
335+
if (method.isForeign)
336+
canUse = false;
337+
});
338+
return canUse;
339+
}
340+
if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
341+
return !GAI->getReferencedGlobal()->getName().startswith("globalinit_");
342+
}
343+
if (auto *MI = dyn_cast<MethodInst>(inst)) {
344+
return !MI->getMember().isForeign;
345+
}
346+
347+
return true;
348+
}
349+
308350
/// Returns true if the function \p func can be used from a serialized function.
309351
///
310352
/// If \p lookIntoThunks is true, serializable shared thunks are also accepted.
@@ -351,12 +393,17 @@ void CrossModuleSerializationSetup::setUpForSerialization(SILFunction *F) {
351393
}
352394
F->setSerialized(IsSerialized);
353395

354-
// As a code size optimization, make serialized functions
355-
// @alwaysEmitIntoClient.
356-
// Also, for shared thunks it's required to make them @alwaysEmitIntoClient.
357-
// SILLinkage::Public would not work for shared functions, because it could
358-
// result in duplicate-symbol linker errors.
359-
F->setLinkage(SILLinkage::PublicNonABI);
396+
if (F->getLoweredFunctionType()->isPolymorphic() ||
397+
F->getLinkage() != SILLinkage::Public) {
398+
// As a code size optimization, make serialized functions
399+
// @alwaysEmitIntoClient.
400+
// Also, for shared thunks it's required to make them @alwaysEmitIntoClient.
401+
// SILLinkage::Public would not work for shared functions, because it could
402+
// result in duplicate-symbol linker errors.
403+
F->setLinkage(SILLinkage::PublicNonABI);
404+
} else {
405+
F->setLinkage(SILLinkage::Public);
406+
}
360407
}
361408

362409
/// Select functions in the module which should be serialized.

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,10 @@ static void addPerfEarlyModulePassPipeline(SILPassPipelinePlan &P) {
447447
// is linked in from the stdlib.
448448
P.addTempRValueOpt();
449449

450+
// Needed to serialize static initializers of globals for cross-module
451+
// optimization.
452+
P.addGlobalOpt();
453+
450454
// Add the outliner pass (Osize).
451455
P.addOutliner();
452456

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
2727
#include "swift/SILOptimizer/Utils/Devirtualize.h"
2828
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
29+
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
2930
#include "llvm/ADT/DenseMap.h"
3031
#include "llvm/ADT/SmallPtrSet.h"
3132
#include "llvm/ADT/SmallVector.h"
@@ -807,6 +808,31 @@ static bool isZeroLoadFromEmptyCollection(LoadInst *LI) {
807808
}
808809
}
809810

811+
static SingleValueInstruction *getValueFromStaticLet(SILValue v) {
812+
if (auto *globalAddr = dyn_cast<GlobalAddrInst>(v)) {
813+
SILGlobalVariable *global = globalAddr->getReferencedGlobal();
814+
if (!global->isLet())
815+
return nullptr;
816+
return dyn_cast_or_null<SingleValueInstruction>(
817+
global->getStaticInitializerValue());
818+
}
819+
if (auto *seai = dyn_cast<StructElementAddrInst>(v)) {
820+
auto *structVal = getValueFromStaticLet(seai->getOperand());
821+
if (!structVal)
822+
return nullptr;
823+
return cast<SingleValueInstruction>(
824+
cast<StructInst>(structVal)->getOperandForField(seai->getField())->get());
825+
}
826+
if (auto *teai = dyn_cast<TupleElementAddrInst>(v)) {
827+
auto *tupleVal = getValueFromStaticLet(teai->getOperand());
828+
if (!tupleVal)
829+
return nullptr;
830+
return cast<SingleValueInstruction>(
831+
cast<TupleInst>(tupleVal)->getElement(teai->getFieldNo()));
832+
}
833+
return nullptr;
834+
}
835+
810836
SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) {
811837
if (LI->getFunction()->hasOwnership())
812838
return nullptr;
@@ -833,6 +859,15 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) {
833859
if (isZeroLoadFromEmptyCollection(LI))
834860
return Builder.createIntegerLiteral(LI->getLoc(), LI->getType(), 0);
835861

862+
// Propagate a value from a static "let" global variable.
863+
// This optimization is also done by GlobalOpt, but not with de-serialized
864+
// globals, which can occur with cross-module optimization.
865+
if (SingleValueInstruction *initVal = getValueFromStaticLet(LI->getOperand())) {
866+
StaticInitCloner cloner(LI);
867+
cloner.add(initVal);
868+
return cloner.clone(initVal);
869+
}
870+
836871
return nullptr;
837872
}
838873

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);

0 commit comments

Comments
 (0)