Skip to content

Commit 8cab09e

Browse files
Merge pull request #67966 from nate-chandler/opaque-values/20230816/1/indirect-pack-tuple-handling
[AddressLowering] Handle indexing into variadic tuples.
2 parents 48695c6 + 84ab0eb commit 8cab09e

24 files changed

+303
-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
@@ -1355,6 +1355,7 @@ class IRGenSILFunction :
13551355
void visitPackElementGetInst(PackElementGetInst *i);
13561356
void visitPackElementSetInst(PackElementSetInst *i);
13571357
void visitTuplePackElementAddrInst(TuplePackElementAddrInst *i);
1358+
void visitTuplePackExtractInst(TuplePackExtractInst *i);
13581359

13591360
void visitProjectBlockStorageInst(ProjectBlockStorageInst *i);
13601361
void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *i);
@@ -7192,6 +7193,11 @@ void IRGenSILFunction::visitTuplePackElementAddrInst(
71927193
setLoweredAddress(i, elementAddr);
71937194
}
71947195

7196+
void IRGenSILFunction::visitTuplePackExtractInst(TuplePackExtractInst *i) {
7197+
llvm::report_fatal_error(
7198+
"tuple_pack_extract not lowered by AddressLowering!?");
7199+
}
7200+
71957201
void IRGenSILFunction::visitProjectBlockStorageInst(ProjectBlockStorageInst *i){
71967202
// TODO
71977203
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
@@ -2431,6 +2431,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
24312431
<< getIDAndType(I->getTuple()) << " as "
24322432
<< I->getElementType();
24332433
}
2434+
void visitTuplePackExtractInst(TuplePackExtractInst *I) {
2435+
*this << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getTuple())
2436+
<< " as " << I->getElementType();
2437+
}
24342438
void visitProjectBlockStorageInst(ProjectBlockStorageInst *PBSI) {
24352439
*this << getIDAndType(PBSI->getOperand());
24362440
}

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
@@ -3591,6 +3591,17 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
35913591
ResultVal = B.createTuplePackElementAddr(InstLoc, index, tuple, elementType);
35923592
break;
35933593
}
3594+
case SILInstructionKind::TuplePackExtractInst: {
3595+
SILValue index, tuple;
3596+
SILType elementType;
3597+
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc,
3598+
B) ||
3599+
parseVerbatim("of") || parseTypedValueRef(tuple, B) ||
3600+
parseVerbatim("as") || parseSILType(elementType))
3601+
return true;
3602+
ResultVal = B.createTuplePackExtract(InstLoc, index, tuple, elementType);
3603+
break;
3604+
}
35943605

35953606
#define UNARY_INSTRUCTION(ID) \
35963607
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/Mandatory/AddressLowering.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,9 @@ static Operand *getProjectedDefOperand(SILValue value) {
974974
case ValueKind::OpenExistentialBoxValueInst:
975975
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
976976
return &cast<SingleValueInstruction>(value)->getAllOperands()[0];
977+
case ValueKind::TuplePackExtractInst:
978+
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
979+
return &cast<SingleValueInstruction>(value)->getAllOperands()[1];
977980
}
978981
}
979982

@@ -1703,6 +1706,8 @@ class AddressMaterialization {
17031706

17041707
SILValue materializeTupleExtract(SILInstruction *extractInst,
17051708
SILValue elementValue, unsigned fieldIdx);
1709+
SILValue materializeTuplePackExtract(SILInstruction *extractInst,
1710+
SILValue elementValue, SILValue index);
17061711

17071712
SILValue materializeProjectionIntoUse(Operand *operand, bool intoPhiOperand);
17081713
SILValue materializeProjectionIntoUseImpl(Operand *operand,
@@ -1859,6 +1864,11 @@ SILValue AddressMaterialization::materializeDefProjection(SILValue origValue) {
18591864
return materializeTupleExtract(extractInst, origValue,
18601865
extractInst->getFieldIndex());
18611866
}
1867+
case ValueKind::TuplePackExtractInst: {
1868+
auto *extractInst = cast<TuplePackExtractInst>(origValue);
1869+
return materializeTuplePackExtract(extractInst, origValue,
1870+
extractInst->getIndex());
1871+
}
18621872
case ValueKind::SILPhiArgument: {
18631873
// Handle this in the caller. unchecked_take_enum_data_addr is
18641874
// destructive. It cannot be materialized on demand.
@@ -1888,6 +1898,14 @@ SILValue AddressMaterialization::materializeTupleExtract(
18881898
elementValue->getType().getAddressType());
18891899
}
18901900

1901+
SILValue AddressMaterialization::materializeTuplePackExtract(
1902+
SILInstruction *extractInst, SILValue elementValue, SILValue fieldIdx) {
1903+
SILValue srcAddr = pass.getMaterializedAddress(extractInst->getOperand(1));
1904+
return projectionBuilder.createTuplePackElementAddr(
1905+
pass.genLoc(), fieldIdx, srcAddr,
1906+
elementValue->getType().getAddressType());
1907+
}
1908+
18911909
SILValue
18921910
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
18931911
bool intoPhiOperand) {
@@ -3528,6 +3546,9 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
35283546
// Extract from an opaque tuple.
35293547
void visitTupleExtractInst(TupleExtractInst *extractInst);
35303548

3549+
// Extract from an opaque pack tuple.
3550+
void visitTuplePackExtractInst(TuplePackExtractInst *extractInst);
3551+
35313552
void
35323553
visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *uncheckedCastInst) {
35333554
SILValue srcVal = uncheckedCastInst->getOperand();
@@ -3819,6 +3840,10 @@ void UseRewriter::visitTupleExtractInst(TupleExtractInst *extractInst) {
38193840
emitExtract(extractInst);
38203841
}
38213842

3843+
void UseRewriter::visitTuplePackExtractInst(TuplePackExtractInst *extractInst) {
3844+
emitExtract(extractInst);
3845+
}
3846+
38223847
// Rewrite switch_enum to switch_enum_addr. All associated block arguments are
38233848
// removed.
38243849
void UseRewriter::visitSwitchEnumInst(SwitchEnumInst * switchEnum) {

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
///

0 commit comments

Comments
 (0)