Skip to content

Commit 1ca5577

Browse files
authored
Merge pull request #34559 from gottesmm/ossa-inst-simplify
[inst-simplify] Update for OSSA
2 parents 579274b + 259d2bb commit 1ca5577

25 files changed

+2074
-104
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class DeadEndBlocks {
8989
}
9090
return ReachableBlocks.empty();
9191
}
92+
93+
const SILFunction *getFunction() const { return F; }
9294
};
9395

9496
/// A struct that contains the intermediate state used in computing

include/swift/SIL/OwnershipUtils.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,15 @@ struct BorrowingOperand {
170170
return *this;
171171
}
172172

173+
// A set of operators so that a BorrowingOperand can be used like a normal
174+
// operand in a light weight way.
175+
operator const Operand *() const { return op; }
176+
operator Operand *() { return op; }
177+
const Operand *operator*() const { return op; }
178+
Operand *operator*() { return op; }
179+
const Operand *operator->() const { return op; }
180+
Operand *operator->() { return op; }
181+
173182
/// If \p op is a borrow introducing operand return it after doing some
174183
/// checks.
175184
static Optional<BorrowingOperand> get(Operand *op) {
@@ -425,7 +434,7 @@ struct BorrowedValue {
425434
///
426435
/// NOTE: Scratch space is used internally to this method to store the end
427436
/// borrow scopes if needed.
428-
bool areUsesWithinScope(ArrayRef<Operand *> instructions,
437+
bool areUsesWithinScope(ArrayRef<Operand *> uses,
429438
SmallVectorImpl<Operand *> &scratchSpace,
430439
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
431440
DeadEndBlocks &deadEndBlocks) const;
@@ -447,6 +456,24 @@ struct BorrowedValue {
447456
bool visitInteriorPointerOperands(
448457
function_ref<void(const InteriorPointerOperand &)> func) const;
449458

459+
/// Visit all immediate uses of this borrowed value and if any of them are
460+
/// reborrows, place them in BorrowingOperand form into \p
461+
/// foundReborrows. Returns true if we appended any such reborrows to
462+
/// foundReborrows... false otherwise.
463+
bool
464+
gatherReborrows(SmallVectorImpl<BorrowingOperand> &foundReborrows) const {
465+
bool foundAnyReborrows = false;
466+
for (auto *op : value->getUses()) {
467+
if (auto borrowingOperand = BorrowingOperand::get(op)) {
468+
if (borrowingOperand->isReborrow()) {
469+
foundReborrows.push_back(*borrowingOperand);
470+
foundAnyReborrows = true;
471+
}
472+
}
473+
}
474+
return foundAnyReborrows;
475+
}
476+
450477
private:
451478
/// Internal constructor for failable static constructor. Please do not expand
452479
/// its usage since it assumes the code passed in is well formed.

include/swift/SILOptimizer/Analysis/SimplifyInstruction.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class SILInstruction;
3030
/// analysis of the operands of the instruction, without looking at its uses
3131
/// (e.g. constant folding). If a simpler result can be found, it is
3232
/// returned, otherwise a null SILValue is returned.
33+
///
34+
/// This is assumed to implement read-none transformations.
3335
SILValue simplifyInstruction(SILInstruction *I);
3436

3537
/// Replace an instruction with a simplified result and erase it. If the
@@ -38,9 +40,17 @@ SILValue simplifyInstruction(SILInstruction *I);
3840
///
3941
/// If it is nonnull, eraseNotify will be called before each instruction is
4042
/// deleted.
43+
///
44+
/// If it is nonnull and inst is in OSSA, newInstNotify will be called with each
45+
/// new instruction inserted to compensate for ownership.
46+
///
47+
/// NOTE: When OSSA is enabled this API assumes OSSA is properly formed and will
48+
/// insert compensating instructions.
4149
SILBasicBlock::iterator replaceAllSimplifiedUsesAndErase(
4250
SILInstruction *I, SILValue result,
43-
std::function<void(SILInstruction *)> eraseNotify = nullptr);
51+
std::function<void(SILInstruction *)> eraseNotify = nullptr,
52+
std::function<void(SILInstruction *)> newInstNotify = nullptr,
53+
DeadEndBlocks *deadEndBlocks = nullptr);
4454

4555
/// Simplify invocations of builtin operations that may overflow.
4656
/// All such operations return a tuple (result, overflow_flag).

include/swift/SILOptimizer/Utils/CanonicalizeInstruction.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#ifndef SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEINSTRUCTION_H
2727
#define SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEINSTRUCTION_H
2828

29+
#include "swift/SIL/BasicBlockUtils.h"
2930
#include "swift/SIL/SILBasicBlock.h"
3031
#include "swift/SIL/SILInstruction.h"
3132
#include "llvm/Support/Debug.h"
@@ -38,8 +39,11 @@ struct CanonicalizeInstruction {
3839
// May be overriden by passes.
3940
static constexpr const char *defaultDebugType = "sil-canonicalize";
4041
const char *debugType = defaultDebugType;
42+
DeadEndBlocks &deadEndBlocks;
4143

42-
CanonicalizeInstruction(const char *passDebugType) {
44+
CanonicalizeInstruction(const char *passDebugType,
45+
DeadEndBlocks &deadEndBlocks)
46+
: deadEndBlocks(deadEndBlocks) {
4347
#ifndef NDEBUG
4448
if (llvm::DebugFlag && !llvm::isCurrentDebugType(debugType))
4549
debugType = passDebugType;
@@ -48,6 +52,8 @@ struct CanonicalizeInstruction {
4852

4953
virtual ~CanonicalizeInstruction();
5054

55+
const SILFunction *getFunction() const { return deadEndBlocks.getFunction(); }
56+
5157
/// Rewrite this instruction, based on its operands and uses, into a more
5258
/// canonical representation.
5359
///

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ namespace swift {
3535
class DominanceInfo;
3636
template <class T> class NullablePtr;
3737

38-
/// Transform a Use Range (Operand*) into a User Range (SILInstruction*)
38+
/// Transform a Use Range (Operand*) into a User Range (SILInstruction *)
3939
using UserTransform = std::function<SILInstruction *(Operand *)>;
4040
using ValueBaseUserRange =
4141
TransformRange<iterator_range<ValueBase::use_iterator>, UserTransform>;
4242

43-
inline ValueBaseUserRange
44-
makeUserRange(iterator_range<ValueBase::use_iterator> range) {
43+
template <typename Range>
44+
inline TransformRange<Range, UserTransform> makeUserRange(Range range) {
4545
auto toUser = [](Operand *operand) { return operand->getUser(); };
4646
return makeTransformRange(range, UserTransform(toUser));
4747
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- OwnershipOptUtils.h ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// Ownership Utilities that rely on SILOptimizer functionality.
16+
///
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_SILOPTIMIZER_UTILS_OWNERSHIPOPTUTILS_H
20+
#define SWIFT_SILOPTIMIZER_UTILS_OWNERSHIPOPTUTILS_H
21+
22+
#include "swift/SIL/OwnershipUtils.h"
23+
#include "swift/SIL/SILModule.h"
24+
25+
namespace swift {
26+
27+
// Defined in BasicBlockUtils.h
28+
struct JointPostDominanceSetComputer;
29+
30+
struct OwnershipFixupContext {
31+
std::function<void(SILInstruction *)> eraseNotify;
32+
std::function<void(SILInstruction *)> newInstNotify;
33+
DeadEndBlocks &deBlocks;
34+
JointPostDominanceSetComputer &jointPostDomSetComputer;
35+
36+
SILBasicBlock::iterator
37+
replaceAllUsesAndEraseFixingOwnership(SingleValueInstruction *oldValue,
38+
SILValue newValue);
39+
40+
/// We can not RAUW all old values with new values.
41+
///
42+
/// Namely, we do not support RAUWing values with ValueOwnershipKind::None
43+
/// that have uses that do not require ValueOwnershipKind::None or
44+
/// ValueOwnershipKind::Any.
45+
static bool canFixUpOwnershipForRAUW(SingleValueInstruction *oldValue,
46+
SILValue newValue);
47+
};
48+
49+
} // namespace swift
50+
51+
#endif

lib/SIL/Utils/BasicBlockUtils.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,20 +387,22 @@ void DeadEndBlocks::compute() {
387387

388388
void JointPostDominanceSetComputer::findJointPostDominatingSet(
389389
SILBasicBlock *dominatingBlock, ArrayRef<SILBasicBlock *> dominatedBlockSet,
390-
function_ref<void(SILBasicBlock *)> foundInputBlocksNotInJointPostDomSet,
390+
function_ref<void(SILBasicBlock *)> inputBlocksFoundDuringWalk,
391391
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
392-
function_ref<void(SILBasicBlock *)> foundInputBlocksInJointPostDomSet) {
392+
function_ref<void(SILBasicBlock *)> inputBlocksInJointPostDomSet) {
393393
// If our reachable block set is empty, assert. This is most likely programmer
394394
// error.
395395
assert(dominatedBlockSet.size() != 0);
396396

397397
// If we have a reachable block set with a single block and that block is
398398
// dominatingBlock, then we return success since a block post-doms its self so
399399
// it is already complete.
400+
//
401+
// NOTE: We do not consider this a visiteed
400402
if (dominatedBlockSet.size() == 1) {
401403
if (dominatingBlock == dominatedBlockSet[0]) {
402-
if (foundInputBlocksInJointPostDomSet)
403-
foundInputBlocksInJointPostDomSet(dominatingBlock);
404+
if (inputBlocksInJointPostDomSet)
405+
inputBlocksInJointPostDomSet(dominatingBlock);
404406
return;
405407
}
406408
}
@@ -475,16 +477,16 @@ void JointPostDominanceSetComputer::findJointPostDominatingSet(
475477
// callback.
476478
sortUnique(reachableInputBlocks);
477479
for (auto *block : reachableInputBlocks)
478-
foundInputBlocksNotInJointPostDomSet(block);
480+
inputBlocksFoundDuringWalk(block);
479481

480482
// Then if were asked to find the subset of our input blocks that are in the
481483
// joint-postdominance set, compute that.
482-
if (!foundInputBlocksInJointPostDomSet)
484+
if (!inputBlocksInJointPostDomSet)
483485
return;
484486

485487
// Pass back the reachable input blocks that were not reachable from other
486488
// input blocks to.
487489
for (auto *block : dominatedBlockSet)
488490
if (lower_bound(reachableInputBlocks, block) == reachableInputBlocks.end())
489-
foundInputBlocksInJointPostDomSet(block);
491+
inputBlocksInJointPostDomSet(block);
490492
}

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,17 @@ bool BorrowingOperand::visitLocalEndScopeUses(
221221
case BorrowingOperandKind::TryApply:
222222
case BorrowingOperandKind::Yield:
223223
return true;
224-
case BorrowingOperandKind::Branch:
224+
case BorrowingOperandKind::Branch: {
225+
auto *br = cast<BranchInst>(op->getUser());
226+
for (auto *use : br->getArgForOperand(op)->getUses())
227+
if (use->isLifetimeEnding())
228+
if (!func(use))
229+
return false;
225230
return true;
226231
}
232+
}
233+
234+
llvm_unreachable("Covered switch isn't covered");
227235
}
228236

229237
void BorrowingOperand::visitBorrowIntroducingUserResults(

0 commit comments

Comments
 (0)