Skip to content

Commit 5a7ec5d

Browse files
author
Harlan Haskins
committed
---
yaml --- r: 349211 b: refs/heads/master-next c: b904133 h: refs/heads/master i: 349209: 6df1602 349207: 6035203
1 parent b24c964 commit 5a7ec5d

23 files changed

+526
-6
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: 77333085fb22f1daf7e0b1fe0434f7a9d33961b5
3+
refs/heads/master-next: b904133c42266035d688dec215138c340efb3eed
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/include/swift/AST/Decl.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5689,7 +5689,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56895689
/// Note that a true return value does not imply that the body was actually
56905690
/// parsed.
56915691
bool hasBody() const {
5692-
return getBodyKind() != BodyKind::None;
5692+
return getBodyKind() != BodyKind::None &&
5693+
getBodyKind() != BodyKind::Skipped;
56935694
}
56945695

56955696
/// Returns true if the text of this function's body can be retrieved either
@@ -5716,14 +5717,22 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
57165717
/// Note that the body was skipped for this function. Function body
57175718
/// cannot be attached after this call.
57185719
void setBodySkipped(SourceRange bodyRange) {
5719-
assert(getBodyKind() == BodyKind::None);
5720+
// FIXME: Remove 'Parsed' from this once we can delay parsing function
5721+
// bodies. Right now -experimental-skip-non-inlinable-function-bodies
5722+
// requires being able to change the state from Parsed to Skipped,
5723+
// because we're still eagerly parsing function bodies.
5724+
assert(getBodyKind() == BodyKind::None ||
5725+
getBodyKind() == BodyKind::Unparsed ||
5726+
getBodyKind() == BodyKind::Parsed);
5727+
assert(bodyRange.isValid());
57205728
BodyRange = bodyRange;
57215729
setBodyKind(BodyKind::Skipped);
57225730
}
57235731

57245732
/// Note that parsing for the body was delayed.
57255733
void setBodyDelayed(SourceRange bodyRange) {
57265734
assert(getBodyKind() == BodyKind::None);
5735+
assert(bodyRange.isValid());
57275736
BodyRange = bodyRange;
57285737
setBodyKind(BodyKind::Unparsed);
57295738
}
@@ -5769,6 +5778,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
57695778
return getBodyKind() == BodyKind::TypeChecked;
57705779
}
57715780

5781+
bool isBodySkipped() const {
5782+
return getBodyKind() == BodyKind::Skipped;
5783+
}
5784+
57725785
bool isMemberwiseInitializer() const {
57735786
return getBodyKind() == BodyKind::MemberwiseInitializer;
57745787
}

branches/master-next/include/swift/AST/DeclContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,15 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
409409
const_cast<DeclContext *>(this)->getInnermostDeclarationDeclContext();
410410
}
411411

412+
/// Returns the innermost context that is an AbstractFunctionDecl whose
413+
/// body has been skipped.
414+
LLVM_READONLY
415+
DeclContext *getInnermostSkippedFunctionContext();
416+
const DeclContext *getInnermostSkippedFunctionContext() const {
417+
return
418+
const_cast<DeclContext *>(this)->getInnermostSkippedFunctionContext();
419+
}
420+
412421
/// Returns the semantic parent of this context. A context has a
413422
/// parent if and only if it is not a module context.
414423
DeclContext *getParent() const {

branches/master-next/include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ ERROR(error_mode_cannot_emit_module_source_info,none,
128128
"this mode does not support emitting module source info files", ())
129129
ERROR(error_mode_cannot_emit_interface,none,
130130
"this mode does not support emitting module interface files", ())
131+
ERROR(cannot_emit_ir_skipping_function_bodies,none,
132+
"-experimental-skip-non-inlinable-function-bodies does not support "
133+
"emitting IR", ())
131134

132135
WARNING(emit_reference_dependencies_without_primary_file,none,
133136
"ignoring -emit-reference-dependencies (requires -primary-file)", ())

branches/master-next/include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class SILOptions {
7070
/// Whether to stop the optimization pipeline after serializing SIL.
7171
bool StopOptimizationAfterSerialization = false;
7272

73+
/// Whether to skip emitting non-inlinable function bodies.
74+
bool SkipNonInlinableFunctionBodies = false;
75+
7376
/// Optimization mode being used.
7477
OptimizationMode OptMode = OptimizationMode::NotSet;
7578

branches/master-next/include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class FrontendOptions {
180180
/// \sa swift::SharedTimer
181181
bool DebugTimeCompilation = false;
182182

183+
bool SkipNonInlinableFunctionBodies = false;
184+
183185
/// The path to which we should output statistics files.
184186
std::string StatsOutputDir;
185187

@@ -339,6 +341,7 @@ class FrontendOptions {
339341

340342
public:
341343
static bool doesActionGenerateSIL(ActionType);
344+
static bool doesActionGenerateIR(ActionType);
342345
static bool doesActionProduceOutput(ActionType);
343346
static bool doesActionProduceTextualOutput(ActionType);
344347
static bool needsProperModuleName(ActionType);

branches/master-next/include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ def stats_output_dir: Separate<["-"], "stats-output-dir">,
254254
def trace_stats_events: Flag<["-"], "trace-stats-events">,
255255
Flags<[FrontendOption, HelpHidden]>,
256256
HelpText<"Trace changes to stats in -stats-output-dir">;
257+
def experimental_skip_non_inlinable_function_bodies:
258+
Flag<["-"], "experimental-skip-non-inlinable-function-bodies">,
259+
Flags<[FrontendOption, HelpHidden]>,
260+
HelpText<"Skip type-checking and SIL generation for non-inlinable function bodies">;
257261
def profile_stats_events: Flag<["-"], "profile-stats-events">,
258262
Flags<[FrontendOption, HelpHidden]>,
259263
HelpText<"Profile changes to stats in -stats-output-dir">;

branches/master-next/include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ PASS(SimplifyUnreachableContainingBlocks, "simplify-unreachable-containing-block
311311
"Utility pass. Removes all non-term insts from blocks with unreachable terms")
312312
PASS(SerializeSILPass, "serialize-sil",
313313
"Utility pass. Serializes the current SILModule")
314+
PASS(NonInlinableFunctionSkippingChecker, "check-non-inlinable-function-skipping",
315+
"Utility pass to ensure -experimental-skip-non-inlinable-function-bodies "
316+
"skips everything it should")
314317
PASS(YieldOnceCheck, "yield-once-check",
315318
"Check correct usage of yields in yield-once coroutines")
316319
PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls")

branches/master-next/include/swift/Subsystems.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ namespace swift {
187187
/// If set, dumps wall time taken to type check each expression to
188188
/// llvm::errs().
189189
DebugTimeExpressions = 1 << 3,
190+
191+
/// If set, the typechecker will skip typechecking non-inlinable function
192+
/// bodies. Set this if you're trying to quickly emit a module or module
193+
/// interface without a full compilation.
194+
SkipNonInlinableFunctionBodies = 1 << 4,
190195
};
191196

192197
/// Once parsing and name-binding are complete, this walks the AST to resolve

branches/master-next/lib/AST/DeclContext.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,17 @@ Decl *DeclContext::getInnermostDeclarationDeclContext() {
231231
return nullptr;
232232
}
233233

234+
DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
235+
auto dc = this;
236+
do {
237+
if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
238+
if (afd->isBodySkipped())
239+
return afd;
240+
} while ((dc = dc->getParent()));
241+
242+
return nullptr;
243+
}
244+
234245
DeclContext *DeclContext::getParentForLookup() const {
235246
if (isa<ProtocolDecl>(this) || isa<ExtensionDecl>(this)) {
236247
// If we are inside a protocol or an extension, skip directly

branches/master-next/lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ bool ArgsToFrontendOptionsConverter::convert(
161161
if (checkUnusedSupplementaryOutputPaths())
162162
return true;
163163

164+
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction)
165+
&& Opts.SkipNonInlinableFunctionBodies) {
166+
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
167+
return true;
168+
}
169+
164170
if (const Arg *A = Args.getLastArg(OPT_module_link_name))
165171
Opts.ModuleLinkName = A->getValue();
166172

@@ -219,6 +225,8 @@ void ArgsToFrontendOptionsConverter::computeDebugTimeOptions() {
219225
Opts.DebugTimeExpressionTypeChecking |=
220226
Args.hasArg(OPT_debug_time_expression_type_checking);
221227
Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation);
228+
Opts.SkipNonInlinableFunctionBodies |=
229+
Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies);
222230
if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) {
223231
Opts.StatsOutputDir = A->getValue();
224232
if (Args.getLastArg(OPT_trace_stats_events)) {

branches/master-next/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
763763
if (Args.hasArg(OPT_sil_merge_partial_modules))
764764
Opts.MergePartialModules = true;
765765

766+
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies))
767+
Opts.SkipNonInlinableFunctionBodies = true;
768+
766769
// Parse the optimization level.
767770
// Default to Onone settings if no option is passed.
768771
Opts.OptMode = OptimizationMode::NoOptimization;

branches/master-next/lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,9 @@ OptionSet<TypeCheckingFlags> CompilerInstance::computeTypeCheckingOptions() {
886886
if (options.DebugTimeExpressionTypeChecking) {
887887
TypeCheckOptions |= TypeCheckingFlags::DebugTimeExpressions;
888888
}
889+
if (options.SkipNonInlinableFunctionBodies) {
890+
TypeCheckOptions |= TypeCheckingFlags::SkipNonInlinableFunctionBodies;
891+
}
889892
return TypeCheckOptions;
890893
}
891894

branches/master-next/lib/Frontend/FrontendOptions.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,41 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) {
520520
llvm_unreachable("unhandled action");
521521
}
522522

523+
bool FrontendOptions::doesActionGenerateIR(ActionType action) {
524+
switch (action) {
525+
case ActionType::NoneAction:
526+
case ActionType::Parse:
527+
case ActionType::DumpParse:
528+
case ActionType::DumpInterfaceHash:
529+
case ActionType::DumpAST:
530+
case ActionType::EmitSyntax:
531+
case ActionType::PrintAST:
532+
case ActionType::DumpScopeMaps:
533+
case ActionType::DumpTypeRefinementContexts:
534+
case ActionType::DumpTypeInfo:
535+
case ActionType::CompileModuleFromInterface:
536+
case ActionType::Typecheck:
537+
case ActionType::ResolveImports:
538+
case ActionType::MergeModules:
539+
case ActionType::EmitModuleOnly:
540+
case ActionType::EmitPCH:
541+
case ActionType::EmitSILGen:
542+
case ActionType::EmitSIL:
543+
case ActionType::EmitSIBGen:
544+
case ActionType::EmitSIB:
545+
case ActionType::EmitImportedModules:
546+
return false;
547+
case ActionType::Immediate:
548+
case ActionType::REPL:
549+
case ActionType::EmitIR:
550+
case ActionType::EmitBC:
551+
case ActionType::EmitAssembly:
552+
case ActionType::EmitObject:
553+
return true;
554+
}
555+
llvm_unreachable("unhandled action");
556+
}
557+
523558

524559
const PrimarySpecificPaths &
525560
FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const {

branches/master-next/lib/SILGen/SILGen.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,9 +1669,13 @@ void SILGenModule::emitSourceFile(SourceFile *sf) {
16691669
visit(D);
16701670
}
16711671

1672-
for (Decl *D : sf->LocalTypeDecls) {
1673-
FrontendStatsTracer StatsTracer(getASTContext().Stats, "SILgen-tydecl", D);
1674-
visit(D);
1672+
for (TypeDecl *TD : sf->LocalTypeDecls) {
1673+
FrontendStatsTracer StatsTracer(getASTContext().Stats, "SILgen-tydecl", TD);
1674+
// FIXME: Delayed parsing would prevent these types from being added to the
1675+
// module in the first place.
1676+
if (TD->getDeclContext()->getInnermostSkippedFunctionContext())
1677+
continue;
1678+
visit(TD);
16751679
}
16761680
}
16771681

branches/master-next/lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ static void addMandatoryOptPipeline(SILPassPipelinePlan &P) {
102102
// there.
103103
const auto &Options = P.getOptions();
104104
P.addClosureLifetimeFixup();
105+
106+
#ifndef NDEBUG
107+
// Add a verification pass to check our work when skipping non-inlinable
108+
// function bodies.
109+
if (Options.SkipNonInlinableFunctionBodies)
110+
P.addNonInlinableFunctionSkippingChecker();
111+
#endif
112+
105113
if (Options.shouldOptimize()) {
106114
P.addSemanticARCOpts();
107115
P.addDestroyHoisting();

branches/master-next/lib/SILOptimizer/UtilityPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ silopt_register_sources(
77
BugReducerTester.cpp
88
CFGPrinter.cpp
99
CallerAnalysisPrinter.cpp
10+
NonInlinableFunctionSkippingChecker.cpp
1011
ComputeDominanceInfo.cpp
1112
ComputeLoopInfo.cpp
1213
ConstantEvaluatorTester.cpp
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===------------- NonInlinableFunctionSkippingChecker.cpp ----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Basic/LLVM.h"
14+
#include "swift/SIL/SILFunction.h"
15+
#include "swift/SIL/SILInstruction.h"
16+
#include "swift/SIL/SILModule.h"
17+
#include "swift/SILOptimizer/PassManager/Transforms.h"
18+
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/Support/raw_ostream.h"
20+
21+
using namespace swift;
22+
23+
/// Determines whether we should have skipped SILGenning a function that
24+
/// appears in a SILModule. This only applies when
25+
/// \c -experimental-skip-non-inlinable-function-bodies is enabled.
26+
static bool shouldHaveSkippedFunction(const SILFunction &F) {
27+
assert(F.getModule().getOptions().SkipNonInlinableFunctionBodies &&
28+
"this check only makes sense if we're skipping function bodies");
29+
30+
// First, we only care about functions that haven't been marked serialized.
31+
// If they've been marked serialized, they will end up in the final module
32+
// and we needed to SILGen them.
33+
if (F.isSerialized())
34+
return false;
35+
36+
// Next, we're looking for functions that shouldn't have a body, but do. If
37+
// the function doesn't have a body (i.e. it's an external declaration), we
38+
// skipped it successfully.
39+
if (F.isExternalDeclaration())
40+
return false;
41+
42+
// Thunks and specializations are automatically synthesized, so it's fine that
43+
// they end up in the module.
44+
if (F.isThunk() || F.isSpecialization())
45+
return false;
46+
47+
// FIXME: We can probably skip property initializers, too.
48+
auto func = F.getLocation().getAsASTNode<AbstractFunctionDecl>();
49+
if (!func)
50+
return false;
51+
52+
// If a body is synthesized/implicit, it shouldn't be skipped.
53+
if (func->isImplicit())
54+
return false;
55+
56+
// Local function bodies in inlinable code are okay to show up in the module.
57+
if (func->getDeclContext()->isLocalContext())
58+
return false;
59+
60+
// FIXME: Identify __ivar_destroyer, __allocating_init, and
61+
// __deallocating_deinit, which have no special marking, are always
62+
// emitted, and do have a source location with the original decl
63+
// attached.
64+
if (isa<DestructorDecl>(func) || isa<ConstructorDecl>(func))
65+
return false;
66+
67+
// If none of those conditions trip, then this is something that _should_
68+
// be serialized in the module even when we're skipping non-inlinable
69+
// function bodies.
70+
return true;
71+
}
72+
73+
namespace {
74+
75+
/// This is a verification utility pass that's meant to be used with
76+
/// \c -experimental-skip-non-inlinable-function-bodies. It checks all the
77+
/// functions in a module and ensures that, if the function was written in
78+
/// source and not serialized, then it wasn't even SILGen'd.
79+
class NonInlinableFunctionSkippingChecker : public SILModuleTransform {
80+
void run() override {
81+
// Skip this if we're not skipping function bodies
82+
if (!getModule()->getOptions().SkipNonInlinableFunctionBodies)
83+
return;
84+
85+
// Skip this verification for SwiftOnoneSupport
86+
if (getModule()->isOptimizedOnoneSupportModule())
87+
return;
88+
89+
for (auto &F : *getModule()) {
90+
if (!shouldHaveSkippedFunction(F))
91+
continue;
92+
93+
llvm::dbgs() << "Function serialized that should have been skipped!\n";
94+
F.getLocation().dump(F.getModule().getSourceManager());
95+
llvm::dbgs() << "\n";
96+
F.dump();
97+
abort();
98+
}
99+
}
100+
101+
};
102+
103+
} // end anonymous namespace
104+
105+
SILTransform *swift::createNonInlinableFunctionSkippingChecker() {
106+
return new NonInlinableFunctionSkippingChecker();
107+
}

0 commit comments

Comments
 (0)