Files
swift-mirror/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
Michael Gottesman bffa7addaf [semantic-arc] Eliminate default {Load,Store}OwnershipQualification argument to SILBuilder::create{Load,Store}(...)
Today, loads and stores are treated as having @unowned(unsafe) ownership
semantics. This leaves the user to specify ownership changes on the loaded or
stored value independently of the load/store by inserting ARC operations. With
the change to Semantic SIL, this will no longer be true. Instead loads, stores
have ownership semantics that one must reason about such as copy, take, and
trivial.

This change moves us closer to that world by eliminating the default
OwnershipQualification argument from create{Load,Store}. This means that the
compiler developer cannot ignore reasoning about the ownership semantics of the
memory operation that they are creating.

Operationally, this is a NFC change since I have just gone through the compiler
and updated all places where we create loads, stores to pass in the former
default argument ({Load,Store}OwnershipQualifier::Unqualified), to
SILBuilder::create{Load,Store}(...). For now, one can just do that in situations
where one needs to create loads/stores, but over time, I am going to tighten the
semantics up via the verifier.

rdar://28685236
2016-10-30 13:07:06 -07:00

196 lines
6.7 KiB
C++

//===--- OwnershipModelEliminator.cpp - Eliminate SILOwnership Instr. -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This file contains a small pass that lowers SIL ownership instructions to
/// their constituent operations. This will enable us to separate
/// implementation
/// of Semantic ARC in SIL and SILGen from ensuring that all of the optimizer
/// passes respect Semantic ARC. This is done by running this pass right after
/// SILGen and as the pass pipeline is updated, moving this pass further and
/// further back in the pipeline.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-ownership-model-eliminator"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILVisitor.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// Implementation
//===----------------------------------------------------------------------===//
namespace {
struct OwnershipModelEliminatorVisitor
: SILInstructionVisitor<OwnershipModelEliminatorVisitor, bool> {
SILBuilder &B;
OwnershipModelEliminatorVisitor(SILBuilder &B) : B(B) {}
void beforeVisit(ValueBase *V) {
auto *I = cast<SILInstruction>(V);
B.setInsertionPoint(I);
B.setCurrentDebugScope(I->getDebugScope());
}
bool visitValueBase(ValueBase *V) { return false; }
bool visitLoadInst(LoadInst *LI);
bool visitStoreInst(StoreInst *SI);
bool visitCopyValueInst(CopyValueInst *CVI);
bool visitDestroyValueInst(DestroyValueInst *DVI);
bool visitLoadBorrowInst(LoadBorrowInst *LBI);
bool visitEndBorrowInst(EndBorrowInst *EBI) {
EBI->eraseFromParent();
return true;
}
};
} // end anonymous namespace
bool OwnershipModelEliminatorVisitor::visitLoadInst(LoadInst *LI) {
auto Qualifier = LI->getOwnershipQualifier();
// If the qualifier is unqualified, there is nothing further to do
// here. Just return.
if (Qualifier == LoadOwnershipQualifier::Unqualified)
return false;
// Otherwise, we need to break down the load inst into its unqualified
// components.
auto *UnqualifiedLoad = B.createLoad(LI->getLoc(), LI->getOperand(),
LoadOwnershipQualifier::Unqualified);
// If we have a copy, insert a retain_value. All other copies do not require
// more work.
if (Qualifier == LoadOwnershipQualifier::Copy) {
B.emitCopyValueOperation(UnqualifiedLoad->getLoc(), UnqualifiedLoad);
}
// Then remove the qualified load and use the unqualified load as the def of
// all of LI's uses.
LI->replaceAllUsesWith(UnqualifiedLoad);
LI->eraseFromParent();
return true;
}
bool OwnershipModelEliminatorVisitor::visitStoreInst(StoreInst *SI) {
auto Qualifier = SI->getOwnershipQualifier();
// If the qualifier is unqualified, there is nothing further to do
// here. Just return.
if (Qualifier == StoreOwnershipQualifier::Unqualified)
return false;
// Otherwise, we need to break down the store.
if (Qualifier != StoreOwnershipQualifier::Assign) {
// If the ownership qualifier is not an assign, we can just emit an
// unqualified store.
B.createStore(SI->getLoc(), SI->getSrc(), SI->getDest(),
StoreOwnershipQualifier::Unqualified);
} else {
// If the ownership qualifier is [assign], then we need to eliminate the
// old value.
//
// 1. Load old value.
// 2. Store new value.
// 3. Release old value.
auto *Old = B.createLoad(SI->getLoc(), SI->getDest(),
LoadOwnershipQualifier::Unqualified);
B.createStore(SI->getLoc(), SI->getSrc(), SI->getDest(),
StoreOwnershipQualifier::Unqualified);
B.emitDestroyValueOperation(SI->getLoc(), Old);
}
// Then remove the qualified store.
SI->eraseFromParent();
return true;
}
bool
OwnershipModelEliminatorVisitor::visitLoadBorrowInst(LoadBorrowInst *LBI) {
// Break down the load borrow into an unqualified load.
auto *UnqualifiedLoad = B.createLoad(LBI->getLoc(), LBI->getOperand(),
LoadOwnershipQualifier::Unqualified);
// Then remove the qualified load and use the unqualified load as the def of
// all of LI's uses.
LBI->replaceAllUsesWith(UnqualifiedLoad);
LBI->eraseFromParent();
return true;
}
bool OwnershipModelEliminatorVisitor::visitCopyValueInst(CopyValueInst *CVI) {
// Now that we have set the unqualified ownership flag, destroy value
// operation will delegate to the appropriate strong_release, etc.
B.emitCopyValueOperation(CVI->getLoc(), CVI->getOperand());
CVI->replaceAllUsesWith(CVI->getOperand());
CVI->eraseFromParent();
return true;
}
bool OwnershipModelEliminatorVisitor::visitDestroyValueInst(DestroyValueInst *DVI) {
// Now that we have set the unqualified ownership flag, destroy value
// operation will delegate to the appropriate strong_release, etc.
B.emitDestroyValueOperation(DVI->getLoc(), DVI->getOperand());
DVI->eraseFromParent();
return true;
}
//===----------------------------------------------------------------------===//
// Top Level Entry Point
//===----------------------------------------------------------------------===//
namespace {
struct OwnershipModelEliminator : SILFunctionTransform {
void run() override {
SILFunction *F = getFunction();
// Set F to have unqualified ownership.
F->setUnqualifiedOwnership();
bool MadeChange = false;
SILBuilder B(*F);
OwnershipModelEliminatorVisitor Visitor(B);
for (auto &BB : *F) {
for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
// Since we are going to be potentially removing instructions, we need
// to make sure to grab out instruction and increment first.
SILInstruction *I = &*II;
++II;
MadeChange |= Visitor.visit(I);
}
}
if (MadeChange) {
// If we made any changes, we just changed instructions, so invalidate
// that analysis.
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
}
}
StringRef getName() override { return "Ownership Model Eliminator"; }
};
} // end anonymous namespace
SILTransform *swift::createOwnershipModelEliminator() {
return new OwnershipModelEliminator();
}