Skip to content

Commit 7bddaf3

Browse files
committed
[SIL] Added tuple_pack_extract.
The new instruction is needed for opaque values mode to allow values to be extracted from tuples containing packs which will appear for example as function arguments.
1 parent 117a5ec commit 7bddaf3

22 files changed

+258
-10
lines changed

docs/SIL.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6403,6 +6403,23 @@ tuple_extract
64036403

64046404
Extracts an element from a loadable tuple value.
64056405

6406+
6407+
tuple_pack_extract
6408+
``````````````````
6409+
::
6410+
6411+
sil-instruction ::= 'tuple_pack_extract' sil-value 'of' sil-operand 'as' sil-type
6412+
6413+
%value = tuple_pack_extract %index of %tuple : $(repeat each T) as $@pack_element("01234567-89AB-CDEF-0123-000000000000") U
6414+
// %index must be of $Builtin.PackIndex type
6415+
// %tuple must be of tuple type
6416+
// %addr will be the result type specified by the 'as' clause
6417+
6418+
Extracts a value at a dynamic index from a tuple value.
6419+
6420+
Only valid in opaque values mode. Lowered by AddressLowering to
6421+
tuple_pack_element_addr. For more details, see that instruction.
6422+
64066423
tuple_element_addr
64076424
``````````````````
64086425
::

include/swift/SIL/InstWrappers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ class ForwardingOperation {
304304
bool canForwardGuaranteedCompatibleValuesOnly() {
305305
switch (forwardingInst->getKind()) {
306306
case SILInstructionKind::TupleExtractInst:
307+
case SILInstructionKind::TuplePackExtractInst:
307308
case SILInstructionKind::StructExtractInst:
308309
case SILInstructionKind::DifferentiableFunctionExtractInst:
309310
case SILInstructionKind::LinearFunctionExtractInst:

include/swift/SIL/SILBuilder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,6 +2150,16 @@ class SILBuilder {
21502150
packIndex, tupleAddr, elementType));
21512151
}
21522152

2153+
TuplePackExtractInst *createTuplePackExtract(SILLocation loc,
2154+
SILValue packIndex,
2155+
SILValue tuple,
2156+
SILType elementType) {
2157+
assert(!getFunction().getModule().useLoweredAddresses());
2158+
return insert(TuplePackExtractInst::create(
2159+
getFunction(), getSILDebugLocation(loc), packIndex, tuple, elementType,
2160+
tuple->getOwnershipKind()));
2161+
}
2162+
21532163
ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc,
21542164
SILValue Storage) {
21552165
auto CaptureTy = Storage->getType()

include/swift/SIL/SILCloner.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,27 @@ void SILCloner<ImplClass>::visitTuplePackElementAddrInst(
27802780
newElementType));
27812781
}
27822782

2783+
template <typename ImplClass>
2784+
void SILCloner<ImplClass>::visitTuplePackExtractInst(
2785+
TuplePackExtractInst *Inst) {
2786+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2787+
auto loc = getOpLocation(Inst->getLoc());
2788+
auto newIndex = getOpValue(Inst->getIndex());
2789+
auto newTuple = getOpValue(Inst->getTuple());
2790+
auto newElementType = getOpType(Inst->getElementType());
2791+
2792+
// If the tuple-ness of the operand disappears due to substitution,
2793+
// replace this instruction with an unchecked_value_cast.
2794+
if (doesOpTupleDisappear(Inst->getTupleType())) {
2795+
recordClonedInstruction(Inst, getBuilder().createUncheckedValueCast(
2796+
loc, newTuple, newElementType));
2797+
return;
2798+
}
2799+
2800+
recordClonedInstruction(Inst, getBuilder().createTuplePackExtract(
2801+
loc, newIndex, newTuple, newElementType));
2802+
}
2803+
27832804
template<typename ImplClass>
27842805
void
27852806
SILCloner<ImplClass>::visitCopyBlockInst(CopyBlockInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7805,6 +7805,45 @@ class TuplePackElementAddrInst final
78057805
}
78067806
};
78077807

7808+
/// Extracts a tuple element as appropriate for the given
7809+
/// pack element index. The pack index must index into a pack with
7810+
/// the same shape as the tuple element type list.
7811+
///
7812+
/// Legal only in opaque values mode. Transformed by AddressLowering to
7813+
/// TuplePackElementAddrInst.
7814+
class TuplePackExtractInst final
7815+
: public InstructionBaseWithTrailingOperands<
7816+
SILInstructionKind::TuplePackExtractInst, TuplePackExtractInst,
7817+
OwnershipForwardingSingleValueInstruction> {
7818+
public:
7819+
enum { IndexOperand = 0, TupleOperand = 1 };
7820+
7821+
private:
7822+
friend SILBuilder;
7823+
7824+
TuplePackExtractInst(SILDebugLocation debugLoc,
7825+
ArrayRef<SILValue> allOperands, SILType elementType,
7826+
ValueOwnershipKind forwardingOwnershipKind)
7827+
: InstructionBaseWithTrailingOperands(allOperands, debugLoc, elementType,
7828+
forwardingOwnershipKind) {}
7829+
7830+
static TuplePackExtractInst *
7831+
create(SILFunction &F, SILDebugLocation debugLoc, SILValue indexOperand,
7832+
SILValue tupleOperand, SILType elementType,
7833+
ValueOwnershipKind forwardingOwnershipKind);
7834+
7835+
public:
7836+
SILValue getIndex() const { return getAllOperands()[IndexOperand].get(); }
7837+
7838+
SILValue getTuple() const { return getAllOperands()[TupleOperand].get(); }
7839+
7840+
CanTupleType getTupleType() const {
7841+
return getTuple()->getType().castTo<TupleType>();
7842+
}
7843+
7844+
SILType getElementType() const { return getType(); }
7845+
};
7846+
78087847
/// Projects the capture storage address from a @block_storage address.
78097848
class ProjectBlockStorageInst
78107849
: public UnaryInstructionBase<SILInstructionKind::ProjectBlockStorageInst,
@@ -10543,6 +10582,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1054310582
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:
1054410583
case SILInstructionKind::MarkUninitializedInst:
1054510584
case SILInstructionKind::TupleExtractInst:
10585+
case SILInstructionKind::TuplePackExtractInst:
1054610586
case SILInstructionKind::StructExtractInst:
1054710587
case SILInstructionKind::DifferentiableFunctionExtractInst:
1054810588
case SILInstructionKind::LinearFunctionExtractInst:

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
588588
SingleValueInstruction, None, DoesNotRelease)
589589
SINGLE_VALUE_INST(TuplePackElementAddrInst, tuple_pack_element_addr,
590590
SingleValueInstruction, None, DoesNotRelease)
591+
SINGLE_VALUE_INST(TuplePackExtractInst, tuple_pack_extract,
592+
SingleValueInstruction, None, DoesNotRelease)
591593
SINGLE_VALUE_INST(PackElementGetInst, pack_element_get,
592594
SingleValueInstruction, None, DoesNotRelease)
593595
SINGLE_VALUE_INST(StructInst, struct,

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,7 @@ class IRGenSILFunction :
13601360
void visitPackElementGetInst(PackElementGetInst *i);
13611361
void visitPackElementSetInst(PackElementSetInst *i);
13621362
void visitTuplePackElementAddrInst(TuplePackElementAddrInst *i);
1363+
void visitTuplePackExtractInst(TuplePackExtractInst *i);
13631364

13641365
void visitProjectBlockStorageInst(ProjectBlockStorageInst *i);
13651366
void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *i);
@@ -7197,6 +7198,11 @@ void IRGenSILFunction::visitTuplePackElementAddrInst(
71977198
setLoweredAddress(i, elementAddr);
71987199
}
71997200

7201+
void IRGenSILFunction::visitTuplePackExtractInst(TuplePackExtractInst *i) {
7202+
llvm::report_fatal_error(
7203+
"tuple_pack_extract not lowered by AddressLowering!?");
7204+
}
7205+
72007206
void IRGenSILFunction::visitProjectBlockStorageInst(ProjectBlockStorageInst *i){
72017207
// TODO
72027208
Address block = getLoweredAddress(i->getOperand());

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ OPERAND_OWNERSHIP(PointerEscape, ExtractExecutor)
312312

313313
// Instructions that propagate a value within a borrow scope.
314314
OPERAND_OWNERSHIP(GuaranteedForwarding, TupleExtract)
315+
OPERAND_OWNERSHIP(GuaranteedForwarding, TuplePackExtract)
315316
OPERAND_OWNERSHIP(GuaranteedForwarding, StructExtract)
316317
OPERAND_OWNERSHIP(GuaranteedForwarding, DifferentiableFunctionExtract)
317318
OPERAND_OWNERSHIP(GuaranteedForwarding, LinearFunctionExtract)

lib/SIL/IR/SILInstructions.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,6 +2423,26 @@ TuplePackElementAddrInst::create(SILFunction &F,
24232423
elementType);
24242424
}
24252425

2426+
TuplePackExtractInst *
2427+
TuplePackExtractInst::create(SILFunction &F, SILDebugLocation debugLoc,
2428+
SILValue indexOperand, SILValue tupleOperand,
2429+
SILType elementType,
2430+
ValueOwnershipKind forwardingOwnershipKind) {
2431+
assert(indexOperand->getType().is<BuiltinPackIndexType>());
2432+
assert(tupleOperand->getType().isObject() &&
2433+
tupleOperand->getType().is<TupleType>());
2434+
2435+
SmallVector<SILValue, 8> allOperands;
2436+
allOperands.push_back(indexOperand);
2437+
allOperands.push_back(tupleOperand);
2438+
collectTypeDependentOperands(allOperands, F, elementType);
2439+
2440+
auto size = totalSizeToAlloc<swift::Operand>(allOperands.size());
2441+
auto buffer = F.getModule().allocateInst(size, alignof(TuplePackExtractInst));
2442+
return ::new (buffer) TuplePackExtractInst(debugLoc, allOperands, elementType,
2443+
forwardingOwnershipKind);
2444+
}
2445+
24262446
BeginCOWMutationInst::BeginCOWMutationInst(SILDebugLocation loc,
24272447
SILValue operand,
24282448
ArrayRef<SILType> resultTypes,

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,6 +2434,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
24342434
<< getIDAndType(I->getTuple()) << " as "
24352435
<< I->getElementType();
24362436
}
2437+
void visitTuplePackExtractInst(TuplePackExtractInst *I) {
2438+
*this << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getTuple())
2439+
<< " as " << I->getElementType();
2440+
}
24372441
void visitProjectBlockStorageInst(ProjectBlockStorageInst *PBSI) {
24382442
*this << getIDAndType(PBSI->getOperand());
24392443
}

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ CONSTANT_OWNERSHIP_INST(None, TuplePackElementAddr)
183183
}
184184
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, StructExtract)
185185
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, TupleExtract)
186+
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, TuplePackExtract)
186187
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, DifferentiableFunctionExtract)
187188
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, LinearFunctionExtract)
188189
// OpenExistentialValue opens the boxed value inside an existential

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,17 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
35943594
ResultVal = B.createTuplePackElementAddr(InstLoc, index, tuple, elementType);
35953595
break;
35963596
}
3597+
case SILInstructionKind::TuplePackExtractInst: {
3598+
SILValue index, tuple;
3599+
SILType elementType;
3600+
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc,
3601+
B) ||
3602+
parseVerbatim("of") || parseTypedValueRef(tuple, B) ||
3603+
parseVerbatim("as") || parseSILType(elementType))
3604+
return true;
3605+
ResultVal = B.createTuplePackExtract(InstLoc, index, tuple, elementType);
3606+
break;
3607+
}
35973608

35983609
#define UNARY_INSTRUCTION(ID) \
35993610
case SILInstructionKind::ID##Inst: \

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
588588
return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
589589
RuntimeEffect::MetaData;
590590

591+
case SILInstructionKind::TuplePackExtractInst:
591592
case SILInstructionKind::TuplePackElementAddrInst:
592593
return RuntimeEffect::MetaData;
593594

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5961,6 +5961,32 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
59615961
/*types are SIL types*/ true);
59625962
}
59635963

5964+
void checkTuplePackExtractInst(TuplePackExtractInst *i) {
5965+
require(!F.getModule().useLoweredAddresses(),
5966+
"tuple_pack_extract is only valid in opaque values");
5967+
auto index = requireValueKind<AnyPackIndexInst>(
5968+
i->getIndex(),
5969+
"pack index operand must be one of the pack_index instructions");
5970+
if (!index)
5971+
return;
5972+
5973+
// Remove the extra tuple element type structure.
5974+
SmallVector<CanType, 8> tupleElements;
5975+
{
5976+
auto tupleType = requireObjectType(TupleType, i->getTuple()->getType(),
5977+
"tuple operand of tuple_pack_extract");
5978+
auto eltTypes = tupleType.getElementTypes();
5979+
tupleElements.append(eltTypes.begin(), eltTypes.end());
5980+
}
5981+
5982+
require(i->getElementType().isObject(),
5983+
"result of tuple_pack_extract must be an object");
5984+
5985+
verifyPackElementType(tupleElements, index,
5986+
i->getElementType().getASTType(),
5987+
/*types are SIL types*/ true);
5988+
}
5989+
59645990
// This verifies that the entry block of a SIL function doesn't have
59655991
// any predecessors and also verifies the entry point arguments.
59665992
void verifyEntryBlock(SILBasicBlock *entry) {

lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context,
241241
case SILInstructionKind::ObjectInst:
242242
case SILInstructionKind::TupleInst:
243243
case SILInstructionKind::TupleExtractInst:
244+
case SILInstructionKind::TuplePackExtractInst:
244245
case SILInstructionKind::TupleElementAddrInst:
245246
case SILInstructionKind::StructInst:
246247
case SILInstructionKind::StructExtractInst:

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
896896
// tuple_pack_element_addr is just a GEP, but getting the offset
897897
// can require accessing metadata, so conservatively treat it as
898898
// expensive.
899+
case SILInstructionKind::TuplePackExtractInst:
899900
case SILInstructionKind::TuplePackElementAddrInst:
900901
return InlineCost::Expensive;
901902

lib/Serialization/DeserializeSIL.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
14941494
elementType);
14951495
break;
14961496
}
1497+
case SILInstructionKind::TuplePackExtractInst: {
1498+
assert(RecordKind == SIL_PACK_ELEMENT_GET);
1499+
auto elementType =
1500+
getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
1501+
auto tupleType =
1502+
getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn);
1503+
auto tuple = getLocalValue(ValID2, tupleType);
1504+
auto indexType = SILType::getPackIndexType(MF->getContext());
1505+
auto index = getLocalValue(ValID3, indexType);
1506+
ResultInst = Builder.createTuplePackExtract(Loc, index, tuple, elementType);
1507+
break;
1508+
}
14971509

14981510
#define ONEOPERAND_ONETYPE_INST(ID) \
14991511
case SILInstructionKind::ID##Inst: \

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 801; // removing builtin tuple conformances
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 802; // added tuple_pack_extract
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

lib/Serialization/SerializeSIL.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,15 +1710,27 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
17101710
auto tupleTypeRef = S.addTypeRef(tupleType.getRawASTType());
17111711
auto tupleRef = addValueRef(tuple);
17121712
auto indexRef = addValueRef(TPEAI->getIndex());
1713-
SILPackElementGetLayout::emitRecord(Out, ScratchRecord,
1714-
SILAbbrCodes[SILPackElementGetLayout::Code],
1715-
(unsigned)SI.getKind(),
1716-
elementTypeRef,
1717-
(unsigned) elementType.getCategory(),
1718-
tupleTypeRef,
1719-
(unsigned) tupleType.getCategory(),
1720-
tupleRef,
1721-
indexRef);
1713+
SILPackElementGetLayout::emitRecord(
1714+
Out, ScratchRecord, SILAbbrCodes[SILPackElementGetLayout::Code],
1715+
(unsigned)SI.getKind(), elementTypeRef,
1716+
(unsigned)elementType.getCategory(), tupleTypeRef,
1717+
(unsigned)tupleType.getCategory(), tupleRef, indexRef);
1718+
break;
1719+
}
1720+
case SILInstructionKind::TuplePackExtractInst: {
1721+
auto TPEI = cast<TuplePackExtractInst>(&SI);
1722+
auto elementType = TPEI->getElementType();
1723+
auto elementTypeRef = S.addTypeRef(elementType.getRawASTType());
1724+
auto tuple = TPEI->getTuple();
1725+
auto tupleType = tuple->getType();
1726+
auto tupleTypeRef = S.addTypeRef(tupleType.getRawASTType());
1727+
auto tupleRef = addValueRef(tuple);
1728+
auto indexRef = addValueRef(TPEI->getIndex());
1729+
SILPackElementGetLayout::emitRecord(
1730+
Out, ScratchRecord, SILAbbrCodes[SILPackElementGetLayout::Code],
1731+
(unsigned)SI.getKind(), elementTypeRef,
1732+
(unsigned)elementType.getCategory(), tupleTypeRef,
1733+
(unsigned)tupleType.getCategory(), tupleRef, indexRef);
17221734
break;
17231735
}
17241736
case SILInstructionKind::TailAddrInst: {

test/SIL/Parser/opaque_values_parse.sil

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ bb0(%instance : @guaranteed $WeakBox<T>):
115115
return %strong_optional : $Optional<T>
116116
}
117117

118+
// Test tuple_pack_extract parsing.
119+
120+
// CHECK-LABEL: sil [ossa] @test_tuple_pack_extract : {{.*}} {
121+
// CHECK: bb0([[TUPLE:%[^,]+]] :
122+
// CHECK: [[ZERO:%[^,]+]] = integer_literal
123+
// CHECK: [[INDEX:%[^,]+]] = dynamic_pack_index [[ZERO]]
124+
// CHECK: [[ELT:%[^,]+]] = tuple_pack_extract [[INDEX]] of [[TUPLE]]
125+
// CHECK-LABEL: } // end sil function 'test_tuple_pack_extract'
126+
sil [ossa] @test_tuple_pack_extract : $@convention(thin) <each T> (@in_guaranteed (repeat each T)) -> () {
127+
entry(%tuple : @guaranteed $(repeat each T)):
128+
%zero = integer_literal $Builtin.Word, 0
129+
%index = dynamic_pack_index %zero of $Pack{repeat each T}
130+
%opened = open_pack_element %index of <each U_1> at <Pack{repeat each T}>, shape $U_1, uuid "00000000-0000-0000-0000-000000000000"
131+
%elt = tuple_pack_extract %index of %tuple : $(repeat each T) as $@pack_element("00000000-0000-0000-0000-000000000000") U_1
132+
%retval = tuple ()
133+
return %retval : $()
134+
}
135+
118136
// Test weak_copy_value parsing.
119137

120138
// CHECK-LABEL: sil [ossa] @test_weak_copy_value_1 : {{.*}} {

0 commit comments

Comments
 (0)