Skip to content

Commit 2e610f0

Browse files
committed
[sil] Add support for the destructure_value instruction.
rdar://31521023
1 parent 3194718 commit 2e610f0

File tree

18 files changed

+161
-14
lines changed

18 files changed

+161
-14
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,12 @@ class SILBuilder {
11841184
Ref, ResultTy));
11851185
}
11861186

1187+
DestructureValueInst *createDestructureValue(SILLocation Loc,
1188+
SILValue Operand) {
1189+
return insert(DestructureValueInst::create(getSILDebugLocation(Loc),
1190+
getFunction(), Operand));
1191+
}
1192+
11871193
ClassMethodInst *createClassMethod(SILLocation Loc, SILValue Operand,
11881194
SILDeclRef Member, SILType MethodTy) {
11891195
return insert(new (getModule()) ClassMethodInst(

include/swift/SIL/SILCloner.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,9 +1527,18 @@ SILCloner<ImplClass>::visitRefTailAddrInst(RefTailAddrInst *Inst) {
15271527
getOpType(Inst->getType())));
15281528
}
15291529

1530-
template<typename ImplClass>
1531-
void
1532-
SILCloner<ImplClass>::visitClassMethodInst(ClassMethodInst *Inst) {
1530+
template <typename ImplClass>
1531+
void SILCloner<ImplClass>::visitDestructureValueInst(
1532+
DestructureValueInst *Inst) {
1533+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1534+
doPostProcess(
1535+
Inst,
1536+
getBuilder().createDestructureValue(getOpLocation(Inst->getLoc()),
1537+
getOpValue(Inst->getOperand())));
1538+
}
1539+
1540+
template <typename ImplClass>
1541+
void SILCloner<ImplClass>::visitClassMethodInst(ClassMethodInst *Inst) {
15331542
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
15341543
doPostProcess(Inst,
15351544
getBuilder().createClassMethod(getOpLocation(Inst->getLoc()),

include/swift/SIL/SILInstruction.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class DeclRefExpr;
4444
class FloatLiteralExpr;
4545
class FuncDecl;
4646
class IntegerLiteralExpr;
47+
class Projection;
4748
class SingleValueInstruction;
4849
class MultipleValueInstruction;
4950
class NonValueInstruction;
@@ -747,9 +748,10 @@ class MultipleValueInstructionResult : public ValueBase {
747748

748749
/// An instruction which always produces a fixed list of values.
749750
class MultipleValueInstruction : public SILInstruction {
750-
// *NOTE* THis is just a stub since we do not currently have any multiple
751-
// value instructions.
752-
static bool isMultipleValueInstKind(SILNodeKind kind) { return false; }
751+
static bool isMultipleValueInstKind(SILNodeKind kind) {
752+
return kind >= SILNodeKind::First_MultipleValueInstruction &&
753+
kind <= SILNodeKind::Last_MultipleValueInstruction;
754+
}
753755

754756
friend class SILInstruction;
755757
friend class SILInstructionResultArray;
@@ -7179,6 +7181,21 @@ SILFunction *ApplyInstBase<Impl, Base, false>::getCalleeFunction() const {
71797181
}
71807182
}
71817183

7184+
class DestructureValueInst final
7185+
: public UnaryInstructionBase<SILInstructionKind::DestructureValueInst,
7186+
MultipleValueInstruction>,
7187+
private llvm::TrailingObjects<DestructureValueInst,
7188+
MultipleValueInstructionResult> {
7189+
friend TrailingObjects;
7190+
7191+
DestructureValueInst(SILDebugLocation Loc, SILValue Operand)
7192+
: UnaryInstructionBase(Loc, Operand) {}
7193+
7194+
public:
7195+
static DestructureValueInst *create(SILDebugLocation Loc, SILFunction &F,
7196+
SILValue Operand);
7197+
};
7198+
71827199
inline SILNode *MultipleValueInstructionResult::getCanonicalSILNodeInObject() {
71837200
return Parent->getCanonicalSILNodeInObject();
71847201
}

include/swift/SIL/SILNodes.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,8 +627,12 @@ NON_VALUE_INST(CondFailInst, cond_fail,
627627

628628
NODE_RANGE(NonValueInstruction, UnreachableInst, CondFailInst)
629629

630-
NODE_RANGE(SILInstruction, AllocStackInst, CondFailInst)
631-
NODE_RANGE(SILNode, SILPHIArgument, CondFailInst)
630+
MULTIPLE_VALUE_INST(DestructureValueInst, destructure_value,
631+
SILInstruction, None, DoesNotRelease)
632+
INST_RANGE(MultipleValueInstruction, DestructureValueInst, DestructureValueInst)
633+
634+
NODE_RANGE(SILInstruction, AllocStackInst, DestructureValueInst)
635+
NODE_RANGE(SILNode, SILPHIArgument, DestructureValueInst)
632636

633637
#undef SINGLE_VALUE_INST_RANGE
634638
#undef INST_RANGE

include/swift/SIL/SILValue.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ struct ValueOwnershipKind {
128128
bool isTrivialOr(ValueOwnershipKind Kind) const {
129129
return Value == Trivial || Value == Kind;
130130
}
131+
132+
/// Given that this is a ValueOwnershipKind of a parent type of \p Proj,
133+
/// return either trivial if the Proj is a trivial subtype or the parent value
134+
/// ownership kind otherwise.
135+
ValueOwnershipKind getProjectedOwnershipKind(SILModule &M,
136+
SILType Proj) const;
131137
};
132138

133139
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ValueOwnershipKind Kind);

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 368; // Last change: objc_method, objc_super_method
57+
const uint16_t VERSION_MINOR = 369; // Last change: destructure_value
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ class IRGenSILFunction :
884884
void visitValueMetatypeInst(ValueMetatypeInst *i);
885885
void visitExistentialMetatypeInst(ExistentialMetatypeInst *i);
886886
void visitTupleExtractInst(TupleExtractInst *i);
887+
void visitDestructureValueInst(DestructureValueInst *i) {
888+
llvm_unreachable("unimplemented");
889+
}
887890
void visitTupleElementAddrInst(TupleElementAddrInst *i);
888891
void visitStructExtractInst(StructExtractInst *i);
889892
void visitStructElementAddrInst(StructElementAddrInst *i);

lib/ParseSIL/ParseSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
23112311
UNARY_INSTRUCTION(DestroyValue)
23122312
UNARY_INSTRUCTION(CondFail)
23132313
UNARY_INSTRUCTION(EndBorrowArgument)
2314+
UNARY_INSTRUCTION(DestructureValue)
23142315
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
23152316
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
23162317
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)

lib/SIL/SILInstructions.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17-
#include "swift/SIL/SILInstruction.h"
1817
#include "swift/AST/Expr.h"
1918
#include "swift/AST/ProtocolConformance.h"
20-
#include "swift/Basic/type_traits.h"
21-
#include "swift/Basic/Unicode.h"
2219
#include "swift/Basic/AssertImplements.h"
20+
#include "swift/Basic/Unicode.h"
21+
#include "swift/Basic/type_traits.h"
2322
#include "swift/SIL/FormalLinkage.h"
23+
#include "swift/SIL/Projection.h"
2424
#include "swift/SIL/SILBuilder.h"
2525
#include "swift/SIL/SILCloner.h"
26+
#include "swift/SIL/SILInstruction.h"
2627
#include "swift/SIL/SILModule.h"
2728
#include "swift/SIL/SILVisitor.h"
2829
#include "llvm/ADT/APInt.h"
@@ -2326,3 +2327,41 @@ GenericSpecializationInformation::create(SILInstruction *Inst, SILBuilder &B) {
23262327

23272328
return nullptr;
23282329
}
2330+
2331+
DestructureValueInst *DestructureValueInst::create(SILDebugLocation Loc,
2332+
SILFunction &F,
2333+
SILValue Operand) {
2334+
SILModule &M = F.getModule();
2335+
SILType OpType = Operand->getType();
2336+
assert((OpType.getStructOrBoundGenericStruct() ||
2337+
OpType.getSwiftRValueType()->is<TupleType>()) &&
2338+
"Expected a struct or tuple typed operand?!");
2339+
2340+
llvm::SmallVector<Projection, 8> Projections;
2341+
Projection::getFirstLevelProjections(OpType, M, Projections);
2342+
assert(Projections.size() && "Can not destructure an operand without fields");
2343+
2344+
unsigned Size =
2345+
totalSizeToAlloc<MultipleValueInstructionResult>(Projections.size());
2346+
void *Buffer =
2347+
F.getModule().allocateInst(Size, alignof(DestructureValueInst));
2348+
2349+
auto *NewI = ::new (Buffer) DestructureValueInst(Loc, Operand);
2350+
MutableArrayRef<MultipleValueInstructionResult> Elts(
2351+
NewI->getTrailingObjects<MultipleValueInstructionResult>(),
2352+
Projections.size());
2353+
2354+
auto OpOwnershipKind = Operand.getOwnershipKind();
2355+
for (unsigned i : indices(Projections)) {
2356+
const auto &P = Projections[i];
2357+
SILType ProjType = P.getType(OpType, M);
2358+
auto ProjOwnershipKind =
2359+
OpOwnershipKind.getProjectedOwnershipKind(M, ProjType);
2360+
2361+
::new (&Elts[i])
2362+
MultipleValueInstructionResult(NewI, ProjType, ProjOwnershipKind);
2363+
}
2364+
NewI->setResults(Elts);
2365+
2366+
return NewI;
2367+
}

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ FORWARD_ANY_OWNERSHIP_INST(BridgeObjectToRef)
686686
FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCast)
687687
FORWARD_ANY_OWNERSHIP_INST(MarkUninitialized)
688688
FORWARD_ANY_OWNERSHIP_INST(UncheckedEnumData)
689+
FORWARD_ANY_OWNERSHIP_INST(DestructureValue)
689690
#undef FORWARD_ANY_OWNERSHIP_INST
690691

691692
// An instruction that forwards a constant ownership or trivial ownership.

lib/SIL/SILPrinter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
660660
/// Print out the users of the SILValue \p V. Return true if we printed out
661661
/// either an id or a use list. Return false otherwise.
662662
bool printUsersOfSILNode(const SILNode *node, bool printedSlashes) {
663-
TinyPtrVector<SILValue> values;
663+
// This allows for multiple return values.
664+
llvm::SmallVector<SILValue, 8> values;
664665
if (auto *value = dyn_cast<ValueBase>(node)) {
665666
// The base pointer of the ultimate ArrayRef here is just the
666667
// ValueBase; we aren't forming a reference to a temporary array.
@@ -1573,6 +1574,7 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
15731574
void visitTupleExtractInst(TupleExtractInst *EI) {
15741575
*this << getIDAndType(EI->getOperand()) << ", " << EI->getFieldNo();
15751576
}
1577+
15761578
void visitTupleElementAddrInst(TupleElementAddrInst *EI) {
15771579
*this << getIDAndType(EI->getOperand()) << ", " << EI->getFieldNo();
15781580
}
@@ -1596,6 +1598,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
15961598
*this << getIDAndType(RTAI->getOperand()) << ", " << RTAI->getTailType();
15971599
}
15981600

1601+
void visitDestructureValueInst(DestructureValueInst *DVI) {
1602+
*this << getIDAndType(DVI->getOperand());
1603+
}
1604+
15991605
void printMethodInst(MethodInst *I, SILValue Operand) {
16001606
*this << getIDAndType(Operand) << ", " << I->getMember();
16011607
}

lib/SIL/SILValue.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ ValueOwnershipKind::ValueOwnershipKind(StringRef S) {
215215
Value = Result.getValue();
216216
}
217217

218+
ValueOwnershipKind
219+
ValueOwnershipKind::getProjectedOwnershipKind(SILModule &M,
220+
SILType Proj) const {
221+
if (Proj.isTrivial(M))
222+
return ValueOwnershipKind::Trivial;
223+
return *this;
224+
}
225+
218226
ValueOwnershipKind SILValue::getOwnershipKind() const {
219227
// Once we have multiple return values, this must be changed.
220228
sil::ValueOwnershipKindClassifier Classifier;

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
265265
case SILInstructionKind::StructInst:
266266
case SILInstructionKind::StructExtractInst:
267267
case SILInstructionKind::TupleExtractInst:
268+
case SILInstructionKind::DestructureValueInst:
268269
return InlineCost::Free;
269270

270271
// Unchecked casts are free.

lib/Serialization/DeserializeSIL.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
14211421
#undef UNARY_INSTRUCTION
14221422
#undef REFCOUNTING_INSTRUCTION
14231423

1424+
case SILInstructionKind::DestructureValueInst: {
1425+
assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
1426+
SILValue Operand = getLocalValue(
1427+
ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
1428+
ResultVal = Builder.createDestructureValue(Loc, Operand);
1429+
break;
1430+
}
14241431
case SILInstructionKind::UncheckedOwnershipConversionInst: {
14251432
auto Ty = MF->getType(TyID);
14261433
auto ResultKind = ValueOwnershipKind(Attr);

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
10621062
}
10631063
case SILInstructionKind::CondFailInst:
10641064
case SILInstructionKind::RetainValueInst:
1065+
case SILInstructionKind::DestructureValueInst:
10651066
case SILInstructionKind::RetainValueAddrInst:
10661067
case SILInstructionKind::UnmanagedRetainValueInst:
10671068
case SILInstructionKind::EndBorrowArgumentInst:

test/SIL/Parser/basic.sil

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ struct TestArray {
2020
var storage : TestArrayStorage
2121
}
2222

23+
struct TestArray2 {
24+
var storage : TestArrayStorage
25+
var someValue : Int32
26+
var storage2 : TestArrayStorage
27+
}
28+
2329
// CHECK-LABEL: sil_global @static_array : $TestArrayStorage = {
2430
// CHECK: %initval = object $TestArrayStorage (%3 : $Int32, [tail_elems] %4 : $Int64, %5 : $Int64)
2531
// CHECK-NEXT: }
@@ -1620,6 +1626,14 @@ bb0(%0 : $Builtin.NativeObject):
16201626
return undef : $()
16211627
}
16221628

1629+
sil @test_destructure_value : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage) {
1630+
bb0(%0 : $(Builtin.NativeObject, Builtin.Int32), %1 : $TestArray2):
1631+
(%2, %3) = destructure_value %0 : $(Builtin.NativeObject, Builtin.Int32)
1632+
(%4, %5, %6) = destructure_value %1 : $TestArray2
1633+
%7 = tuple(%2 : $Builtin.NativeObject, %3 : $Builtin.Int32, %4 : $TestArrayStorage, %5 : $Int32, %6 : $TestArrayStorage)
1634+
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage)
1635+
}
1636+
16231637
// CHECK-LABEL: sil_vtable Foo {
16241638
// CHECK: #Foo.subscript!getter.1: {{.*}} : hidden _TFC3tmp3Foog9subscriptFTVs5Int32S1__S1_
16251639
// CHECK: #Foo.subscript!setter.1: {{.*}} : _TFC3tmp3Foos9subscriptFTVs5Int32S1__S1_

test/SIL/Serialization/basic.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,26 @@ bb0(%0 : $Builtin.NativeObject):
2222
end_lifetime %0 : $Builtin.NativeObject
2323
return undef : $()
2424
}
25+
26+
class TestArrayStorage {
27+
@sil_stored var count: Int32
28+
init()
29+
}
30+
31+
struct TestArray2 {
32+
var storage : TestArrayStorage
33+
var someValue : Int32
34+
var storage2 : TestArrayStorage
35+
}
36+
37+
struct Int32 {
38+
var x: Builtin.Int32
39+
}
40+
41+
sil @test_destructure_value : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage) {
42+
bb0(%0 : $(Builtin.NativeObject, Builtin.Int32), %1 : $TestArray2):
43+
(%2, %3) = destructure_value %0 : $(Builtin.NativeObject, Builtin.Int32)
44+
(%4, %5, %6) = destructure_value %1 : $TestArray2
45+
%7 = tuple(%2 : $Builtin.NativeObject, %3 : $Builtin.Int32, %4 : $TestArrayStorage, %5 : $Int32, %6 : $TestArrayStorage)
46+
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage)
47+
}

utils/sil-mode.el

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@
121121
"autorelease_value" "copy_value" "destroy_value"
122122
"unmanaged_retain_value" "unmanaged_release_value"
123123
"unmanaged_autorelease_value"
124-
"copy_unowned_value")
124+
"copy_unowned_value"
125+
"destructure_value")
125126
'words) . font-lock-keyword-face)
126127
;; Enums. *NOTE* We do not include enum itself here since enum is a
127128
;; swift declaration as well handled at the top.

0 commit comments

Comments
 (0)