Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 16 additions & 16 deletions include/swift/SIL/DebugUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,18 @@ inline SILInstruction *getSingleNonDebugUser(SILValue V) {
/// Precondition: The instruction may only have debug instructions as uses.
/// If the iterator \p InstIter references any deleted instruction, it is
/// incremented.
inline void eraseFromParentWithDebugInsts(SILInstruction *I,
SILBasicBlock::iterator &InstIter) {
///
/// \p callBack will be invoked before each instruction is deleted. \p callBack
/// is not responsible for deleting the instruction because this utility
/// unconditionally deletes the \p I and its debug users.
///
/// Returns an iterator to the next non-deleted instruction after \p I.
inline SILBasicBlock::iterator eraseFromParentWithDebugInsts(
SILInstruction *I, llvm::function_ref<void(SILInstruction *)> callBack =
[](SILInstruction *) {}) {

auto nextII = std::next(I->getIterator());

auto results = I->getResults();

bool foundAny;
Expand All @@ -183,26 +193,16 @@ inline void eraseFromParentWithDebugInsts(SILInstruction *I,
foundAny = true;
auto *User = result->use_begin()->getUser();
assert(User->isDebugInstruction());
if (InstIter == User->getIterator())
InstIter++;

if (nextII == User->getIterator())
nextII++;
callBack(User);
User->eraseFromParent();
}
}
} while (foundAny);

if (InstIter == I->getIterator())
++InstIter;

I->eraseFromParent();
}

/// Erases the instruction \p I from it's parent block and deletes it, including
/// all debug instructions which use \p I.
/// Precondition: The instruction may only have debug instructions as uses.
inline void eraseFromParentWithDebugInsts(SILInstruction *I) {
SILBasicBlock::iterator nullIter;
eraseFromParentWithDebugInsts(I, nullIter);
return nextII;
}

/// Return true if the def-use graph rooted at \p V contains any non-debug,
Expand Down
32 changes: 32 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3252,9 +3252,27 @@ class BeginBorrowInst
SingleValueInstruction> {
friend class SILBuilder;

/// Predicate used to filter EndBorrowRange.
struct UseToEndBorrow;

BeginBorrowInst(SILDebugLocation DebugLoc, SILValue LValue)
: UnaryInstructionBase(DebugLoc, LValue,
LValue->getType().getObjectType()) {}

public:
using EndBorrowRange =
OptionalTransformRange<use_range, UseToEndBorrow, use_iterator>;

/// Return a range over all EndBorrow instructions for this BeginBorrow.
EndBorrowRange getEndBorrows() const;

/// Return the single use of this BeginBorrowInst, not including any
/// EndBorrowInst uses, or return nullptr if the borrow is dead or has
/// multiple uses.
///
/// Useful for matching common SILGen patterns that emit one borrow per use,
/// and simplifying pass logic.
Operand *getSingleNonEndingUse() const;
};

/// Represents a store of a borrowed value into an address. Returns the borrowed
Expand Down Expand Up @@ -3346,6 +3364,20 @@ class EndBorrowInst
}
};

struct BeginBorrowInst::UseToEndBorrow {
Optional<EndBorrowInst *> operator()(Operand *use) const {
if (auto borrow = dyn_cast<EndBorrowInst>(use->getUser())) {
return borrow;
} else {
return None;
}
}
};

inline auto BeginBorrowInst::getEndBorrows() const -> EndBorrowRange {
return EndBorrowRange(getUses(), UseToEndBorrow());
}

/// Different kinds of access.
enum class SILAccessKind : uint8_t {
/// An access which takes uninitialized memory and initializes it.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SILOptimizer/Analysis/SimplifyInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ SILValue simplifyInstruction(SILInstruction *I);
///
/// If it is nonnull, eraseNotify will be called before each instruction is
/// deleted.
void replaceAllSimplifiedUsesAndErase(
SILBasicBlock::iterator replaceAllSimplifiedUsesAndErase(
SILInstruction *I, SILValue result,
std::function<void(SILInstruction *)> eraseNotify = nullptr);

Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ PASS(SideEffectsDumper, "side-effects-dump",
"Print Side-Effect Information for all Functions")
PASS(IRGenPrepare, "irgen-prepare",
"Cleanup SIL in preparation for IRGen")
PASS(SILGenCleanup, "silgen-cleanup",
"Cleanup SIL in preparation for diagnostics")
PASS(SILCombine, "sil-combine",
"Combine SIL Instructions via Peephole Optimization")
PASS(SILDebugInfoGenerator, "sil-debuginfo-gen",
Expand Down
87 changes: 87 additions & 0 deletions include/swift/SILOptimizer/Utils/CanonicalizeInstruction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//===-- CanonicalizeInstruction.h - canonical SIL peepholes -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// SSA-peephole transformations that yield a more canonical SIL representation.
///
/// Unlike simplifyInstruction, these transformations may effect any
/// instruction, not only single-values, and may arbitrarily generate new SIL
/// instructions.
///
/// Unlike SILCombine, these peepholes must work on 'raw' SIL form and should be
/// limited to those necessary to aid in diagnostics and other mandatory
/// pipelin/e passes. Optimization may only be done to the extent that it
/// neither interferes with diagnostics nor increases compile time.
///
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEINSTRUCTION_H
#define SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEINSTRUCTION_H

#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILInstruction.h"
#include "llvm/Support/Debug.h"

namespace swift {

/// Abstract base class. Implements all canonicalization transforms. Extended by
/// passes to be notified of each SIL modification.
struct CanonicalizeInstruction {
// May be overriden by passes.
static constexpr const char *defaultDebugType = "sil-canonicalize";
const char *debugType = defaultDebugType;

CanonicalizeInstruction(const char *passDebugType) {
#ifndef NDEBUG
if (llvm::DebugFlag && !llvm::isCurrentDebugType(debugType))
debugType = passDebugType;
#endif
}

virtual ~CanonicalizeInstruction();

/// Rewrite this instruction, based on its operands and uses, into a more
/// canonical representation.
///
/// Return an iterator to the next instruction or to the end of the block.
/// The returned iterator will follow any newly added or to-be-deleted
/// instructions, regardless of whether the pass immediately deletes the
/// instructions or simply records them for later deletion.
///
/// To (re)visit new instructions, override notifyNewInstruction().
///
/// To determine if any transformation at all occurred, override
/// notifyNewInstruction(), killInstruction(), and notifyNewUsers().
///
/// Warning: If the \p inst argument is killed and the client immediately
/// erases \p inst, then it may be an invalid pointer upon return.
SILBasicBlock::iterator canonicalize(SILInstruction *inst);

/// Record a newly generated instruction.
virtual void notifyNewInstruction(SILInstruction *inst) = 0;

/// Kill an instruction that no longer has uses, or whose side effect is now
/// represented by a different instruction. The client can defer erasing the
/// instruction but must eventually erase all killed instructions to restore
/// valid SIL.
///
/// This callback should not mutate any other instructions. It may only delete
/// the given argument. It will be called separately for each end-of-scope and
/// debug use before being called on the instruction they use.
virtual void killInstruction(SILInstruction *inst) = 0;

/// Record a SIL value that has acquired new users.
virtual void notifyHasNewUsers(SILValue value) = 0;
};

} // end namespace swift

#endif // SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEINSTRUCTION_H
19 changes: 1 addition & 18 deletions include/swift/SILOptimizer/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,14 @@ recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction*> I, bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *){});

/// For each of the given instructions, if they are dead delete them
/// along with their dead operands.
///
/// \param I The ArrayRef of instructions to be deleted.
/// \param InstIter is updated to the next valid instruction if it points to any
/// deleted instruction, including debug values.
/// \param Force If Force is set, don't check if the top level instructions
/// are considered dead - delete them regardless.
/// \param C a callback called whenever an instruction is deleted.
void recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction *> I, SILBasicBlock::iterator &InstIter,
bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *) {});

/// If the given instruction is dead, delete it along with its dead
/// operands.
///
/// \param I The instruction to be deleted.
/// \param Force If Force is set, don't check if the top level instruction is
/// considered dead - delete it regardless.
/// \param C a callback called whenever an instruction is deleted.
///
/// Returns a valid instruction iterator to the next nondeleted instruction
/// after `I`.
SILBasicBlock::iterator recursivelyDeleteTriviallyDeadInstructions(
void recursivelyDeleteTriviallyDeadInstructions(
SILInstruction *I, bool Force = false,
llvm::function_ref<void(SILInstruction *)> C = [](SILInstruction *) {});

Expand Down
14 changes: 14 additions & 0 deletions lib/SIL/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,20 @@ void SILInstruction::replaceAllUsesPairwiseWith(
}
}

Operand *BeginBorrowInst::getSingleNonEndingUse() const {
Operand *singleUse = nullptr;
for (auto *use : getUses()) {
if (isa<EndBorrowInst>(use->getUser()))
continue;

if (singleUse)
return nullptr;

singleUse = use;
}
return singleUse;
}

namespace {
class InstructionDestroyer
: public SILInstructionVisitor<InstructionDestroyer> {
Expand Down
38 changes: 29 additions & 9 deletions lib/SILOptimizer/Analysis/SimplifyInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// An SSA-peephole analysis. Given a single-value instruction, find an existing
/// equivalent but less costly or more canonical SIL value.
///
/// This analysis must handle 'raw' SIL form. It should be possible to perform
/// the substitution discovered by the analysis without interfering with
/// subsequent diagnostic passes.
///
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-simplify"
#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h"
Expand Down Expand Up @@ -665,29 +674,40 @@ SILValue swift::simplifyInstruction(SILInstruction *I) {
/// Replace an instruction with a simplified result, including any debug uses,
/// and erase the instruction. If the instruction initiates a scope, do not
/// replace the end of its scope; it will be deleted along with its parent.
void swift::replaceAllSimplifiedUsesAndErase(
///
/// This is a simple transform based on the above analysis.
///
/// Return an iterator to the next (nondeleted) instruction.
SILBasicBlock::iterator swift::replaceAllSimplifiedUsesAndErase(
SILInstruction *I, SILValue result,
std::function<void(SILInstruction *)> eraseNotify) {
std::function<void(SILInstruction *)> eraseHandler) {

auto *SVI = cast<SingleValueInstruction>(I);
assert(SVI != result && "Cannot RAUW a value with itself");
SILBasicBlock::iterator nextii = std::next(I->getIterator());

// Only SingleValueInstructions are currently simplified.
while (!SVI->use_empty()) {
Operand *use = *SVI->use_begin();
SILInstruction *user = use->getUser();
// Erase the end of scope marker.
if (isEndOfScopeMarker(user)) {
if (eraseNotify)
eraseNotify(user);
user->eraseFromParent();
if (&*nextii == user)
++nextii;
if (eraseHandler)
eraseHandler(user);
else
user->eraseFromParent();
continue;
}
use->set(result);
}
I->eraseFromParent();
if (eraseNotify)
eraseNotify(I);
if (eraseHandler)
eraseHandler(I);
else
I->eraseFromParent();

return nextii;
}

/// Simplify invocations of builtin operations that may overflow.
Expand Down
5 changes: 3 additions & 2 deletions lib/SILOptimizer/Mandatory/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ silopt_register_sources(
AccessEnforcementSelection.cpp
AccessMarkerElimination.cpp
AddressLowering.cpp
ClosureLifetimeFixup.cpp
ConstantPropagation.cpp
DefiniteInitialization.cpp
DIMemoryUseCollector.cpp
Expand All @@ -15,8 +16,8 @@ silopt_register_sources(
MandatoryInlining.cpp
PredictableMemOpt.cpp
PMOMemoryUseCollector.cpp
SemanticARCOpts.cpp
ClosureLifetimeFixup.cpp
RawSILInstLowering.cpp
SemanticARCOpts.cpp
SILGenCleanup.cpp
YieldOnceCheck.cpp
)
3 changes: 1 addition & 2 deletions lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,8 +861,7 @@ void LifetimeChecker::handleLoadForTypeOfSelfUse(const DIMemoryUse &Use) {
valueMetatype->getLoc(), metatypeArgument,
valueMetatype->getType());
}
replaceAllSimplifiedUsesAndErase(valueMetatype, metatypeArgument,
[](SILInstruction*) { });
replaceAllSimplifiedUsesAndErase(valueMetatype, metatypeArgument);
}
}

Expand Down
Loading