Skip to content

Commit b6175ab

Browse files
committed
SIL: add the borrowed-from instruction.
It declares from which enclosing values a guaranteed phi argument is borrowed from.
1 parent dc21240 commit b6175ab

33 files changed

+304
-16
lines changed

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ public struct Phi {
139139
value.ownership == .owned || value.isReborrow
140140
}
141141

142+
public var borrowedFrom: BorrowedFromInst? {
143+
for use in value.uses {
144+
if let bfi = use.forwardingBorrowedFromUser {
145+
return bfi
146+
}
147+
}
148+
return nil
149+
}
150+
142151
public static func ==(lhs: Phi, rhs: Phi) -> Bool {
143152
lhs.value === rhs.value
144153
}
@@ -148,6 +157,15 @@ public struct Phi {
148157
}
149158
}
150159

160+
extension Operand {
161+
public var forwardingBorrowedFromUser: BorrowedFromInst? {
162+
if let bfi = instruction as? BorrowedFromInst, index == 0 {
163+
return bfi
164+
}
165+
return nil
166+
}
167+
}
168+
151169
public struct TerminatorResult {
152170
public let value: Argument
153171

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ public struct Builder {
184184
return notifyNew(bridged.createBeginBorrow(value.bridged).getAs(BeginBorrowInst.self))
185185
}
186186

187+
public func createBorrowedFrom(borrowedValue: Value, enclosingValues: [Value]) -> BorrowedFromInst {
188+
let bfi = enclosingValues.withBridgedValues { valuesRef in
189+
return bridged.createBorrowedFrom(borrowedValue.bridged, valuesRef)
190+
}
191+
return notifyNew(bfi.getAs(BorrowedFromInst.self))
192+
}
193+
187194
@discardableResult
188195
public func createEndBorrow(of beginBorrow: Value) -> EndBorrowInst {
189196
return notifyNew(bridged.createEndBorrow(beginBorrow.bridged).getAs(EndBorrowInst.self))

SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,14 @@ extension LinearFunctionExtractInst: ForwardingInstruction {
438438
public var canForwardOwnedValues: Bool { true }
439439
}
440440

441+
extension BorrowedFromInst: ForwardingInstruction {
442+
public var singleForwardedOperand: Operand? { operands[0] }
443+
public var preservesIdentity: Bool { true }
444+
public var preservesRepresentation: Bool { true }
445+
public var canForwardGuaranteedValues: Bool { true }
446+
public var canForwardOwnedValues: Bool { false }
447+
}
448+
441449
// -----------------------------------------------------------------------------
442450
// ownership transition instructions
443451

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,18 @@ final public class BridgeObjectToRefInst : SingleValueInstruction, UnaryInstruct
963963

964964
final public class BridgeObjectToWordInst : SingleValueInstruction, UnaryInstruction {}
965965

966+
final public class BorrowedFromInst : SingleValueInstruction, BorrowIntroducingInstruction {
967+
public var borrowedValue: Value { operands[0].value }
968+
public var borrowedPhi: Phi { Phi(borrowedValue)! }
969+
public var enclosingOperands: OperandArray {
970+
let ops = operands
971+
return ops[1..<ops.count]
972+
}
973+
public var enclosingValues: LazyMapSequence<LazySequence<OperandArray>.Elements, Value> {
974+
enclosingOperands.values
975+
}
976+
}
977+
966978
final public class ProjectBoxInst : SingleValueInstruction, UnaryInstruction {
967979
public var box: Value { operand.value }
968980
public var fieldIndex: Int { bridged.ProjectBoxInst_fieldIndex() }

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ public func registerSILClasses() {
201201
register(ExtractExecutorInst.self)
202202
register(BeginAccessInst.self)
203203
register(BeginBorrowInst.self)
204+
register(BorrowedFromInst.self)
204205
register(ProjectBoxInst.self)
205206
register(ProjectExistentialBoxInst.self)
206207
register(CopyValueInst.self)

docs/SIL.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4616,6 +4616,38 @@ We require that ``%1`` and ``%0`` have the same type ignoring SILValueCategory.
46164616

46174617
This instruction is only valid in functions in Ownership SSA form.
46184618

4619+
borrowed from
4620+
`````````````
4621+
4622+
::
4623+
4624+
sil-instruction ::= 'borrowed' sil-operand 'from' '(' (sil-operand (',' sil-operand)*)? ')'
4625+
4626+
bb1(%1 : @owned $T, %2 : @guaranteed $T):
4627+
%3 = borrowed %2 : $T from (%1 : $T, %0 : $S)
4628+
// %3 has type $T and guaranteed ownership
4629+
4630+
Declares from which enclosing values a guaranteed phi argument is borrowed
4631+
from.
4632+
An enclosing value is either a dominating borrow introducer (``%0``) of the
4633+
borrowed operand (``%2``) or an adjacent phi-argument in the same block
4634+
(``%1``).
4635+
In case of an adjacent phi, all incoming values of the adjacent phi must be
4636+
borrow introducers for the corresponding incoming value of the borrowed
4637+
operand in all predecessor blocks.
4638+
4639+
The borrowed operand (``%2``) must be a guaranteed phi argument and is
4640+
forwarded to the instruction result.
4641+
4642+
The list of enclosing values (operands after ``from``) can be empty if the
4643+
borrowed operand stems from a borrow introducer with no enclosing value, e.g.
4644+
a ``load_borrow``.
4645+
4646+
Guaranteed phi arguments must not have other users than borrowed-from
4647+
instructions.
4648+
4649+
This instruction is only valid in functions in Ownership SSA form.
4650+
46194651
end_lifetime
46204652
````````````
46214653

include/swift/SIL/InstWrappers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ class ForwardingOperation {
278278
&forwardingInst->getOperandRef(RefToBridgeObjectInst::ConvertedOperand);
279279
case SILInstructionKind::TuplePackExtractInst:
280280
return &forwardingInst->getOperandRef(TuplePackExtractInst::TupleOperand);
281+
case SILInstructionKind::BorrowedFromInst:
282+
return &forwardingInst->getOperandRef(0);
281283
default:
282284
int numRealOperands = forwardingInst->getNumRealOperands();
283285
if (numRealOperands == 0) {

include/swift/SIL/OwnershipUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class BorrowingOperandKind {
254254
enum Kind : uint8_t {
255255
Invalid = 0,
256256
BeginBorrow,
257+
BorrowedFrom,
257258
StoreBorrow,
258259
BeginApply,
259260
Branch,
@@ -279,6 +280,8 @@ class BorrowingOperandKind {
279280
return Kind::Invalid;
280281
case SILInstructionKind::BeginBorrowInst:
281282
return Kind::BeginBorrow;
283+
case SILInstructionKind::BorrowedFromInst:
284+
return Kind::BorrowedFrom;
282285
case SILInstructionKind::StoreBorrowInst:
283286
return Kind::StoreBorrow;
284287
case SILInstructionKind::BeginApplyInst:
@@ -399,6 +402,7 @@ struct BorrowingOperand {
399402
case BorrowingOperandKind::Invalid:
400403
llvm_unreachable("Using invalid case?!");
401404
case BorrowingOperandKind::BeginBorrow:
405+
case BorrowingOperandKind::BorrowedFrom:
402406
case BorrowingOperandKind::StoreBorrow:
403407
case BorrowingOperandKind::BeginApply:
404408
case BorrowingOperandKind::Apply:
@@ -431,6 +435,7 @@ struct BorrowingOperand {
431435
case BorrowingOperandKind::Invalid:
432436
llvm_unreachable("Using invalid case?!");
433437
case BorrowingOperandKind::BeginBorrow:
438+
case BorrowingOperandKind::BorrowedFrom:
434439
case BorrowingOperandKind::Branch:
435440
return true;
436441
case BorrowingOperandKind::StoreBorrow:

include/swift/SIL/SILBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,8 @@ struct BridgedBuilder{
11631163
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createFunctionRef(BridgedFunction function) const;
11641164
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCopyValue(BridgedValue op) const;
11651165
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBeginBorrow(BridgedValue op) const;
1166+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBorrowedFrom(BridgedValue borrowedValue,
1167+
BridgedValueArray enclosingValues) const;
11661168
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEndBorrow(BridgedValue op) const;
11671169
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCopyAddr(BridgedValue from, BridgedValue to,
11681170
bool takeSource, bool initializeDest) const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,13 @@ BridgedInstruction BridgedBuilder::createBeginBorrow(BridgedValue op) const {
15751575
return {unbridged().createBeginBorrow(regularLoc(), op.getSILValue())};
15761576
}
15771577

1578+
BridgedInstruction BridgedBuilder::createBorrowedFrom(BridgedValue borrowedValue,
1579+
BridgedValueArray enclosingValues) const {
1580+
llvm::SmallVector<swift::SILValue, 16> evs;
1581+
return {unbridged().createBorrowedFrom(regularLoc(), borrowedValue.getSILValue(),
1582+
enclosingValues.getValues(evs))};
1583+
}
1584+
15781585
BridgedInstruction BridgedBuilder::createEndBorrow(BridgedValue op) const {
15791586
return {unbridged().createEndBorrow(regularLoc(), op.getSILValue())};
15801587
}

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,12 @@ class SILBuilder {
837837
hasPointerEscape, fromVarDecl, fixed));
838838
}
839839

840+
BorrowedFromInst *createBorrowedFrom(SILLocation Loc, SILValue borrowedValue,
841+
ArrayRef<SILValue> enclosingValues) {
842+
return insert(BorrowedFromInst::create(getSILDebugLocation(Loc), borrowedValue,
843+
enclosingValues, getModule()));
844+
}
845+
840846
/// Convenience function for creating a load_borrow on non-trivial values and
841847
/// load [trivial] on trivial values. Becomes load unqualified in non-ossa
842848
/// functions.

include/swift/SIL/SILCloner.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,21 @@ void SILCloner<ImplClass>::visitBeginBorrowInst(BeginBorrowInst *Inst) {
12391239
Inst->hasPointerEscape(), Inst->isFromVarDecl()));
12401240
}
12411241

1242+
template <typename ImplClass>
1243+
void SILCloner<ImplClass>::visitBorrowedFromInst(BorrowedFromInst *bfi) {
1244+
getBuilder().setCurrentDebugScope(getOpScope(bfi->getDebugScope()));
1245+
if (!getBuilder().hasOwnership()) {
1246+
return recordFoldedValue(bfi, getOpValue(bfi->getBorrowedValue()));
1247+
}
1248+
1249+
auto enclosingValues = getOpValueArray<8>(bfi->getEnclosingValues());
1250+
recordClonedInstruction(bfi,
1251+
getBuilder().createBorrowedFrom(
1252+
getOpLocation(bfi->getLoc()),
1253+
getOpValue(bfi->getBorrowedValue()),
1254+
enclosingValues));
1255+
}
1256+
12421257
template <typename ImplClass>
12431258
void SILCloner<ImplClass>::visitStoreInst(StoreInst *Inst) {
12441259
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));

include/swift/SIL/SILInstruction.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4647,6 +4647,37 @@ class BeginBorrowInst
46474647
Operand *getSingleNonEndingUse() const;
46484648
};
46494649

4650+
/// BorrowedFromInst - Establishes borrow relations.
4651+
class BorrowedFromInst final : public InstructionBaseWithTrailingOperands<
4652+
SILInstructionKind::BorrowedFromInst, BorrowedFromInst,
4653+
OwnershipForwardingSingleValueInstruction> {
4654+
friend SILBuilder;
4655+
4656+
/// Because of the storage requirements of BorrowedFromInst, object
4657+
/// creation goes through 'create()'.
4658+
BorrowedFromInst(SILDebugLocation DebugLoc, ArrayRef<SILValue> operands);
4659+
4660+
/// Construct a BorrowedFromInst.
4661+
static BorrowedFromInst *create(SILDebugLocation DebugLoc, SILValue borrowedValue,
4662+
ArrayRef<SILValue> enclosingValues, SILModule &M);
4663+
4664+
public:
4665+
4666+
SILValue getBorrowedValue() {
4667+
return getAllOperands()[0].get();
4668+
}
4669+
4670+
/// The elements referenced by this StructInst.
4671+
ArrayRef<Operand> getEnclosingValueOperands() const {
4672+
return getAllOperands().drop_front();
4673+
}
4674+
4675+
/// The elements referenced by this StructInst.
4676+
OperandValueArrayRef getEnclosingValues() const {
4677+
return OperandValueArrayRef(getEnclosingValueOperands());
4678+
}
4679+
};
4680+
46504681
inline auto BeginBorrowInst::getEndBorrows() const -> EndBorrowRange {
46514682
return getUsersOfType<EndBorrowInst>();
46524683
}
@@ -11133,6 +11164,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1113311164
case SILInstructionKind::ThinToThickFunctionInst:
1113411165
case SILInstructionKind::UnconditionalCheckedCastInst:
1113511166
case SILInstructionKind::FunctionExtractIsolationInst:
11167+
case SILInstructionKind::BorrowedFromInst:
1113611168
return true;
1113711169
default:
1113811170
return false;

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
543543
SingleValueInstruction, MayRead, DoesNotRelease)
544544
SINGLE_VALUE_INST(BeginBorrowInst, begin_borrow,
545545
SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
546+
SINGLE_VALUE_INST(BorrowedFromInst, borrowed,
547+
SingleValueInstruction, None, DoesNotRelease)
546548
SINGLE_VALUE_INST(StoreBorrowInst, store_borrow,
547549
SILInstruction, MayWrite, DoesNotRelease)
548550
// begin_access may trap. Trapping is unordered with respect to memory access,

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,9 @@ class IRGenSILFunction :
13381338
void visitBeginBorrowInst(BeginBorrowInst *i) {
13391339
llvm_unreachable("unimplemented");
13401340
}
1341+
void visitBorrowedFromInst(BorrowedFromInst *i) {
1342+
llvm_unreachable("unimplemented");
1343+
}
13411344
void visitEndBorrowInst(EndBorrowInst *i) {
13421345
llvm_unreachable("unimplemented");
13431346
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,12 @@ OperandOwnershipClassifier::visitBeginBorrowInst(BeginBorrowInst *borrow) {
421421
return OperandOwnership::Borrow;
422422
}
423423

424+
OperandOwnership
425+
OperandOwnershipClassifier::visitBorrowedFromInst(BorrowedFromInst *bfi) {
426+
return getOperandIndex() == 0 ? OperandOwnership::GuaranteedForwarding
427+
: OperandOwnership::InstantaneousUse;
428+
}
429+
424430
// MARK: Instructions whose use ownership depends on the operand in question.
425431

426432
OperandOwnership OperandOwnershipClassifier::

lib/SIL/IR/SILInstructions.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,24 @@ StructInst::StructInst(SILDebugLocation Loc, SILType Ty,
14841484
assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage());
14851485
}
14861486

1487+
BorrowedFromInst *BorrowedFromInst::create(SILDebugLocation DebugLoc, SILValue borrowedValue,
1488+
ArrayRef<SILValue> enclosingValues, SILModule &M) {
1489+
auto Size = totalSizeToAlloc<swift::Operand>(enclosingValues.size() + 1);
1490+
auto Buffer = M.allocateInst(Size, alignof(StructInst));
1491+
SmallVector<SILValue, 8> operands;
1492+
operands.push_back(borrowedValue);
1493+
for (SILValue ev : enclosingValues) {
1494+
operands.push_back(ev);
1495+
}
1496+
return ::new (Buffer) BorrowedFromInst(DebugLoc, operands);
1497+
}
1498+
1499+
BorrowedFromInst::BorrowedFromInst(SILDebugLocation DebugLoc, ArrayRef<SILValue> operands)
1500+
: InstructionBaseWithTrailingOperands(operands, DebugLoc, operands[0]->getType(),
1501+
operands[0]->getOwnershipKind()) {
1502+
assert(operands[0]->getOwnershipKind() != OwnershipKind::Owned);
1503+
}
1504+
14871505
ObjectInst *ObjectInst::create(SILDebugLocation Loc, SILType Ty,
14881506
ArrayRef<SILValue> Elements,
14891507
unsigned NumBaseElements, SILModule &M) {

lib/SIL/IR/SILPrinter.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,20 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
17531753
*this << getIDAndType(BBI->getOperand());
17541754
}
17551755

1756+
void visitBorrowedFromInst(BorrowedFromInst *bfi) {
1757+
*this << getIDAndType(bfi->getBorrowedValue());
1758+
*this << " from (";
1759+
bool first = true;
1760+
for (SILValue ev : bfi->getEnclosingValues()) {
1761+
if (!first) {
1762+
*this << ", ";
1763+
}
1764+
first = false;
1765+
*this << getIDAndType(ev);
1766+
}
1767+
*this << ")";
1768+
}
1769+
17561770
void printStoreOwnershipQualifier(StoreOwnershipQualifier Qualifier) {
17571771
switch (Qualifier) {
17581772
case StoreOwnershipQualifier::Unqualified:

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ CONSTANT_OWNERSHIP_INST(Owned, WeakCopyValue)
7171
#include "swift/AST/ReferenceStorage.def"
7272

7373
CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
74+
CONSTANT_OWNERSHIP_INST(Guaranteed, BorrowedFrom)
7475
CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
7576
CONSTANT_OWNERSHIP_INST(Guaranteed, FunctionExtractIsolation)
7677
CONSTANT_OWNERSHIP_INST(None, GlobalValue)

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3773,6 +3773,30 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37733773
break;
37743774
}
37753775

3776+
case SILInstructionKind::BorrowedFromInst: {
3777+
SILValue guaranteedValue;
3778+
if (parseTypedValueRef(guaranteedValue, B))
3779+
return true;
3780+
3781+
if (parseVerbatim("from") ||
3782+
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
3783+
return true;
3784+
3785+
if (P.Tok.isNot(tok::r_paren)) {
3786+
do {
3787+
if (parseTypedValueRef(Val, B))
3788+
return true;
3789+
OpList.push_back(Val);
3790+
} while (P.consumeIf(tok::comma));
3791+
}
3792+
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
3793+
return true;
3794+
3795+
ResultVal = B.createBorrowedFrom(InstLoc, guaranteedValue, OpList);
3796+
break;
3797+
}
3798+
3799+
37763800
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
37773801
case SILInstructionKind::Load##Name##Inst: { \
37783802
bool isTake = false; \

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
506506
case SILInstructionKind::LoadInst:
507507
case SILInstructionKind::LoadBorrowInst:
508508
case SILInstructionKind::BeginBorrowInst:
509+
case SILInstructionKind::BorrowedFromInst:
509510
case SILInstructionKind::StoreBorrowInst:
510511
case SILInstructionKind::MarkUninitializedInst:
511512
case SILInstructionKind::ProjectExistentialBoxInst:

0 commit comments

Comments
 (0)