Skip to content

Commit c7f2130

Browse files
authored
Merge pull request #36245 from atrick/mandatory-copyprop
Add support for a mandatory-copy-propagation pass.
2 parents 109a33c + 291467c commit c7f2130

24 files changed

+675
-562
lines changed

include/swift/AST/SILOptions.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class SILOptions {
4444
/// Remove all runtime assertions during optimizations.
4545
bool RemoveRuntimeAsserts = false;
4646

47+
/// Force-run SIL copy propagation to shorten object lifetime in whatever
48+
/// optimization pipeline is currently used.
49+
/// When this is 'false' the pipeline has default behavior.
50+
bool EnableCopyPropagation = false;
51+
52+
/// Disable SIL copy propagation to preserve object lifetime in whatever
53+
/// optimization pipeline is currently used.
54+
/// When this is 'false' the pipeline has default behavior.
55+
bool DisableCopyPropagation = false;
56+
4757
/// Controls whether the SIL ARC optimizations are run.
4858
bool EnableARCOptimizations = true;
4959

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ def batch_scan_input_file
188188
def import_prescan : Flag<["-"], "import-prescan">,
189189
HelpText<"When performing a dependency scan, only dentify all imports of the main Swift module sources">;
190190

191+
def enable_copy_propagation : Flag<["-"], "enable-copy-propagation">,
192+
HelpText<"Run SIL copy propagation to shorten object lifetime.">;
193+
def disable_copy_propagation : Flag<["-"], "disable-copy-propagation">,
194+
HelpText<"Don't run SIL copy propagation to preserve object lifetime.">;
195+
191196
def enable_infer_public_concurrent_value : Flag<["-"], "enable-infer-public-concurrent-value">,
192197
HelpText<"Enable inference of ConcurrentValue conformances for public structs and enums">;
193198

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ PASS(GlobalOpt, "global-opt",
202202
"SIL Global Optimization")
203203
PASS(GlobalPropertyOpt, "global-property-opt",
204204
"Global Property Optimization")
205-
PASS(GuaranteedARCOpts, "guaranteed-arc-opts",
206-
"Guaranteed ARC Optimization")
205+
PASS(MandatoryARCOpts, "mandatory-arc-opts",
206+
"Mandatory ARC Optimization")
207207
PASS(HighLevelCSE, "high-level-cse",
208208
"Common Subexpression Elimination on High-Level SIL")
209209
PASS(HighLevelLICM, "high-level-licm",

include/swift/SILOptimizer/Utils/CanonicalOSSALifetime.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class CanonicalizeOSSALifetime {
187187
private:
188188
/// If true, then debug_value instructions outside of non-debug
189189
/// liveness may be pruned during canonicalization.
190-
bool pruneDebug;
190+
bool pruneDebugMode;
191191

192192
NonLocalAccessBlockAnalysis *accessBlockAnalysis;
193193
// Lazily initialize accessBlocks only when
@@ -237,12 +237,13 @@ class CanonicalizeOSSALifetime {
237237
CanonicalOSSAConsumeInfo consumes;
238238

239239
public:
240-
CanonicalizeOSSALifetime(bool pruneDebug,
240+
CanonicalizeOSSALifetime(bool pruneDebugMode,
241241
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
242242
DominanceAnalysis *dominanceAnalysis,
243243
DeadEndBlocks *deBlocks)
244-
: pruneDebug(pruneDebug), accessBlockAnalysis(accessBlockAnalysis),
245-
dominanceAnalysis(dominanceAnalysis), deBlocks(deBlocks) {}
244+
: pruneDebugMode(pruneDebugMode),
245+
accessBlockAnalysis(accessBlockAnalysis),
246+
dominanceAnalysis(dominanceAnalysis), deBlocks(deBlocks) {}
246247

247248
SILValue getCurrentDef() const { return currentDef; }
248249

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
11891189
// -Ounchecked might also set removal of runtime asserts (cond_fail).
11901190
Opts.RemoveRuntimeAsserts |= Args.hasArg(OPT_RemoveRuntimeAsserts);
11911191

1192+
Opts.EnableCopyPropagation |= Args.hasArg(OPT_enable_copy_propagation);
1193+
Opts.DisableCopyPropagation |= Args.hasArg(OPT_disable_copy_propagation);
11921194
Opts.EnableARCOptimizations &= !Args.hasArg(OPT_disable_arc_opts);
11931195
Opts.EnableOSSAModules |= Args.hasArg(OPT_enable_ossa_modules);
11941196
Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts);

lib/SIL/Verifier/MemoryLifetime.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,13 @@ void MemoryLocations::analyzeLocations(SILFunction *function) {
168168
case SILArgumentConvention::Indirect_In:
169169
case SILArgumentConvention::Indirect_In_Constant:
170170
case SILArgumentConvention::Indirect_In_Guaranteed:
171-
case SILArgumentConvention::Indirect_Inout:
172171
case SILArgumentConvention::Indirect_Out:
172+
// These are not SIL addresses under -enable-sil-opaque-values
173+
if (!function->getConventions().useLoweredAddresses())
174+
break;
175+
176+
LLVM_FALLTHROUGH;
177+
case SILArgumentConvention::Indirect_Inout:
173178
analyzeLocation(funcArg);
174179
break;
175180
default:

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,9 @@ void addFunctionPasses(SILPassPipelinePlan &P,
350350
if (P.getOptions().EnableOSSAModules) {
351351
// We earlier eliminated ownership if we are not compiling the stdlib. Now
352352
// handle the stdlib functions, re-simplifying, eliminating ARC as we do.
353-
P.addCopyPropagation();
353+
if (!P.getOptions().DisableCopyPropagation) {
354+
P.addCopyPropagation();
355+
}
354356
P.addSemanticARCOpts();
355357
}
356358

@@ -372,7 +374,9 @@ void addFunctionPasses(SILPassPipelinePlan &P,
372374

373375
// Clean up Semantic ARC before we perform additional post-inliner opts.
374376
if (P.getOptions().EnableOSSAModules) {
375-
P.addCopyPropagation();
377+
if (!P.getOptions().DisableCopyPropagation) {
378+
P.addCopyPropagation();
379+
}
376380
P.addSemanticARCOpts();
377381
}
378382

@@ -437,7 +441,9 @@ void addFunctionPasses(SILPassPipelinePlan &P,
437441

438442
// Run a final round of ARC opts when ownership is enabled.
439443
if (P.getOptions().EnableOSSAModules) {
440-
P.addCopyPropagation();
444+
if (!P.getOptions().DisableCopyPropagation) {
445+
P.addCopyPropagation();
446+
}
441447
P.addSemanticARCOpts();
442448
}
443449
}
@@ -471,7 +477,9 @@ static void addPerfEarlyModulePassPipeline(SILPassPipelinePlan &P) {
471477
// Cleanup after SILGen: remove trivial copies to temporaries.
472478
P.addTempRValueOpt();
473479
// Cleanup after SILGen: remove unneeded borrows/copies.
474-
P.addCopyPropagation();
480+
if (!P.getOptions().DisableCopyPropagation) {
481+
P.addCopyPropagation();
482+
}
475483
P.addSemanticARCOpts();
476484

477485
// Devirtualizes differentiability witnesses into functions that reference them.
@@ -785,7 +793,9 @@ SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) {
785793
// Run one last copy propagation/semantic arc opts run before serialization/us
786794
// lowering ownership.
787795
if (P.getOptions().EnableOSSAModules) {
788-
P.addCopyPropagation();
796+
if (!P.getOptions().DisableCopyPropagation) {
797+
P.addCopyPropagation();
798+
}
789799
P.addSemanticARCOpts();
790800
}
791801

@@ -835,7 +845,13 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) {
835845
P.startPipeline("non-Diagnostic Enabling Mandatory Optimizations");
836846
P.addForEachLoopUnroll();
837847
P.addMandatoryCombine();
838-
P.addGuaranteedARCOpts();
848+
if (P.getOptions().EnableCopyPropagation) {
849+
// MandatoryCopyPropagation should only be run at -Onone, not -O.
850+
P.addMandatoryCopyPropagation();
851+
}
852+
// TODO: MandatoryARCOpts should be subsumed by CopyPropagation. There should
853+
// be no need to run another analysis of copies at -Onone.
854+
P.addMandatoryARCOpts();
839855

840856
// First serialize the SIL if we are asked to.
841857
P.startPipeline("Serialization");

lib/SILOptimizer/SemanticARC/Context.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ struct LLVM_LIBRARY_VISIBILITY Context {
109109
/// As an example, we do not do load [copy] optimizations here since they
110110
/// generally involve more complex analysis, but simple peepholes of
111111
/// copy_values we /do/ allow.
112-
bool onlyGuaranteedOpts;
112+
bool onlyMandatoryOpts;
113113

114114
/// Callbacks that we must use to remove or RAUW values.
115115
InstModCallbacks instModCallbacks;
@@ -119,11 +119,11 @@ struct LLVM_LIBRARY_VISIBILITY Context {
119119

120120
DeadEndBlocks &getDeadEndBlocks() { return deadEndBlocks; }
121121

122-
Context(SILFunction &fn, DeadEndBlocks &deBlocks, bool onlyGuaranteedOpts,
122+
Context(SILFunction &fn, DeadEndBlocks &deBlocks, bool onlyMandatoryOpts,
123123
InstModCallbacks callbacks)
124124
: fn(fn), deadEndBlocks(deBlocks), lifetimeFrontier(),
125125
addressToExhaustiveWriteListCache(constructCacheValue),
126-
onlyGuaranteedOpts(onlyGuaranteedOpts), instModCallbacks(callbacks) {}
126+
onlyMandatoryOpts(onlyMandatoryOpts), instModCallbacks(callbacks) {}
127127

128128
void verify() const;
129129

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,11 @@ using namespace swift::semanticarc;
6666
// are within the borrow scope.
6767
//
6868
// TODO: This needs a better name.
69-
//
70-
// FIXME: CanonicalizeOSSALifetime replaces this once it supports borrows.
7169
bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
7270
CopyValueInst *cvi) {
73-
// For now, do not run this optimization. This is just to be careful.
74-
if (ctx.onlyGuaranteedOpts)
71+
// All mandatory copy optimization is handled by CanonicalizeOSSALifetime,
72+
// which knows how to preserve lifetimes for debugging.
73+
if (ctx.onlyMandatoryOpts)
7574
return false;
7675

7776
SmallVector<BorrowedValue, 4> borrowScopeIntroducers;
@@ -721,11 +720,11 @@ bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand(
721720

722721
/// Given an owned value that is completely enclosed within its parent owned
723722
/// value and is not consumed, eliminate the copy.
724-
///
725-
/// FIXME: CanonicalizeOSSALifetime replaces this.
726723
bool SemanticARCOptVisitor::tryPerformOwnedCopyValueOptimization(
727724
CopyValueInst *cvi) {
728-
if (ctx.onlyGuaranteedOpts)
725+
// All mandatory copy optimization is handled by CanonicalizeOSSALifetime,
726+
// which knows how to preserve lifetimes for debugging.
727+
if (ctx.onlyMandatoryOpts)
729728
return false;
730729

731730
auto originalValue = cvi->getOperand();

lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ static bool isWrittenTo(Context &ctx, LoadInst *load,
321321
bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
322322
// This optimization can use more complex analysis. We should do some
323323
// experiments before enabling this by default as a guaranteed optimization.
324-
if (ctx.onlyGuaranteedOpts)
324+
if (ctx.onlyMandatoryOpts)
325325
return false;
326326

327327
// If we are not supposed to perform this transform, bail.

0 commit comments

Comments
 (0)