Skip to content

IRGen: Fulfill pack metadata from tuple metadata #68130

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 3 commits into from
Aug 25, 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
22 changes: 11 additions & 11 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5937,6 +5937,14 @@ class VarDecl : public AbstractStorageDecl {
Bits.VarDecl.IsDebuggerVar = IsDebuggerVar;
}

/// Visit all auxiliary declarations to this VarDecl.
///
/// An auxiliary declaration is a declaration synthesized by the compiler to support
/// this VarDecl, such as synthesized property wrapper variables.
///
/// \note this function only visits auxiliary decls that are not part of the AST.
void visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)>) const;

/// Is this the synthesized storage for a 'lazy' property?
bool isLazyStorageProperty() const {
return Bits.VarDecl.IsLazyStorageProperty;
Expand All @@ -5945,6 +5953,9 @@ class VarDecl : public AbstractStorageDecl {
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
}

/// Retrieve the backing storage property for a lazy property.
VarDecl *getLazyStorageProperty() const;

/// True if this is a top-level global variable from the main source file.
bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; }
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
Expand Down Expand Up @@ -6052,17 +6063,6 @@ class VarDecl : public AbstractStorageDecl {
/// wrapper that has storage.
bool hasStorageOrWrapsStorage() const;

/// Visit all auxiliary declarations to this VarDecl.
///
/// An auxiliary declaration is a declaration synthesized by the compiler to support
/// this VarDecl, such as synthesized property wrapper variables.
///
/// \note this function only visits auxiliary decls that are not part of the AST.
void visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)>) const;

/// Retrieve the backing storage property for a lazy property.
VarDecl *getLazyStorageProperty() const;

/// Whether the memberwise initializer parameter for a property with a
/// property wrapper type uses the wrapped type. This will occur, for example,
/// when there is an explicitly-specified initializer like:
Expand Down
28 changes: 27 additions & 1 deletion lib/IRGen/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,33 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
source, std::move(path), keys);
}

// TODO: tuples
if (auto tupleType = dyn_cast<TupleType>(type)) {
if (tupleType->getNumElements() == 1 &&
isa<PackExpansionType>(tupleType.getElementType(0))) {

bool hadFulfillment = false;
auto packType = tupleType.getInducedPackType();

{
auto argPath = path;
argPath.addTuplePackComponent();
hadFulfillment |= searchTypeMetadataPack(IGM, packType,
isExact, metadataState, source,
std::move(argPath), keys);
}

{
auto argPath = path;
argPath.addTupleShapeComponent();
hadFulfillment |= searchShapeRequirement(IGM, packType, source,
std::move(argPath));

}

return hadFulfillment;
}
}

// TODO: functions
// TODO: metatypes

Expand Down
55 changes: 49 additions & 6 deletions lib/IRGen/GenPack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ static llvm::Value *emitPackExpansionElementMetadata(
/// dynamicLength) produced by the provided function \p elementForIndex into
/// the indicated buffer \p pack.
static void emitPackExpansionPack(
IRGenFunction &IGF, Address pack, CanPackExpansionType expansionTy,
IRGenFunction &IGF, Address pack,
llvm::Value *dynamicIndex, llvm::Value *dynamicLength,
function_ref<llvm::Value *(llvm::Value *)> elementForIndex) {
auto *prev = IGF.Builder.GetInsertBlock();
Expand Down Expand Up @@ -442,7 +442,7 @@ static void emitPackExpansionMetadataPack(IRGenFunction &IGF, Address pack,
llvm::Value *dynamicLength,
DynamicMetadataRequest request) {
emitPackExpansionPack(
IGF, pack, expansionTy, dynamicIndex, dynamicLength, [&](auto *index) {
IGF, pack, dynamicIndex, dynamicLength, [&](auto *index) {
auto context =
OpenedElementContext::createForContextualExpansion(IGF.IGM.Context, expansionTy);
auto patternTy = expansionTy.getPatternType();
Expand Down Expand Up @@ -587,7 +587,7 @@ static void emitPackExpansionWitnessTablePack(
ProtocolConformanceRef conformance, llvm::Value *dynamicIndex,
llvm::Value *dynamicLength) {
emitPackExpansionPack(
IGF, pack, expansionTy, dynamicIndex, dynamicLength, [&](auto *index) {
IGF, pack, dynamicIndex, dynamicLength, [&](auto *index) {
llvm::Value *_metadata = nullptr;
auto context =
OpenedElementContext::createForContextualExpansion(IGF.IGM.Context, expansionTy);
Expand Down Expand Up @@ -1379,8 +1379,8 @@ irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,

// If we're looking at a pack expansion, insert the appropriate
// number of flags fields.
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
emitPackExpansionPack(IGF, array.getAddress(), expansionTy,
if (isa<PackExpansionType>(eltTy)) {
emitPackExpansionPack(IGF, array.getAddress(),
dynamicIndex, dynamicLength,
[&](llvm::Value *) -> llvm::Value * {
return flagsVal;
Expand Down Expand Up @@ -1408,4 +1408,47 @@ irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
(void) visitPackExplosion(IGF, packType, visitFn);

return array;
}
}

std::pair<StackAddress, llvm::Value *>
irgen::emitInducedTupleTypeMetadataPack(
IRGenFunction &IGF, llvm::Value *tupleMetadata) {
auto *shape = emitTupleTypeMetadataLength(IGF, tupleMetadata);

auto pack = IGF.emitDynamicAlloca(IGF.IGM.TypeMetadataPtrTy, shape,
IGF.IGM.getPointerAlignment(),
/*allowTaskAlloc=*/true);
auto elementForIndex =
[&](llvm::Value *index) -> llvm::Value * {
return irgen::emitTupleTypeMetadataElementType(IGF, tupleMetadata, index);
};

auto *index = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
emitPackExpansionPack(IGF, pack.getAddress(), index, shape,
elementForIndex);

IGF.recordStackPackMetadataAlloc(pack, shape);

return {pack, shape};
}

MetadataResponse
irgen::emitInducedTupleTypeMetadataPackRef(
IRGenFunction &IGF, CanPackType packType,
llvm::Value *tupleMetadata) {
StackAddress pack;
llvm::Value *shape;
std::tie(pack, shape) = emitInducedTupleTypeMetadataPack(
IGF, tupleMetadata);

auto *metadata = pack.getAddress().getAddress();

if (!IGF.canStackPromotePackMetadata()) {
metadata = IGF.Builder.CreateCall(
IGF.IGM.getAllocateMetadataPackFunctionPointer(), {metadata, shape});

cleanupTypeMetadataPack(IGF, pack, shape);
}

return MetadataResponse::forComplete(metadata);
}
9 changes: 9 additions & 0 deletions lib/IRGen/GenPack.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,15 @@ emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
CanPackType packType,
llvm::Value *shapeExpression);

std::pair<StackAddress, llvm::Value *>
emitInducedTupleTypeMetadataPack(
IRGenFunction &IGF, llvm::Value *tupleMetadata);

MetadataResponse
emitInducedTupleTypeMetadataPackRef(
IRGenFunction &IGF, CanPackType packType,
llvm::Value *tupleMetadata);

} // end namespace irgen
} // end namespace swift

Expand Down
41 changes: 40 additions & 1 deletion lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include "GenPack.h"
#include "GenPointerAuth.h"
#include "GenPoly.h"
#include "GenTuple.h"
#include "GenType.h"
#include "GenericRequirement.h"
#include "IRGenDebugInfo.h"
Expand Down Expand Up @@ -3184,6 +3185,38 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
return MetadataResponse::forComplete(capturedWTable);
}

case Component::Kind::TuplePack: {
assert(component.getPrimaryIndex() == 0);

auto tupleType = cast<TupleType>(sourceKey.Type);
auto packType = tupleType.getInducedPackType();

sourceKey.Kind = LocalTypeDataKind::forFormalTypeMetadata();
sourceKey.Type = packType;

if (!source) return MetadataResponse();

auto sourceMetadata = source.getMetadata();
return emitInducedTupleTypeMetadataPackRef(IGF, packType,
sourceMetadata);
}

case Component::Kind::TupleShape: {
assert(component.getPrimaryIndex() == 0);

auto tupleType = cast<TupleType>(sourceKey.Type);

sourceKey.Kind = LocalTypeDataKind::forPackShapeExpression();
sourceKey.Type = tupleType.getInducedPackType();

if (!source) return MetadataResponse();

auto sourceMetadata = source.getMetadata();
auto count = irgen::emitTupleTypeMetadataLength(IGF, sourceMetadata);

return MetadataResponse::forComplete(count);
}

case Component::Kind::Impossible:
llvm_unreachable("following an impossible path!");

Expand Down Expand Up @@ -3222,11 +3255,17 @@ void MetadataPath::print(llvm::raw_ostream &out) const {
out << "pack_expansion_count[" << component.getPrimaryIndex() << "]";
break;
case Component::Kind::PackExpansionPattern:
out << "pack_expansion_patttern[" << component.getPrimaryIndex() << "]";
out << "pack_expansion_pattern[" << component.getPrimaryIndex() << "]";
break;
case Component::Kind::ConditionalConformance:
out << "conditional_conformance[" << component.getPrimaryIndex() << "]";
break;
case Component::Kind::TuplePack:
out << "tuple_pack";
break;
case Component::Kind::TupleShape:
out << "tuple_shape";
break;
case Component::Kind::Impossible:
out << "impossible";
break;
Expand Down
29 changes: 29 additions & 0 deletions lib/IRGen/GenTuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,4 +667,33 @@ llvm::Constant *irgen::getTupleLabelsString(IRGenModule &IGM,
// Otherwise, create a new string literal.
// This method implicitly adds a null terminator.
return IGM.getAddrOfGlobalString(buffer);
}

llvm::Value *irgen::emitTupleTypeMetadataLength(IRGenFunction &IGF,
llvm::Value *metadata) {
llvm::Value *indices[] = {
IGF.IGM.getSize(Size(0)), // (*tupleType)
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) // .NumElements
};
auto slot = IGF.Builder.CreateInBoundsGEP(IGF.IGM.TupleTypeMetadataTy,
metadata, indices);

return IGF.Builder.CreateLoad(slot, IGF.IGM.SizeTy,
IGF.IGM.getPointerAlignment());
}

llvm::Value *irgen::emitTupleTypeMetadataElementType(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *index) {
llvm::Value *indices[] = {
IGF.IGM.getSize(Size(0)), // (*tupleType)
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 3), // .Elements
index, // [index]
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0) // .Metadata
};
auto slot = IGF.Builder.CreateInBoundsGEP(IGF.IGM.TupleTypeMetadataTy,
metadata, indices);

return IGF.Builder.CreateLoad(slot, IGF.IGM.SizeTy,
IGF.IGM.getPointerAlignment());
}
7 changes: 7 additions & 0 deletions lib/IRGen/GenTuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ namespace irgen {
llvm::Constant *getTupleLabelsString(IRGenModule &IGM,
CanTupleType type);

/// Load the NumElements of a tuple type metadata.
llvm::Value *emitTupleTypeMetadataLength(IRGenFunction &IGF,
llvm::Value *metadata);

llvm::Value *emitTupleTypeMetadataElementType(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *index);
} // end namespace irgen
} // end namespace swift

Expand Down
18 changes: 17 additions & 1 deletion lib/IRGen/MetadataPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ class MetadataPath {
/// The count type of a pack expansion at index P in a pack.
PackExpansionCount,

LastWithPrimaryIndex = PackExpansionCount,
/// Materialize tuple as a pack.
TuplePack,

/// Materialize length of tuple as a pack shape expression.
TupleShape,

LastWithPrimaryIndex = TupleShape,

// Everything past this point has no index.

Expand Down Expand Up @@ -117,8 +123,10 @@ class MetadataPath {
case Kind::NominalTypeArgumentShape:
case Kind::NominalTypeArgument:
case Kind::ConditionalConformance:
case Kind::TupleShape:
return OperationCost::Load;

case Kind::TuplePack:
case Kind::AssociatedConformance:
return OperationCost::Call;

Expand Down Expand Up @@ -210,6 +218,14 @@ class MetadataPath {
Path.push_back(Component(Component::Kind::PackExpansionCount, index));
}

void addTuplePackComponent() {
Path.push_back(Component(Component::Kind::TuplePack, /*index=*/0));
}

void addTupleShapeComponent() {
Path.push_back(Component(Component::Kind::TupleShape, /*index=*/0));
}

/// Return an abstract measurement of the cost of this path.
OperationCost cost() const {
auto cost = OperationCost::Free;
Expand Down
20 changes: 15 additions & 5 deletions test/IRGen/tuple_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,37 @@
import Swift

protocol P {
func f()
func defaultRequirement()
static func staticRequirement()
}

extension P {
func f() {}
func defaultRequirement() {}
}

extension Builtin.TheTupleType: P where repeat each Elements: P {
static func staticRequirement() {}
}

func takesP<T: P>(_ t: T) {
t.f()
t.defaultRequirement()
T.staticRequirement()
}

struct S: P {}
struct S: P {
static func staticRequirement() {
print(self)
}
}

func use() {
takesP(())
takesP((S(), S()))
}

// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP1fyyFTW"({{i32|i64}} %0, ptr %"{{.*}}", ptr {{.*}} swiftself %1, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP18defaultRequirementyyFTW"(ptr {{.*}} swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {

// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP17staticRequirementyyFZTW"(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {

// CHECK-LABEL: define hidden swiftcc void @"$s18tuple_conformances3useyyF"() {{.*}} {
// CHECK: call ptr @"$s18tuple_conformances1SV_ACtxxQp_tAA1PAAWl"()
Expand Down