Skip to content

Commit b1dbb65

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

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
@@ -182,6 +182,13 @@ public struct Builder {
182182
return notifyNew(bridged.createBeginBorrow(value.bridged).getAs(BeginBorrowInst.self))
183183
}
184184

185+
public func createBorrowedFrom(borrowedValue: Value, enclosingValues: [Value]) -> BorrowedFromInst {
186+
let bfi = enclosingValues.withBridgedValues { valuesRef in
187+
return bridged.createBorrowedFrom(borrowedValue.bridged, valuesRef)
188+
}
189+
return notifyNew(bfi.getAs(BorrowedFromInst.self))
190+
}
191+
185192
@discardableResult
186193
public func createEndBorrow(of beginBorrow: Value) -> EndBorrowInst {
187194
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
@@ -1034,6 +1034,18 @@ final public class BeginBorrowInst : SingleValueInstruction, UnaryInstruction, B
10341034
public var isFromVarDecl: Bool { bridged.BeginBorrow_isFromVarDecl() }
10351035
}
10361036

1037+
final public class BorrowedFromInst : SingleValueInstruction, BorrowIntroducingInstruction {
1038+
public var borrowedValue: Value { operands[0].value }
1039+
public var borrowedPhi: Phi { Phi(borrowedValue)! }
1040+
public var enclosingOperands: OperandArray {
1041+
let ops = operands
1042+
return ops[1..<ops.count]
1043+
}
1044+
public var enclosingValues: LazyMapSequence<LazySequence<OperandArray>.Elements, Value> {
1045+
enclosingOperands.values
1046+
}
1047+
}
1048+
10371049
final public class ProjectBoxInst : SingleValueInstruction, UnaryInstruction {
10381050
public var box: Value { operand.value }
10391051
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
@@ -4605,6 +4605,38 @@ We require that ``%1`` and ``%0`` have the same type ignoring SILValueCategory.
46054605

46064606
This instruction is only valid in functions in Ownership SSA form.
46074607

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

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:
@@ -392,6 +395,7 @@ struct BorrowingOperand {
392395
case BorrowingOperandKind::Invalid:
393396
llvm_unreachable("Using invalid case?!");
394397
case BorrowingOperandKind::BeginBorrow:
398+
case BorrowingOperandKind::BorrowedFrom:
395399
case BorrowingOperandKind::StoreBorrow:
396400
case BorrowingOperandKind::BeginApply:
397401
case BorrowingOperandKind::Apply:
@@ -424,6 +428,7 @@ struct BorrowingOperand {
424428
case BorrowingOperandKind::Invalid:
425429
llvm_unreachable("Using invalid case?!");
426430
case BorrowingOperandKind::BeginBorrow:
431+
case BorrowingOperandKind::BorrowedFrom:
427432
case BorrowingOperandKind::Branch:
428433
return true;
429434
case BorrowingOperandKind::StoreBorrow:

include/swift/SIL/SILBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,8 @@ struct BridgedBuilder{
11521152
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createFunctionRef(BridgedFunction function) const;
11531153
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCopyValue(BridgedValue op) const;
11541154
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBeginBorrow(BridgedValue op) const;
1155+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBorrowedFrom(BridgedValue borrowedValue,
1156+
BridgedValueArray enclosingValues) const;
11551157
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEndBorrow(BridgedValue op) const;
11561158
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCopyAddr(BridgedValue from, BridgedValue to,
11571159
bool takeSource, bool initializeDest) const;

include/swift/SIL/SILBridgingImpl.h

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

1548+
BridgedInstruction BridgedBuilder::createBorrowedFrom(BridgedValue borrowedValue,
1549+
BridgedValueArray enclosingValues) const {
1550+
llvm::SmallVector<swift::SILValue, 16> evs;
1551+
return {unbridged().createBorrowedFrom(regularLoc(), borrowedValue.getSILValue(),
1552+
enclosingValues.getValues(evs))};
1553+
}
1554+
15481555
BridgedInstruction BridgedBuilder::createEndBorrow(BridgedValue op) const {
15491556
return {unbridged().createEndBorrow(regularLoc(), op.getSILValue())};
15501557
}

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,12 @@ class SILBuilder {
830830
hasPointerEscape, fromVarDecl, fixed));
831831
}
832832

833+
BorrowedFromInst *createBorrowedFrom(SILLocation Loc, SILValue borrowedValue,
834+
ArrayRef<SILValue> enclosingValues) {
835+
return insert(BorrowedFromInst::create(getSILDebugLocation(Loc), borrowedValue,
836+
enclosingValues, getModule()));
837+
}
838+
833839
/// Convenience function for creating a load_borrow on non-trivial values and
834840
/// load [trivial] on trivial values. Becomes load unqualified in non-ossa
835841
/// functions.

include/swift/SIL/SILCloner.h

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

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

include/swift/SIL/SILInstruction.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4577,6 +4577,37 @@ class BeginBorrowInst
45774577
Operand *getSingleNonEndingUse() const;
45784578
};
45794579

4580+
/// BorrowedFromInst - Establishes borrow relations.
4581+
class BorrowedFromInst final : public InstructionBaseWithTrailingOperands<
4582+
SILInstructionKind::BorrowedFromInst, BorrowedFromInst,
4583+
OwnershipForwardingSingleValueInstruction> {
4584+
friend SILBuilder;
4585+
4586+
/// Because of the storage requirements of BorrowedFromInst, object
4587+
/// creation goes through 'create()'.
4588+
BorrowedFromInst(SILDebugLocation DebugLoc, ArrayRef<SILValue> operands);
4589+
4590+
/// Construct a BorrowedFromInst.
4591+
static BorrowedFromInst *create(SILDebugLocation DebugLoc, SILValue borrowedValue,
4592+
ArrayRef<SILValue> enclosingValues, SILModule &M);
4593+
4594+
public:
4595+
4596+
SILValue getBorrowedValue() {
4597+
return getAllOperands()[0].get();
4598+
}
4599+
4600+
/// The elements referenced by this StructInst.
4601+
ArrayRef<Operand> getEnclosingValueOperands() const {
4602+
return getAllOperands().drop_front();
4603+
}
4604+
4605+
/// The elements referenced by this StructInst.
4606+
OperandValueArrayRef getEnclosingValues() const {
4607+
return OperandValueArrayRef(getEnclosingValueOperands());
4608+
}
4609+
};
4610+
45804611
inline auto BeginBorrowInst::getEndBorrows() const -> EndBorrowRange {
45814612
return getUsersOfType<EndBorrowInst>();
45824613
}
@@ -11048,6 +11079,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1104811079
case SILInstructionKind::ThinToThickFunctionInst:
1104911080
case SILInstructionKind::UnconditionalCheckedCastInst:
1105011081
case SILInstructionKind::FunctionExtractIsolationInst:
11082+
case SILInstructionKind::BorrowedFromInst:
1105111083
return true;
1105211084
default:
1105311085
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
@@ -1315,6 +1315,9 @@ class IRGenSILFunction :
13151315
void visitBeginBorrowInst(BeginBorrowInst *i) {
13161316
llvm_unreachable("unimplemented");
13171317
}
1318+
void visitBorrowedFromInst(BorrowedFromInst *i) {
1319+
llvm_unreachable("unimplemented");
1320+
}
13181321
void visitEndBorrowInst(EndBorrowInst *i) {
13191322
llvm_unreachable("unimplemented");
13201323
}

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

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

lib/SIL/IR/SILPrinter.cpp

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

1746+
void visitBorrowedFromInst(BorrowedFromInst *bfi) {
1747+
*this << getIDAndType(bfi->getBorrowedValue());
1748+
*this << " from (";
1749+
bool first = true;
1750+
for (SILValue ev : bfi->getEnclosingValues()) {
1751+
if (!first) {
1752+
*this << ", ";
1753+
}
1754+
first = false;
1755+
*this << getIDAndType(ev);
1756+
}
1757+
*this << ")";
1758+
}
1759+
17461760
void printStoreOwnershipQualifier(StoreOwnershipQualifier Qualifier) {
17471761
switch (Qualifier) {
17481762
case StoreOwnershipQualifier::Unqualified:

lib/SIL/IR/ValueOwnership.cpp

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

7272
CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
73+
CONSTANT_OWNERSHIP_INST(Guaranteed, BorrowedFrom)
7374
CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
7475
CONSTANT_OWNERSHIP_INST(Guaranteed, FunctionExtractIsolation)
7576
CONSTANT_OWNERSHIP_INST(None, GlobalValue)

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3758,6 +3758,30 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37583758
break;
37593759
}
37603760

3761+
case SILInstructionKind::BorrowedFromInst: {
3762+
SILValue guaranteedValue;
3763+
if (parseTypedValueRef(guaranteedValue, B))
3764+
return true;
3765+
3766+
if (parseVerbatim("from") ||
3767+
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
3768+
return true;
3769+
3770+
if (P.Tok.isNot(tok::r_paren)) {
3771+
do {
3772+
if (parseTypedValueRef(Val, B))
3773+
return true;
3774+
OpList.push_back(Val);
3775+
} while (P.consumeIf(tok::comma));
3776+
}
3777+
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
3778+
return true;
3779+
3780+
ResultVal = B.createBorrowedFrom(InstLoc, guaranteedValue, OpList);
3781+
break;
3782+
}
3783+
3784+
37613785
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
37623786
case SILInstructionKind::Load##Name##Inst: { \
37633787
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)