Skip to content

Commit 02c1343

Browse files
committed
[Sema] Add option to skip non-inlinable functions without types
This frontend flag can be used as an alternative to -experimental-skip-non-inlinable-function-bodies that doesn’t skip functions defining nested types. We want to keep these types as they are used by LLDB. Other functions ares safe to skip parsing and type-checking. rdar://71130519
1 parent 92d2c23 commit 02c1343

File tree

9 files changed

+116
-9
lines changed

9 files changed

+116
-9
lines changed

include/swift/AST/Decl.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ class alignas(1 << DeclAlignInBits) Decl {
391391
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
392392
StaticSpelling : 2
393393
);
394-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1,
394+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1,
395395
/// \see AbstractFunctionDecl::BodyKind
396396
BodyKind : 3,
397397

@@ -415,7 +415,11 @@ class alignas(1 << DeclAlignInBits) Decl {
415415
Synthesized : 1,
416416

417417
/// Whether this member's body consists of a single expression.
418-
HasSingleExpressionBody : 1
418+
HasSingleExpressionBody : 1,
419+
420+
/// Whether peeking into this function detected nested type declarations.
421+
/// This is set when skipping over the decl at parsing.
422+
HasNestedTypeDeclarations : 1
419423
);
420424

421425
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
@@ -5544,6 +5548,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
55445548
Bits.AbstractFunctionDecl.Throws = Throws;
55455549
Bits.AbstractFunctionDecl.Synthesized = false;
55465550
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
5551+
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false;
55475552
}
55485553

55495554
void setBodyKind(BodyKind K) {
@@ -5690,6 +5695,16 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56905695
setBody(S, BodyKind::Parsed);
56915696
}
56925697

5698+
/// Was there a nested type declaration detected when parsing this
5699+
/// function was skipped?
5700+
bool hasNestedTypeDeclarations() const {
5701+
return Bits.AbstractFunctionDecl.HasNestedTypeDeclarations;
5702+
}
5703+
5704+
void setHasNestedTypeDeclarations(bool value) {
5705+
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = value;
5706+
}
5707+
56935708
/// Note that parsing for the body was delayed.
56945709
///
56955710
/// The function should return the body statement and a flag indicating

include/swift/Basic/FunctionBodySkipping.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ enum class FunctionBodySkipping : uint8_t {
2323
None,
2424
/// Only non-inlinable function bodies should be skipped.
2525
NonInlinable,
26+
/// Only non-inlinable functions bodies without type definitions should
27+
/// be skipped.
28+
NonInlinableWithoutTypes,
2629
/// All function bodies should be skipped, where not otherwise required
2730
/// for type inference.
2831
All

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ def experimental_skip_non_inlinable_function_bodies:
297297
Flag<["-"], "experimental-skip-non-inlinable-function-bodies">,
298298
Flags<[FrontendOption, HelpHidden]>,
299299
HelpText<"Skip type-checking and SIL generation for non-inlinable function bodies">;
300+
def experimental_skip_non_inlinable_function_bodies_without_types:
301+
Flag<["-"], "experimental-skip-non-inlinable-function-bodies-without-types">,
302+
Flags<[FrontendOption, HelpHidden]>,
303+
HelpText<"Skip work on non-inlinable function bodies that do not declare nested types">;
300304
def profile_stats_events: Flag<["-"], "profile-stats-events">,
301305
Flags<[FrontendOption, HelpHidden]>,
302306
HelpText<"Profile changes to stats in -stats-output-dir">;

include/swift/Parse/Parser.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,10 @@ class Parser {
687687

688688
/// Skip a braced block (e.g. function body). The current token must be '{'.
689689
/// Returns \c true if the parser hit the eof before finding matched '}'.
690-
bool skipBracedBlock();
690+
///
691+
/// Set \c HasNestedTypeDeclarations to true if a token for a type
692+
/// declaration is detected in the skipped block.
693+
bool skipBracedBlock(bool &HasNestedTypeDeclarations);
691694

692695
/// Skip over SIL decls until we encounter the start of a Swift decl or eof.
693696
void skipSILUntilSwiftDecl();

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ bool ArgsToFrontendOptionsConverter::convert(
195195

196196
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) &&
197197
(Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
198-
Args.hasArg(OPT_experimental_skip_all_function_bodies))) {
198+
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
199+
Args.hasArg(
200+
OPT_experimental_skip_non_inlinable_function_bodies_without_types))) {
199201
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
200202
return true;
201203
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,12 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args,
716716
Opts.DebugTimeExpressions |=
717717
Args.hasArg(OPT_debug_time_expression_type_checking);
718718

719+
// Check for SkipFunctionBodies arguments in order from skipping less to
720+
// skipping more.
721+
if (Args.hasArg(
722+
OPT_experimental_skip_non_inlinable_function_bodies_without_types))
723+
Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinableWithoutTypes;
724+
719725
// If asked to perform InstallAPI, go ahead and enable non-inlinable function
720726
// body skipping.
721727
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||

lib/Parse/ParseDecl.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,10 +3519,12 @@ static void diagnoseOperatorFixityAttributes(Parser &P,
35193519
static unsigned skipUntilMatchingRBrace(Parser &P,
35203520
bool &HasPoundDirective,
35213521
bool &HasOperatorDeclarations,
3522-
bool &HasNestedClassDeclarations) {
3522+
bool &HasNestedClassDeclarations,
3523+
bool &HasNestedTypeDeclarations) {
35233524
HasPoundDirective = false;
35243525
HasOperatorDeclarations = false;
35253526
HasNestedClassDeclarations = false;
3527+
HasNestedTypeDeclarations = false;
35263528

35273529
unsigned OpenBraces = 1;
35283530

@@ -3541,6 +3543,10 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
35413543

35423544
HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line,
35433545
tok::pound_if, tok::pound_else, tok::pound_endif, tok::pound_elseif);
3546+
3547+
HasNestedTypeDeclarations |= P.Tok.isAny(tok::kw_class, tok::kw_struct,
3548+
tok::kw_enum);
3549+
35443550
if (P.consumeIf(tok::l_brace)) {
35453551
++OpenBraces;
35463552
continue;
@@ -4823,10 +4829,12 @@ bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
48234829
// we can't lazily parse.
48244830
BacktrackingScope BackTrack(*this);
48254831
bool HasPoundDirective;
4832+
bool HasNestedTypeDeclarations;
48264833
skipUntilMatchingRBrace(*this,
48274834
HasPoundDirective,
48284835
HasOperatorDeclarations,
4829-
HasNestedClassDeclarations);
4836+
HasNestedClassDeclarations,
4837+
HasNestedTypeDeclarations);
48304838
if (!HasPoundDirective)
48314839
BackTrack.cancelBacktrack();
48324840
return !BackTrack.willBacktrack();
@@ -5514,7 +5522,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
55145522
return ParameterList::create(P.Context, StartLoc, param, EndLoc);
55155523
}
55165524

5517-
bool Parser::skipBracedBlock() {
5525+
bool Parser::skipBracedBlock(bool &HasNestedTypeDeclarations) {
55185526
SyntaxParsingContext disabled(SyntaxContext);
55195527
SyntaxContext->disable();
55205528
consumeToken(tok::l_brace);
@@ -5528,7 +5536,8 @@ bool Parser::skipBracedBlock() {
55285536
unsigned OpenBraces = skipUntilMatchingRBrace(*this,
55295537
HasPoundDirectives,
55305538
HasOperatorDeclarations,
5531-
HasNestedClassDeclarations);
5539+
HasNestedClassDeclarations,
5540+
HasNestedTypeDeclarations);
55325541
if (consumeIf(tok::r_brace))
55335542
--OpenBraces;
55345543
return OpenBraces != 0;
@@ -6424,11 +6433,13 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
64246433
BodyRange.Start = Tok.getLoc();
64256434

64266435
// Advance the parser to the end of the block; '{' ... '}'.
6427-
skipBracedBlock();
6436+
bool HasNestedTypeDeclarations;
6437+
skipBracedBlock(HasNestedTypeDeclarations);
64286438

64296439
BodyRange.End = PreviousLoc;
64306440

64316441
AFD->setBodyDelayed(BodyRange);
6442+
AFD->setHasNestedTypeDeclarations(HasNestedTypeDeclarations);
64326443

64336444
if (isCodeCompletionFirstPass() &&
64346445
SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) {

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23452345
FunctionBodySkipping::All)
23462346
return true;
23472347

2348+
// If we want all types (for LLDB) we can't skip functions with nested
2349+
// types. We could probably improve upon this and type-check only the
2350+
// nested types instead for better performances.
2351+
if (AFD->hasNestedTypeDeclarations() &&
2352+
getASTContext().TypeCheckerOpts.SkipFunctionBodies ==
2353+
FunctionBodySkipping::NonInlinableWithoutTypes)
2354+
return false;
2355+
23482356
// Only skip functions where their body won't be serialized
23492357
return AFD->getResilienceExpansion() != ResilienceExpansion::Minimal;
23502358
}

test/Frontend/skip-function-bodies.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// Check -emit-ir and -c are invalid when skipping function bodies
44
// RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-non-inlinable-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR
55
// RUN: not %target-swift-frontend -c %s -experimental-skip-non-inlinable-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR
6+
// RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-non-inlinable-function-bodies-without-types %s 2>&1 | %FileCheck %s --check-prefix ERROR
7+
// RUN: not %target-swift-frontend -c %s -experimental-skip-non-inlinable-function-bodies-without-types %s 2>&1 | %FileCheck %s --check-prefix ERROR
68
// RUN: not %target-swift-frontend -emit-ir %s -experimental-skip-all-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR
79
// RUN: not %target-swift-frontend -c %s -experimental-skip-all-function-bodies %s 2>&1 | %FileCheck %s --check-prefix ERROR
810
// ERROR: -experimental-skip-*-function-bodies do not support emitting IR
@@ -14,8 +16,10 @@
1416

1517
// Check skipped bodies are neither typechecked nor SILgen'd
1618
// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix INLINENOTYPECHECK %s -o %t/Skip.noninlinable.sil
19+
// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-non-inlinable-function-bodies-without-types -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix TYPESNOTYPECHECK %s -o %t/Skip.withouttypes.sil
1720
// RUN: %target-swift-frontend -emit-sil -emit-sorted-sil -experimental-skip-all-function-bodies -debug-forbid-typecheck-prefix NEVERTYPECHECK -debug-forbid-typecheck-prefix ALLNOTYPECHECK %s -o %t/Skip.all.sil
1821
// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-NONINLINE-ONLY,CHECK-NONINLINE-SIL < %t/Skip.noninlinable.sil
22+
// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-WITHOUTTYPES-ONLY,CHECK-NONINLINE-SIL < %t/Skip.withouttypes.sil
1923
// RUN: %FileCheck %s --check-prefixes CHECK,CHECK-ALL-ONLY < %t/Skip.all.sil
2024

2125
// Emit the module interface and check it against the same set of strings.
@@ -178,6 +182,57 @@ public func inlinableNestedLocalTypeFunc() {
178182
nestedFunc()
179183
}
180184

185+
public func funcWithEnum() {
186+
let INLINENOTYPECHECK_local = 1
187+
let ALLNOTYPECHECK_local = 1
188+
_blackHole("func with enum body")
189+
// CHECK-WITHOUTTYPES-ONLY: "func with enum body"
190+
// CHECK-NONINLINE-ONLY-NOT: "func with enum body"
191+
// CHECK-ALL-ONLY-NOT: "func with enum body"
192+
enum E {}
193+
}
194+
195+
public func funcWithClass() {
196+
let INLINENOTYPECHECK_local = 1
197+
let ALLNOTYPECHECK_local = 1
198+
_blackHole("func with class body")
199+
// CHECK-WITHOUTTYPES-ONLY: "func with class body"
200+
// CHECK-NONINLINE-ONLY-NOT: "func with class body"
201+
// CHECK-ALL-ONLY-NOT: "func with class body"
202+
class C {}
203+
}
204+
205+
public func funcWithStruct() {
206+
let INLINENOTYPECHECK_local = 1
207+
let ALLNOTYPECHECK_local = 1
208+
_blackHole("func with struct body")
209+
// CHECK-WITHOUTTYPES-ONLY: "func with struct body"
210+
// CHECK-NONINLINE-ONLY-NOT: "func with struct body"
211+
// CHECK-ALL-ONLY-NOT: "func with struct body"
212+
struct S {}
213+
}
214+
215+
public func funcWithNestedFuncs() {
216+
let INLINENOTYPECHECK_local = 1
217+
let ALLNOTYPECHECK_local = 1
218+
_blackHole("func with nested funcs body")
219+
// CHECK-WITHOUTTYPES-ONLY: "func with nested funcs body"
220+
// CHECK-NONINLINE-ONLY-NOT: "func with nested funcs body"
221+
// CHECK-ALL-ONLY-NOT: "func with nested funcs body"
222+
223+
func bar() {
224+
_blackHole("nested func body")
225+
// CHECK-WITHOUTTYPES-ONLY: "nested func body"
226+
// FIXME: We could skip this nested function.
227+
}
228+
229+
func foo() {
230+
_blackHole("nested func with type body")
231+
// CHECK-WITHOUTTYPES-ONLY: "nested func with type body"
232+
struct S {}
233+
}
234+
}
235+
181236
public struct Struct {
182237
@inlinable public var inlinableVar: Int {
183238
let ALLNOTYPECHECK_local = 1

0 commit comments

Comments
 (0)