Skip to content

Commit d6d848c

Browse files
Merge pull request #40517 from nate-chandler/cherrypick/lexical-lifetimes/enable-with-copy-propagation/release/5.6
[5.6] Copy-propagation enables lexical-lifetimes.
2 parents f67efdd + e352d64 commit d6d848c

File tree

83 files changed

+1280
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1280
-344
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ ERROR(error_unknown_arg,none,
8080
"unknown argument: '%0'", (StringRef))
8181
ERROR(error_invalid_arg_value,none,
8282
"invalid value '%1' in '%0'", (StringRef, StringRef))
83+
ERROR(error_invalid_arg_combination,none,
84+
"unsupported argument combination: '%0' and '%1'", (StringRef, StringRef))
8385
WARNING(warning_invalid_locale_code,none,
8486
"unsupported locale code; supported locale codes are: '%0'", (StringRef))
8587
WARNING(warning_locale_path_not_found,none,

include/swift/AST/SILOptions.h

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,31 @@
3131
namespace swift {
3232

3333
enum class LexicalLifetimesOption : uint8_t {
34-
// Do not insert any lexical lifetimes.
34+
// Do not insert lexical markers.
3535
Off = 0,
3636

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

40-
// Insert lexical lifetimes and do not remove them until OSSA is lowered. This
41-
// is experimental.
42-
ExperimentalLate,
42+
// Insert lexical markers and use them to lengthen object lifetime based on
43+
// lexical scope.
44+
On,
45+
};
46+
47+
enum class CopyPropagationOption : uint8_t {
48+
// Do not add any copy propagation passes.
49+
Off = 0,
50+
51+
// Only add the copy propagation passes requested by other flags, currently
52+
// just -enable-ossa-modules.
53+
RequestedPassesOnly,
54+
55+
// Add all relevant copy propagation passes. If a setting, e.g.
56+
// -enable-ossa-modules, requests to add copy propagation to the pipeline, do
57+
// so.
58+
On
4359
};
4460

4561
class SILModule;
@@ -59,17 +75,15 @@ class SILOptions {
5975
bool RemoveRuntimeAsserts = false;
6076

6177
/// Enable experimental support for emitting defined borrow scopes.
62-
LexicalLifetimesOption LexicalLifetimes = LexicalLifetimesOption::Early;
63-
64-
/// Force-run SIL copy propagation to shorten object lifetime in whatever
65-
/// optimization pipeline is currently used.
66-
/// When this is 'false' the pipeline has default behavior.
67-
bool EnableCopyPropagation = false;
78+
LexicalLifetimesOption LexicalLifetimes =
79+
LexicalLifetimesOption::DiagnosticMarkersOnly;
6880

69-
/// Disable SIL copy propagation to preserve object lifetime in whatever
81+
/// Whether to run SIL copy propagation to shorten object lifetime in whatever
7082
/// optimization pipeline is currently used.
71-
/// When this is 'false' the pipeline has default behavior.
72-
bool DisableCopyPropagation = false;
83+
///
84+
/// When this is 'RequestedPassesOnly' the pipeline has default behavior.
85+
CopyPropagationOption CopyPropagation =
86+
CopyPropagationOption::RequestedPassesOnly;
7387

7488
/// Controls whether the SIL ARC optimizations are run.
7589
bool EnableARCOptimizations = true;

include/swift/Option/FrontendOptions.td

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,12 @@ def dependency_scan_cache_remarks : Flag<["-"], "Rdependency-scan-cache">,
213213
HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">;
214214

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

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

262-
def disable_lexical_lifetimes :
263-
Flag<["-"], "disable-lexical-lifetimes">,
264-
HelpText<"Disables early lexical lifetimes. Mutually exclusive with "
265-
"-enable-lexical-lifetimes">;
266-
265+
def enable_lexical_borrow_scopes :
266+
Joined<["-"], "enable-lexical-borrow-scopes=">,
267+
HelpText<"Whether to emit lexical borrow scopes (default: true)">,
268+
MetaVarName<"true|false">;
269+
267270
def enable_lexical_lifetimes :
271+
Joined<["-"], "enable-lexical-lifetimes=">,
272+
HelpText<"Whether to enable lexical lifetimes">,
273+
MetaVarName<"true|false">;
274+
def enable_lexical_lifetimes_noArg :
268275
Flag<["-"], "enable-lexical-lifetimes">,
269-
HelpText<"Enable lexical lifetimes. Mutually exclusive with "
270-
"-disable-lexical-lifetimes">;
276+
HelpText<"Enable lexical lifetimes">;
271277

272278
def enable_experimental_move_only :
273279
Flag<["-"], "enable-experimental-move-only">,

include/swift/SIL/OwnershipUtils.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,9 @@ inline bool isForwardingConsume(SILValue value) {
104104
bool findInnerTransitiveGuaranteedUses(
105105
SILValue guaranteedValue, SmallVectorImpl<Operand *> *usePoints = nullptr);
106106

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

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

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

1209+
/// Whether the specified lexical begin_borrow instruction is nested.
1210+
///
1211+
/// A begin_borrow [lexical] is nested if the borrowed value's lifetime is
1212+
/// guaranteed by another lexical scope. That happens if:
1213+
/// - the value is a guaranteed argument to the function
1214+
/// - the value is itself a begin_borrow [lexical]
1215+
bool isNestedLexicalBeginBorrow(BeginBorrowInst *bbi);
1216+
12091217
} // namespace swift
12101218

12111219
#endif

include/swift/SIL/PrunedLiveness.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,9 @@ class PrunedLiveness {
334334
/// client already knows that inst occurs after the start of liveness.
335335
bool isWithinBoundary(SILInstruction *inst) const;
336336

337+
/// \p deadEndBlocks is optional.
337338
bool areUsesWithinBoundary(ArrayRef<Operand *> uses,
338-
DeadEndBlocks &deadEndBlocks) const;
339+
DeadEndBlocks *deadEndBlocks) const;
339340

340341
/// Compute liveness for a single SSA definition.
341342
void computeSSALiveness(SILValue def);

include/swift/SIL/SILModule.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,14 +911,17 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILModule &M){
911911
inline bool SILOptions::supportsLexicalLifetimes(const SILModule &mod) const {
912912
switch (mod.getStage()) {
913913
case SILStage::Raw:
914-
// In Raw SIL, we support lexical lifetimes as long as lexical lifetimes is
915-
// not turned off all the way. This means lexical lifetimes is set to either
916-
// early or experimental late.
914+
// In raw SIL, lexical markers are used for diagnostics. These markers are
915+
// present as long as the lexical lifetimes feature is not disabled
916+
// entirely.
917917
return LexicalLifetimes != LexicalLifetimesOption::Off;
918918
case SILStage::Canonical:
919-
// In Canonical SIL, we only support lexical lifetimes when in experimental
920-
// late mode.
921-
return LexicalLifetimes == LexicalLifetimesOption::ExperimentalLate;
919+
// In Canonical SIL, lexical markers are used to ensure that object
920+
// lifetimes do not get observably shortened from the end of a lexical
921+
// scope. That behavior only occurs when lexical lifetimes is (fully)
922+
// enabled. (When only diagnostic markers are enabled, the markers are
923+
// stripped as part of lowering from raw to canonical SIL.)
924+
return LexicalLifetimes == LexicalLifetimesOption::On;
922925
case SILStage::Lowered:
923926
// We do not support OSSA in Lowered SIL, so this is always false.
924927
return false;

include/swift/SIL/SILValue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
438438

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

441-
/// Returns true if this operand has exactly two.
441+
/// Returns true if this operand has exactly two uses.
442442
///
443443
/// This is useful if one has found a predefined set of 2 unique users and
444444
/// wants to check if there are any other users without iterating over the

include/swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ class CanonicalizeBorrowScope {
147147
bool consolidateBorrowScope();
148148
};
149149

150-
bool shrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter);
150+
bool shrinkBorrowScope(
151+
BeginBorrowInst *bbi, InstructionDeleter &deleter,
152+
SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts);
151153

152154
} // namespace swift
153155

lib/Frontend/CompilerInvocation.cpp

Lines changed: 121 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,25 +1455,131 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
14551455
// -Ounchecked might also set removal of runtime asserts (cond_fail).
14561456
Opts.RemoveRuntimeAsserts |= Args.hasArg(OPT_RemoveRuntimeAsserts);
14571457

1458-
// If experimental move only is enabled, always enable lexical lifetime as
1459-
// well. Move only depends on lexical lifetimes.
1460-
bool enableExperimentalLexicalLifetimes =
1461-
Args.hasArg(OPT_enable_lexical_lifetimes) ||
1462-
Args.hasArg(OPT_enable_experimental_move_only);
1463-
// Error if both experimental lexical lifetimes and disable lexical lifetimes
1464-
// are both set.
1465-
if (enableExperimentalLexicalLifetimes &&
1466-
Args.hasArg(OPT_disable_lexical_lifetimes)) {
1458+
Optional<CopyPropagationOption> specifiedCopyPropagationOption;
1459+
if (Arg *A = Args.getLastArg(OPT_copy_propagation_state_EQ)) {
1460+
specifiedCopyPropagationOption =
1461+
llvm::StringSwitch<Optional<CopyPropagationOption>>(A->getValue())
1462+
.Case("true", CopyPropagationOption::On)
1463+
.Case("false", CopyPropagationOption::Off)
1464+
.Case("requested-passes-only",
1465+
CopyPropagationOption::RequestedPassesOnly)
1466+
.Default(None);
1467+
}
1468+
if (Args.hasArg(OPT_enable_copy_propagation)) {
1469+
if (specifiedCopyPropagationOption) {
1470+
if (*specifiedCopyPropagationOption == CopyPropagationOption::Off) {
1471+
// Error if copy propagation has been set to ::Off via the meta-var form
1472+
// and enabled via the flag.
1473+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1474+
"enable-copy-propagation",
1475+
"enable-copy-propagation=false");
1476+
return true;
1477+
} else if (*specifiedCopyPropagationOption ==
1478+
CopyPropagationOption::RequestedPassesOnly) {
1479+
// Error if copy propagation has been set to ::RequestedPassesOnly via
1480+
// the meta-var form and enabled via the flag.
1481+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1482+
"enable-copy-propagation",
1483+
"enable-copy-propagation=requested-passes-only");
1484+
return true;
1485+
}
1486+
} else {
1487+
specifiedCopyPropagationOption = CopyPropagationOption::On;
1488+
}
1489+
}
1490+
if (specifiedCopyPropagationOption) {
1491+
Opts.CopyPropagation = *specifiedCopyPropagationOption;
1492+
}
1493+
1494+
Optional<bool> enableLexicalBorrowScopesFlag;
1495+
if (Arg *A = Args.getLastArg(OPT_enable_lexical_borrow_scopes)) {
1496+
enableLexicalBorrowScopesFlag =
1497+
llvm::StringSwitch<Optional<bool>>(A->getValue())
1498+
.Case("true", true)
1499+
.Case("false", false)
1500+
.Default(None);
1501+
}
1502+
Optional<bool> enableLexicalLifetimesFlag;
1503+
if (Arg *A = Args.getLastArg(OPT_enable_lexical_lifetimes)) {
1504+
enableLexicalLifetimesFlag =
1505+
llvm::StringSwitch<Optional<bool>>(A->getValue())
1506+
.Case("true", true)
1507+
.Case("false", false)
1508+
.Default(None);
1509+
}
1510+
if (Args.getLastArg(OPT_enable_lexical_lifetimes_noArg)) {
1511+
if (!enableLexicalLifetimesFlag.getValueOr(true)) {
1512+
// Error if lexical lifetimes have been disabled via the meta-var form
1513+
// and enabled via the flag.
1514+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1515+
"enable-lexical-lifetimes",
1516+
"enable-lexical-lifetimes=false");
1517+
return true;
1518+
} else {
1519+
enableLexicalLifetimesFlag = true;
1520+
}
1521+
}
1522+
1523+
if (enableLexicalLifetimesFlag.getValueOr(false) &&
1524+
!enableLexicalBorrowScopesFlag.getValueOr(true)) {
1525+
// Error if lexical lifetimes have been enabled but lexical borrow scopes--
1526+
// on which they are dependent--have been disabled.
1527+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1528+
"enable-lexical-lifetimes=true",
1529+
"enable-lexical-borrow-scopes=false");
14671530
return true;
1468-
} else {
1469-
if (enableExperimentalLexicalLifetimes)
1470-
Opts.LexicalLifetimes = LexicalLifetimesOption::ExperimentalLate;
1471-
if (Args.hasArg(OPT_disable_lexical_lifetimes))
1531+
}
1532+
1533+
if (Args.hasArg(OPT_enable_experimental_move_only) &&
1534+
!enableLexicalBorrowScopesFlag.getValueOr(true)) {
1535+
// Error if move-only is enabled and lexical borrow scopes--on which it
1536+
// depends--has been disabled.
1537+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1538+
"enable-experimental-move-only",
1539+
"enable-lexical-borrow-scopes=false");
1540+
return true;
1541+
}
1542+
1543+
if (Args.hasArg(OPT_enable_experimental_move_only) &&
1544+
!enableLexicalLifetimesFlag.getValueOr(true)) {
1545+
// Error if move-only is enabled and lexical lifetimes--on which it
1546+
// depends--has been disabled.
1547+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_combination,
1548+
"enable-experimental-move-only",
1549+
"enable-lexical-lifetimes=false");
1550+
return true;
1551+
}
1552+
1553+
// Unless overridden below, enabling copy propagation means enabling lexical
1554+
// lifetimes.
1555+
if (Opts.CopyPropagation == CopyPropagationOption::On)
1556+
Opts.LexicalLifetimes = LexicalLifetimesOption::On;
1557+
1558+
// Unless overridden below, disable copy propagation means disabling lexical
1559+
// lifetimes.
1560+
if (Opts.CopyPropagation == CopyPropagationOption::Off)
1561+
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;
1562+
1563+
// If move-only is enabled, always enable lexical lifetime as well. Move-only
1564+
// depends on lexical lifetimes.
1565+
if (Args.hasArg(OPT_enable_experimental_move_only))
1566+
Opts.LexicalLifetimes = LexicalLifetimesOption::On;
1567+
1568+
if (enableLexicalLifetimesFlag) {
1569+
if (*enableLexicalLifetimesFlag) {
1570+
Opts.LexicalLifetimes = LexicalLifetimesOption::On;
1571+
} else {
1572+
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;
1573+
}
1574+
}
1575+
if (enableLexicalBorrowScopesFlag) {
1576+
if (*enableLexicalBorrowScopesFlag) {
1577+
Opts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly;
1578+
} else {
14721579
Opts.LexicalLifetimes = LexicalLifetimesOption::Off;
1580+
}
14731581
}
14741582

1475-
Opts.EnableCopyPropagation |= Args.hasArg(OPT_enable_copy_propagation);
1476-
Opts.DisableCopyPropagation |= Args.hasArg(OPT_disable_copy_propagation);
14771583
Opts.EnableARCOptimizations &= !Args.hasArg(OPT_disable_arc_opts);
14781584
Opts.EnableOSSAModules |= Args.hasArg(OPT_enable_ossa_modules);
14791585
Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts);

lib/IRGen/AllocStackHoisting.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ insertDeallocStackAtEndOf(SmallVectorImpl<SILInstruction *> &FunctionExits,
118118
// Insert dealloc_stack in the exit blocks.
119119
for (auto *Exit : FunctionExits) {
120120
SILBuilderWithScope Builder(Exit);
121-
Builder.createDeallocStack(AllocStack->getLoc(), AllocStack);
121+
Builder.createDeallocStack(CleanupLocation(AllocStack->getLoc()),
122+
AllocStack);
122123
}
123124
}
124125

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -856,9 +856,8 @@ BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, DestroyDefaultActor)
856856

857857
BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDistributedRemoteActor)
858858

859-
// FIXME: Why do these reqiuire a borrowed value at all?
860-
BUILTIN_OPERAND_OWNERSHIP(ForwardingBorrow, AutoDiffAllocateSubcontext)
861-
BUILTIN_OPERAND_OWNERSHIP(ForwardingBorrow, AutoDiffProjectTopLevelSubcontext)
859+
BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffAllocateSubcontext)
860+
BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffProjectTopLevelSubcontext)
862861

863862
// FIXME: ConvertTaskToJob is documented as taking NativePointer. It's operand's
864863
// ownership should be 'TrivialUse'.

0 commit comments

Comments
 (0)