Merge pull request #5420 from gottesmm/enable_ownership_model_eliminator_by_default
[semantic-arc] Move the Ownership Model Eliminator and management of SILFunction::hasQualifiedOwnership in front of SILOptions::EnableSILOwnership.
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index ef2a51f..ebe7200 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -517,6 +517,8 @@
"unknown key '%0' in debug variable declaration", (StringRef))
ERROR(sil_objc_with_tail_elements,none,
"alloc_ref [objc] cannot have tail allocated elements", ())
+ERROR(found_unqualified_instruction_in_qualified_function,none,
+ "found unqualified instruction in qualified function '%0'", (StringRef))
// SIL Basic Blocks
ERROR(expected_sil_block_name,none,
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index 1e24f08..6f7dfce 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -176,16 +176,12 @@
/// method itself. In this case we need to create a vtable stub for it.
bool Zombie = false;
- /// True if SILOwnership is enabled for this function. It is always false when
- /// the SILOption HasQualifiedOwnership is not set. When the SILOption
- /// HasQualifiedOwnership /is/ set, this value is initialized to true. Once
- /// the
- /// OwnershipModelEliminator runs on the function, it is set to false.
+ /// True if SILOwnership is enabled for this function.
///
/// This enables the verifier to easily prove that before the Ownership Model
/// Eliminator runs on a function, we only see a non-semantic-arc world and
/// after the pass runs, we only see a semantic-arc world.
- Optional<bool> HasQualifiedOwnership;
+ bool HasQualifiedOwnership = true;
SILFunction(SILModule &module, SILLinkage linkage,
StringRef mangledName, CanSILFunctionType loweredType,
@@ -293,26 +289,15 @@
bool isZombie() const { return Zombie; }
/// Returns true if this function has qualified ownership instructions in it.
- Optional<bool> hasQualifiedOwnership() const {
- if (HasQualifiedOwnership.hasValue())
- return HasQualifiedOwnership.getValue();
- return None;
- }
+ bool hasQualifiedOwnership() const { return HasQualifiedOwnership; }
/// Returns true if this function has unqualified ownership instructions in
/// it.
- Optional<bool> hasUnqualifiedOwnership() const {
- if (HasQualifiedOwnership.hasValue())
- return !HasQualifiedOwnership.getValue();
- return None;
- }
+ bool hasUnqualifiedOwnership() const { return !HasQualifiedOwnership; }
/// Sets the HasQualifiedOwnership flag to false. This signals to SIL that no
/// ownership instructions should be in this function any more.
void setUnqualifiedOwnership() {
- assert(
- HasQualifiedOwnership.hasValue() &&
- "Should never set unqualified ownership when SILOwnership is disabled");
HasQualifiedOwnership = false;
}
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index b9d1480..117bcd0 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -3985,8 +3985,12 @@
// Evaluate how the just parsed instruction effects this functions Ownership
// Qualification. For more details, see the comment on the
// FunctionOwnershipEvaluator class.
- if (!OwnershipEvaluator.evaluate(&*BB->rbegin()))
- return true;
+ SILInstruction *ParsedInst = &*BB->rbegin();
+ if (!OwnershipEvaluator.evaluate(ParsedInst)) {
+ P.diagnose(ParsedInst->getLoc().getSourceLoc(),
+ diag::found_unqualified_instruction_in_qualified_function,
+ F->getName());
+ }
} while (isStartOfSILInstruction());
return false;
diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp
index ae1b529..694fdaf 100644
--- a/lib/SIL/InstructionUtils.cpp
+++ b/lib/SIL/InstructionUtils.cpp
@@ -269,16 +269,11 @@
"does not belong to the instruction "
"that we are evaluating");
- // If SIL ownership is not enabled in this module, just return true. There is
- // no further work to do here.
- if (!I->getModule().getOptions().EnableSILOwnership)
- return true;
-
switch (OwnershipQualifiedKindVisitor().visit(I)) {
case OwnershipQualifiedKind::Unqualified: {
// If we already know that the function has unqualified ownership, just
// return early.
- if (!F.get()->hasQualifiedOwnership().getValue())
+ if (!F.get()->hasQualifiedOwnership())
return true;
// Ok, so we know at this point that we have qualified ownership. If we have
@@ -298,7 +293,7 @@
// have unqualified ownership, then we know that we have already seen an
// unqualified ownership instruction. This means the function has both
// qualified and unqualified instructions. =><=.
- if (!F.get()->hasQualifiedOwnership().getValue())
+ if (!F.get()->hasQualifiedOwnership())
return false;
// Ok, at this point we know that we are still qualified. Since functions
diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp
index 0c7dc3f..b1ff6b1 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -85,7 +85,7 @@
Bare(isBareSILFunction), Transparent(isTrans), Fragile(isFragile),
Thunk(isThunk), ClassVisibility(classVisibility), GlobalInitFlag(false),
InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
- KeepAsPublic(false), EffectsKindAttr(E), HasQualifiedOwnership() {
+ KeepAsPublic(false), EffectsKindAttr(E) {
if (InsertBefore)
Module.functions.insert(SILModule::iterator(InsertBefore), this);
else
@@ -96,12 +96,6 @@
// Set our BB list to have this function as its parent. This enables us to
// splice efficiently basic blocks in between functions.
BlockList.Parent = this;
-
- // If SILOwnership is not enabled, HasQualifiedOwnership is None. If
- // SILOwnership is enabled, we always initialize functions to have
- // SILOwnership initially.
- if (Module.getOptions().EnableSILOwnership)
- HasQualifiedOwnership = true;
}
SILFunction::~SILFunction() {
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index f3996de..4727151 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -106,6 +106,10 @@
SILVerifier(const SILVerifier&) = delete;
void operator=(const SILVerifier&) = delete;
public:
+ bool isSILOwnershipEnabled() const {
+ return F.getModule().getOptions().EnableSILOwnership;
+ }
+
void _require(bool condition, const Twine &complaint,
const std::function<void()> &extraContext = nullptr) {
if (condition) return;
@@ -128,11 +132,8 @@
}
#define require(condition, complaint) \
_require(bool(condition), complaint ": " #condition)
-#define requireTrueOrNone(condition, complaint) \
- _require(!condition.hasValue() || bool(condition.getValue()), \
- complaint ": " #condition)
-#define requireFalseOrNone(condition, complaint) \
- _require(!condition.hasValue() || !bool(condition.getValue()), \
+#define requireTrueAndSILOwnership(verifier, condition, complaint) \
+ _require(!verifier->isSILOwnershipEnabled() || bool(condition), \
complaint ": " #condition)
template <class T> typename CanTypeWrapperTraits<T>::type
@@ -1122,14 +1123,14 @@
case LoadOwnershipQualifier::Unqualified:
// We should not see loads with unqualified ownership when SILOwnership is
// enabled.
- requireFalseOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasUnqualifiedOwnership(),
"Load with unqualified ownership in a qualified function");
break;
case LoadOwnershipQualifier::Copy:
case LoadOwnershipQualifier::Take:
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Load with qualified ownership in an unqualified function");
// TODO: Could probably make this a bit stricter.
require(!LI->getType().isTrivial(LI->getModule()),
@@ -1137,8 +1138,8 @@
"types");
break;
case LoadOwnershipQualifier::Trivial:
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Load with qualified ownership in an unqualified function");
require(LI->getType().isTrivial(LI->getModule()),
"A load with trivial ownership must load a trivial type");
@@ -1147,8 +1148,8 @@
}
void checkLoadBorrowInst(LoadBorrowInst *LBI) {
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Inst with qualified ownership in a function that is not qualified");
require(LBI->getType().isObject(), "Result of load must be an object");
require(LBI->getType().isLoadable(LBI->getModule()),
@@ -1160,8 +1161,8 @@
}
void checkEndBorrowInst(EndBorrowInst *EBI) {
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Inst with qualified ownership in a function that is not qualified");
// We allow for end_borrow to express relationships in between addresses and
// values, but we require that the types are the same ignoring value
@@ -1187,13 +1188,13 @@
case StoreOwnershipQualifier::Unqualified:
// We should not see loads with unqualified ownership when SILOwnership is
// enabled.
- requireFalseOrNone(F.hasQualifiedOwnership(),
- "Invalid load with unqualified ownership");
+ requireTrueAndSILOwnership(this, F.hasUnqualifiedOwnership(),
+ "Invalid load with unqualified ownership");
break;
case StoreOwnershipQualifier::Init:
case StoreOwnershipQualifier::Assign:
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Inst with qualified ownership in a function that is not qualified");
// TODO: Could probably make this a bit stricter.
require(!SI->getSrc()->getType().isTrivial(SI->getModule()),
@@ -1201,8 +1202,8 @@
"non-trivial types");
break;
case StoreOwnershipQualifier::Trivial:
- requireTrueOrNone(
- F.hasQualifiedOwnership(),
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
"Inst with qualified ownership in a function that is not qualified");
require(SI->getSrc()->getType().isTrivial(SI->getModule()),
"A store with trivial ownership must store a trivial type");
@@ -1352,17 +1353,19 @@
void checkCopyValueInst(CopyValueInst *I) {
require(I->getOperand()->getType().isObject(),
"Source value should be an object value");
- requireTrueOrNone(F.hasQualifiedOwnership(),
- "copy_value is only valid in functions with qualified "
- "ownership");
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
+ "copy_value is only valid in functions with qualified "
+ "ownership");
}
void checkDestroyValueInst(DestroyValueInst *I) {
require(I->getOperand()->getType().isObject(),
"Source value should be an object value");
- requireTrueOrNone(F.hasQualifiedOwnership(),
- "destroy_value is only valid in functions with qualified "
- "ownership");
+ requireTrueAndSILOwnership(
+ this, F.hasQualifiedOwnership(),
+ "destroy_value is only valid in functions with qualified "
+ "ownership");
}
void checkReleaseValueInst(ReleaseValueInst *I) {
diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp
index c7f3c73..03999df 100644
--- a/lib/SILOptimizer/PassManager/Passes.cpp
+++ b/lib/SILOptimizer/PassManager/Passes.cpp
@@ -86,12 +86,10 @@
return Ctx.hadError();
}
- // If SILOwnership is enabled, run the ownership model eliminator.
- if (Module.getOptions().EnableSILOwnership) {
- PM.addOwnershipModelEliminator();
- PM.runOneIteration();
- PM.resetAndRemoveTransformations();
- }
+ // Lower all ownership instructions right after SILGen for now.
+ PM.addOwnershipModelEliminator();
+ PM.runOneIteration();
+ PM.resetAndRemoveTransformations();
// Otherwise run the rest of diagnostics.
PM.addCapturePromotion();
diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
index 5199e82..d14c95d 100644
--- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
+++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
@@ -151,10 +151,6 @@
struct OwnershipModelEliminator : SILFunctionTransform {
void run() override {
SILFunction *F = getFunction();
- // We should only run this when SILOwnership is enabled.
- assert(F->getModule().getOptions().EnableSILOwnership &&
- "Can not run ownership model eliminator when SIL ownership is not "
- "enabled");
bool MadeChange = false;
SILBuilder B(*F);
OwnershipModelEliminatorVisitor Visitor(B);
diff --git a/test/SIL/Parser/ownership_qualified_memopts.sil b/test/SIL/Parser/ownership_qualified_memopts.sil
index 8993163..c3c85f8 100644
--- a/test/SIL/Parser/ownership_qualified_memopts.sil
+++ b/test/SIL/Parser/ownership_qualified_memopts.sil
@@ -5,18 +5,14 @@
// CHECK-LABEL: sil @non_trivial : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $Builtin.NativeObject):
-// CHECK: load [[ARG1]] : $*Builtin.NativeObject
// CHECK: load [take] [[ARG1]] : $*Builtin.NativeObject
// CHECK: load [copy] [[ARG1]] : $*Builtin.NativeObject
-// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
// CHECK: store [[ARG2]] to [init] [[ARG1]] : $*Builtin.NativeObject
// CHECK: store [[ARG2]] to [assign] [[ARG1]] : $*Builtin.NativeObject
sil @non_trivial : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject):
- load %0 : $*Builtin.NativeObject
load [take] %0 : $*Builtin.NativeObject
load [copy] %0 : $*Builtin.NativeObject
- store %1 to %0 : $*Builtin.NativeObject
store %1 to [init] %0 : $*Builtin.NativeObject
store %1 to [assign] %0 : $*Builtin.NativeObject
%2 = tuple()
@@ -25,15 +21,11 @@
// CHECK-LABEL: sil @trivial : $@convention(thin) (@in Builtin.Int32, Builtin.Int32) -> () {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.Int32, [[ARG2:%[0-9]+]] : $Builtin.Int32):
-// CHECK: load [[ARG1]] : $*Builtin.Int32
// CHECK: load [trivial] [[ARG1]] : $*Builtin.Int32
-// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.Int32
// CHECK: store [[ARG2]] to [trivial] [[ARG1]] : $*Builtin.Int32
sil @trivial : $@convention(thin) (@in Builtin.Int32, Builtin.Int32) -> () {
bb0(%0 : $*Builtin.Int32, %1 : $Builtin.Int32):
- load %0 : $*Builtin.Int32
load [trivial] %0 : $*Builtin.Int32
- store %1 to %0 : $*Builtin.Int32
store %1 to [trivial] %0 : $*Builtin.Int32
%2 = tuple()
return %2 : $()
diff --git a/test/SIL/Serialization/ownership_qualified_memopts.sil b/test/SIL/Serialization/ownership_qualified_memopts.sil
index e1e123a..5e7f446 100644
--- a/test/SIL/Serialization/ownership_qualified_memopts.sil
+++ b/test/SIL/Serialization/ownership_qualified_memopts.sil
@@ -12,15 +12,11 @@
// CHECK-LABEL: sil @trivial : $@convention(thin) (@in Builtin.Int32, Builtin.Int32) -> () {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.Int32, [[ARG2:%[0-9]+]] : $Builtin.Int32):
-// CHECK: load [[ARG1]] : $*Builtin.Int32
// CHECK: load [trivial] [[ARG1]] : $*Builtin.Int32
-// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.Int32
// CHECK: store [[ARG2]] to [trivial] [[ARG1]] : $*Builtin.Int32
sil @trivial : $@convention(thin) (@in Builtin.Int32, Builtin.Int32) -> () {
bb0(%0 : $*Builtin.Int32, %1 : $Builtin.Int32):
- load %0 : $*Builtin.Int32
load [trivial] %0 : $*Builtin.Int32
- store %1 to %0 : $*Builtin.Int32
store %1 to [trivial] %0 : $*Builtin.Int32
%2 = tuple()
return %2 : $()
@@ -28,18 +24,14 @@
// CHECK-LABEL: sil @non_trivial : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $Builtin.NativeObject):
-// CHECK: load [[ARG1]] : $*Builtin.NativeObject
// CHECK: load [take] [[ARG1]] : $*Builtin.NativeObject
// CHECK: load [copy] [[ARG1]] : $*Builtin.NativeObject
-// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
// CHECK: store [[ARG2]] to [init] [[ARG1]] : $*Builtin.NativeObject
// CHECK: store [[ARG2]] to [assign] [[ARG1]] : $*Builtin.NativeObject
sil @non_trivial : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject):
- load %0 : $*Builtin.NativeObject
load [take] %0 : $*Builtin.NativeObject
load [copy] %0 : $*Builtin.NativeObject
- store %1 to %0 : $*Builtin.NativeObject
store %1 to [init] %0 : $*Builtin.NativeObject
store %1 to [assign] %0 : $*Builtin.NativeObject
%2 = tuple()