Skip to content

Commit 69d7227

Browse files
committed
[sil] Add support for the destructure_{struct,tuple} instructions.
rdar://31521023
1 parent 6d7b176 commit 69d7227

File tree

21 files changed

+382
-28
lines changed

21 files changed

+382
-28
lines changed

docs/SIL.rst

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -784,8 +784,11 @@ Basic Blocks
784784
sil-label ::= sil-identifier ('(' sil-argument (',' sil-argument)* ')')? ':'
785785
sil-argument ::= sil-value-name ':' sil-type
786786

787-
sil-instruction-def ::= (sil-value-name '=')? sil-instruction
788-
(',' sil-loc)? (',' sil-scope-ref)?
787+
sil-instruction-result ::= sil-value-name
788+
sil-instruction-result ::= '(' (sil-value-name (',' sil-value-name)*)? ')'
789+
sil-instruction-source-info ::= (',' sil-scope-ref)? (',' sil-loc)?
790+
sil-instruction-def ::=
791+
(sil-instruction-result '=')? sil-instruction sil-instruction-source-info
789792

790793
A function body consists of one or more basic blocks that correspond
791794
to the nodes of the function's control flow graph. Each basic block
@@ -3506,6 +3509,19 @@ tuple_element_addr
35063509
Given the address of a tuple in memory, derives the
35073510
address of an element within that value.
35083511

3512+
destructure_tuple
3513+
`````````````````
3514+
3515+
::
3516+
3517+
sil-instruction ::= 'destructure_tuple' sil-operand
3518+
3519+
(%elt1, ..., %eltn) = destructure_tuple %0 : $(Elt1Ty, ..., EltNTy)
3520+
// %0 must be a tuple of type $(Elt1Ty, ..., EltNTy)
3521+
// %eltN must have the type $EltNTy
3522+
3523+
Given a tuple value, split the value into its constituent elements.
3524+
35093525
struct
35103526
``````
35113527
::
@@ -3547,6 +3563,19 @@ struct_element_addr
35473563
Given the address of a struct value in memory, derives the address of a
35483564
physical field within the value.
35493565

3566+
destructure_struct
3567+
``````````````````
3568+
3569+
::
3570+
3571+
sil-instruction ::= 'destructure_struct' sil-operand
3572+
3573+
(%elt1, ..., %eltn) = destructure_struct %0 : $S
3574+
// %0 must be a struct of type $S
3575+
// %eltN must have the same type as the Nth field of $S
3576+
3577+
Given a struct, split the struct into its constituant fields.
3578+
35503579
object
35513580
``````
35523581
::

include/swift/SIL/SILBuilder.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,18 @@ class SILBuilder {
11781178
Ref, ResultTy));
11791179
}
11801180

1181+
DestructureStructInst *createDestructureStruct(SILLocation Loc,
1182+
SILValue Operand) {
1183+
return insert(DestructureStructInst::create(
1184+
getModule(), getSILDebugLocation(Loc), Operand));
1185+
}
1186+
1187+
DestructureTupleInst *createDestructureTuple(SILLocation Loc,
1188+
SILValue Operand) {
1189+
return insert(DestructureTupleInst::create(
1190+
getModule(), getSILDebugLocation(Loc), Operand));
1191+
}
1192+
11811193
ClassMethodInst *createClassMethod(SILLocation Loc, SILValue Operand,
11821194
SILDeclRef Member, SILType MethodTy) {
11831195
return insert(new (getModule()) ClassMethodInst(

include/swift/SIL/SILCloner.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,9 +1518,28 @@ SILCloner<ImplClass>::visitRefTailAddrInst(RefTailAddrInst *Inst) {
15181518
getOpType(Inst->getType())));
15191519
}
15201520

1521-
template<typename ImplClass>
1522-
void
1523-
SILCloner<ImplClass>::visitClassMethodInst(ClassMethodInst *Inst) {
1521+
template <typename ImplClass>
1522+
void SILCloner<ImplClass>::visitDestructureStructInst(
1523+
DestructureStructInst *Inst) {
1524+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1525+
doPostProcess(
1526+
Inst,
1527+
getBuilder().createDestructureStruct(getOpLocation(Inst->getLoc()),
1528+
getOpValue(Inst->getOperand())));
1529+
}
1530+
1531+
template <typename ImplClass>
1532+
void SILCloner<ImplClass>::visitDestructureTupleInst(
1533+
DestructureTupleInst *Inst) {
1534+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1535+
doPostProcess(
1536+
Inst,
1537+
getBuilder().createDestructureTuple(getOpLocation(Inst->getLoc()),
1538+
getOpValue(Inst->getOperand())));
1539+
}
1540+
1541+
template <typename ImplClass>
1542+
void SILCloner<ImplClass>::visitClassMethodInst(ClassMethodInst *Inst) {
15241543
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
15251544
doPostProcess(Inst,
15261545
getBuilder().createClassMethod(getOpLocation(Inst->getLoc()),

include/swift/SIL/SILInstruction.h

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,9 @@ class MultipleValueInstructionResult : public ValueBase {
788788
static bool classof(const SILNode *node) {
789789
// This is an abstract class without anything implementing it right now, so
790790
// just return false. This will be fixed in a subsequent commit.
791-
return false;
791+
SILNodeKind kind = node->getKind();
792+
return kind >= SILNodeKind::First_MultipleValueInstructionResult &&
793+
kind <= SILNodeKind::Last_MultipleValueInstructionResult;
792794
}
793795

794796
protected:
@@ -830,9 +832,9 @@ class MultipleValueInstruction : public SILInstruction {
830832
unsigned getNumResults() const { return getResults().size(); }
831833

832834
static bool classof(const SILNode *node) {
833-
// This is an abstract class without anything implementing it right now, so
834-
// just return false. This will be fixed in a subsequent commit.
835-
return false;
835+
SILNodeKind kind = node->getKind();
836+
return kind >= SILNodeKind::First_MultipleValueInstruction &&
837+
kind <= SILNodeKind::Last_MultipleValueInstruction;
836838
}
837839
};
838840

@@ -7265,14 +7267,81 @@ SILFunction *ApplyInstBase<Impl, Base, false>::getCalleeFunction() const {
72657267
}
72667268
}
72677269

7268-
inline SILNode *MultipleValueInstructionResult::getCanonicalSILNodeInObject() {
7269-
return getParent();
7270-
}
7270+
/// A result for the destructure_struct instruction. See documentation for
7271+
/// destructure_struct for more information.
7272+
class DestructureStructResult final : public MultipleValueInstructionResult {
7273+
public:
7274+
DestructureStructResult(unsigned Index, SILType Type,
7275+
ValueOwnershipKind OwnershipKind)
7276+
: MultipleValueInstructionResult(ValueKind::DestructureStructResult,
7277+
Index, Type, OwnershipKind) {}
72717278

7272-
inline const SILNode *
7273-
MultipleValueInstructionResult::getCanonicalSILNodeInObject() const {
7274-
return getParent();
7275-
}
7279+
static bool classof(const SILNode *N) {
7280+
return N->getKind() == SILNodeKind::DestructureStructResult;
7281+
}
7282+
};
7283+
7284+
/// Instruction that takes in a struct value and splits the struct into the
7285+
/// struct's fields.
7286+
class DestructureStructInst final
7287+
: public UnaryInstructionBase<SILInstructionKind::DestructureStructInst,
7288+
MultipleValueInstruction>,
7289+
public MultipleValueInstructionTrailingObjects<
7290+
SILInstructionKind::DestructureStructInst, DestructureStructInst,
7291+
DestructureStructResult> {
7292+
friend TrailingObjects;
7293+
7294+
DestructureStructInst(SILModule &M, SILDebugLocation Loc, SILValue Operand,
7295+
ArrayRef<SILType> Types,
7296+
ArrayRef<ValueOwnershipKind> OwnershipKinds)
7297+
: UnaryInstructionBase(Loc, Operand),
7298+
MultipleValueInstructionTrailingObjects(this, Types, OwnershipKinds) {}
7299+
7300+
public:
7301+
static DestructureStructInst *create(SILModule &M, SILDebugLocation Loc,
7302+
SILValue Operand);
7303+
static bool classof(const SILNode *N) {
7304+
return N->getKind() == SILNodeKind::DestructureStructInst;
7305+
}
7306+
};
7307+
7308+
/// A result for the destructure_tuple instruction. See documentation for
7309+
/// destructure_tuple for more information.
7310+
class DestructureTupleResult final : public MultipleValueInstructionResult {
7311+
public:
7312+
DestructureTupleResult(unsigned Index, SILType Type,
7313+
ValueOwnershipKind OwnershipKind)
7314+
: MultipleValueInstructionResult(ValueKind::DestructureTupleResult, Index,
7315+
Type, OwnershipKind) {}
7316+
7317+
static bool classof(const SILNode *N) {
7318+
return N->getKind() == SILNodeKind::DestructureTupleResult;
7319+
}
7320+
};
7321+
7322+
/// Instruction that takes in a tuple value and splits the tuple into the
7323+
/// tuples's elements.
7324+
class DestructureTupleInst final
7325+
: public UnaryInstructionBase<SILInstructionKind::DestructureTupleInst,
7326+
MultipleValueInstruction>,
7327+
public MultipleValueInstructionTrailingObjects<
7328+
SILInstructionKind::DestructureTupleInst, DestructureTupleInst,
7329+
DestructureTupleResult> {
7330+
friend TrailingObjects;
7331+
7332+
DestructureTupleInst(SILModule &M, SILDebugLocation Loc, SILValue Operand,
7333+
ArrayRef<SILType> Types,
7334+
ArrayRef<ValueOwnershipKind> OwnershipKinds)
7335+
: UnaryInstructionBase(Loc, Operand),
7336+
MultipleValueInstructionTrailingObjects(this, Types, OwnershipKinds) {}
7337+
7338+
public:
7339+
static DestructureTupleInst *create(SILModule &M, SILDebugLocation Loc,
7340+
SILValue Operand);
7341+
static bool classof(const SILNode *N) {
7342+
return N->getKind() == SILNodeKind::DestructureTupleInst;
7343+
}
7344+
};
72767345

72777346
} // end swift namespace
72787347

include/swift/SIL/SILNodes.def

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,10 @@ ABSTRACT_VALUE(SILArgument, ValueBase)
214214
ARGUMENT(SILFunctionArgument, SILArgument)
215215
VALUE_RANGE(SILArgument, SILPHIArgument, SILFunctionArgument)
216216

217-
ABSTRACT_VALUE(MultipleValueResult, ValueBase)
217+
ABSTRACT_VALUE(MultipleValueInstructionResult, ValueBase)
218+
MULTIPLE_VALUE_INST_RESULT(DestructureStructResult, MultipleValueInstructionResult)
219+
MULTIPLE_VALUE_INST_RESULT(DestructureTupleResult, MultipleValueInstructionResult)
220+
VALUE_RANGE(MultipleValueInstructionResult, DestructureStructResult, DestructureTupleResult)
218221

219222
VALUE(SILUndef, ValueBase)
220223

@@ -633,8 +636,15 @@ NON_VALUE_INST(CondFailInst, cond_fail,
633636

634637
NODE_RANGE(NonValueInstruction, UnreachableInst, CondFailInst)
635638

636-
NODE_RANGE(SILInstruction, AllocStackInst, CondFailInst)
637-
NODE_RANGE(SILNode, SILPHIArgument, CondFailInst)
639+
ABSTRACT_INST(MultipleValueInstruction, SILInstruction)
640+
MULTIPLE_VALUE_INST(DestructureStructInst, destructure_struct,
641+
SILInstruction, None, DoesNotRelease)
642+
MULTIPLE_VALUE_INST(DestructureTupleInst, destructure_tuple,
643+
SILInstruction, None, DoesNotRelease)
644+
INST_RANGE(MultipleValueInstruction, DestructureStructInst, DestructureTupleInst)
645+
646+
NODE_RANGE(SILInstruction, AllocStackInst, DestructureTupleInst)
647+
NODE_RANGE(SILNode, SILPHIArgument, DestructureTupleInst)
638648

639649
#undef SINGLE_VALUE_INST_RANGE
640650
#undef INST_RANGE

include/swift/SIL/SILValue.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ struct ValueOwnershipKind {
138138
bool isTrivialOr(ValueOwnershipKind Kind) const {
139139
return Value == Trivial || Value == Kind;
140140
}
141+
142+
/// Given that there is an aggregate value (like a struct or enum) with this
143+
/// ownership kind, and a subobject of type Proj is being projected from the
144+
/// aggregate, return Trivial if Proj has trivial type and the aggregate's
145+
/// ownership kind otherwise.
146+
ValueOwnershipKind getProjectedOwnershipKind(SILModule &M,
147+
SILType Proj) const;
141148
};
142149

143150
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 = 372; // Last change: VTable serialized
57+
const uint16_t VERSION_MINOR = 373; // Last change: destructure
5858

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

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,12 @@ class IRGenSILFunction :
884884
void visitValueMetatypeInst(ValueMetatypeInst *i);
885885
void visitExistentialMetatypeInst(ExistentialMetatypeInst *i);
886886
void visitTupleExtractInst(TupleExtractInst *i);
887+
void visitDestructureTupleInst(DestructureTupleInst *i) {
888+
llvm_unreachable("unimplemented");
889+
}
890+
void visitDestructureStructInst(DestructureStructInst *i) {
891+
llvm_unreachable("unimplemented");
892+
}
887893
void visitTupleElementAddrInst(TupleElementAddrInst *i);
888894
void visitStructExtractInst(StructExtractInst *i);
889895
void visitStructElementAddrInst(StructElementAddrInst *i);

lib/ParseSIL/ParseSIL.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
23152315
UNARY_INSTRUCTION(DestroyValue)
23162316
UNARY_INSTRUCTION(CondFail)
23172317
UNARY_INSTRUCTION(EndBorrowArgument)
2318+
UNARY_INSTRUCTION(DestructureStruct)
2319+
UNARY_INSTRUCTION(DestructureTuple)
23182320
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
23192321
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
23202322
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)

lib/SIL/SILInstructions.cpp

Lines changed: 70 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,69 @@ GenericSpecializationInformation::create(SILInstruction *Inst, SILBuilder &B) {
23262327

23272328
return nullptr;
23282329
}
2330+
2331+
static void computeAggregateFirstLevelSubtypeInfo(
2332+
SILModule &M, SILValue Operand, llvm::SmallVectorImpl<SILType> &Types,
2333+
llvm::SmallVectorImpl<ValueOwnershipKind> &OwnershipKinds) {
2334+
SILType OpType = Operand->getType();
2335+
2336+
// TODO: Create an iterator for accessing first level projections to eliminate
2337+
// this SmallVector.
2338+
llvm::SmallVector<Projection, 8> Projections;
2339+
Projection::getFirstLevelProjections(OpType, M, Projections);
2340+
2341+
auto OpOwnershipKind = Operand.getOwnershipKind();
2342+
for (auto &P : Projections) {
2343+
SILType ProjType = P.getType(OpType, M);
2344+
Types.emplace_back(ProjType);
2345+
OwnershipKinds.emplace_back(
2346+
OpOwnershipKind.getProjectedOwnershipKind(M, ProjType));
2347+
}
2348+
}
2349+
2350+
DestructureStructInst *DestructureStructInst::create(SILModule &M,
2351+
SILDebugLocation Loc,
2352+
SILValue Operand) {
2353+
assert(Operand->getType().getStructOrBoundGenericStruct() &&
2354+
"Expected a struct typed operand?!");
2355+
2356+
llvm::SmallVector<SILType, 8> Types;
2357+
llvm::SmallVector<ValueOwnershipKind, 8> OwnershipKinds;
2358+
computeAggregateFirstLevelSubtypeInfo(M, Operand, Types, OwnershipKinds);
2359+
assert(Types.size() == OwnershipKinds.size() &&
2360+
"Expected same number of Types and OwnerKinds");
2361+
2362+
unsigned NumElts = Types.size();
2363+
unsigned Size =
2364+
totalSizeToAlloc<MultipleValueInstruction *, DestructureStructResult>(
2365+
1, NumElts);
2366+
2367+
void *Buffer = M.allocateInst(Size, alignof(DestructureStructInst));
2368+
2369+
return ::new (Buffer)
2370+
DestructureStructInst(M, Loc, Operand, Types, OwnershipKinds);
2371+
}
2372+
2373+
DestructureTupleInst *DestructureTupleInst::create(SILModule &M,
2374+
SILDebugLocation Loc,
2375+
SILValue Operand) {
2376+
assert(Operand->getType().getSwiftRValueType()->is<TupleType>() &&
2377+
"Expected a tuple typed operand?!");
2378+
2379+
llvm::SmallVector<SILType, 8> Types;
2380+
llvm::SmallVector<ValueOwnershipKind, 8> OwnershipKinds;
2381+
computeAggregateFirstLevelSubtypeInfo(M, Operand, Types, OwnershipKinds);
2382+
assert(Types.size() == OwnershipKinds.size() &&
2383+
"Expected same number of Types and OwnerKinds");
2384+
2385+
// We add 1 since we store an offset to our
2386+
unsigned NumElts = Types.size();
2387+
unsigned Size =
2388+
totalSizeToAlloc<MultipleValueInstruction *, DestructureTupleResult>(
2389+
1, NumElts);
2390+
2391+
void *Buffer = M.allocateInst(Size, alignof(DestructureTupleInst));
2392+
2393+
return ::new (Buffer)
2394+
DestructureTupleInst(M, Loc, Operand, Types, OwnershipKinds);
2395+
}

0 commit comments

Comments
 (0)