Files
swift-mirror/lib/SILOptimizer/Mandatory/AccessMarkerElimination.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

191 lines
6.3 KiB
C++

//===--- AccessMarkerElimination.cpp - Eliminate access markers. ----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// This pass eliminates the instructions that demarcate memory access regions.
/// If no memory access markers exist, then the pass does nothing. Otherwise, it
/// unconditionally eliminates all non-dynamic markers (plus any dynamic markers
/// if dynamic exclusivity checking is disabled).
///
/// This is an always-on pass for temporary bootstrapping. It allows running
/// test cases through the pipeline and exercising SIL verification before all
/// passes support access markers.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "access-marker-elim"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/Support/CommandLine.h"
using namespace swift;
// This temporary option allows markers during optimization passes. Enabling
// this flag causes this pass to preserve only dynamic checks when dynamic
// checking is enabled. Otherwise, this pass removes all checks.
//
// This is currently unsupported because tail duplication results in
// address-type block arguments.
llvm::cl::opt<bool> EnableOptimizedAccessMarkers(
"sil-optimized-access-markers", llvm::cl::init(false),
llvm::cl::desc("Enable memory access markers during optimization passes."));
namespace {
struct AccessMarkerElimination {
SILModule *Mod;
SILFunction *F;
bool removedAny = false;
AccessMarkerElimination(SILFunction *F)
: Mod(&F->getModule()), F(F) {}
SILBasicBlock::iterator eraseInst(SILInstruction *inst) {
DEBUG(llvm::dbgs() << "Erasing access marker: " << *inst);
removedAny = true;
return inst->getParent()->erase(inst);
};
void replaceBeginAccessUsers(BeginAccessInst *beginAccess);
bool shouldPreserveAccess(SILAccessEnforcement enforcement);
// Check if the instruction is a marker that should be eliminated. If so,
// updated the SIL, short of erasing the marker itself, and return true.
bool checkAndEliminateMarker(SILInstruction *inst);
// Entry point called either by the pass by the same name
// or as a utility (e.g. during deserialization).
bool stripMarkers();
};
void AccessMarkerElimination::replaceBeginAccessUsers(
BeginAccessInst *beginAccess) {
// Handle all the uses:
while (!beginAccess->use_empty()) {
Operand *op = *beginAccess->use_begin();
// Delete any associated end_access instructions.
if (auto endAccess = dyn_cast<EndAccessInst>(op->getUser())) {
endAccess->eraseFromParent();
// Forward all other uses to the original address.
} else {
op->set(beginAccess->getSource());
}
}
}
bool AccessMarkerElimination::shouldPreserveAccess(
SILAccessEnforcement enforcement) {
if (!EnableOptimizedAccessMarkers)
return false;
switch (enforcement) {
case SILAccessEnforcement::Static:
case SILAccessEnforcement::Unsafe:
return false;
case SILAccessEnforcement::Unknown:
case SILAccessEnforcement::Dynamic:
return Mod->getOptions().EnforceExclusivityDynamic;
}
}
// Check if the instruction is a marker that should be eliminated. If so,
// updated the SIL, short of erasing the marker itself, and return true.
bool AccessMarkerElimination::checkAndEliminateMarker(SILInstruction *inst) {
if (auto beginAccess = dyn_cast<BeginAccessInst>(inst)) {
// Leave dynamic accesses in place, but delete all others.
if (shouldPreserveAccess(beginAccess->getEnforcement()))
return false;
replaceBeginAccessUsers(beginAccess);
return true;
}
// end_access instructions will be handled when we process the
// begin_access.
// begin_unpaired_access instructions will be directly removed and
// simply replaced with their operand.
if (auto BUA = dyn_cast<BeginUnpairedAccessInst>(inst)) {
if (shouldPreserveAccess(BUA->getEnforcement()))
return false;
return true;
}
// end_unpaired_access instructions will be directly removed and
// simply replaced with their operand.
if (auto EUA = dyn_cast<EndUnpairedAccessInst>(inst)) {
if (shouldPreserveAccess(EUA->getEnforcement()))
return false;
return true;
}
return false;
}
// Top-level per-function entry-point.
// Return `true` if any markers were removed.
bool AccessMarkerElimination::stripMarkers() {
// Iterating in reverse eliminates more begin_access users before they
// need to be replaced.
for (auto &BB : reversed(*F)) {
// Don't cache the begin iterator since we're reverse iterating.
for (auto II = BB.end(); II != BB.begin();) {
SILInstruction *inst = &*(--II);
if (checkAndEliminateMarker(inst))
II = eraseInst(inst);
}
}
return removedAny;
}
} // end anonymous namespace
// Implement a SILModule::SILFunctionBodyCallback that strips all access
// markers from newly deserialized function bodies.
static void prepareSILFunctionForOptimization(ModuleDecl *, SILFunction *F) {
DEBUG(llvm::dbgs() << "Stripping all markers in: " << F->getName() << "\n");
AccessMarkerElimination(F).stripMarkers();
}
namespace {
struct AccessMarkerEliminationPass : SILModuleTransform {
void run() override {
auto &M = *getModule();
for (auto &F : M) {
bool removedAny = AccessMarkerElimination(&F).stripMarkers();
// Only invalidate analyses if we removed some markers.
if (removedAny) {
auto InvalidKind = SILAnalysis::InvalidationKind::Instructions;
invalidateAnalysis(&F, InvalidKind);
}
// Markers from all current SIL functions are stripped. Register a
// callback to strip an subsequently loaded functions on-the-fly.
if (!EnableOptimizedAccessMarkers)
M.registerDeserializationCallback(prepareSILFunctionForOptimization);
}
}
};
} // end anonymous namespace
SILTransform *swift::createAccessMarkerElimination() {
return new AccessMarkerEliminationPass();
}