Skip to content

Commit aa38be6

Browse files
committed
[inst-simplify] Hide simplifyInstruction in favor of using simplifyAndReplaceAllSimplifiedUsesAndErase.
Currently all of these places in the code base perform simplifyInstruction and then a replaceAllSimplifiedUsesAndErase(...). This is a bad pattern since: 1. simplifyInstruction assumes its result will be passed to replaceAllSimplifiedUsesAndErase. So by leaving these as separate things, we allow for users to pointlessly make this mistake. 2. I am going to implement in a subsequent commit a utility that lifetime extends interior pointer bases when replacing an address with an interior pointer derived address. To do this efficiently, I want to reuse state I compute during simplifyInstruction during the actual RAUW meaning that if the two operations are split, that is difficult without extending the API. So by removing this, I can make the transform and eliminate mistakes at the same time.
1 parent 31881ae commit aa38be6

File tree

9 files changed

+60
-62
lines changed

9 files changed

+60
-62
lines changed

include/swift/SILOptimizer/Analysis/SimplifyInstruction.h

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,28 @@ namespace swift {
2727
class SILInstruction;
2828
class InstModCallbacks;
2929

30-
/// Try to simplify the specified instruction, performing local
31-
/// analysis of the operands of the instruction, without looking at its uses
32-
/// (e.g. constant folding). If a simpler result can be found, it is
33-
/// returned, otherwise a null SILValue is returned.
34-
///
35-
/// This is assumed to implement read-none transformations.
36-
SILValue simplifyInstruction(SILInstruction *I);
37-
3830
/// Replace an instruction with a simplified result and erase it. If the
3931
/// instruction initiates a scope, do not replace the end of its scope; it will
4032
/// be deleted along with its parent.
4133
///
42-
/// If it is nonnull, eraseNotify will be called before each instruction is
43-
/// deleted.
44-
///
45-
/// If it is nonnull and inst is in OSSA, newInstNotify will be called with each
46-
/// new instruction inserted to compensate for ownership.
47-
///
4834
/// NOTE: When OSSA is enabled this API assumes OSSA is properly formed and will
4935
/// insert compensating instructions.
5036
SILBasicBlock::iterator
5137
replaceAllSimplifiedUsesAndErase(SILInstruction *I, SILValue result,
5238
InstModCallbacks &callbacks,
5339
DeadEndBlocks *deadEndBlocks = nullptr);
5440

41+
/// Attempt to map \p inst to a simplified result. Upon success, replace \p inst
42+
/// with this simplified result and erase \p inst. If the instruction initiates
43+
/// a scope, do not replace the end of its scope; it will be deleted along with
44+
/// its parent.
45+
///
46+
/// NOTE: When OSSA is enabled this API assumes OSSA is properly formed and will
47+
/// insert compensating instructions.
48+
SILBasicBlock::iterator simplifyAndReplaceAllSimplifiedUsesAndErase(
49+
SILInstruction *I, InstModCallbacks &callbacks,
50+
DeadEndBlocks *deadEndBlocks = nullptr);
51+
5552
// Simplify invocations of builtin operations that may overflow.
5653
/// All such operations return a tuple (result, overflow_flag).
5754
/// This function try to simplify such operations, but returns only a

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ class InstModCallbacks {
399399
}
400400

401401
bool hadCallbackInvocation() const { return wereAnyCallbacksInvoked; }
402+
403+
/// Set \p wereAnyCallbacksInvoked to false. Useful if one wants to reuse an
404+
/// InstModCallback in between iterations.
405+
void resetHadCallbackInvocation() { wereAnyCallbacksInvoked = false; }
402406
};
403407

404408
/// Get all consumed arguments of a partial_apply.

lib/SILOptimizer/Analysis/SimplifyInstruction.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ SILValue swift::simplifyOverflowBuiltinInstruction(BuiltinInst *BI) {
779779
///
780780
/// NOTE: We assume that the insertion point associated with the SILValue must
781781
/// dominate \p i.
782-
SILValue swift::simplifyInstruction(SILInstruction *i) {
782+
static SILValue simplifyInstruction(SILInstruction *i) {
783783
SILValue result = InstSimplifier().visit(i);
784784
if (!result)
785785
return SILValue();
@@ -795,3 +795,25 @@ SILValue swift::simplifyInstruction(SILInstruction *i) {
795795

796796
return result;
797797
}
798+
799+
SILBasicBlock::iterator swift::simplifyAndReplaceAllSimplifiedUsesAndErase(
800+
SILInstruction *i, InstModCallbacks &callbacks,
801+
DeadEndBlocks *deadEndBlocks) {
802+
auto next = std::next(i->getIterator());
803+
auto *svi = dyn_cast<SingleValueInstruction>(i);
804+
if (!svi)
805+
return next;
806+
SILValue result = simplifyInstruction(i);
807+
808+
// If we fail to simplify or the simplified value returned is our passed in
809+
// value, just return std::next since we can't simplify.
810+
if (!result || svi == result)
811+
return next;
812+
813+
if (svi->getFunction()->hasOwnership()) {
814+
JointPostDominanceSetComputer computer(*deadEndBlocks);
815+
OwnershipFixupContext ctx{callbacks, *deadEndBlocks, computer};
816+
return ctx.replaceAllUsesAndErase(svi, result);
817+
}
818+
return replaceAllUsesAndErase(svi, result, callbacks);
819+
}

lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -479,13 +479,11 @@ static bool stripOwnership(SILFunction &func) {
479479
auto value = visitor.instructionsToSimplify.pop_back_val();
480480
if (!value.hasValue())
481481
continue;
482-
if (SILValue newValue = simplifyInstruction(*value)) {
483-
InstModCallbacks callbacks([&](SILInstruction *instToErase) {
484-
visitor.eraseInstruction(instToErase);
485-
});
486-
replaceAllSimplifiedUsesAndErase(*value, newValue, callbacks);
487-
madeChange = true;
488-
}
482+
InstModCallbacks callbacks([&](SILInstruction *instToErase) {
483+
visitor.eraseInstruction(instToErase);
484+
});
485+
simplifyAndReplaceAllSimplifiedUsesAndErase(*value, callbacks);
486+
madeChange |= callbacks.hadCallbackInvocation();
489487
}
490488

491489
return madeChange;

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,6 @@ static bool isLazyPropertyGetter(ApplyInst *ai) {
937937

938938
bool CSE::processNode(DominanceInfoNode *Node) {
939939
SILBasicBlock *BB = Node->getBlock();
940-
InstModCallbacks callbacks;
941940
bool Changed = false;
942941

943942
// See if any instructions in the block can be eliminated. If so, do it. If
@@ -961,12 +960,12 @@ bool CSE::processNode(DominanceInfoNode *Node) {
961960

962961
// If the instruction can be simplified (e.g. X+0 = X) then replace it with
963962
// its simpler value.
964-
if (SILValue V = simplifyInstruction(Inst)) {
965-
LLVM_DEBUG(llvm::dbgs()
966-
<< "SILCSE SIMPLIFY: " << *Inst << " to: " << *V << '\n');
967-
nextI = replaceAllSimplifiedUsesAndErase(Inst, V, callbacks, &DeadEndBBs);
968-
Changed = true;
963+
InstModCallbacks callbacks;
964+
nextI = simplifyAndReplaceAllSimplifiedUsesAndErase(Inst, callbacks,
965+
&DeadEndBBs);
966+
if (callbacks.hadCallbackInvocation()) {
969967
++NumSimplify;
968+
Changed = true;
970969
continue;
971970
}
972971

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,24 +1138,15 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
11381138
/// simplifyBranchOperands - Simplify operands of branches, since it can
11391139
/// result in exposing opportunities for CFG simplification.
11401140
bool SimplifyCFG::simplifyBranchOperands(OperandValueArrayRef Operands) {
1141-
bool Simplified = false;
11421141
InstModCallbacks callbacks;
11431142
for (auto O = Operands.begin(), E = Operands.end(); O != E; ++O) {
11441143
// All of our interesting simplifications are on single-value instructions
11451144
// for now.
11461145
if (auto *I = dyn_cast<SingleValueInstruction>(*O)) {
1147-
SILValue Result = simplifyInstruction(I);
1148-
1149-
// The Result can be the same instruction I in case it is in an
1150-
// unreachable block. In this case it can reference itself as operand.
1151-
if (Result && Result != I) {
1152-
LLVM_DEBUG(llvm::dbgs() << "simplify branch operand " << *I);
1153-
replaceAllSimplifiedUsesAndErase(I, Result, callbacks);
1154-
Simplified = true;
1155-
}
1146+
simplifyAndReplaceAllSimplifiedUsesAndErase(I, callbacks);
11561147
}
11571148
}
1158-
return Simplified;
1149+
return callbacks.hadCallbackInvocation();
11591150
}
11601151

11611152
static bool onlyHasTerminatorAndDebugInsts(SILBasicBlock *BB) {

lib/SILOptimizer/Transforms/TempRValueElimination.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -756,9 +756,7 @@ void TempRValueOptPass::run() {
756756
// Simplify any access scope markers that were only used by the dead
757757
// copy_addr and other potentially unused addresses.
758758
if (srcInst) {
759-
if (SILValue result = simplifyInstruction(srcInst)) {
760-
replaceAllSimplifiedUsesAndErase(srcInst, result, callbacks);
761-
}
759+
simplifyAndReplaceAllSimplifiedUsesAndErase(srcInst, callbacks);
762760
}
763761
}
764762
if (changed) {

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,16 @@ killInstAndIncidentalUses(SingleValueInstruction *inst,
8181
// intruction that wasn't erased.
8282
static Optional<SILBasicBlock::iterator>
8383
simplifyAndReplace(SILInstruction *inst, CanonicalizeInstruction &pass) {
84-
SILValue result = simplifyInstruction(inst);
85-
if (!result)
86-
return None;
87-
88-
++NumSimplified;
89-
90-
LLVM_DEBUG(llvm::dbgs() << "Simplify Old = " << *inst
91-
<< " New = " << *result << '\n');
92-
9384
// Erase the simplified instruction and any instructions that end its
9485
// scope. Nothing needs to be added to the worklist except for Result,
9586
// because the instruction and all non-replaced users will be deleted.
96-
auto nextII = replaceAllSimplifiedUsesAndErase(inst, result, pass.callbacks,
97-
&pass.deadEndBlocks);
87+
pass.callbacks.resetHadCallbackInvocation();
88+
auto result = simplifyAndReplaceAllSimplifiedUsesAndErase(
89+
inst, pass.callbacks, &pass.deadEndBlocks);
90+
if (!pass.callbacks.hadCallbackInvocation())
91+
return None;
9892

99-
// Push the new instruction and any users onto the worklist.
100-
pass.notifyHasNewUsers(result);
101-
return nextII;
93+
return result;
10294
}
10395

10496
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,12 +1458,9 @@ bool swift::simplifyUsers(SingleValueInstruction *inst) {
14581458
if (!svi)
14591459
continue;
14601460

1461-
SILValue S = simplifyInstruction(svi);
1462-
if (!S)
1463-
continue;
1464-
1465-
replaceAllSimplifiedUsesAndErase(svi, S, callbacks);
1466-
changed = true;
1461+
callbacks.resetHadCallbackInvocation();
1462+
simplifyAndReplaceAllSimplifiedUsesAndErase(svi, callbacks);
1463+
changed |= callbacks.hadCallbackInvocation();
14671464
}
14681465

14691466
return changed;

0 commit comments

Comments
 (0)