diff --git a/include/swift/SIL/OwnershipUseVisitor.h b/include/swift/SIL/OwnershipUseVisitor.h index 56fe705fba4a4..eea820af9aa38 100644 --- a/include/swift/SIL/OwnershipUseVisitor.h +++ b/include/swift/SIL/OwnershipUseVisitor.h @@ -317,14 +317,11 @@ bool OwnershipUseVisitor::visitInteriorUses(SILValue ssaDef) { // Inner adjacent reborrows are considered inner borrow scopes. if (auto phi = SILArgument::asPhi(ssaDef)) { if (!visitInnerAdjacentPhis(phi, [&](SILArgument *innerPhi) { - // TODO: Remove this call to isGuaranteedForwarding. - // The phi itself should know if it is a reborrow. - if (isGuaranteedForwarding(innerPhi)) { - return visitGuaranteedUses(innerPhi); - } else { - return visitInnerAdjacentReborrow(innerPhi); - } - })) { + if (innerPhi->isGuaranteedForwarding()) { + return visitGuaranteedUses(innerPhi); + } + return visitInnerAdjacentReborrow(innerPhi); + })) { return false; } } diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index fb51996cc0620..0a514db65241a 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -57,45 +57,13 @@ bool canOpcodeForwardInnerGuaranteedValues(SILValue value); /// the operation may be trivially rewritten with Guaranteed ownership. bool canOpcodeForwardInnerGuaranteedValues(Operand *use); +bool computeIsScoped(SILArgument *arg); + +bool computeIsReborrow(SILArgument *arg); + // This is the use-def equivalent of use->getOperandOwnership() == // OperandOwnership::GuaranteedForwarding. -inline bool isGuaranteedForwarding(SILValue value) { - if (value->getOwnershipKind() != OwnershipKind::Guaranteed) { - return false; - } - // NOTE: canOpcodeForwardInnerGuaranteedValues returns true for transformation - // terminator results. - if (canOpcodeForwardInnerGuaranteedValues(value) || - isa(value)) { - return true; - } - // If not a phi, return false - auto *phi = dyn_cast(value); - if (!phi || !phi->isPhi()) { - return false; - } - // For a phi, if we find GuaranteedForwarding phi operand on any incoming - // path, we return true. Additional verification is added to ensure - // GuaranteedForwarding phi operands are found on zero or all paths in the - // OwnershipVerifier. - bool isGuaranteedForwardingPhi = false; - phi->visitTransitiveIncomingPhiOperands([&](auto *, auto *op) -> bool { - auto opValue = op->get(); - assert(opValue->getOwnershipKind().isCompatibleWith( - OwnershipKind::Guaranteed)); - if (canOpcodeForwardInnerGuaranteedValues(opValue) || - isa(opValue)) { - isGuaranteedForwardingPhi = true; - return false; - } - auto *phi = dyn_cast(opValue); - if (!phi || !phi->isPhi()) { - return false; - } - return true; - }); - return isGuaranteedForwardingPhi; -} +bool computeIsGuaranteedForwarding(SILValue value); /// Is the opcode that produces \p value capable of forwarding owned values? /// @@ -523,7 +491,7 @@ class BorrowedValueKind { })) { return Kind::Invalid; } - if (isGuaranteedForwarding(value)) { + if (cast(value)->isGuaranteedForwarding()) { return Kind::Invalid; } return Kind::Phi; diff --git a/include/swift/SIL/SILArgument.h b/include/swift/SIL/SILArgument.h index 078d9d7784732..601b3b4ffaa28 100644 --- a/include/swift/SIL/SILArgument.h +++ b/include/swift/SIL/SILArgument.h @@ -75,16 +75,21 @@ class SILArgument : public ValueBase { protected: SILArgument(ValueKind subClassKind, SILBasicBlock *inputParentBlock, SILType type, ValueOwnershipKind ownershipKind, - const ValueDecl *inputDecl = nullptr); + const ValueDecl *inputDecl = nullptr, bool reborrow = false, + bool escaping = false); // A special constructor, only intended for use in // SILBasicBlock::replacePHIArg and replaceFunctionArg. explicit SILArgument(ValueKind subClassKind, SILType type, ValueOwnershipKind ownershipKind, - const ValueDecl *inputDecl = nullptr) - : ValueBase(subClassKind, type), - parentBlock(nullptr), decl(inputDecl) { + const ValueDecl *inputDecl = nullptr, + bool reborrow = false, bool escaping = false) + : ValueBase(subClassKind, type), parentBlock(nullptr), decl(inputDecl) { sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind); + // When the optimizer creates reborrows, reborrow flag needs to be set by + // calling setReborrow. + sharedUInt8().SILArgument.reborrow = false; + sharedUInt8().SILArgument.escaping = false; } public: @@ -95,10 +100,41 @@ class SILArgument : public ValueBase { return ValueOwnershipKind(sharedUInt8().SILArgument.valueOwnershipKind); } + bool isScoped() const { + auto ownershipKind = getOwnershipKind(); + if (ownershipKind == OwnershipKind::Owned) { + return true; + } + if (ownershipKind != OwnershipKind::Guaranteed) { + return false; + } + return isReborrow(); + } + + bool isReborrow() const { + return ValueOwnershipKind(sharedUInt8().SILArgument.reborrow); + } + + bool isGuaranteedForwarding() const { + return getOwnershipKind() == OwnershipKind::Guaranteed && !isReborrow(); + } + + bool isEscaping() const { + return ValueOwnershipKind(sharedUInt8().SILArgument.escaping); + } + void setOwnershipKind(ValueOwnershipKind newKind) { sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(newKind); } + void setReborrow(bool isReborrow) { + sharedUInt8().SILArgument.reborrow = isReborrow; + } + + void setEscaping(bool isEscaping) { + sharedUInt8().SILArgument.escaping = isEscaping; + } + SILBasicBlock *getParent() const { return parentBlock; } /// Returns true if this argument is erased from a basic block. @@ -223,14 +259,18 @@ class SILPhiArgument : public SILArgument { SILPhiArgument(SILBasicBlock *parentBlock, SILType type, ValueOwnershipKind ownershipKind, - const ValueDecl *decl = nullptr) + const ValueDecl *decl = nullptr, bool isReborrow = false, + bool isEscaping = false) : SILArgument(ValueKind::SILPhiArgument, parentBlock, type, ownershipKind, - decl) {} + decl, isReborrow, isEscaping) {} + // A special constructor, only intended for use in // SILBasicBlock::replacePHIArg. explicit SILPhiArgument(SILType type, ValueOwnershipKind ownershipKind, - const ValueDecl *decl = nullptr) - : SILArgument(ValueKind::SILPhiArgument, type, ownershipKind, decl) {} + const ValueDecl *decl = nullptr, + bool isReborrow = false, bool isEscaping = false) + : SILArgument(ValueKind::SILPhiArgument, type, ownershipKind, decl, + isReborrow, isEscaping) {} public: /// Return true if this is block argument is a phi, as opposed to a terminator diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h index 40558a076e26d..b44c3c528616d 100644 --- a/include/swift/SIL/SILBasicBlock.h +++ b/include/swift/SIL/SILBasicBlock.h @@ -350,24 +350,31 @@ public SwiftObjectHeader { /// replacePhiArgumentAndRAUW. SILPhiArgument *replacePhiArgument(unsigned i, SILType type, ValueOwnershipKind kind, - const ValueDecl *decl = nullptr); + const ValueDecl *decl = nullptr, + bool isReborrow = false, + bool isEscaping = false); /// Replace phi argument \p i and RAUW all uses. - SILPhiArgument * - replacePhiArgumentAndReplaceAllUses(unsigned i, SILType type, - ValueOwnershipKind kind, - const ValueDecl *decl = nullptr); + SILPhiArgument *replacePhiArgumentAndReplaceAllUses( + unsigned i, SILType type, ValueOwnershipKind kind, + const ValueDecl *decl = nullptr, bool isReborrow = false, + bool isEscaping = false); /// Allocate a new argument of type \p Ty and append it to the argument - /// list. Optionally you can pass in a value decl parameter. + /// list. Optionally you can pass in a value decl parameter, reborrow flag and + /// escaping flag. SILPhiArgument *createPhiArgument(SILType Ty, ValueOwnershipKind Kind, - const ValueDecl *D = nullptr); + const ValueDecl *D = nullptr, + bool isReborrow = false, + bool isEscaping = false); /// Insert a new SILPhiArgument with type \p Ty and \p Decl at position \p /// AtArgPos. SILPhiArgument *insertPhiArgument(unsigned AtArgPos, SILType Ty, ValueOwnershipKind Kind, - const ValueDecl *D = nullptr); + const ValueDecl *D = nullptr, + bool isReborrow = false, + bool isEscaping = false); /// Remove all block arguments. void dropAllArguments(); diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 4ba596c70e204..982c4744d4190 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -734,7 +734,8 @@ void SILCloner::clonePhiArgs(SILBasicBlock *oldBB) { // Create new arguments for each of the original block's arguments. for (auto *Arg : oldBB->getSILPhiArguments()) { SILValue mappedArg = mappedBB->createPhiArgument( - getOpType(Arg->getType()), Arg->getOwnershipKind()); + getOpType(Arg->getType()), Arg->getOwnershipKind(), Arg->getDecl(), + Arg->isReborrow(), Arg->isEscaping()); asImpl().mapValue(Arg, mappedArg); } diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h index 108a1cfbf9303..72166c73340d9 100644 --- a/include/swift/SIL/SILNode.h +++ b/include/swift/SIL/SILNode.h @@ -181,7 +181,6 @@ class alignas(8) SILNode : SHARED_TEMPLATE_FIELD(typename, SwitchEnumInstBase, bool hasDefault); SHARED_TEMPLATE_FIELD(SILInstructionKind, LoadReferenceInstBase, bool isTake); SHARED_TEMPLATE_FIELD(SILInstructionKind, StoreReferenceInstBase, bool isInitializationOfDest); - SHARED_FIELD(SILArgument, uint8_t valueOwnershipKind); SHARED_FIELD(MultipleValueInstructionResult, uint8_t valueOwnershipKind); SHARED_FIELD(UncheckedOwnershipConversionInst, uint8_t valueOwnershipKind); SHARED_FIELD(StoreInst, uint8_t ownershipQualifier); @@ -203,6 +202,11 @@ class alignas(8) SILNode : SHARED_FIELD(ConvertFunctionInst, bool withoutActuallyEscaping); SHARED_FIELD(BeginCOWMutationInst, bool native); + SHARED_FIELD(SILArgument, uint8_t + valueOwnershipKind : NumVOKindBits, + reborrow : 1, + escaping : 1); + SHARED_FIELD(DebugValueInst, uint8_t poisonRefs : 1, usesMoveableValueDebugInfo : 1, diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 21cb9c323fc3b..a6d437d21cc82 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -570,6 +570,8 @@ class ValueBase : public SILNode, public SILAllocated { bool isLexical() const; + bool isGuaranteedForwarding() const; + /// Unsafely eliminate moveonly from this value's type. Returns true if the /// value's underlying type was move only and thus was changed. Returns false /// otherwise. diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 6155967241cb5..47e6456091d6c 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -435,11 +435,11 @@ OperandOwnershipClassifier::visitSelectEnumInst(SelectEnumInst *i) { } OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) { - ValueOwnershipKind destBlockArgOwnershipKind = - bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind(); + auto *destArg = bi->getDestBB()->getArgument(getOperandIndex()); + ValueOwnershipKind destBlockArgOwnershipKind = destArg->getOwnershipKind(); if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) { - return isGuaranteedForwarding(getValue()) + return destArg->isGuaranteedForwarding() ? OperandOwnership::GuaranteedForwarding : OperandOwnership::Reborrow; } diff --git a/lib/SIL/IR/SILArgument.cpp b/lib/SIL/IR/SILArgument.cpp index 0f8821671a62c..2194124d6aa0a 100644 --- a/lib/SIL/IR/SILArgument.cpp +++ b/lib/SIL/IR/SILArgument.cpp @@ -27,10 +27,13 @@ using namespace swift; SILArgument::SILArgument(ValueKind subClassKind, SILBasicBlock *inputParentBlock, SILType type, ValueOwnershipKind ownershipKind, - const ValueDecl *inputDecl) - : ValueBase(subClassKind, type), - parentBlock(inputParentBlock), decl(inputDecl) { + const ValueDecl *inputDecl, bool reborrow, + bool escaping) + : ValueBase(subClassKind, type), parentBlock(inputParentBlock), + decl(inputDecl) { sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind); + sharedUInt8().SILArgument.reborrow = reborrow; + sharedUInt8().SILArgument.escaping = escaping; inputParentBlock->insertArgument(inputParentBlock->args_end(), this); } diff --git a/lib/SIL/IR/SILBasicBlock.cpp b/lib/SIL/IR/SILBasicBlock.cpp index fb1dcb163aae0..4c8ad8f23eecd 100644 --- a/lib/SIL/IR/SILBasicBlock.cpp +++ b/lib/SIL/IR/SILBasicBlock.cpp @@ -203,7 +203,9 @@ SILFunctionArgument *SILBasicBlock::replaceFunctionArgument( /// ValueDecl D). SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty, ValueOwnershipKind Kind, - const ValueDecl *D) { + const ValueDecl *D, + bool isReborrow, + bool isEscaping) { assert(!isEntry() && "PHI Arguments can not be in the entry block"); SILFunction *F = getParent(); SILModule &M = F->getModule(); @@ -212,7 +214,8 @@ SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty, assert(ArgumentList[i]->use_empty() && "Expected no uses of the old BB arg!"); - SILPhiArgument *NewArg = new (M) SILPhiArgument(Ty, Kind, D); + SILPhiArgument *NewArg = + new (M) SILPhiArgument(Ty, Kind, D, isReborrow, isEscaping); NewArg->setParent(this); ArgumentList[i]->parentBlock = nullptr; @@ -224,7 +227,8 @@ SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty, } SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses( - unsigned i, SILType ty, ValueOwnershipKind kind, const ValueDecl *d) { + unsigned i, SILType ty, ValueOwnershipKind kind, const ValueDecl *d, + bool isReborrow, bool isEscaping) { // Put in an undef placeholder before we do the replacement since // replacePhiArgument() expects the replaced argument to not have // any uses. @@ -238,7 +242,7 @@ SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses( } // Perform the replacement. - auto *newArg = replacePhiArgument(i, ty, kind, d); + auto *newArg = replacePhiArgument(i, ty, kind, d, isReborrow, isEscaping); // Wire back up the uses. while (!operands.empty()) { @@ -250,20 +254,26 @@ SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses( SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty, ValueOwnershipKind Kind, - const ValueDecl *D) { + const ValueDecl *D, + bool isReborrow, + bool isEscaping) { assert(!isEntry() && "PHI Arguments can not be in the entry block"); if (Ty.isTrivial(*getParent())) Kind = OwnershipKind::None; - return new (getModule()) SILPhiArgument(this, Ty, Kind, D); + return new (getModule()) + SILPhiArgument(this, Ty, Kind, D, isReborrow, isEscaping); } SILPhiArgument *SILBasicBlock::insertPhiArgument(unsigned AtArgPos, SILType Ty, ValueOwnershipKind Kind, - const ValueDecl *D) { + const ValueDecl *D, + bool isReborrow, + bool isEscaping) { assert(!isEntry() && "PHI Arguments can not be in the entry block"); if (Ty.isTrivial(*getParent())) Kind = OwnershipKind::None; - auto *arg = new (getModule()) SILPhiArgument(Ty, Kind, D); + auto *arg = + new (getModule()) SILPhiArgument(Ty, Kind, D, isReborrow, isEscaping); arg->parentBlock = this; insertArgument(ArgumentList.begin() + AtArgPos, arg); return arg; diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 98b5ea2f8f57f..d954697cc54fe 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -161,6 +161,8 @@ struct SILValuePrinterInfo { bool IsNoImplicitCopy = false; LifetimeAnnotation Lifetime = LifetimeAnnotation::None; bool IsCapture = false; + bool IsReborrow = false; + bool IsEscaping = false; SILValuePrinterInfo(ID ValueID) : ValueID(ValueID), Type(), OwnershipKind() {} SILValuePrinterInfo(ID ValueID, SILType Type) @@ -170,15 +172,22 @@ struct SILValuePrinterInfo { : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind) {} SILValuePrinterInfo(ID ValueID, SILType Type, ValueOwnershipKind OwnershipKind, bool IsNoImplicitCopy, - LifetimeAnnotation Lifetime, bool IsCapture) + LifetimeAnnotation Lifetime, bool IsCapture, + bool IsReborrow, bool IsEscaping) : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind), IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime), - IsCapture(IsCapture) {} + IsCapture(IsCapture), IsReborrow(IsReborrow), IsEscaping(IsEscaping) {} SILValuePrinterInfo(ID ValueID, SILType Type, bool IsNoImplicitCopy, - LifetimeAnnotation Lifetime, bool IsCapture) + LifetimeAnnotation Lifetime, bool IsCapture, + bool IsReborrow, bool IsEscaping) : ValueID(ValueID), Type(Type), OwnershipKind(), IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime), - IsCapture(IsCapture) {} + IsCapture(IsCapture), IsReborrow(IsReborrow), IsEscaping(IsEscaping) {} + SILValuePrinterInfo(ID ValueID, SILType Type, + ValueOwnershipKind OwnershipKind, bool IsReborrow, + bool IsEscaping) + : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind), + IsReborrow(IsReborrow), IsEscaping(IsEscaping) {} }; /// Return the fully qualified dotted path for DeclContext. @@ -671,6 +680,10 @@ class SILPrinter : public SILInstructionVisitor { } if (i.IsCapture) *this << "@closureCapture "; + if (i.IsReborrow) + *this << "@reborrow "; + if (i.IsEscaping) + *this << "@escaping "; if (i.OwnershipKind && *i.OwnershipKind != OwnershipKind::None) { *this << "@" << i.OwnershipKind.value() << " "; } @@ -704,9 +717,12 @@ class SILPrinter : public SILInstructionVisitor { return {Ctx.getID(V), V ? V->getType() : SILType()}; } SILValuePrinterInfo getIDAndType(SILFunctionArgument *arg) { - return {Ctx.getID(arg), arg->getType(), arg->isNoImplicitCopy(), - arg->getLifetimeAnnotation(), arg->isClosureCapture()}; + return {Ctx.getID(arg), arg->getType(), + arg->isNoImplicitCopy(), arg->getLifetimeAnnotation(), + arg->isClosureCapture(), arg->isReborrow(), + arg->isEscaping()}; } + SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType(), V->getOwnershipKind()}; } @@ -716,7 +732,13 @@ class SILPrinter : public SILInstructionVisitor { arg->getOwnershipKind(), arg->isNoImplicitCopy(), arg->getLifetimeAnnotation(), - arg->isClosureCapture()}; + arg->isClosureCapture(), + arg->isReborrow(), + arg->isEscaping()}; + } + SILValuePrinterInfo getIDAndTypeAndOwnership(SILArgument *arg) { + return {Ctx.getID(arg), arg->getType(), arg->getOwnershipKind(), + arg->isReborrow(), arg->isEscaping()}; } //===--------------------------------------------------------------------===// diff --git a/lib/SIL/IR/SILValue.cpp b/lib/SIL/IR/SILValue.cpp index 8405e9e8c8abb..f585646afe9d9 100644 --- a/lib/SIL/IR/SILValue.cpp +++ b/lib/SIL/IR/SILValue.cpp @@ -154,6 +154,25 @@ bool ValueBase::isLexical() const { return false; } +bool ValueBase::isGuaranteedForwarding() const { + if (getOwnershipKind() != OwnershipKind::Guaranteed) { + return false; + } + // NOTE: canOpcodeForwardInnerGuaranteedValues returns true for transformation + // terminator results. + if (canOpcodeForwardInnerGuaranteedValues(this) || + isa(this)) { + return true; + } + // If not a phi, return false + auto *phi = dyn_cast(this); + if (!phi || !phi->isPhi()) { + return false; + } + + return phi->isGuaranteedForwarding(); +} + bool ValueBase::hasDebugTrace() const { for (auto *op : getUses()) { if (auto *debugValue = dyn_cast(op->getUser())) { diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index ffafc2e1b48ee..c393eb48b789e 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -27,9 +27,9 @@ #include "swift/Parse/Lexer.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/Parser.h" -#include "swift/Sema/SILTypeResolutionContext.h" #include "swift/SIL/AbstractionPattern.h" #include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/OwnershipUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDebugScope.h" @@ -37,6 +37,7 @@ #include "swift/SIL/SILMoveOnlyDeinit.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" +#include "swift/Sema/SILTypeResolutionContext.h" #include "swift/Subsystems.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" @@ -58,6 +59,11 @@ static llvm::cl::opt ParseIncompleteOSSA("parse-incomplete-ossa", llvm::cl::desc("Parse OSSA with incomplete lifetimes")); +static llvm::cl::opt DisablePopulateOwnershipFlags( + "disable-populate-ownership-flags", + llvm::cl::desc("Disable populating ownership flags"), + llvm::cl::init(false)); + //===----------------------------------------------------------------------===// // SILParserState implementation //===----------------------------------------------------------------------===// @@ -6784,9 +6790,11 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { bool foundClosureCapture = false; bool foundLexical = false; bool foundEagerMove = false; - while (auto attributeName = - parseOptionalAttribute({"noImplicitCopy", "_lexical", - "_eagerMove", "closureCapture"})) { + bool foundReborrow = false; + bool foundEscaping = false; + while (auto attributeName = parseOptionalAttribute( + {"noImplicitCopy", "_lexical", "_eagerMove", + "closureCapture", "reborrow", "escaping"})) { if (*attributeName == "noImplicitCopy") foundNoImplicitCopy = true; else if (*attributeName == "_lexical") @@ -6795,6 +6803,10 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { foundEagerMove = true; else if (*attributeName == "closureCapture") foundClosureCapture = true; + else if (*attributeName == "reborrow") + foundReborrow = true; + else if (*attributeName == "escaping") + foundEscaping = true; else { llvm_unreachable("Unexpected attribute!"); } @@ -6825,6 +6837,8 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { fArg->setNoImplicitCopy(foundNoImplicitCopy); fArg->setClosureCapture(foundClosureCapture); fArg->setLifetimeAnnotation(lifetime); + fArg->setReborrow(foundReborrow); + fArg->setEscaping(foundEscaping); Arg = fArg; // Today, we construct the ownership kind straight from the function @@ -6840,7 +6854,8 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { return true; } } else { - Arg = BB->createPhiArgument(Ty, OwnershipKind); + Arg = BB->createPhiArgument(Ty, OwnershipKind, /*decl*/ nullptr, + foundReborrow, foundEscaping); } setLocalValue(Arg, Name, NameLoc); } while (P.consumeIf(tok::comma)); @@ -6866,6 +6881,16 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { return false; } +static void populateOwnershipFlags(SILFunction *func) { + for (auto &bb : *func) { + for (auto &arg : bb.getArguments()) { + if (computeIsReborrow(arg)) { + arg->setReborrow(true); + } + } + } +} + /// decl-sil: [[only in SIL mode]] /// 'sil' sil-linkage '@' identifier ':' sil-type decl-sil-body? /// decl-sil-body: @@ -7033,6 +7058,13 @@ bool SILParserState::parseDeclSIL(Parser &P) { return true; } while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof)); + // OSSA uses flags to represent "reborrow", "escaping" etc. + // These flags are populated here as a shortcut to rewriting all + // existing OSSA tests with flags. + if (!DisablePopulateOwnershipFlags) { + populateOwnershipFlags(FunctionState.F); + } + SourceLoc RBraceLoc; P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index 277533318da7b..cea24da9de3a7 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -147,6 +147,63 @@ bool swift::canOpcodeForwardOwnedValues(Operand *use) { return false; } +bool swift::computeIsReborrow(SILArgument *arg) { + if (arg->getOwnershipKind() != OwnershipKind::Guaranteed) { + return false; + } + if (isa(arg)) { + return false; + } + return !computeIsGuaranteedForwarding(arg); +} + +bool swift::computeIsScoped(SILArgument *arg) { + if (arg->getOwnershipKind() == OwnershipKind::Owned) { + return true; + } + return computeIsReborrow(arg); +} + +// This is the use-def equivalent of use->getOperandOwnership() == +// OperandOwnership::GuaranteedForwarding. +bool swift::computeIsGuaranteedForwarding(SILValue value) { + if (value->getOwnershipKind() != OwnershipKind::Guaranteed) { + return false; + } + // NOTE: canOpcodeForwardInnerGuaranteedValues returns true for transformation + // terminator results. + if (canOpcodeForwardInnerGuaranteedValues(value) || + isa(value)) { + return true; + } + // If not a phi, return false + auto *phi = dyn_cast(value); + if (!phi || !phi->isPhi()) { + return false; + } + // For a phi, if we find GuaranteedForwarding phi operand on any incoming + // path, we return true. Additional verification is added to ensure + // GuaranteedForwarding phi operands are found on zero or all paths in the + // OwnershipVerifier. + bool isGuaranteedForwardingPhi = false; + phi->visitTransitiveIncomingPhiOperands([&](auto *, auto *op) -> bool { + auto opValue = op->get(); + assert(opValue->getOwnershipKind().isCompatibleWith( + OwnershipKind::Guaranteed)); + if (canOpcodeForwardInnerGuaranteedValues(opValue) || + isa(opValue)) { + isGuaranteedForwardingPhi = true; + return false; + } + auto *phi = dyn_cast(opValue); + if (!phi || !phi->isPhi()) { + return false; + } + return true; + }); + return isGuaranteedForwardingPhi; +} + //===----------------------------------------------------------------------===// // Guaranteed Use-Point (Lifetime) Discovery //===----------------------------------------------------------------------===// @@ -1132,7 +1189,7 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue, // Otherwise if v is an ownership forwarding value, add its defining // instruction - if (isGuaranteedForwarding(value)) { + if (value->isGuaranteedForwarding()) { if (auto *i = value->getDefiningInstruction()) { for (SILValue opValue : i->getNonTypeDependentOperandValues()) { worklist.insert(opValue); @@ -1181,7 +1238,7 @@ BorrowedValue swift::getSingleBorrowIntroducingValue(SILValue inputValue) { // Otherwise if v is an ownership forwarding value, add its defining // instruction - if (isGuaranteedForwarding(currentValue)) { + if (currentValue->isGuaranteedForwarding()) { if (auto *i = currentValue->getDefiningInstructionOrTerminator()) { auto instOps = i->getNonTypeDependentOperandValues(); // If we have multiple incoming values, return .None. We can't handle diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index 360f97ac0d180..5e3376ee3f498 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -564,7 +564,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses( // have lifetime ending uses, since our lifetime is guaranteed by our // operand, so there is nothing further to do. So just return true. if (value->getOwnershipKind() == OwnershipKind::Guaranteed) { - if (isGuaranteedForwarding(value)) { + if (value->isGuaranteedForwarding()) { return true; } } @@ -720,7 +720,7 @@ bool SILValueOwnershipChecker::checkUses() { // Check if we are an instruction that forwards guaranteed // ownership. In such a case, we are a subobject projection. We should not // have any lifetime ending uses. - if (isGuaranteedForwarding(value)) { + if (value->isGuaranteedForwarding()) { if (!isSubobjectProjectionWithLifetimeEndingUses(value, lifetimeEndingUsers)) { return false; diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index d211d66ea7737..a06d8e509e1ff 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -1119,6 +1119,12 @@ class SILVerifier : public SILVerifierBase { void visitSILArgument(SILArgument *arg) { CurArgument = arg; checkLegalType(arg->getFunction(), arg, nullptr); + + // Ensure flags on the argument are not stale. + require(!arg->getFunction()->hasOwnership() || + computeIsReborrow(arg) == arg->isReborrow(), + "Stale reborrow flag"); + if (checkLinearLifetime) { checkValueBaseOwnership(arg); } diff --git a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp index afce8677801b0..ec2c8b89a8a29 100644 --- a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp +++ b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp @@ -278,6 +278,7 @@ static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { case OwnedValueIntroducerKind::Phi: { auto *phiArg = cast(introducer.value); phiArg->setOwnershipKind(OwnershipKind::Guaranteed); + phiArg->setReborrow(computeIsReborrow(phiArg)); return phiArg; } case OwnedValueIntroducerKind::Struct: { diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 6b1fe72d4acd3..03747a93adfc4 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -1749,6 +1749,9 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { if (!Dest) { addToWorklist(SEI->getParent()); SILBuilderWithScope(SEI).createUnreachable(SEI->getLoc()); + for (auto &succ : SEI->getSuccessors()) { + removeDeadBlock(succ.getBB()); + } SEI->eraseFromParent(); return true; } @@ -1773,9 +1776,11 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { .createUncheckedEnumData(SEI->getLoc(), SEI->getOperand(), Element, Ty); assert(Dest->args_size() == 1 && "Expected only one argument!"); - SmallVector Args; - Args.push_back(UED); - SILBuilderWithScope(SEI).createBranch(SEI->getLoc(), Dest, Args); + auto *DestArg = Dest->getArgument(0); + DestArg->replaceAllUsesWith(UED); + Dest->eraseArgument(0); + + SILBuilderWithScope(SEI).createBranch(SEI->getLoc(), Dest); addToWorklist(SEI->getParent()); addToWorklist(Dest); diff --git a/lib/SILOptimizer/Utils/LoopUtils.cpp b/lib/SILOptimizer/Utils/LoopUtils.cpp index c9882da185b51..b83334a0cc2b3 100644 --- a/lib/SILOptimizer/Utils/LoopUtils.cpp +++ b/lib/SILOptimizer/Utils/LoopUtils.cpp @@ -127,8 +127,9 @@ static SILBasicBlock *insertBackedgeBlock(SILLoop *L, DominanceInfo *DT, // the backedge block which correspond to any PHI nodes in the header block. SmallVector BBArgs; for (auto *BBArg : Header->getArguments()) { - BBArgs.push_back(BEBlock->createPhiArgument(BBArg->getType(), - BBArg->getOwnershipKind())); + BBArgs.push_back(BEBlock->createPhiArgument( + BBArg->getType(), BBArg->getOwnershipKind(), /* decl */ nullptr, + BBArg->isReborrow(), BBArg->isEscaping())); } // Arbitrarily pick one of the predecessor's branch locations. diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index 7e7bde86c06e1..b3f6084d42cc7 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -12,6 +12,7 @@ #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "swift/Basic/Malloc.h" +#include "swift/SIL/OwnershipUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" @@ -234,6 +235,9 @@ SILValue SILSSAUpdater::getValueInMiddleOfBlock(SILBasicBlock *block) { addNewEdgeValueToBranch(pair.first->getTerminator(), block, pair.second, deleter); } + // Set the reborrow flag on the newly created phi. + phiArg->setReborrow(computeIsReborrow(phiArg)); + if (insertedPhis) insertedPhis->push_back(phiArg); @@ -343,6 +347,9 @@ class SSAUpdaterTraits { auto *ti = predBlock->getTerminator(); changeEdgeValue(ti, phiBlock, phiArgIndex, value); + + // Set the reborrow flag. + phi->setReborrow(computeIsReborrow(phi)); } /// Check if an instruction is a PHI. diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 6706a81fff2e0..5e9029d42bdb7 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -33,10 +33,11 @@ #include "swift/SIL/SILProperty.h" #include "swift/SIL/SILUndef.h" +#include "swift/SIL/OwnershipUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/DJB.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/OnDiskHashTable.h" #include @@ -970,20 +971,23 @@ SILBasicBlock *SILDeserializer::readSILBasicBlock(SILFunction *Fn, SILArgument *Arg; auto ValueCategory = SILValueCategory(Args[I + 1] & 0xF); SILType SILArgTy = getSILType(ArgTy, ValueCategory, Fn); + auto OwnershipKind = ValueOwnershipKind((Args[I + 1] >> 8) & 0x7); + auto reborrow = (Args[I + 1] >> 11) & 0x1; + auto escaping = (Args[I + 1] >> 12) & 0x1; if (IsEntry) { auto *fArg = CurrentBB->createFunctionArgument(SILArgTy); - bool isNoImplicitCopy = (Args[I + 1] >> 16) & 0x1; + bool isNoImplicitCopy = (Args[I + 1] >> 13) & 0x1; fArg->setNoImplicitCopy(isNoImplicitCopy); - auto lifetime = (LifetimeAnnotation::Case)((Args[I + 1] >> 17) & 0x3); + auto lifetime = (LifetimeAnnotation::Case)((Args[I + 1] >> 14) & 0x3); fArg->setLifetimeAnnotation(lifetime); - bool isClosureCapture = (Args[I + 1] >> 19) & 0x1; + bool isClosureCapture = (Args[I + 1] >> 16) & 0x1; fArg->setClosureCapture(isClosureCapture); - bool isFormalParameterPack = (Args[I + 1] >> 20) & 0x1; + bool isFormalParameterPack = (Args[I + 1] >> 17) & 0x1; fArg->setFormalParameterPack(isFormalParameterPack); Arg = fArg; } else { - auto OwnershipKind = ValueOwnershipKind((Args[I + 1] >> 8) & 0xF); - Arg = CurrentBB->createPhiArgument(SILArgTy, OwnershipKind); + Arg = CurrentBB->createPhiArgument(SILArgTy, OwnershipKind, + /*decl*/ nullptr, reborrow, escaping); } LastValueID = LastValueID + 1; setLocalValue(Arg, LastValueID); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 2afc7ad2f7a56..917215c2b9882 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 781; // compound introduced names +const uint16_t SWIFTMODULE_VERSION_MINOR = 782; // reborrow, escaped SIL flags /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index d36ca940dd2d0..b7ed6f2071f0b 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -641,15 +641,17 @@ void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) { "Expected an underlying uint8_t type"); // This is 31 bits in size. unsigned packedMetadata = 0; - packedMetadata |= unsigned(SA->getType().getCategory()); // 8 bits - packedMetadata |= unsigned(SA->getOwnershipKind()) << 8; // 8 bits + packedMetadata |= unsigned(SA->getType().getCategory()); // 8 bits + packedMetadata |= unsigned(SA->getOwnershipKind()) << 8; // 3 bits + packedMetadata |= unsigned(SA->isReborrow()) << 11; // 1 bit + packedMetadata |= unsigned(SA->isEscaping()) << 12; // 1 bit if (auto *SFA = dyn_cast(SA)) { - packedMetadata |= unsigned(SFA->isNoImplicitCopy()) << 16; // 1 bit - packedMetadata |= unsigned(SFA->getLifetimeAnnotation()) << 17; // 2 bits - packedMetadata |= unsigned(SFA->isClosureCapture()) << 19; // 1 bit - packedMetadata |= unsigned(SFA->isFormalParameterPack()) << 20; // 1 bit + packedMetadata |= unsigned(SFA->isNoImplicitCopy()) << 13; // 1 bit + packedMetadata |= unsigned(SFA->getLifetimeAnnotation()) << 14; // 2 bits + packedMetadata |= unsigned(SFA->isClosureCapture()) << 16; // 1 bit + packedMetadata |= unsigned(SFA->isFormalParameterPack()) << 17; // 1 bit } - // Used: 19 bits. Free: 13. + // Used: 17 bits. Free: 15. // // TODO: We should be able to shrink the packed metadata of the first two. Args.push_back(packedMetadata); diff --git a/test/SIL/OwnershipVerifier/guaranteed_phis_errors.sil b/test/SIL/OwnershipVerifier/guaranteed_phis_errors.sil index 5fc3e304421a4..0fa004e628f5c 100644 --- a/test/SIL/OwnershipVerifier/guaranteed_phis_errors.sil +++ b/test/SIL/OwnershipVerifier/guaranteed_phis_errors.sil @@ -180,11 +180,17 @@ bb2(%phi : @guaranteed $SuperKlass): return %9999 : $() } -// CHECK: Error#: 0. Begin Error in Function: 'test7' +// Error#: 0. Begin Error in Function: 'test7' +// Invalid End Borrow! +// Original Value: %0 = argument of bb0 : $Klass +// End Borrow: br bb3(%3 : $SuperKlass) +// +// Error#: 0. End Error in Function: 'test7' +// CHECK: Error#: 1. Begin Error in Function: 'test7' // CHECK: Malformed @guaranteed phi! // CHECK: Phi: %7 = argument of bb3 : $SuperKlass // CHECK: Guaranteed forwarding operands not found on all paths! -// CHECK: Error#: 0. End Error in Function: 'test7' +// CHECK: Error#: 1. End Error in Function: 'test7' sil [ossa] @test7 : $@convention(thin) (@guaranteed Klass, @owned SuperKlass) -> () { bb0(%0 : @guaranteed $Klass, %1 : @owned $SuperKlass): cond_br undef, bb1, bb2 diff --git a/test/SIL/OwnershipVerifier/reborrowflag.sil b/test/SIL/OwnershipVerifier/reborrowflag.sil new file mode 100644 index 0000000000000..53f568f5b73e5 --- /dev/null +++ b/test/SIL/OwnershipVerifier/reborrowflag.sil @@ -0,0 +1,30 @@ +// RUN: %target-sil-opt %s -disable-populate-ownership-flags -verify-continue-on-failure=true -sil-ownership-verifier-enable-testing -o /dev/null 2>&1 | %FileCheck %s +sil_stage canonical + +class Klass {} + +// CHECK: Begin Error in function reborrowTest +// CHECK: SIL verification failed: Stale reborrow flag: !arg->getFunction()->hasOwnership() || computeIsReborrow(arg) == arg->isReborrow() +// CHECK: Verifying argument: +// CHECK: -> %6 = argument of bb3 : $Klass +// CHECK: end_borrow %6 : $Klass +// CHECK: End Error in function reborrowTest +sil [ossa] @reborrowTest : $@convention(thin) (@owned Klass) -> () { +bb0(%0 : @owned $Klass): + cond_br undef, bb1, bb2 + +bb1: + %b1 = begin_borrow %0 : $Klass + br bb3(%b1 : $Klass) + +bb2: + %b2 = begin_borrow %0 : $Klass + br bb3(%b2 : $Klass) + +bb3(%r : @guaranteed $Klass): + end_borrow %r : $Klass + destroy_value %0 : $Klass + %9999 = tuple() + return %9999 : $() +} + diff --git a/test/SIL/Parser/borrow.sil b/test/SIL/Parser/borrow.sil index fbce300ea7435..37aae49e12db4 100644 --- a/test/SIL/Parser/borrow.sil +++ b/test/SIL/Parser/borrow.sil @@ -44,3 +44,26 @@ sil [ossa] @foo : $@convention(thin) () -> () { %res = tuple () return %res : $() } + +// CHECK-LABEL: sil [ossa] @reborrowTest : $@convention(thin) (@owned C) -> () { +// CHECK: bb3([[ARG:%.*]] : @reborrow @guaranteed $C): +// CHECK: } // end sil function 'reborrowTest' +sil [ossa] @reborrowTest : $@convention(thin) (@owned C) -> () { +bb0(%0 : @owned $C): + cond_br undef, bb1, bb2 + +bb1: + %b1 = begin_borrow %0 : $C + br bb3(%b1 : $C) + +bb2: + %b2 = begin_borrow %0 : $C + br bb3(%b2 : $C) + +bb3(%r : @reborrow @guaranteed $C): + end_borrow %r : $C + destroy_value %0 : $C + %9999 = tuple() + return %9999 : $() +} + diff --git a/test/SIL/Parser/borrow_argument.sil b/test/SIL/Parser/borrow_argument.sil index 36b5bd43cd5f9..914e82a2ae5da 100644 --- a/test/SIL/Parser/borrow_argument.sil +++ b/test/SIL/Parser/borrow_argument.sil @@ -5,7 +5,7 @@ sil_stage canonical import Builtin // CHECK-LABEL: sil [ossa] @borrow_argument_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { -// CHECK: bb1([[PHIBBARG:%.*]] : @guaranteed $Builtin.NativeObject): +// CHECK: bb1([[PHIBBARG:%.*]] : @reborrow @guaranteed $Builtin.NativeObject): // CHECK: end_borrow [[PHIBBARG]] : $Builtin.NativeObject sil [ossa] @borrow_argument_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : @guaranteed $Builtin.NativeObject): diff --git a/test/SIL/Parser/ownership_arguments.sil b/test/SIL/Parser/ownership_arguments.sil index f8ce108a92e35..eca20b4e68255 100644 --- a/test/SIL/Parser/ownership_arguments.sil +++ b/test/SIL/Parser/ownership_arguments.sil @@ -6,7 +6,7 @@ import Builtin // CHECK-LABEL: sil [ossa] @simple : $@convention(thin) (@owned Builtin.NativeObject, Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.Int32) -> () { // CHECK: bb0({{%.*}} : @owned $Builtin.NativeObject, {{%.*}} : @unowned $Builtin.NativeObject, {{%.*}} : @guaranteed $Builtin.NativeObject, {{%.*}} : $Builtin.Int32): -// CHECK: bb1({{%[0-9][0-9]*}} : @owned $Builtin.NativeObject, {{%[0-9][0-9]*}} : @unowned $Builtin.NativeObject, {{%[0-9][0-9]*}} : @guaranteed $Builtin.NativeObject, {{%[0-9][0-9]*}} : $Builtin.Int32): +// CHECK: bb1({{%[0-9][0-9]*}} : @owned $Builtin.NativeObject, {{%[0-9][0-9]*}} : @unowned $Builtin.NativeObject, {{%[0-9][0-9]*}} : @reborrow @guaranteed $Builtin.NativeObject, {{%[0-9][0-9]*}} : $Builtin.Int32): sil [ossa] @simple : $@convention(thin) (@owned Builtin.NativeObject, Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.Int32) -> () { bb0(%0 : @owned $Builtin.NativeObject, %1 : @unowned $Builtin.NativeObject, %2 : @guaranteed $Builtin.NativeObject, %3 : $Builtin.Int32): diff --git a/test/SIL/Serialization/borrow_argument.sil b/test/SIL/Serialization/borrow_argument.sil index 7862b46853df7..8a5e80f251b06 100644 --- a/test/SIL/Serialization/borrow_argument.sil +++ b/test/SIL/Serialization/borrow_argument.sil @@ -9,7 +9,7 @@ sil_stage canonical import Builtin // CHECK-LABEL: sil [serialized] [ossa] @borrow_argument_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { -// CHECK: bb1([[PHIBBARG:%.*]] : @guaranteed $Builtin.NativeObject): +// CHECK: bb1([[PHIBBARG:%.*]] : @reborrow @guaranteed $Builtin.NativeObject): // CHECK: end_borrow [[PHIBBARG]] : $Builtin.NativeObject sil [serialized] [ossa] @borrow_argument_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : @guaranteed $Builtin.NativeObject): diff --git a/test/SIL/Serialization/reborrow.sil b/test/SIL/Serialization/reborrow.sil new file mode 100644 index 0000000000000..f7be2d7b23650 --- /dev/null +++ b/test/SIL/Serialization/reborrow.sil @@ -0,0 +1,31 @@ +// First parse this and then emit a *.sib. Then read in the *.sib, then recreate + +// RUN: %empty-directory(%t) +// RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name reborrow +// RUN: %target-sil-opt %t/tmp.sib -module-name reborrow | %FileCheck %s + +sil_stage canonical + +class Klass {} + +// CHECK-LABEL: sil [serialized] [ossa] @reborrowTest : $@convention(thin) (@owned Klass) -> () { +// CHECK: bb3([[ARG:%.*]] : @reborrow @guaranteed $Klass): +// CHECK: } // end sil function 'reborrowTest' +sil [serialized] [ossa] @reborrowTest : $@convention(thin) (@owned Klass) -> () { +bb0(%0 : @owned $Klass): + cond_br undef, bb1, bb2 + +bb1: + %b1 = begin_borrow %0 : $Klass + br bb3(%b1 : $Klass) + +bb2: + %b2 = begin_borrow %0 : $Klass + br bb3(%b2 : $Klass) + +bb3(%r : @reborrow @guaranteed $Klass): + end_borrow %r : $Klass + destroy_value %0 : $Klass + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/borrow_introducer_unit.sil b/test/SILOptimizer/borrow_introducer_unit.sil index 2fa5fab510860..17b207c67046d 100644 --- a/test/SILOptimizer/borrow_introducer_unit.sil +++ b/test/SILOptimizer/borrow_introducer_unit.sil @@ -162,7 +162,7 @@ exit: // paths, but should only appear in the introducer list once. // // CHECK-LABEL: introducer_revisit_reborrow: find-borrow-introducers with: @trace[0] -// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C +// CHECK: bb1([[REBORROW:%.*]] : @reborrow @guaranteed $C // CHECK: } // end sil function 'introducer_revisit_reborrow' // CHECK: Introducers: // CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C @@ -194,7 +194,7 @@ exit: // CHECK-LABEL: introducer_multiple_borrow: find-borrow-introducers with: @trace[0] // CHECK: begin_borrow %0 : $C // CHECK: [[BORROW2:%.*]] = begin_borrow %0 : $C -// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C +// CHECK: bb1([[REBORROW:%.*]] : @reborrow @guaranteed $C // CHECK: } // end sil function 'introducer_multiple_borrow' // CHECK: Introducers: // CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C diff --git a/test/SILOptimizer/copy_propagation_borrow.sil b/test/SILOptimizer/copy_propagation_borrow.sil index be3a1a7b47b0c..04fcc44110896 100644 --- a/test/SILOptimizer/copy_propagation_borrow.sil +++ b/test/SILOptimizer/copy_propagation_borrow.sil @@ -564,7 +564,7 @@ bb0(%0 : @guaranteed $HasObject): // CHECK: br bb3([[CP]] : $C, [[BORROW]] : $C) // CHECK: bb2: // CHECK: br bb3([[CP]] : $C, [[BORROW]] : $C) -// CHECK: bb3([[OWNEDPHI:%.*]] : @owned $C, [[BORROWPHI:%.*]] @guaranteed $C +// CHECK: bb3([[OWNEDPHI:%.*]] : @owned $C, [[BORROWPHI:%.*]] @reborrow @guaranteed $C // CHECK: end_borrow [[BORROWPHI]] // CHECK: destroy_value [[OWNEDPHI]] : $C // CHECK: destroy_value %0 : $C @@ -603,7 +603,7 @@ bb3(%phi : @owned $C, %borrowphi : @guaranteed $C): // // CHECK-LABEL: sil [ossa] @testLiveCopyAfterReborrow : $@convention(thin) () -> () { // CHECK: [[ALLOC:%.*]] = alloc_ref $C -// CHECK: bb3([[BORROWPHI:%.*]] : @guaranteed $C): +// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow @guaranteed $C): // CHECK: [[COPY:%.*]] = copy_value [[BORROWPHI]] // CHECK: end_borrow [[BORROWPHI]] : $C // CHECK-NOT: copy_value @@ -651,7 +651,7 @@ bb3(%borrowphi : @guaranteed $C): // // CHECK-LABEL: sil [ossa] @testDeadCopyAfterReborrow : $@convention(thin) () -> () { // CHECK: [[ALLOC:%.*]] = alloc_ref $C -// CHECK: bb3([[BORROWPHI:%.*]] : @guaranteed $C): +// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow @guaranteed $C): // CHECK-NOT: copy_value // CHECK: end_borrow [[BORROWPHI]] : $C // CHECK-NOT: copy_value @@ -691,7 +691,7 @@ bb3(%borrowphi : @guaranteed $C): // // CHECK-LABEL: sil [ossa] @testNestedReborrowOutsideUse : $@convention(thin) () -> () { // CHECK: [[ALLOC:%.*]] = alloc_ref $C -// CHECK: bb3([[BORROWPHI:%.*]] : @guaranteed $C): +// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow @guaranteed $C): // CHECK-NOT: copy // CHECK: end_borrow [[BORROWPHI]] // CHECK-NEXT: destroy_value [[ALLOC]] : $C @@ -737,7 +737,7 @@ bb3(%borrowphi : @guaranteed $C): // CHECK: bb2: // CHECK: begin_borrow %0 : $C // CHECK: br bb3(%{{.*}} : $C, %0 : $C) -// CHECK: bb3(%{{.*}} : @guaranteed $C, [[COPYPHI:%.*]] : @owned $C): +// CHECK: bb3(%{{.*}} : @reborrow @guaranteed $C, [[COPYPHI:%.*]] : @owned $C): // CHECK: end_borrow // CHECK: destroy_value [[COPYPHI]] : $C // CHECK-LABEL: } // end sil function 'testOwnedReborrow' diff --git a/test/SILOptimizer/copy_propagation_canonicalize_with_reborrows.sil b/test/SILOptimizer/copy_propagation_canonicalize_with_reborrows.sil index 8796f90729d00..94ad5cf0f2792 100644 --- a/test/SILOptimizer/copy_propagation_canonicalize_with_reborrows.sil +++ b/test/SILOptimizer/copy_propagation_canonicalize_with_reborrows.sil @@ -11,7 +11,7 @@ sil [ossa] @getX : $@convention(thin) () -> (@owned X) sil [ossa] @holdX : $@convention(thin) (@guaranteed X) -> () // CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_endborrow : {{.*}} { -// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): +// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): // CHECK: end_borrow [[REBORROW]] // CHECK: destroy_value [[VALUE]] // CHECK-LABEL: } // end sil function 'nohoist_destroy_over_reborrow_endborrow' @@ -33,7 +33,7 @@ exit: } // CHECK-LABEL: sil [ossa] @hoist_destroy_over_unrelated_endborrow : {{.*}} { -// CHECK: {{bb[0-9]+}}([[UNRELATED:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): +// CHECK: {{bb[0-9]+}}([[UNRELATED:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): // CHECK: destroy_value [[VALUE]] // CHECK: end_borrow [[UNRELATED]] // CHECK-LABEL: } // end sil function 'hoist_destroy_over_unrelated_endborrow' @@ -57,8 +57,8 @@ exit: } // CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_reborrow_endborrow : {{.*}} { -// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $X, {{%[^,]+}} : @owned $X): -// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): +// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @reborrow @guaranteed $X, {{%[^,]+}} : @owned $X): +// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): // CHECK: end_borrow [[REBORROW]] // CHECK: destroy_value [[VALUE]] // CHECK-LABEL: } // end sil function 'nohoist_destroy_over_reborrow_reborrow_endborrow' @@ -83,8 +83,8 @@ exit: } // CHECK-LABEL: sil [ossa] @hoist_destroy_over_unrelated_reborrow_reborrow_endborrow : {{.*}} { -// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $X, {{%[^,]+}} : @owned $X): -// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): +// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @reborrow @guaranteed $X, {{%[^,]+}} : @owned $X): +// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): // CHECK: destroy_value [[VALUE]] // CHECK: end_borrow [[REBORROW]] // CHECK-LABEL: } // end sil function 'hoist_destroy_over_unrelated_reborrow_reborrow_endborrow' @@ -111,7 +111,7 @@ exit: } // CHECK-LABEL: sil [ossa] @nohoist_destroy_over_forward_reborrow_endborrow : {{.*}} { -// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): +// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : @owned $X): // CHECK: end_borrow [[REBORROW]] // CHECK: destroy_value [[VALUE]] // CHECK-LABEL: } // end sil function 'nohoist_destroy_over_forward_reborrow_endborrow' @@ -136,7 +136,7 @@ exit: } // CHECK-LABEL: sil [ossa] @nohoist_destroy_over_reborrow_loop : {{.*}} { -// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @guaranteed $FakeOptional, [[VALUE:%[^,]+]] : @owned $FakeOptional): +// CHECK: {{bb[0-9]+}}([[REBORROW:%[^,]+]] : @reborrow @guaranteed $FakeOptional, [[VALUE:%[^,]+]] : @owned $FakeOptional): // CHECK: cond_br undef, [[LOOP:bb[0-9]+]], [[BODY:bb[0-9]+]] // CHECK: [[LOOP]]: // CHECK: end_borrow [[REBORROW]] : $FakeOptional @@ -175,7 +175,7 @@ exit: // a non-lifetime ending use and extend liveness beyond the instruction where // the reborrow occurs. // CHECK-LABEL: sil [ossa] @reborrow_adjacent_to_consume_doesnt_extend_lifetime : {{.*}} { -// CHECK: bb1([[REBORROW:%[^,]+]] : @guaranteed $X, [[VALUE:%[^,]+]] : +// CHECK: bb1([[REBORROW:%[^,]+]] : @reborrow @guaranteed $X, [[VALUE:%[^,]+]] : // CHECK: {{bb[0-9]+}}: // CHECK: end_borrow [[REBORROW]] // CHECK: destroy_value [[VALUE]] @@ -298,9 +298,9 @@ bb1(%4 : @guaranteed $X, %5 : @owned $X): // end_borrow/destroy maintain their position. // // CHECK-LABEL: sil [ossa] @reborrow_adjacent_to_consume : $@convention(thin) () -> () { -// CHECK: bb1(%{{.*}} : @guaranteed $X, %{{.*}} : @owned $X): +// CHECK: bb1(%{{.*}} : @reborrow @guaranteed $X, %{{.*}} : @owned $X): // CHECK-NEXT: br bb2 -// CHECK: bb2(%{{.*}} : @guaranteed $X, %{{.*}} : @owned $X): +// CHECK: bb2(%{{.*}} : @reborrow @guaranteed $X, %{{.*}} : @owned $X): // CHECK-NEXT: end_borrow // CHECK-NEXT: destroy_value sil [ossa] @reborrow_adjacent_to_consume : $@convention(thin) () -> () { @@ -330,9 +330,9 @@ bb2(%6 : @guaranteed $X, %7 : @owned $X): // Lifetime analysis is successful; the copy/destroy in bb2 are removed. // // CHECK-LABEL: sil [ossa] @reborrow_no_adjacent_consume : $@convention(thin) () -> () { -// CHECK: bb1(%{{.*}} : @guaranteed $X, %{{.*}} : @owned $X): +// CHECK: bb1(%{{.*}} : @reborrow @guaranteed $X, %{{.*}} : @owned $X): // CHECK-NEXT: br bb2 -// CHECK: bb2(%{{.*}} : @guaranteed $X): +// CHECK: bb2(%{{.*}} : @reborrow @guaranteed $X): // CHECK-NEXT: end_borrow // CHECK-NEXT: destroy_value sil [ossa] @reborrow_no_adjacent_consume : $@convention(thin) () -> () { diff --git a/test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil b/test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil index 8f1571bc54a82..6bd8a340bc183 100644 --- a/test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil +++ b/test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil @@ -378,7 +378,7 @@ bb0(%0 : @owned $TestStruct): } // CHECK-LABEL: sil [ossa] @dce_borrowlifetime1 : -// CHECK: bb1([[ARG1:%.*]] : @owned $NonTrivialStruct, [[ARG2:%.*]] : @guaranteed $NonTrivialStruct): +// CHECK: bb1([[ARG1:%.*]] : @owned $NonTrivialStruct, [[ARG2:%.*]] : @reborrow @guaranteed $NonTrivialStruct): // CHECK-LABEL: } // end sil function 'dce_borrowlifetime1' sil [ossa] @dce_borrowlifetime1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned NonTrivialStruct { bb0(%0 : @guaranteed $NonTrivialStruct): @@ -592,7 +592,7 @@ bb4: } // CHECK-LABEL: sil [ossa] @dce_reborrow_with_different_basevalues : -// CHECK: bb3([[ARG1:%.*]] : @guaranteed $NonTrivialStruct, [[ARG2:%.*]] : @owned $NonTrivialStruct, [[ARG3:%.*]] : @owned $NonTrivialStruct): +// CHECK: bb3([[ARG1:%.*]] : @reborrow @guaranteed $NonTrivialStruct, [[ARG2:%.*]] : @owned $NonTrivialStruct, [[ARG3:%.*]] : @owned $NonTrivialStruct): // CHECK-LABEL: } // end sil function 'dce_reborrow_with_different_basevalues' sil [ossa] @dce_reborrow_with_different_basevalues : $@convention(thin) (@guaranteed NonTrivialStruct, @guaranteed NonTrivialStruct) -> @owned NonTrivialStruct { bb0(%0 : @guaranteed $NonTrivialStruct, %1 : @guaranteed $NonTrivialStruct): @@ -802,7 +802,7 @@ exit: // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass): // CHECK: [[OUTER_LIFETIME_1:%[^,]+]] = begin_borrow [[INSTANCE]] // CHECK: br [[EXIT:bb[0-9]+]]([[OUTER_LIFETIME_1]] : $Klass) -// CHECK: [[EXIT]]([[OUTER_LIFETIME_2:%[^,]+]] : @guaranteed $Klass): +// CHECK: [[EXIT]]([[OUTER_LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $Klass): // CHECK: end_borrow [[OUTER_LIFETIME_2]] // CHECK: destroy_value [[INSTANCE]] // CHECK: [[RETVAL:%[^,]+]] = tuple () @@ -825,9 +825,9 @@ exit(%outer_lifetime_2 : @guaranteed $Klass, %inner_lifetime_2 : @guaranteed $Kl // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass): // CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] // CHECK: br [[WORK:bb[0-9]+]]([[LIFETIME]] : $Klass) -// CHECK: [[WORK]]([[LIFETIME_1:%[^,]+]] : @guaranteed $Klass): +// CHECK: [[WORK]]([[LIFETIME_1:%[^,]+]] : @reborrow @guaranteed $Klass): // CHECK: br [[EXIT:bb[0-9]+]]([[LIFETIME_1]] : $Klass) -// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @guaranteed $Klass): +// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $Klass): // CHECK: end_borrow [[LIFETIME_2]] // CHECK: destroy_value [[INSTANCE]] // CHECK: [[RETVAL:%[^,]+]] = tuple () @@ -907,7 +907,7 @@ exit(%inner_lifetime_2 : @guaranteed $Klass): // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : $*Klass): // CHECK: [[LIFETIME:%[^,]+]] = load_borrow [[INSTANCE]] // CHECK: br [[BASIC_BLOCK1:bb[0-9]+]]([[LIFETIME]] : $Klass) -// CHECK: [[BASIC_BLOCK1]]([[LIFETIME_2:%[^,]+]] : @guaranteed $Klass): +// CHECK: [[BASIC_BLOCK1]]([[LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $Klass): // CHECK: end_borrow [[LIFETIME_2]] // CHECK: [[RETVAL:%[^,]+]] = tuple () // CHECK: return [[RETVAL]] @@ -928,7 +928,7 @@ bb1(%4 : @guaranteed $Klass, %5 : @guaranteed $Klass): // CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : $*Klass): // CHECK: [[LIFETIME:%[^,]+]] = load_borrow [[ADDR]] : $*Klass // CHECK: br [[EXIT:bb[0-9]+]]([[LIFETIME]] : $Klass) -// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @guaranteed $Klass): +// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $Klass): // CHECK: end_borrow [[LIFETIME_2]] : $Klass // CHECK: [[EXIT:%[^,]+]] = tuple () // CHECK: return [[EXIT]] : $() diff --git a/test/SILOptimizer/enclosing_def_unit.sil b/test/SILOptimizer/enclosing_def_unit.sil index 35a9773d73984..ff74f70932267 100644 --- a/test/SILOptimizer/enclosing_def_unit.sil +++ b/test/SILOptimizer/enclosing_def_unit.sil @@ -155,7 +155,7 @@ bb3(%reborrow3 : @guaranteed $C): // CHECK-LABEL: begin running test 1 of 1 on enclosing_def_reborrow: find-enclosing-defs with: @trace[0] // CHECK: sil [ossa] @enclosing_def_reborrow : $@convention(thin) (@guaranteed C) -> () { -// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C, %{{.*}} : @guaranteed $C): +// CHECK: bb1([[REBORROW:%.*]] : @reborrow @guaranteed $C, %{{.*}} : @reborrow @guaranteed $C): // CHECK: } // end sil function 'enclosing_def_reborrow' // CHECK: Enclosing Defs: // CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C @@ -184,7 +184,7 @@ bb3(%reborrow_inner3 : @guaranteed $C): // CHECK-LABEL: begin running test 1 of 1 on enclosing_def_cycle: find-enclosing-defs with: @trace[0] // CHECK: sil [ossa] @enclosing_def_cycle : $@convention(thin) (@guaranteed C) -> () { -// CHECK: bb1([[REBORROW:%.*]] : @guaranteed $C, +// CHECK: bb1([[REBORROW:%.*]] : @reborrow @guaranteed $C, // CHECK: } // end sil function 'enclosing_def_cycle' // CHECK: Enclosing Defs: // CHECK-NEXT: [[REBORROW]] = argument of bb1 : $C diff --git a/test/SILOptimizer/lexical_destroy_hoisting.sil b/test/SILOptimizer/lexical_destroy_hoisting.sil index d0ede1ce78477..a6481479d48a2 100644 --- a/test/SILOptimizer/lexical_destroy_hoisting.sil +++ b/test/SILOptimizer/lexical_destroy_hoisting.sil @@ -186,7 +186,7 @@ exit: // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C): // CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] // CHECK: br [[WORK:bb[0-9]+]]([[LIFETIME]] : $C) -// CHECK: [[WORK]]([[LIFETIME_2:%[^,]+]] : @guaranteed $C): +// CHECK: [[WORK]]([[LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $C): // CHECK: end_borrow [[LIFETIME_2]] // CHECK: tuple () // CHECK: destroy_value [[INSTANCE]] diff --git a/test/SILOptimizer/looprotate_nontrivial_ossa.sil b/test/SILOptimizer/looprotate_nontrivial_ossa.sil index 02c5b09b8862a..b92c58d0ddc52 100644 --- a/test/SILOptimizer/looprotate_nontrivial_ossa.sil +++ b/test/SILOptimizer/looprotate_nontrivial_ossa.sil @@ -174,7 +174,7 @@ bb3: } // CHECK-LABEL: sil [ossa] @guaranteed_phi_argument : $@convention(thin) (@owned Klass) -> () { -// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $Klass): +// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @reborrow @guaranteed $Klass): // CHECK-LABEL: } // end sil function 'guaranteed_phi_argument' sil [ossa] @guaranteed_phi_argument : $@convention(thin) (@owned Klass) -> () { entry(%instance : @owned $Klass): @@ -203,7 +203,7 @@ exit: // A guaranteed value whose ownership has been forwarded must not be reborrowed. // // CHECK-LABEL: sil [ossa] @forwarded_borrow_cant_be_reborrowed : $@convention(thin) (@owned BoxStruct) -> () { -// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @guaranteed $BoxStruct, {{%[^,]+}} : @guaranteed $Klass): +// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @reborrow @guaranteed $BoxStruct, {{%[^,]+}} : @guaranteed $Klass): // CHECK-LABEL: } // end sil function 'forwarded_borrow_cant_be_reborrowed' sil [ossa] @forwarded_borrow_cant_be_reborrowed : $@convention(thin) (@owned BoxStruct) -> () { bb0(%0 : @owned $BoxStruct): diff --git a/test/SILOptimizer/ownership_liveness_unit.sil b/test/SILOptimizer/ownership_liveness_unit.sil index 95bd5514823a2..0967154a39c32 100644 --- a/test/SILOptimizer/ownership_liveness_unit.sil +++ b/test/SILOptimizer/ownership_liveness_unit.sil @@ -153,7 +153,7 @@ bb3(%outer : @guaranteed $C, %inner : @guaranteed $C): // CHECK: [[BORROW1:%[^,]+]] = begin_borrow %1 // CHECK: [[BORROW2:%[^,]+]] = begin_borrow %1 // CHECK: br [[EXIT:bb[0-9]+]]([[C]] : $C, [[BORROW1]] : $C, [[BORROW2]] : -// CHECK: [[EXIT]]({{%[^,]+}} : @owned $C, [[GUARANTEED1:%[^,]+]] : @guaranteed $C, [[GUARANTEED2:%[^,]+]] : +// CHECK: [[EXIT]]({{%[^,]+}} : @owned $C, [[GUARANTEED1:%[^,]+]] : @reborrow @guaranteed $C, [[GUARANTEED2:%[^,]+]] : // CHECK: } // end sil function 'pay_the_phi' // // CHECK:[[GUARANTEED1]] = argument of [[EXIT]] @@ -180,7 +180,7 @@ exit(%owned : @owned $C, %guaranteed_1 : @guaranteed $C, %guaranteed_2 : @guaran } // CHECK-LABEL: begin running test 1 of 1 on pay_the_phi_forward: visit-inner-adjacent-phis with: @trace[0] -// CHECK: bb1(%{{.*}} : @guaranteed $C, [[INNER:%.*]] : @guaranteed $D): // Preds: bb0 +// CHECK: bb1(%{{.*}} : @reborrow @guaranteed $C, [[INNER:%.*]] : @guaranteed $D): // Preds: bb0 // CHECK: } // end sil function 'pay_the_phi_forward' // CHECK: [[INNER]] = argument of bb1 : $D // CHECK: end running test 1 of 1 on pay_the_phi_forward: visit-inner-adjacent-phis with: @trace[0] diff --git a/test/SILOptimizer/redundant_phi_elimination_ossa.sil b/test/SILOptimizer/redundant_phi_elimination_ossa.sil index 7d6d6478cf769..2629bb29ea9c9 100644 --- a/test/SILOptimizer/redundant_phi_elimination_ossa.sil +++ b/test/SILOptimizer/redundant_phi_elimination_ossa.sil @@ -188,7 +188,7 @@ bb3(%1 : @guaranteed $FakeOptional, %2 : @guaranteed $FakeOptional } // CHECK-LABEL: sil [ossa] @test_redundantguaranteedphiarg2 : -// CHECK: bb3([[ARG1:%.*]] : @owned $FakeOptional, [[ARG2:%.*]] : @guaranteed $FakeOptional): +// CHECK: bb3([[ARG1:%.*]] : @owned $FakeOptional, [[ARG2:%.*]] : @reborrow @guaranteed $FakeOptional): // CHECK-LABEL: } // end sil function 'test_redundantguaranteedphiarg2' sil [ossa] @test_redundantguaranteedphiarg2 : $@convention(thin) () -> () { bb0: @@ -210,7 +210,7 @@ bb3(%1 : @owned $FakeOptional, %2 : @guaranteed $FakeOptional): } // CHECK-LABEL: sil [ossa] @test_redundantguaranteedphiarg3 : -// CHECK: bb3([[ARG3:%.*]] : @guaranteed $FakeOptional, [[ARG2:%.*]] : @guaranteed $FakeOptional): +// CHECK: bb3([[ARG3:%.*]] : @reborrow @guaranteed $FakeOptional, [[ARG2:%.*]] : @reborrow @guaranteed $FakeOptional): // CHECK-LABEL: } // end sil function 'test_redundantguaranteedphiarg3' sil [ossa] @test_redundantguaranteedphiarg3 : $@convention(thin) () -> () { bb0: diff --git a/test/SILOptimizer/semantic-arc-opt-owned-to-guaranteed-phi.sil b/test/SILOptimizer/semantic-arc-opt-owned-to-guaranteed-phi.sil index 8c763b5479eb0..ddda9dd429ad5 100644 --- a/test/SILOptimizer/semantic-arc-opt-owned-to-guaranteed-phi.sil +++ b/test/SILOptimizer/semantic-arc-opt-owned-to-guaranteed-phi.sil @@ -24,7 +24,7 @@ bb3(%copy : @owned $Klass): } // CHECK-LABEL: sil [ossa] @test_owned_to_guaranteed2 : -// CHECK: bb3([[ARG1:%.*]] : @owned $Klass, [[ARG2:%.*]] : @guaranteed $Klass) +// CHECK: bb3([[ARG1:%.*]] : @owned $Klass, [[ARG2:%.*]] : @reborrow @guaranteed $Klass) // CHECK-LABEL: } // end sil function 'test_owned_to_guaranteed2' sil [ossa] @test_owned_to_guaranteed2 : $@convention(thin) (@owned Klass, @owned Klass) -> () { bb0(%0 : @owned $Klass, %1 : @owned $Klass): diff --git a/test/SILOptimizer/shrink_borrow_scope.sil b/test/SILOptimizer/shrink_borrow_scope.sil index b7a7eb0c73f57..808f936d604fa 100644 --- a/test/SILOptimizer/shrink_borrow_scope.sil +++ b/test/SILOptimizer/shrink_borrow_scope.sil @@ -359,7 +359,7 @@ exit: // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C): // CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] // CHECK: br [[WORK:bb[0-9]+]]([[LIFETIME]] : $C) -// CHECK: [[WORK]]([[LIFETIME_2:%[^,]+]] : @guaranteed $C): +// CHECK: [[WORK]]([[LIFETIME_2:%[^,]+]] : @reborrow @guaranteed $C): // CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]] // CHECK: [[LEFT]]: // CHECK: end_borrow [[LIFETIME_2]] diff --git a/test/SILOptimizer/simplify_cfg_ossa_switch_enum.sil b/test/SILOptimizer/simplify_cfg_ossa_switch_enum.sil index ed3439d65a75f..3f7df2c4430de 100644 --- a/test/SILOptimizer/simplify_cfg_ossa_switch_enum.sil +++ b/test/SILOptimizer/simplify_cfg_ossa_switch_enum.sil @@ -1,4 +1,4 @@ -// RUN: %target-sil-opt -unit-test-runner %s 2>&1 | %FileCheck %s +// RUN: %target-sil-opt -unit-test-runner %s | %FileCheck %s class Klass { }