Skip to content

IRGen: Preliminary support for working with pack shapes #62548

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 10 commits into from
Dec 14, 2022
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
2 changes: 2 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6054,6 +6054,8 @@ class PackArchetypeType final
return T->getKind() == TypeKind::PackArchetype;
}

CanTypeWrapper<PackType> getSingletonPackType();

private:
PackArchetypeType(const ASTContext &Ctx, GenericEnvironment *GenericEnv,
Type InterfaceType, ArrayRef<ProtocolDecl *> ConformsTo,
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3942,6 +3942,7 @@ namespace {
printField("index", T->getIndex());
if (auto decl = T->getDecl())
printField("decl", decl->printRef());
printFlag(T->isParameterPack(), "pack");
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

Expand Down
21 changes: 11 additions & 10 deletions lib/AST/ParameterPack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,11 @@ PackExpansionType *PackExpansionType::expand() {
}

CanType PackExpansionType::getReducedShape() {
if (auto *archetypeType = countType->getAs<PackArchetypeType>()) {
auto shape = archetypeType->getReducedShape();
return CanType(PackExpansionType::get(shape, shape));
} else if (auto *packType = countType->getAs<PackType>()) {
auto shape = packType->getReducedShape();
return CanType(PackExpansionType::get(shape, shape));
}
auto reducedShape = countType->getReducedShape();
if (reducedShape == getASTContext().TheEmptyTupleType)
return reducedShape;

assert(countType->is<PlaceholderType>());
return getASTContext().TheEmptyTupleType;
return CanType(PackExpansionType::get(reducedShape, reducedShape));
}

bool TupleType::containsPackExpansionType() const {
Expand Down Expand Up @@ -423,4 +418,10 @@ PackType *PackType::get(const ASTContext &C,
}

return get(C, wrappedArgs)->flattenPackTypes();
}
}

CanPackType PackArchetypeType::getSingletonPackType() {
SmallVector<Type, 1> types;
types.push_back(PackExpansionType::get(this, getReducedShape()));
return CanPackType(PackType::get(getASTContext(), types));
}
1 change: 1 addition & 0 deletions lib/IRGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ add_swift_host_library(swiftIRGen STATIC
GenMeta.cpp
GenObjC.cpp
GenOpaque.cpp
GenPack.cpp
GenPointerAuth.cpp
GenPoly.cpp
GenProto.cpp
Expand Down
6 changes: 1 addition & 5 deletions lib/IRGen/ClassMetadataVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,7 @@ class ClassMetadataScanner : public ClassMetadataVisitor<Impl> {
addPointer();
}
}
void addGenericArgument(GenericRequirement requirement, ClassDecl *forClass) {
addPointer();
}
void addGenericWitnessTable(GenericRequirement requirement,
ClassDecl *forClass) {
void addGenericRequirement(GenericRequirement requirement, ClassDecl *forClass) {
addPointer();
}
void addPlaceholder(MissingMemberDecl *MMD) {
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/EnumMetadataVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ class EnumMetadataScanner : public EnumMetadataVisitor<Impl> {
void addMetadataFlags() { addPointer(); }
void addValueWitnessTable() { addPointer(); }
void addNominalTypeDescriptor() { addPointer(); }
void addGenericArgument(GenericRequirement requirement) { addPointer(); }
void addGenericWitnessTable(GenericRequirement requirement) { addPointer(); }
void addGenericRequirement(GenericRequirement requirement) { addPointer(); }
void addPayloadSize() { addPointer(); }
void noteStartOfTypeSpecificMembers() {}
void addTrailingFlags() { addInt64(); }
Expand Down
67 changes: 36 additions & 31 deletions lib/IRGen/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,38 +279,43 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,

bool hadFulfillment = false;

auto subs = type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal);

GenericTypeRequirements requirements(IGM, nominal);
requirements.enumerateFulfillments(
IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal),
[&](unsigned reqtIndex, CanType arg, ProtocolConformanceRef conf) {
// Skip uninteresting type arguments.
if (!keys.hasInterestingType(arg))
return;

// If the fulfilled value is type metadata, refine the path.
if (conf.isInvalid()) {
auto argState =
getPresumedMetadataStateForTypeArgument(metadataState);
MetadataPath argPath = path;
argPath.addNominalTypeArgumentComponent(reqtIndex);
hadFulfillment |= searchTypeMetadata(
IGM, arg, IsExact, argState, source, std::move(argPath), keys);
return;
}

// Otherwise, it's a conformance.

// Ignore it unless the type itself is interesting.
if (!keys.isInterestingType(arg))
return;

// Refine the path.
MetadataPath argPath = path;
argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);

hadFulfillment |= searchWitnessTable(IGM, arg, conf.getRequirement(),
source, std::move(argPath), keys);
});

for (unsigned reqtIndex : indices(requirements.getRequirements())) {
auto requirement = requirements.getRequirements()[reqtIndex];
auto arg = requirement.getTypeParameter().subst(subs)->getCanonicalType();

// Skip uninteresting type arguments.
if (!keys.hasInterestingType(arg))
continue;

// If the fulfilled value is type metadata, refine the path.
if (requirement.isMetadata()) {
auto argState =
getPresumedMetadataStateForTypeArgument(metadataState);
MetadataPath argPath = path;
argPath.addNominalTypeArgumentComponent(reqtIndex);
hadFulfillment |= searchTypeMetadata(
IGM, arg, IsExact, argState, source, std::move(argPath), keys);
continue;
}

// Otherwise, it's a conformance.
assert(requirement.isWitnessTable());

// Ignore it unless the type itself is interesting.
if (!keys.isInterestingType(arg))
continue;

// Refine the path.
MetadataPath argPath = path;
argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);

hadFulfillment |= searchWitnessTable(IGM, arg, requirement.getProtocol(),
source, std::move(argPath), keys);
}

return hadFulfillment;
}
Expand Down
13 changes: 6 additions & 7 deletions lib/IRGen/GenDistributed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,22 +680,21 @@ void DistributedAccessor::emit() {
// We need this to determine the expected number of witness tables
// to load from the buffer provided by the caller.
llvm::SmallVector<llvm::Type *, 4> targetGenericArguments;
auto numDirectGenericArgs =
auto expandedSignature =
expandPolymorphicSignature(IGM, targetTy, targetGenericArguments);
assert(expandedSignature.numShapes == 0 &&
"Distributed actors don't support variadic generics");

// Generic arguments associated with the distributed thunk directly
// e.g. `distributed func echo<T, U>(...)`
assert(
!IGM.getLLVMContext().supportsTypedPointers() ||
numDirectGenericArgs ==
expandedSignature.numTypeMetadataPtrs ==
llvm::count_if(targetGenericArguments, [&](const llvm::Type *type) {
return type == IGM.TypeMetadataPtrTy;
}));

auto expectedWitnessTables =
targetGenericArguments.size() - numDirectGenericArgs;

for (unsigned index = 0; index < numDirectGenericArgs; ++index) {
for (unsigned index = 0; index < expandedSignature.numTypeMetadataPtrs; ++index) {
auto offset =
Size(index * IGM.DataLayout.getTypeAllocSize(IGM.TypeMetadataPtrTy));
auto alignment =
Expand All @@ -708,7 +707,7 @@ void DistributedAccessor::emit() {
}

emitLoadOfWitnessTables(witnessTables, numWitnessTables,
expectedWitnessTables, arguments);
expandedSignature.numWitnessTablePtrs, arguments);
}

// Step two, let's form and emit a call to the distributed method
Expand Down
71 changes: 29 additions & 42 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3851,13 +3851,8 @@ namespace {
llvm_unreachable("Fixed class metadata cannot have missing members");
}

void addGenericArgument(GenericRequirement requirement,
ClassDecl *forClass) {
llvm_unreachable("Fixed class metadata cannot have generic parameters");
}

void addGenericWitnessTable(GenericRequirement requirement,
ClassDecl *forClass) {
void addGenericRequirement(GenericRequirement requirement,
ClassDecl *forClass) {
llvm_unreachable("Fixed class metadata cannot have generic requirements");
}
};
Expand Down Expand Up @@ -3899,16 +3894,19 @@ namespace {
}
}

void addGenericArgument(GenericRequirement requirement,
ClassDecl *forClass) {
// Filled in at runtime.
B.addNullPointer(IGM.TypeMetadataPtrTy);
}

void addGenericWitnessTable(GenericRequirement requirement,
ClassDecl *forClass) {
// Filled in at runtime.
B.addNullPointer(IGM.WitnessTablePtrTy);
void addGenericRequirement(GenericRequirement requirement,
ClassDecl *forClass) {
switch (requirement.getKind()) {
case GenericRequirement::Kind::Shape:
B.addInt(IGM.SizeTy, 0);
break;
case GenericRequirement::Kind::Metadata:
B.addNullPointer(IGM.TypeMetadataPtrTy);
break;
case GenericRequirement::Kind::WitnessTable:
B.addNullPointer(IGM.WitnessTablePtrTy);
break;
}
}
};

Expand Down Expand Up @@ -4249,14 +4247,16 @@ namespace {
return emitValueWitnessTable(relativeReference);
}

void addGenericArgument(GenericRequirement requirement) {
auto t = requirement.getTypeParameter().subst(genericSubstitutions());
ConstantReference ref = IGM.getAddrOfTypeMetadata(
CanType(t), SymbolReferenceKind::Relative_Direct);
this->B.add(ref.getDirectValue());
}
void addGenericRequirement(GenericRequirement requirement) {
if (requirement.isMetadata()) {
auto t = requirement.getTypeParameter().subst(genericSubstitutions());
ConstantReference ref = IGM.getAddrOfTypeMetadata(
CanType(t), SymbolReferenceKind::Relative_Direct);
this->B.add(ref.getDirectValue());
return;
}

void addGenericWitnessTable(GenericRequirement requirement) {
assert(requirement.isWitnessTable());
auto conformance = genericSubstitutions().lookupConformance(
requirement.getTypeParameter()->getCanonicalType(),
requirement.getProtocol());
Expand Down Expand Up @@ -4334,14 +4334,9 @@ namespace {
const ClassLayout &fieldLayout)
: super(IGM, type, decl, B, fieldLayout), FieldLayout(fieldLayout) {}

void addGenericArgument(GenericRequirement requirement,
ClassDecl *theClass) {
super::addGenericArgument(requirement);
}

void addGenericWitnessTable(GenericRequirement requirement,
ClassDecl *theClass) {
super::addGenericWitnessTable(requirement);
void addGenericRequirement(GenericRequirement requirement,
ClassDecl *theClass) {
super::addGenericRequirement(requirement);
}

void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
Expand Down Expand Up @@ -4800,11 +4795,7 @@ namespace {
B.addAlignmentPadding(super::IGM.getPointerAlignment());
}

void addGenericArgument(GenericRequirement requirement) {
llvm_unreachable("Concrete type metadata cannot have generic parameters");
}

void addGenericWitnessTable(GenericRequirement requirement) {
void addGenericRequirement(GenericRequirement requirement) {
llvm_unreachable("Concrete type metadata cannot have generic requirements");
}

Expand Down Expand Up @@ -5169,11 +5160,7 @@ namespace {
PointerAuthEntity::Special::TypeDescriptor);
}

void addGenericArgument(GenericRequirement requirement) {
llvm_unreachable("Concrete type metadata cannot have generic parameters");
}

void addGenericWitnessTable(GenericRequirement requirement) {
void addGenericRequirement(GenericRequirement requirement) {
llvm_unreachable("Concrete type metadata cannot have generic requirements");
}

Expand Down
72 changes: 72 additions & 0 deletions lib/IRGen/GenPack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===--- GenPack.cpp - Swift IR Generation For Variadic Generics ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for type and value packs in Swift.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Decl.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Types.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "llvm/IR/DerivedTypes.h"

#include "GenType.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"

using namespace swift;
using namespace irgen;

llvm::Value *IRGenFunction::emitPackShapeExpression(CanType type) {

type = type->getReducedShape()->getCanonicalType();

auto kind = LocalTypeDataKind::forPackShapeExpression();

llvm::Value *result = tryGetLocalTypeData(type, kind);
if (result != nullptr)
return result;

// If shape(T) == t and shape(U) == u, the shape expression for a pack
// {T..., Int, T..., U..., String} becomes 't + t + u + 2'.
unsigned scalarElements = 0;

auto accumulate = [&](llvm::Value *value) {
if (result == nullptr) {
result = value;
return;
}

result = Builder.CreateAdd(result, value);
};

auto packType = cast<PackType>(type);
for (auto elt : packType.getElementTypes()) {
if (auto expansionType = dyn_cast<PackExpansionType>(elt)) {
auto reducedShape = expansionType.getCountType();
accumulate(emitPackShapeExpression(reducedShape));
continue;
}

++scalarElements;
}

if (scalarElements > 0) {
auto *constant = llvm::ConstantInt::get(IGM.SizeTy, scalarElements);
accumulate(constant);
}

setScopedLocalTypeData(type, kind, result);
return result;
}
Loading