Skip to content

Commit 667d5f8

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

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
@@ -441,6 +441,14 @@ extension LinearFunctionExtractInst: ForwardingInstruction {
441441
public var canForwardOwnedValues: Bool { true }
442442
}
443443

444+
extension BorrowedFromInst: ForwardingInstruction {
445+
public var singleForwardedOperand: Operand? { operands[0] }
446+
public var preservesIdentity: Bool { true }
447+
public var preservesRepresentation: Bool { true }
448+
public var canForwardGuaranteedValues: Bool { true }
449+
public var canForwardOwnedValues: Bool { false }
450+
}
451+
444452
// -----------------------------------------------------------------------------
445453
// ownership transition instructions
446454

SwiftCompilerSources/Sources/SIL/Instruction.swift

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

957957
final public class BridgeObjectToWordInst : SingleValueInstruction, UnaryInstruction {}
958958

959+
final public class BorrowedFromInst : SingleValueInstruction, BorrowIntroducingInstruction {
960+
public var borrowedValue: Value { operands[0].value }
961+
public var borrowedPhi: Phi { Phi(borrowedValue)! }
962+
public var enclosingOperands: OperandArray {
963+
let ops = operands
964+
return ops[1..<ops.count]
965+
}
966+
public var enclosingValues: LazyMapSequence<LazySequence<OperandArray>.Elements, Value> {
967+
enclosingOperands.values
968+
}
969+
}
970+
959971
final public class ProjectBoxInst : SingleValueInstruction, UnaryInstruction {
960972
public var box: Value { operand.value }
961973
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
@@ -4615,6 +4615,38 @@ We require that ``%1`` and ``%0`` have the same type ignoring SILValueCategory.
46154615

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

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

include/swift/SIL/InstWrappers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ class ForwardingOperation {
279279
&forwardingInst->getOperandRef(RefToBridgeObjectInst::ConvertedOperand);
280280
case SILInstructionKind::TuplePackExtractInst:
281281
return &forwardingInst->getOperandRef(TuplePackExtractInst::TupleOperand);
282+
case SILInstructionKind::BorrowedFromInst:
283+
return &forwardingInst->getOperandRef(0);
282284
default:
283285
int numRealOperands = forwardingInst->getNumRealOperands();
284286
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
@@ -1240,6 +1240,21 @@ void SILCloner<ImplClass>::visitBeginBorrowInst(BeginBorrowInst *Inst) {
12401240
Inst->hasPointerEscape(), Inst->isFromVarDecl()));
12411241
}
12421242

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

include/swift/SIL/SILInstruction.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4643,6 +4643,37 @@ class BeginBorrowInst
46434643
Operand *getSingleNonEndingUse() const;
46444644
};
46454645

4646+
/// BorrowedFromInst - Establishes borrow relations.
4647+
class BorrowedFromInst final : public InstructionBaseWithTrailingOperands<
4648+
SILInstructionKind::BorrowedFromInst, BorrowedFromInst,
4649+
OwnershipForwardingSingleValueInstruction> {
4650+
friend SILBuilder;
4651+
4652+
/// Because of the storage requirements of BorrowedFromInst, object
4653+
/// creation goes through 'create()'.
4654+
BorrowedFromInst(SILDebugLocation DebugLoc, ArrayRef<SILValue> operands);
4655+
4656+
/// Construct a BorrowedFromInst.
4657+
static BorrowedFromInst *create(SILDebugLocation DebugLoc, SILValue borrowedValue,
4658+
ArrayRef<SILValue> enclosingValues, SILModule &M);
4659+
4660+
public:
4661+
4662+
SILValue getBorrowedValue() {
4663+
return getAllOperands()[0].get();
4664+
}
4665+
4666+
/// The elements referenced by this StructInst.
4667+
ArrayRef<Operand> getEnclosingValueOperands() const {
4668+
return getAllOperands().drop_front();
4669+
}
4670+
4671+
/// The elements referenced by this StructInst.
4672+
OperandValueArrayRef getEnclosingValues() const {
4673+
return OperandValueArrayRef(getEnclosingValueOperands());
4674+
}
4675+
};
4676+
46464677
inline auto BeginBorrowInst::getEndBorrows() const -> EndBorrowRange {
46474678
return getUsersOfType<EndBorrowInst>();
46484679
}
@@ -11136,6 +11167,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1113611167
case SILInstructionKind::UnconditionalCheckedCastInst:
1113711168
case SILInstructionKind::FunctionExtractIsolationInst:
1113811169
case SILInstructionKind::DropDeinitInst:
11170+
case SILInstructionKind::BorrowedFromInst:
1113911171
return true;
1114011172
default:
1114111173
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
@@ -1339,6 +1339,9 @@ class IRGenSILFunction :
13391339
void visitBeginBorrowInst(BeginBorrowInst *i) {
13401340
llvm_unreachable("unimplemented");
13411341
}
1342+
void visitBorrowedFromInst(BorrowedFromInst *i) {
1343+
llvm_unreachable("unimplemented");
1344+
}
13421345
void visitEndBorrowInst(EndBorrowInst *i) {
13431346
llvm_unreachable("unimplemented");
13441347
}

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
@@ -1477,6 +1477,24 @@ StructInst::StructInst(SILDebugLocation Loc, SILType Ty,
14771477
assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage());
14781478
}
14791479

1480+
BorrowedFromInst *BorrowedFromInst::create(SILDebugLocation DebugLoc, SILValue borrowedValue,
1481+
ArrayRef<SILValue> enclosingValues, SILModule &M) {
1482+
auto Size = totalSizeToAlloc<swift::Operand>(enclosingValues.size() + 1);
1483+
auto Buffer = M.allocateInst(Size, alignof(StructInst));
1484+
SmallVector<SILValue, 8> operands;
1485+
operands.push_back(borrowedValue);
1486+
for (SILValue ev : enclosingValues) {
1487+
operands.push_back(ev);
1488+
}
1489+
return ::new (Buffer) BorrowedFromInst(DebugLoc, operands);
1490+
}
1491+
1492+
BorrowedFromInst::BorrowedFromInst(SILDebugLocation DebugLoc, ArrayRef<SILValue> operands)
1493+
: InstructionBaseWithTrailingOperands(operands, DebugLoc, operands[0]->getType(),
1494+
operands[0]->getOwnershipKind()) {
1495+
assert(operands[0]->getOwnershipKind() != OwnershipKind::Owned);
1496+
}
1497+
14801498
ObjectInst *ObjectInst::create(SILDebugLocation Loc, SILType Ty,
14811499
ArrayRef<SILValue> Elements,
14821500
unsigned NumBaseElements, SILModule &M) {

lib/SIL/IR/SILPrinter.cpp

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

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

lib/SIL/IR/ValueOwnership.cpp

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

7474
CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
75+
CONSTANT_OWNERSHIP_INST(Guaranteed, BorrowedFrom)
7576
CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
7677
CONSTANT_OWNERSHIP_INST(Guaranteed, FunctionExtractIsolation)
7778
CONSTANT_OWNERSHIP_INST(None, GlobalValue)

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3779,6 +3779,30 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37793779
break;
37803780
}
37813781

3782+
case SILInstructionKind::BorrowedFromInst: {
3783+
SILValue guaranteedValue;
3784+
if (parseTypedValueRef(guaranteedValue, B))
3785+
return true;
3786+
3787+
if (parseVerbatim("from") ||
3788+
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
3789+
return true;
3790+
3791+
if (P.Tok.isNot(tok::r_paren)) {
3792+
do {
3793+
if (parseTypedValueRef(Val, B))
3794+
return true;
3795+
OpList.push_back(Val);
3796+
} while (P.consumeIf(tok::comma));
3797+
}
3798+
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
3799+
return true;
3800+
3801+
ResultVal = B.createBorrowedFrom(InstLoc, guaranteedValue, OpList);
3802+
break;
3803+
}
3804+
3805+
37823806
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
37833807
case SILInstructionKind::Load##Name##Inst: { \
37843808
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)