Skip to content

[Sema] Add flag to optimize building swiftmodule files preserving type info for LLDB #34612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ class alignas(1 << DeclAlignInBits) Decl {
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
StaticSpelling : 2
);
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1,
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1,
/// \see AbstractFunctionDecl::BodyKind
BodyKind : 3,

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

/// Whether this member's body consists of a single expression.
HasSingleExpressionBody : 1
HasSingleExpressionBody : 1,

/// Whether peeking into this function detected nested type declarations.
/// This is set when skipping over the decl at parsing.
HasNestedTypeDeclarations : 1
);

SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
Expand Down Expand Up @@ -5544,6 +5548,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
Bits.AbstractFunctionDecl.Throws = Throws;
Bits.AbstractFunctionDecl.Synthesized = false;
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false;
}

void setBodyKind(BodyKind K) {
Expand Down Expand Up @@ -5690,6 +5695,16 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
setBody(S, BodyKind::Parsed);
}

/// Was there a nested type declaration detected when parsing this
/// function was skipped?
bool hasNestedTypeDeclarations() const {
return Bits.AbstractFunctionDecl.HasNestedTypeDeclarations;
}

void setHasNestedTypeDeclarations(bool value) {
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = value;
}

/// Note that parsing for the body was delayed.
///
/// The function should return the body statement and a flag indicating
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/FunctionBodySkipping.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ enum class FunctionBodySkipping : uint8_t {
None,
/// Only non-inlinable function bodies should be skipped.
NonInlinable,
/// Only non-inlinable functions bodies without type definitions should
/// be skipped.
NonInlinableWithoutTypes,
/// All function bodies should be skipped, where not otherwise required
/// for type inference.
All
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ def experimental_skip_non_inlinable_function_bodies:
Flag<["-"], "experimental-skip-non-inlinable-function-bodies">,
Flags<[FrontendOption, HelpHidden]>,
HelpText<"Skip type-checking and SIL generation for non-inlinable function bodies">;
def experimental_skip_non_inlinable_function_bodies_without_types:
Flag<["-"], "experimental-skip-non-inlinable-function-bodies-without-types">,
Flags<[FrontendOption, HelpHidden]>,
HelpText<"Skip work on non-inlinable function bodies that do not declare nested types">;
def profile_stats_events: Flag<["-"], "profile-stats-events">,
Flags<[FrontendOption, HelpHidden]>,
HelpText<"Profile changes to stats in -stats-output-dir">;
Expand Down
5 changes: 4 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,10 @@ class Parser {

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

/// Skip over SIL decls until we encounter the start of a Swift decl or eof.
void skipSILUntilSwiftDecl();
Expand Down
4 changes: 3 additions & 1 deletion lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ bool ArgsToFrontendOptionsConverter::convert(

if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) &&
(Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
Args.hasArg(OPT_experimental_skip_all_function_bodies))) {
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
Args.hasArg(
OPT_experimental_skip_non_inlinable_function_bodies_without_types))) {
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
return true;
}
Expand Down
6 changes: 6 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,12 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args,
Opts.DebugTimeExpressions |=
Args.hasArg(OPT_debug_time_expression_type_checking);

// Check for SkipFunctionBodies arguments in order from skipping less to
// skipping more.
if (Args.hasArg(
OPT_experimental_skip_non_inlinable_function_bodies_without_types))
Opts.SkipFunctionBodies = FunctionBodySkipping::NonInlinableWithoutTypes;

// If asked to perform InstallAPI, go ahead and enable non-inlinable function
// body skipping.
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
Expand Down
21 changes: 16 additions & 5 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3519,10 +3519,12 @@ static void diagnoseOperatorFixityAttributes(Parser &P,
static unsigned skipUntilMatchingRBrace(Parser &P,
bool &HasPoundDirective,
bool &HasOperatorDeclarations,
bool &HasNestedClassDeclarations) {
bool &HasNestedClassDeclarations,
bool &HasNestedTypeDeclarations) {
HasPoundDirective = false;
HasOperatorDeclarations = false;
HasNestedClassDeclarations = false;
HasNestedTypeDeclarations = false;

unsigned OpenBraces = 1;

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

HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line,
tok::pound_if, tok::pound_else, tok::pound_endif, tok::pound_elseif);

HasNestedTypeDeclarations |= P.Tok.isAny(tok::kw_class, tok::kw_struct,
tok::kw_enum);

if (P.consumeIf(tok::l_brace)) {
++OpenBraces;
continue;
Expand Down Expand Up @@ -4823,10 +4829,12 @@ bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
// we can't lazily parse.
BacktrackingScope BackTrack(*this);
bool HasPoundDirective;
bool HasNestedTypeDeclarations;
skipUntilMatchingRBrace(*this,
HasPoundDirective,
HasOperatorDeclarations,
HasNestedClassDeclarations);
HasNestedClassDeclarations,
HasNestedTypeDeclarations);
if (!HasPoundDirective)
BackTrack.cancelBacktrack();
return !BackTrack.willBacktrack();
Expand Down Expand Up @@ -5514,7 +5522,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
return ParameterList::create(P.Context, StartLoc, param, EndLoc);
}

bool Parser::skipBracedBlock() {
bool Parser::skipBracedBlock(bool &HasNestedTypeDeclarations) {
SyntaxParsingContext disabled(SyntaxContext);
SyntaxContext->disable();
consumeToken(tok::l_brace);
Expand All @@ -5528,7 +5536,8 @@ bool Parser::skipBracedBlock() {
unsigned OpenBraces = skipUntilMatchingRBrace(*this,
HasPoundDirectives,
HasOperatorDeclarations,
HasNestedClassDeclarations);
HasNestedClassDeclarations,
HasNestedTypeDeclarations);
if (consumeIf(tok::r_brace))
--OpenBraces;
return OpenBraces != 0;
Expand Down Expand Up @@ -6424,11 +6433,13 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
BodyRange.Start = Tok.getLoc();

// Advance the parser to the end of the block; '{' ... '}'.
skipBracedBlock();
bool HasNestedTypeDeclarations;
skipBracedBlock(HasNestedTypeDeclarations);

BodyRange.End = PreviousLoc;

AFD->setBodyDelayed(BodyRange);
AFD->setHasNestedTypeDeclarations(HasNestedTypeDeclarations);

if (isCodeCompletionFirstPass() &&
SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) {
Expand Down
8 changes: 8 additions & 0 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
FunctionBodySkipping::All)
return true;

// If we want all types (for LLDB) we can't skip functions with nested
// types. We could probably improve upon this and type-check only the
// nested types instead for better performances.
if (AFD->hasNestedTypeDeclarations() &&
getASTContext().TypeCheckerOpts.SkipFunctionBodies ==
FunctionBodySkipping::NonInlinableWithoutTypes)
return false;

// Only skip functions where their body won't be serialized
return AFD->getResilienceExpansion() != ResilienceExpansion::Minimal;
}
Expand Down
Loading