Skip to content

[5.6] Copy-propagation enables lexical-lifetimes. #40517

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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
fc2701c
[Test] Add two lexical lifetime verification tests.
nate-chandler Dec 8, 2021
806c6db
[CopyPropagation] Note ShrinkBorrowScope changes.
nate-chandler Dec 8, 2021
10681eb
[Gardening] Merged two conditions.
nate-chandler Dec 8, 2021
180e04c
[Gardening] Updated comment.
nate-chandler Dec 8, 2021
9499b09
[OwnershipUtils] Extracted utility for common use.
nate-chandler Dec 8, 2021
878e034
[CanonicalizeInst] Remove redundant lexical bbis.
nate-chandler Dec 8, 2021
8fa8262
[LoopRotate] Don't phi forwarded guaranteed value.
nate-chandler Dec 7, 2021
4fb8eed
Enabling copy propagation enables lexical lifetimes.
nate-chandler Dec 8, 2021
2513c91
[SIL] Reenable destroy hoisting under lexical lifetimes.
nate-chandler Dec 9, 2021
321fecd
[AllocStackHoisting] New dealloc_stack's locs are cleanups.
nate-chandler Dec 11, 2021
790bcd9
Fix OperandOwnership for AutoDiff builtins.
atrick Dec 8, 2021
7235aef
SemanticARCOpts fix - remove deadEndBlocks checks
atrick Dec 10, 2021
aa3d068
[NFC] Renamed LexicalLifetimesOption cases.
nate-chandler Dec 11, 2021
f4845c8
Disable lexical-lifetimes with copy-propagation.
nate-chandler Dec 11, 2021
ebb5d9c
Test case for SemanticARCOpts fix - remove deadEndBlocks checks
atrick Dec 13, 2021
64c60b4
Workaround OSSA dead borrow scope bugs.
atrick Dec 13, 2021
177f73a
Fixed flag checking for lexical borrow scopes.
nate-chandler Dec 13, 2021
1147f7f
[SILOpt] Tweaked error message.
nate-chandler Dec 14, 2021
0c1b56a
Error on bad copy propagation flag combo.
nate-chandler Dec 14, 2021
f67df31
[NFC] Used SILOption field for copy propagation.
nate-chandler Dec 14, 2021
019a75d
[NFC] [SILOpt] Explicitly specified flag defaults.
nate-chandler Dec 14, 2021
dab3f61
Base LexicalLifetimes dflt on SILOpts::CopyProp.
nate-chandler Dec 14, 2021
f3774f8
Replaced -disable-copy-prop with multi-var.
nate-chandler Dec 14, 2021
d92a4bc
[Test] Specified copy-prop and lex-lt behavior.
nate-chandler Dec 14, 2021
d1a7574
[SILOpt] Make lex-lt options optional.
nate-chandler Dec 14, 2021
42078f1
[Gardening] Added omitted word.
nate-chandler Dec 16, 2021
0fd48fc
[CopyPropagation] Cleanup after borrow shrinking.
nate-chandler Dec 16, 2021
78a2eeb
[ShrinkBorrowScope] Hoist over copies of borrow.
nate-chandler Dec 16, 2021
704133c
[OwnershipUtils] Repurpose utility.
nate-chandler Dec 17, 2021
834558e
[Gardening] Improved variable name.
nate-chandler Dec 17, 2021
ab0be3a
[ShrinkBorrowScope] Return modified copy_values.
nate-chandler Dec 17, 2021
e3b4a7b
[NFC] Demoted variable to function scope.
nate-chandler Dec 17, 2021
7d16503
[Gardening] Doc'd field.
nate-chandler Dec 17, 2021
4a6f85c
[Gardening] Improved variable name.
nate-chandler Dec 17, 2021
12e2663
[Gardening] Improved variable name.
nate-chandler Dec 17, 2021
21069bb
[ShrinkBorrowScope] Avoid spurious mutation.
nate-chandler Dec 17, 2021
067efb1
[Test] Stopped passing wrong flag.
nate-chandler Dec 17, 2021
d9e7cf6
[Test] Added swift test for ShrinkBorrowScope.
nate-chandler Dec 17, 2021
4508571
[Test] Added more end_borrow hoisting tests.
nate-chandler Dec 18, 2021
880f15d
[Test] Adapted tests to CopyPropagation changes.
nate-chandler Dec 18, 2021
707e78e
[Gardening] Doc'd field.
nate-chandler Dec 18, 2021
027fac7
[ShrinkBorrowScope] Enable querying hoistability.
nate-chandler Dec 19, 2021
284559f
[ShrinkBorrowScope] Checked before adding preds.
nate-chandler Dec 19, 2021
e352d64
[SILOptimizer] Add flag to print pre-OSSA lowering.
nate-chandler Dec 9, 2021
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
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ ERROR(error_unknown_arg,none,
"unknown argument: '%0'", (StringRef))
ERROR(error_invalid_arg_value,none,
"invalid value '%1' in '%0'", (StringRef, StringRef))
ERROR(error_invalid_arg_combination,none,
"unsupported argument combination: '%0' and '%1'", (StringRef, StringRef))
WARNING(warning_invalid_locale_code,none,
"unsupported locale code; supported locale codes are: '%0'", (StringRef))
WARNING(warning_locale_path_not_found,none,
Expand Down
44 changes: 29 additions & 15 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,31 @@
namespace swift {

enum class LexicalLifetimesOption : uint8_t {
// Do not insert any lexical lifetimes.
// Do not insert lexical markers.
Off = 0,

// Insert lexical lifetimes in SILGen, but remove them before leaving Raw SIL.
Early,
// Insert lexical markers via lexical borrow scopes and the lexical flag on
// alloc_stacks produced from alloc_boxes, but strip them when lowering out of
// Raw SIL.
DiagnosticMarkersOnly,

// Insert lexical lifetimes and do not remove them until OSSA is lowered. This
// is experimental.
ExperimentalLate,
// Insert lexical markers and use them to lengthen object lifetime based on
// lexical scope.
On,
};

enum class CopyPropagationOption : uint8_t {
// Do not add any copy propagation passes.
Off = 0,

// Only add the copy propagation passes requested by other flags, currently
// just -enable-ossa-modules.
RequestedPassesOnly,

// Add all relevant copy propagation passes. If a setting, e.g.
// -enable-ossa-modules, requests to add copy propagation to the pipeline, do
// so.
On
};

class SILModule;
Expand All @@ -59,17 +75,15 @@ class SILOptions {
bool RemoveRuntimeAsserts = false;

/// Enable experimental support for emitting defined borrow scopes.
LexicalLifetimesOption LexicalLifetimes = LexicalLifetimesOption::Early;

/// Force-run SIL copy propagation to shorten object lifetime in whatever
/// optimization pipeline is currently used.
/// When this is 'false' the pipeline has default behavior.
bool EnableCopyPropagation = false;
LexicalLifetimesOption LexicalLifetimes =
LexicalLifetimesOption::DiagnosticMarkersOnly;

/// Disable SIL copy propagation to preserve object lifetime in whatever
/// Whether to run SIL copy propagation to shorten object lifetime in whatever
/// optimization pipeline is currently used.
/// When this is 'false' the pipeline has default behavior.
bool DisableCopyPropagation = false;
///
/// When this is 'RequestedPassesOnly' the pipeline has default behavior.
CopyPropagationOption CopyPropagation =
CopyPropagationOption::RequestedPassesOnly;

/// Controls whether the SIL ARC optimizations are run.
bool EnableARCOptimizations = true;
Expand Down
26 changes: 16 additions & 10 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,12 @@ def dependency_scan_cache_remarks : Flag<["-"], "Rdependency-scan-cache">,
HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">;

def enable_copy_propagation : Flag<["-"], "enable-copy-propagation">,
HelpText<"Run SIL copy propagation to shorten object lifetime.">;
def disable_copy_propagation : Flag<["-"], "disable-copy-propagation">,
HelpText<"Don't run SIL copy propagation to preserve object lifetime.">;
HelpText<"Run SIL copy propagation with lexical lifetimes to shorten object "
"lifetimes while preserving variable lifetimes.">;
def copy_propagation_state_EQ :
Joined<["-"], "enable-copy-propagation=">,
HelpText<"Whether to enable copy propagation">,
MetaVarName<"true|requested-passes-only|false">;

def enable_infer_public_concurrent_value : Flag<["-"], "enable-infer-public-sendable">,
HelpText<"Enable inference of Sendable conformances for public structs and enums">;
Expand Down Expand Up @@ -259,15 +262,18 @@ def enable_experimental_concurrency :
Flag<["-"], "enable-experimental-concurrency">,
HelpText<"Enable experimental concurrency model">;

def disable_lexical_lifetimes :
Flag<["-"], "disable-lexical-lifetimes">,
HelpText<"Disables early lexical lifetimes. Mutually exclusive with "
"-enable-lexical-lifetimes">;

def enable_lexical_borrow_scopes :
Joined<["-"], "enable-lexical-borrow-scopes=">,
HelpText<"Whether to emit lexical borrow scopes (default: true)">,
MetaVarName<"true|false">;
def enable_lexical_lifetimes :
Joined<["-"], "enable-lexical-lifetimes=">,
HelpText<"Whether to enable lexical lifetimes">,
MetaVarName<"true|false">;
def enable_lexical_lifetimes_noArg :
Flag<["-"], "enable-lexical-lifetimes">,
HelpText<"Enable lexical lifetimes. Mutually exclusive with "
"-disable-lexical-lifetimes">;
HelpText<"Enable lexical lifetimes">;

def enable_experimental_move_only :
Flag<["-"], "enable-experimental-move-only">,
Expand Down
22 changes: 15 additions & 7 deletions include/swift/SIL/OwnershipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,9 @@ inline bool isForwardingConsume(SILValue value) {
bool findInnerTransitiveGuaranteedUses(
SILValue guaranteedValue, SmallVectorImpl<Operand *> *usePoints = nullptr);

/// Like findInnerTransitiveGuaranteedUses except that rather than it being a
/// precondition that the provided value not be a BorrowedValue, it is a [type-
/// system-enforced] precondition that the provided value be a BorrowedValue.
///
/// TODO: Merge with findInnerTransitiveGuaranteedUses.
bool findInnerTransitiveGuaranteedUsesOfBorrowedValue(
/// Find all uses in the extended lifetime (i.e. including copies) of a simple
/// (i.e. not reborrowed) borrow scope and its transitive uses.
bool findExtendedUsesOfSimpleBorrowedValue(
BorrowedValue borrowedValue,
SmallVectorImpl<Operand *> *usePoints = nullptr);

Expand Down Expand Up @@ -566,8 +563,11 @@ struct BorrowedValue {
/// This ignores reborrows. The assumption is that, since \p uses are
/// dominated by this local scope, checking the extended borrow scope should
/// not be necessary to determine they are within the scope.
///
/// \p deadEndBlocks is optional during transition. It will be completely
/// removed in an upcoming commit.
bool areUsesWithinLocalScope(ArrayRef<Operand *> uses,
DeadEndBlocks &deadEndBlocks) const;
DeadEndBlocks *deadEndBlocks) const;

/// Given a local borrow scope introducer, visit all non-forwarding consuming
/// users. This means that this looks through guaranteed block arguments. \p
Expand Down Expand Up @@ -1206,6 +1206,14 @@ void visitTransitiveEndBorrows(
BorrowedValue beginBorrow,
function_ref<void(EndBorrowInst *)> visitEndBorrow);

/// Whether the specified lexical begin_borrow instruction is nested.
///
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
/// guaranteed by another lexical scope. That happens if:
/// - the value is a guaranteed argument to the function
/// - the value is itself a begin_borrow [lexical]
bool isNestedLexicalBeginBorrow(BeginBorrowInst *bbi);

} // namespace swift

#endif
3 changes: 2 additions & 1 deletion include/swift/SIL/PrunedLiveness.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,9 @@ class PrunedLiveness {
/// client already knows that inst occurs after the start of liveness.
bool isWithinBoundary(SILInstruction *inst) const;

/// \p deadEndBlocks is optional.
bool areUsesWithinBoundary(ArrayRef<Operand *> uses,
DeadEndBlocks &deadEndBlocks) const;
DeadEndBlocks *deadEndBlocks) const;

/// Compute liveness for a single SSA definition.
void computeSSALiveness(SILValue def);
Expand Down
15 changes: 9 additions & 6 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -911,14 +911,17 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILModule &M){
inline bool SILOptions::supportsLexicalLifetimes(const SILModule &mod) const {
switch (mod.getStage()) {
case SILStage::Raw:
// In Raw SIL, we support lexical lifetimes as long as lexical lifetimes is
// not turned off all the way. This means lexical lifetimes is set to either
// early or experimental late.
// In raw SIL, lexical markers are used for diagnostics. These markers are
// present as long as the lexical lifetimes feature is not disabled
// entirely.
return LexicalLifetimes != LexicalLifetimesOption::Off;
case SILStage::Canonical:
// In Canonical SIL, we only support lexical lifetimes when in experimental
// late mode.
return LexicalLifetimes == LexicalLifetimesOption::ExperimentalLate;
// In Canonical SIL, lexical markers are used to ensure that object
// lifetimes do not get observably shortened from the end of a lexical
// scope. That behavior only occurs when lexical lifetimes is (fully)
// enabled. (When only diagnostic markers are enabled, the markers are
// stripped as part of lowering from raw to canonical SIL.)
return LexicalLifetimes == LexicalLifetimesOption::On;
case SILStage::Lowered:
// We do not support OSSA in Lowered SIL, so this is always false.
return false;
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {

template <class T> inline T *getSingleConsumingUserOfType() const;

/// Returns true if this operand has exactly two.
/// Returns true if this operand has exactly two uses.
///
/// This is useful if one has found a predefined set of 2 unique users and
/// wants to check if there are any other users without iterating over the
Expand Down
4 changes: 3 additions & 1 deletion include/swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ class CanonicalizeBorrowScope {
bool consolidateBorrowScope();
};

bool shrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter);
bool shrinkBorrowScope(
BeginBorrowInst *bbi, InstructionDeleter &deleter,
SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts);

} // namespace swift

Expand Down
136 changes: 121 additions & 15 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1455,25 +1455,131 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
// -Ounchecked might also set removal of runtime asserts (cond_fail).
Opts.RemoveRuntimeAsserts |= Args.hasArg(OPT_RemoveRuntimeAsserts);

// If experimental move only is enabled, always enable lexical lifetime as
// well. Move only depends on lexical lifetimes.
bool enableExperimentalLexicalLifetimes =
Args.hasArg(OPT_enable_lexical_lifetimes) ||
Args.hasArg(OPT_enable_experimental_move_only);
// Error if both experimental lexical lifetimes and disable lexical lifetimes
// are both set.
if (enableExperimentalLexicalLifetimes &&
Args.hasArg(OPT_disable_lexical_lifetimes)) {
Optional<CopyPropagationOption> specifiedCopyPropagationOption;
if (Arg *A = Args.getLastArg(OPT_copy_propagation_state_EQ)) {
specifiedCopyPropagationOption =
llvm::StringSwitch<Optional<CopyPropagationOption>>(A->getValue())
.Case("true", CopyPropagationOption::On)
.Case("false", CopyPropagationOption::Off)
.Case("requested-passes-only",
CopyPropagationOption::RequestedPassesOnly)
.Default(None);
}
if (Args.hasArg(OPT_enable_copy_propagation)) {
if (specifiedCopyPropagationOption) {
if (*specifiedCopyPropagationOption == CopyPropagationOption::Off) {
// Error if copy propagation has been set to ::Off via the meta-var form
// and enabled via the flag.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-copy-propagation",
"enable-copy-propagation=false");
return true;
} else if (*specifiedCopyPropagationOption ==
CopyPropagationOption::RequestedPassesOnly) {
// Error if copy propagation has been set to ::RequestedPassesOnly via
// the meta-var form and enabled via the flag.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-copy-propagation",
"enable-copy-propagation=requested-passes-only");
return true;
}
} else {
specifiedCopyPropagationOption = CopyPropagationOption::On;
}
}
if (specifiedCopyPropagationOption) {
Opts.CopyPropagation = *specifiedCopyPropagationOption;
}

Optional<bool> enableLexicalBorrowScopesFlag;
if (Arg *A = Args.getLastArg(OPT_enable_lexical_borrow_scopes)) {
enableLexicalBorrowScopesFlag =
llvm::StringSwitch<Optional<bool>>(A->getValue())
.Case("true", true)
.Case("false", false)
.Default(None);
}
Optional<bool> enableLexicalLifetimesFlag;
if (Arg *A = Args.getLastArg(OPT_enable_lexical_lifetimes)) {
enableLexicalLifetimesFlag =
llvm::StringSwitch<Optional<bool>>(A->getValue())
.Case("true", true)
.Case("false", false)
.Default(None);
}
if (Args.getLastArg(OPT_enable_lexical_lifetimes_noArg)) {
if (!enableLexicalLifetimesFlag.getValueOr(true)) {
// Error if lexical lifetimes have been disabled via the meta-var form
// and enabled via the flag.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-lexical-lifetimes",
"enable-lexical-lifetimes=false");
return true;
} else {
enableLexicalLifetimesFlag = true;
}
}

if (enableLexicalLifetimesFlag.getValueOr(false) &&
!enableLexicalBorrowScopesFlag.getValueOr(true)) {
// Error if lexical lifetimes have been enabled but lexical borrow scopes--
// on which they are dependent--have been disabled.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-lexical-lifetimes=true",
"enable-lexical-borrow-scopes=false");
return true;
} else {
if (enableExperimentalLexicalLifetimes)
Opts.LexicalLifetimes = LexicalLifetimesOption::ExperimentalLate;
if (Args.hasArg(OPT_disable_lexical_lifetimes))
}

if (Args.hasArg(OPT_enable_experimental_move_only) &&
!enableLexicalBorrowScopesFlag.getValueOr(true)) {
// Error if move-only is enabled and lexical borrow scopes--on which it
// depends--has been disabled.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-experimental-move-only",
"enable-lexical-borrow-scopes=false");
return true;
}

if (Args.hasArg(OPT_enable_experimental_move_only) &&
!enableLexicalLifetimesFlag.getValueOr(true)) {
// Error if move-only is enabled and lexical lifetimes--on which it
// depends--has been disabled.
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
"enable-experimental-move-only",
"enable-lexical-lifetimes=false");
return true;
}

// Unless overridden below, enabling copy propagation means enabling lexical
// lifetimes.
if (Opts.CopyPropagation == CopyPropagationOption::On)
Opts.LexicalLifetimes = LexicalLifetimesOption::On;

// Unless overridden below, disable copy propagation means disabling lexical
// lifetimes.
if (Opts.CopyPropagation == CopyPropagationOption::Off)
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;

// If move-only is enabled, always enable lexical lifetime as well. Move-only
// depends on lexical lifetimes.
if (Args.hasArg(OPT_enable_experimental_move_only))
Opts.LexicalLifetimes = LexicalLifetimesOption::On;

if (enableLexicalLifetimesFlag) {
if (*enableLexicalLifetimesFlag) {
Opts.LexicalLifetimes = LexicalLifetimesOption::On;
} else {
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;
}
}
if (enableLexicalBorrowScopesFlag) {
if (*enableLexicalBorrowScopesFlag) {
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;
} else {
Opts.LexicalLifetimes = LexicalLifetimesOption::Off;
}
}

Opts.EnableCopyPropagation |= Args.hasArg(OPT_enable_copy_propagation);
Opts.DisableCopyPropagation |= Args.hasArg(OPT_disable_copy_propagation);
Opts.EnableARCOptimizations &= !Args.hasArg(OPT_disable_arc_opts);
Opts.EnableOSSAModules |= Args.hasArg(OPT_enable_ossa_modules);
Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts);
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/AllocStackHoisting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ insertDeallocStackAtEndOf(SmallVectorImpl<SILInstruction *> &FunctionExits,
// Insert dealloc_stack in the exit blocks.
for (auto *Exit : FunctionExits) {
SILBuilderWithScope Builder(Exit);
Builder.createDeallocStack(AllocStack->getLoc(), AllocStack);
Builder.createDeallocStack(CleanupLocation(AllocStack->getLoc()),
AllocStack);
}
}

Expand Down
5 changes: 2 additions & 3 deletions lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,9 +856,8 @@ BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, DestroyDefaultActor)

BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDistributedRemoteActor)

// FIXME: Why do these reqiuire a borrowed value at all?
BUILTIN_OPERAND_OWNERSHIP(ForwardingBorrow, AutoDiffAllocateSubcontext)
BUILTIN_OPERAND_OWNERSHIP(ForwardingBorrow, AutoDiffProjectTopLevelSubcontext)
BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffAllocateSubcontext)
BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffProjectTopLevelSubcontext)

// FIXME: ConvertTaskToJob is documented as taking NativePointer. It's operand's
// ownership should be 'TrivialUse'.
Expand Down
Loading