Files
swift-mirror/lib/SILOptimizer/Transforms/MarkUninitializedFixup.cpp
John McCall ab3f77baf2 Make SILInstruction no longer a subclass of ValueBase and
introduce a common superclass, SILNode.

This is in preparation for allowing instructions to have multiple
results.  It is also a somewhat more elegant representation for
instructions that have zero results.  Instructions that are known
to have exactly one result inherit from a class, SingleValueInstruction,
that subclasses both ValueBase and SILInstruction.  Some care must be
taken when working with SILNode pointers and testing for equality;
please see the comment on SILNode for more information.

A number of SIL passes needed to be updated in order to handle this
new distinction between SIL values and SIL instructions.

Note that the SIL parser is now stricter about not trying to assign
a result value from an instruction (like 'return' or 'strong_retain')
that does not produce any.
2017-09-25 02:06:26 -04:00

147 lines
5.2 KiB
C++

//===--- MarkUninitializedFixup.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-ownership-model-eliminator"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// Top Level Entry Point
//===----------------------------------------------------------------------===//
static ProjectBoxInst *
getInitialProjectBox(MarkUninitializedInst *MUI,
ArrayRef<ProjectBoxInst *> Projections) {
assert(!Projections.empty());
if (Projections.size() == 1) {
auto *PBI = Projections[0];
assert(PBI->getParent() == MUI->getParent());
return PBI;
}
// Otherwise, we want to select the earliest project box. There should
// only be one.
ProjectBoxInst *PBI = Projections[0];
// Otherwise, we need to find the one that is closest to the
// mark_uninitialized. It should be in the same block.
for (auto *I : makeArrayRef(Projections).slice(1)) {
// If the new instruction is in a different block than the
// mark_uninitialized, it can not be a good solution, so skip it.
if (I->getParent() != MUI->getParent()) {
continue;
}
// If PBI is not in the same block as the MUI, but I is, we picked a
// bad initial PBI, set PBI to I.
if (PBI->getParent() != MUI->getParent()) {
// Otherwise, I is a better candidate than PBI so set PBI to I.
PBI = I;
continue;
}
// Otherwise, we have that PBI and I are both in the same block. See
// which one is first.
auto *BB = PBI->getParent();
if (BB->end() != std::find_if(PBI->getIterator(), BB->end(),
[&I](const SILInstruction &InnerI) -> bool {
return I == &InnerI;
})) {
continue;
}
PBI = I;
}
assert(PBI->getParent() == MUI->getParent());
return PBI;
}
namespace {
struct MarkUninitializedFixup : SILModuleTransform {
void run() override {
bool MadeChange = false;
for (auto &F : *getModule()) {
for (auto &BB : F) {
for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
// Grab our given instruction and advance the iterator. This is
// important since we may be destroying the given instruction.
auto *MUI = dyn_cast<MarkUninitializedInst>(&*II);
++II;
// If we do not have a mark_uninitialized or we have a
// mark_uninitialized of an alloc_box, continue. These are not
// interesting to us.
if (!MUI)
continue;
auto *Box = dyn_cast<AllocBoxInst>(MUI->getOperand());
if (!Box)
continue;
// We expect there to be in most cases exactly one project_box. That
// being said, it is not impossible for there to be multiple. In such
// a case, we assume that the correct project_box is the one that is
// nearest to the mark_uninitialized in the same block. This preserves
// the existing behavior.
llvm::TinyPtrVector<ProjectBoxInst *> Projections;
for (auto *Op : MUI->getUses()) {
if (auto *PBI = dyn_cast<ProjectBoxInst>(Op->getUser())) {
Projections.push_back(PBI);
}
}
assert(!Projections.empty() && "SILGen should never emit a "
"mark_uninitialized by itself");
// First replace all uses of the mark_uninitialized with the box.
MUI->replaceAllUsesWith(Box);
// That means now our project box now has the alloc_box as its
// operand. Grab that project_box.
auto *PBI = getInitialProjectBox(MUI, Projections);
// Then create the new mark_uninitialized and force all uses of the
// project_box to go through the new mark_uninitialized.
SILBuilder B(std::next(PBI->getIterator()));
SILValue Undef = SILUndef::get(PBI->getType(), PBI->getModule());
auto *NewMUI = B.createMarkUninitialized(PBI->getLoc(), Undef,
MUI->getKind());
PBI->replaceAllUsesWith(NewMUI);
NewMUI->setOperand(PBI);
// Finally, remove the old mark_uninitialized.
MUI->eraseFromParent();
MadeChange = true;
}
}
if (MadeChange) {
auto InvalidKind =
SILAnalysis::InvalidationKind::BranchesAndInstructions;
invalidateAnalysis(&F, InvalidKind);
}
}
}
};
} // end anonymous namespace
SILTransform *swift::createMarkUninitializedFixup() {
return new MarkUninitializedFixup();
}