Skip to content

Add the tuple_pack_element_addr SIL instruction #63512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1991,6 +1991,14 @@ class SILBuilder {
elementValue, packIndex, pack));
}

TuplePackElementAddrInst *
createTuplePackElementAddr(SILLocation loc, SILValue packIndex,
SILValue tupleAddr, SILType elementType) {
return insert(TuplePackElementAddrInst::create(getFunction(),
getSILDebugLocation(loc),
packIndex, tupleAddr, elementType));
}

ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc,
SILValue Storage) {
auto CaptureTy = Storage->getType()
Expand Down
15 changes: 15 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2539,6 +2539,21 @@ void SILCloner<ImplClass>::visitPackElementSetInst(PackElementSetInst *Inst) {
newIndex, newPack));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitTuplePackElementAddrInst(
TuplePackElementAddrInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
auto loc = getOpLocation(Inst->getLoc());
auto newIndex = getOpValue(Inst->getIndex());
auto newTuple = getOpValue(Inst->getTuple());
auto newElementType = getOpType(Inst->getElementType());
// FIXME: do we need to rewrite when substitution removes the
// tuple-ness of the type? If so, what do we rewrite to?
recordClonedInstruction(
Inst, getBuilder().createTuplePackElementAddr(loc, newIndex, newTuple,
newElementType));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitCopyBlockInst(CopyBlockInst *Inst) {
Expand Down
47 changes: 47 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -7747,6 +7747,53 @@ class PackElementSetInst
}
};

/// Projects a tuple element as appropriate for the given
/// pack element index. The pack index must index into a pack with
/// the same shape as the tuple element type list.
class TuplePackElementAddrInst final
: public InstructionBaseWithTrailingOperands<
SILInstructionKind::TuplePackElementAddrInst,
TuplePackElementAddrInst,
SingleValueInstruction> {
public:
enum {
IndexOperand = 0,
TupleOperand = 1
};

private:
friend SILBuilder;

TuplePackElementAddrInst(SILDebugLocation debugLoc,
ArrayRef<SILValue> allOperands,
SILType elementType)
: InstructionBaseWithTrailingOperands(allOperands, debugLoc,
elementType) {}

static TuplePackElementAddrInst *create(SILFunction &F,
SILDebugLocation debugLoc,
SILValue indexOperand,
SILValue tupleOperand,
SILType elementType);

public:
SILValue getIndex() const {
return getAllOperands()[IndexOperand].get();
}

SILValue getTuple() const {
return getAllOperands()[TupleOperand].get();
}

CanTupleType getTupleType() const {
return getTuple()->getType().castTo<TupleType>();
}

SILType getElementType() const {
return getType();
}
};

/// Projects the capture storage address from a @block_storage address.
class ProjectBlockStorageInst
: public UnaryInstructionBase<SILInstructionKind::ProjectBlockStorageInst,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(TupleElementAddrInst, tuple_element_addr,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(TuplePackElementAddrInst, tuple_pack_element_addr,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(PackElementGetInst, pack_element_get,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(StructInst, struct,
Expand Down
15 changes: 15 additions & 0 deletions lib/IRGen/GenTuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,21 @@ Address irgen::projectTupleElementAddress(IRGenFunction &IGF,
tupleType, fieldNo);
}

Address irgen::projectTupleElementAddressByDynamicIndex(IRGenFunction &IGF,
Address tuple,
SILType tupleType,
llvm::Value *index,
SILType elementType) {
// TODO: retrieve type metadata (ForLayout) for the tuple type
// and retrieve the field offset for the given index. Consider
// special-casing constant indices if we can reason statically
// about the prior elements. It's probably not necessary to try
// to handle fixed-size tuples specially, because the optimizer
// should ideally be lowering this operation to something static
// in that case.
llvm_unreachable("unimplemented");
}

Optional<Size> irgen::getFixedTupleElementOffset(IRGenModule &IGM,
SILType tupleType,
unsigned fieldNo) {
Expand Down
11 changes: 11 additions & 0 deletions lib/IRGen/GenTuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

#include "swift/Basic/LLVM.h"

namespace llvm {
class Value;
}

namespace swift {
class CanType;

Expand All @@ -34,6 +38,13 @@ namespace irgen {
SILType tupleType,
unsigned fieldNo);

/// Project the address of a tuple element, given a dynamic index.
Address projectTupleElementAddressByDynamicIndex(IRGenFunction &IGF,
Address base,
SILType tupleType,
llvm::Value *index,
SILType elementType);

/// Project a tuple element rvalue from an already-exploded tuple rvalue.
void projectTupleElementFromExplosion(IRGenFunction &IGF,
SILType tupleType,
Expand Down
14 changes: 14 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,7 @@ class IRGenSILFunction :
void visitScalarPackIndexInst(ScalarPackIndexInst *i);
void visitPackElementGetInst(PackElementGetInst *i);
void visitPackElementSetInst(PackElementSetInst *i);
void visitTuplePackElementAddrInst(TuplePackElementAddrInst *i);

void visitProjectBlockStorageInst(ProjectBlockStorageInst *i);
void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *i);
Expand Down Expand Up @@ -6920,6 +6921,19 @@ void IRGenSILFunction::visitPackElementSetInst(PackElementSetInst *i) {
Builder.CreateStore(elementValue.getAddress(), elementStorageAddress);
}

void IRGenSILFunction::visitTuplePackElementAddrInst(
TuplePackElementAddrInst *i) {
Address tuple = getLoweredAddress(i->getTuple());
llvm::Value *index = getLoweredSingletonExplosion(i->getIndex());

auto elementType = i->getElementType();
auto elementAddr =
projectTupleElementAddressByDynamicIndex(*this, tuple,
i->getTuple()->getType(),
index, elementType);
setLoweredAddress(i, elementAddr);
}

void IRGenSILFunction::visitProjectBlockStorageInst(ProjectBlockStorageInst *i){
// TODO
Address block = getLoweredAddress(i->getOperand());
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ OPERAND_OWNERSHIP(TrivialUse, DynamicPackIndex)
OPERAND_OWNERSHIP(TrivialUse, PackPackIndex)
OPERAND_OWNERSHIP(TrivialUse, PackElementGet)
OPERAND_OWNERSHIP(TrivialUse, PackElementSet)
OPERAND_OWNERSHIP(TrivialUse, TuplePackElementAddr)

// The dealloc_stack_ref operand needs to have NonUse ownership because
// this use comes after the last consuming use (which is usually a dealloc_ref).
Expand Down
22 changes: 22 additions & 0 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2400,6 +2400,28 @@ PackElementGetInst *PackElementGetInst::create(SILFunction &F,
return ::new (buffer) PackElementGetInst(debugLoc, allOperands, elementType);
}

TuplePackElementAddrInst *
TuplePackElementAddrInst::create(SILFunction &F,
SILDebugLocation debugLoc,
SILValue indexOperand,
SILValue tupleOperand,
SILType elementType) {
assert(indexOperand->getType().is<BuiltinPackIndexType>());
assert(tupleOperand->getType().isAddress() &&
tupleOperand->getType().is<TupleType>());

SmallVector<SILValue, 8> allOperands;
allOperands.push_back(indexOperand);
allOperands.push_back(tupleOperand);
collectTypeDependentOperands(allOperands, F, elementType);

auto size = totalSizeToAlloc<swift::Operand>(allOperands.size());
auto buffer =
F.getModule().allocateInst(size, alignof(TuplePackElementAddrInst));
return ::new (buffer) TuplePackElementAddrInst(debugLoc, allOperands,
elementType);
}

BeginCOWMutationInst::BeginCOWMutationInst(SILDebugLocation loc,
SILValue operand,
ArrayRef<SILType> resultTypes,
Expand Down
5 changes: 5 additions & 0 deletions lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,11 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
<< Ctx.getID(I->getIndex()) << " of "
<< getIDAndType(I->getPack());
}
void visitTuplePackElementAddrInst(TuplePackElementAddrInst *I) {
*this << Ctx.getID(I->getIndex()) << " of "
<< getIDAndType(I->getTuple()) << " as "
<< I->getElementType();
}
void visitProjectBlockStorageInst(ProjectBlockStorageInst *PBSI) {
*this << getIDAndType(PBSI->getOperand());
}
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/ValueOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ CONSTANT_OWNERSHIP_INST(None, DynamicPackIndex)
CONSTANT_OWNERSHIP_INST(None, PackPackIndex)
CONSTANT_OWNERSHIP_INST(None, ScalarPackIndex)
CONSTANT_OWNERSHIP_INST(None, PackElementGet)
CONSTANT_OWNERSHIP_INST(None, TuplePackElementAddr)

#undef CONSTANT_OWNERSHIP_INST

Expand Down
12 changes: 12 additions & 0 deletions lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3453,6 +3453,18 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
ResultVal = B.createPackElementSet(InstLoc, value, index, pack);
break;
}
case SILInstructionKind::TuplePackElementAddrInst: {
SILValue index, tuple;
SILType elementType;
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc, B) ||
parseVerbatim("of") ||
parseTypedValueRef(tuple, B) ||
parseVerbatim("as") ||
parseSILType(elementType))
return true;
ResultVal = B.createTuplePackElementAddr(InstLoc, index, tuple, elementType);
break;
}

#define UNARY_INSTRUCTION(ID) \
case SILInstructionKind::ID##Inst: \
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/Utils/InstructionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
RuntimeEffect::MetaData;

case SILInstructionKind::TuplePackElementAddrInst:
return RuntimeEffect::MetaData;

case SILInstructionKind::SwitchEnumAddrInst:
case SILInstructionKind::InjectEnumAddrInst:
case SILInstructionKind::TupleElementAddrInst:
Expand Down
21 changes: 21 additions & 0 deletions lib/SIL/Verifier/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5721,6 +5721,27 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
verifyPackElementType(i->getPackType(), index, i->getElementType());
}

void checkTuplePackElementAddrInst(TuplePackElementAddrInst *i) {
auto index = requireValueKind<AnyPackIndexInst>(i->getIndex(),
"pack index operand must be one of the pack_index instructions");
if (!index) return;

// Remove the extra tuple element type structure.
SmallVector<CanType, 8> tupleElements; {
auto tupleType = requireAddressType(TupleType, i->getTuple()->getType(),
"tuple operand of tuple_pack_element_addr");
auto eltTypes = tupleType.getElementTypes();
tupleElements.append(eltTypes.begin(), eltTypes.end());
}

require(i->getElementType().isAddress(),
"result of tuple_pack_element_addr must be an address");

verifyPackElementType(tupleElements, index,
i->getElementType().getASTType(),
/*types are SIL types*/ true);
}

// This verifies that the entry block of a SIL function doesn't have
// any predecessors and also verifies the entry point arguments.
void verifyEntryBlock(SILBasicBlock *entry) {
Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context,
case SILInstructionKind::HasSymbolInst:
case SILInstructionKind::PackElementGetInst:
case SILInstructionKind::PackElementSetInst:
case SILInstructionKind::TuplePackElementAddrInst:
// Handle by operand and result check.
break;

Expand Down
6 changes: 6 additions & 0 deletions lib/SILOptimizer/Utils/SILInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,12 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
case SILInstructionKind::ProjectBlockStorageInst:
return InlineCost::Free;

// tuple_pack_element_addr is just a GEP, but getting the offset
// can require accessing metadata, so conservatively treat it as
// expensive.
case SILInstructionKind::TuplePackElementAddrInst:
return InlineCost::Expensive;

// dynamic_pack_index is free. The other pack-indexing instructions
// are just adds of values that should be trivially dynamically
// available; that's cheap enough to still consider free under the
Expand Down
13 changes: 13 additions & 0 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,19 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
ResultInst = Builder.createPackElementSet(Loc, value, index, pack);
break;
}
case SILInstructionKind::TuplePackElementAddrInst: {
assert(RecordKind == SIL_PACK_ELEMENT_GET);
auto elementType = getSILType(MF->getType(TyID),
(SILValueCategory) TyCategory, Fn);
auto tupleType = getSILType(MF->getType(TyID2),
(SILValueCategory) TyCategory2, Fn);
auto tuple = getLocalValue(ValID2, tupleType);
auto indexType = SILType::getPackIndexType(MF->getContext());
auto index = getLocalValue(ValID3, indexType);
ResultInst = Builder.createTuplePackElementAddr(Loc, index, tuple,
elementType);
break;
}

#define ONEOPERAND_ONETYPE_INST(ID) \
case SILInstructionKind::ID##Inst: \
Expand Down
6 changes: 3 additions & 3 deletions lib/Serialization/SILFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ namespace sil_block {
SIL_MOVEONLY_DEINIT,
SIL_INST_HAS_SYMBOL,
SIL_PACK_ELEMENT_GET,
SIL_PACK_ELEMENT_SET,
SIL_PACK_ELEMENT_SET,
};

using SILInstNoOperandLayout = BCRecordLayout<
Expand Down Expand Up @@ -474,7 +474,7 @@ namespace sil_block {
SILTypeCategoryField, // element type category
TypeIDField, // pack type
SILTypeCategoryField, // pack type category
ValueIDField, // pack value
ValueIDField, // pack value
ValueIDField // index value
>;

Expand All @@ -486,7 +486,7 @@ namespace sil_block {
ValueIDField, // element value
TypeIDField, // pack type
SILTypeCategoryField, // pack type category
ValueIDField, // pack value
ValueIDField, // pack value
ValueIDField // index value
>;

Expand Down
19 changes: 19 additions & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,25 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
indexRef);
break;
}
case SILInstructionKind::TuplePackElementAddrInst: {
auto TPEAI = cast<TuplePackElementAddrInst>(&SI);
auto elementType = TPEAI->getElementType();
auto elementTypeRef = S.addTypeRef(elementType.getASTType());
auto tuple = TPEAI->getTuple();
auto tupleType = tuple->getType();
auto tupleTypeRef = S.addTypeRef(tupleType.getASTType());
auto tupleRef = addValueRef(tuple);
auto indexRef = addValueRef(TPEAI->getIndex());
SILPackElementGetLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILPackElementGetLayout::Code],
elementTypeRef,
(unsigned) elementType.getCategory(),
tupleTypeRef,
(unsigned) tupleType.getCategory(),
tupleRef,
indexRef);
break;
}
case SILInstructionKind::TailAddrInst: {
const TailAddrInst *TAI = cast<TailAddrInst>(&SI);
SILTailAddrLayout::emitRecord(Out, ScratchRecord,
Expand Down
12 changes: 12 additions & 0 deletions test/SIL/Parser/variadic_generics.sil
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,15 @@ bb0(%i : $Builtin.Word):
%ret = tuple ()
return %ret : $()
}

// CHECK-LABEL: sil @test6
// CHECK: [[INDEX:%.*]] = dynamic_pack_index
// CHECK: tuple_pack_element_addr [[INDEX]] of %0 : $*(String, repeat each T, Int) as $*@pack_element("01234567-89AB-CDEF-0123-000000000004") U
sil @test6 : $<T...> (@inout (String, repeat each T, Int), Builtin.Word) -> () {
bb0(%tuple : $*(String, repeat each T, Int), %i : $Builtin.Word):
%index = dynamic_pack_index %i of $Pack{Float, repeat each T, Float}
%0 = open_pack_element %index of <U...> at <Pack{String, repeat each T, Int}>, shape $U, uuid "01234567-89AB-CDEF-0123-000000000004"
%elt = tuple_pack_element_addr %index of %tuple : $*(String, repeat each T, Int) as $*@pack_element("01234567-89AB-CDEF-0123-000000000004") U
%ret = tuple ()
return %ret : $()
}