Skip to content

IRGen: Refactor GenericRequirement #62515

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 2 commits into from
Dec 12, 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
51 changes: 0 additions & 51 deletions include/swift/AST/GenericRequirement.h

This file was deleted.

129 changes: 129 additions & 0 deletions include/swift/IRGen/GenericRequirement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//===--- GenericRequirement.h - Generic requirement -------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_GENERIC_REQUIREMENT_H
#define SWIFT_AST_GENERIC_REQUIREMENT_H

#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "llvm/Support/raw_ostream.h"

namespace swift {

class ProtocolDecl;

/// The three kinds of entities passed in the runtime calling convention for
/// generic code: pack shapes, type metadata, and witness tables.
///
/// A pack shape describes an equivalence class of type parameter packs; the
/// runtime value is a single integer, which is the length of the pack.
///
/// Type metadata is emitted for each reduced generic parameter (that is,
/// not same-type constrained to another generic parameter or concrete type).
///
/// A witness table is emitted for each conformance requirement in the
/// generic signature.
class GenericRequirement {
public:
enum class Kind: uint8_t {
Shape,
Metadata,
WitnessTable
};

private:
Kind kind;
CanType type;
ProtocolDecl *proto;

GenericRequirement(Kind kind, CanType type, ProtocolDecl *proto)
: kind(kind), type(type), proto(proto) {}

public:
Kind getKind() const {
return kind;
}

CanType getTypeParameter() const {
return type;
}

ProtocolDecl *getProtocol() const {
return proto;
}

bool isShape() const {
return kind == Kind::Shape;
}

static GenericRequirement forShape(CanType type) {
assert(type->isParameterPack());
return GenericRequirement(Kind::Shape, type, nullptr);
}

bool isMetadata() const {
return kind == Kind::Metadata;
}

static GenericRequirement forMetadata(CanType type) {
return GenericRequirement(Kind::Metadata, type, nullptr);
}

bool isWitnessTable() const {
return kind == Kind::WitnessTable;
}

static GenericRequirement forWitnessTable(CanType type, ProtocolDecl *proto) {
assert(proto != nullptr);
return GenericRequirement(Kind::WitnessTable, type, proto);
}

void dump(llvm::raw_ostream &out) const {
switch (kind) {
case Kind::Shape:
out << "shape: " << type;
break;
case Kind::Metadata:
out << "metadata: " << type;
break;
case Kind::WitnessTable:
out << "witness_table: " << type << " : " << proto->getName();
break;
}
}
};

} // end namespace swift

namespace llvm {
template <> struct DenseMapInfo<swift::GenericRequirement> {
using GenericRequirement = swift::GenericRequirement;
using CanTypeInfo = llvm::DenseMapInfo<swift::CanType>;
static GenericRequirement getEmptyKey() {
return GenericRequirement::forMetadata(CanTypeInfo::getEmptyKey());
}
static GenericRequirement getTombstoneKey() {
return GenericRequirement::forMetadata(CanTypeInfo::getTombstoneKey());
}
static llvm::hash_code getHashValue(GenericRequirement req) {
return hash_combine(CanTypeInfo::getHashValue(req.getTypeParameter()),
hash_value(req.getProtocol()));
}
static bool isEqual(GenericRequirement lhs, GenericRequirement rhs) {
return (lhs.getKind() == rhs.getKind() &&
lhs.getTypeParameter() == rhs.getTypeParameter() &&
lhs.getProtocol() == rhs.getProtocol());
}
};
} // end namespace llvm

#endif // SWIFT_AST_GENERIC_REQUIREMENT_H
2 changes: 1 addition & 1 deletion include/swift/IRGen/IRABIDetailsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
#define SWIFT_IRGEN_IRABIDETAILSPROVIDER_H

#include "swift/AST/Decl.h"
#include "swift/AST/GenericRequirement.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/IRGen/GenericRequirement.h"
#include "clang/AST/CharUnits.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Optional.h"
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/EntryPointArgumentEmission.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Value;

namespace swift {

struct GenericRequirement;
class GenericRequirement;
class SILArgument;

namespace irgen {
Expand Down
15 changes: 7 additions & 8 deletions lib/IRGen/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
}

// Add the fulfillment.
hadFulfillment |= addFulfillment({type, nullptr},
hadFulfillment |= addFulfillment(GenericRequirement::forMetadata(type),
source, std::move(path), metadataState);
return hadFulfillment;
}
Expand Down Expand Up @@ -251,8 +251,9 @@ bool FulfillmentMap::searchWitnessTable(
// If we're not limiting the set of interesting conformances, or if
// this is an interesting conformance, record it.
if (!interestingConformances || interestingConformances->count(protocol)) {
hadFulfillment |= addFulfillment({type, protocol}, source,
std::move(path), MetadataState::Complete);
hadFulfillment |= addFulfillment(
GenericRequirement::forWitnessTable(type, protocol), source,
std::move(path), MetadataState::Complete);
}

return hadFulfillment;
Expand Down Expand Up @@ -315,7 +316,7 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
}

/// Testify that there's a fulfillment at the given path.
bool FulfillmentMap::addFulfillment(FulfillmentKey key,
bool FulfillmentMap::addFulfillment(GenericRequirement key,
unsigned source,
MetadataPath &&path,
MetadataState metadataState) {
Expand Down Expand Up @@ -360,10 +361,8 @@ static StringRef getStateName(MetadataState state) {
void FulfillmentMap::dump() const {
auto &out = llvm::errs();
for (auto &entry : Fulfillments) {
out << "(" << entry.first.first;
if (auto proto = entry.first.second) {
out << ", " << proto->getNameStr();
}
out << "(";
entry.first.dump(out);
out << ") => " << getStateName(entry.second.getState())
<< " at sources[" << entry.second.SourceIndex
<< "]." << entry.second.Path << "\n";
Expand Down
26 changes: 14 additions & 12 deletions lib/IRGen/Fulfillment.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/ADT/DenseMap.h"
#include "swift/AST/Types.h"
#include "swift/AST/GenericSignature.h"
#include "swift/IRGen/GenericRequirement.h"
#include "MetadataPath.h"

namespace swift {
Expand Down Expand Up @@ -48,9 +49,7 @@ struct Fulfillment {
};

class FulfillmentMap {
using FulfillmentKey = std::pair<Type, ProtocolDecl*>;

llvm::DenseMap<FulfillmentKey, Fulfillment> Fulfillments;
llvm::DenseMap<GenericRequirement, Fulfillment> Fulfillments;

public:
struct InterestingKeysCallback {
Expand Down Expand Up @@ -115,25 +114,28 @@ class FulfillmentMap {
///
/// \return true if the fulfillment was added, which won't happen if there's
/// already a fulfillment that was at least as good
bool addFulfillment(FulfillmentKey key, unsigned source,
bool addFulfillment(GenericRequirement key, unsigned source,
MetadataPath &&path, MetadataState state);

const Fulfillment *getTypeMetadata(CanType type) const {
auto it = Fulfillments.find({type, nullptr});
const Fulfillment *getFulfillment(GenericRequirement key) const {
auto it = Fulfillments.find(key);
if (it != Fulfillments.end()) {
return &it->second;
} else {
return nullptr;
}
}

const Fulfillment *getShape(CanType type) const {
return getFulfillment(GenericRequirement::forShape(type));
}

const Fulfillment *getTypeMetadata(CanType type) const {
return getFulfillment(GenericRequirement::forMetadata(type));
}

const Fulfillment *getWitnessTable(CanType type, ProtocolDecl *proto) const {
auto it = Fulfillments.find({type, proto});
if (it != Fulfillments.end()) {
return &it->second;
} else {
return nullptr;
}
return getFulfillment(GenericRequirement::forWitnessTable(type, proto));
}

void dump() const;
Expand Down
9 changes: 5 additions & 4 deletions lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,14 +435,15 @@ withOpaqueTypeGenericArgs(IRGenFunction &IGF,
enumerateGenericSignatureRequirements(
opaqueDecl->getGenericSignature().getCanonicalSignature(),
[&](GenericRequirement reqt) {
auto ty = reqt.TypeParameter.subst(archetype->getSubstitutions())
auto ty = reqt.getTypeParameter().subst(archetype->getSubstitutions())
->getReducedType(opaqueDecl->getGenericSignature());
if (reqt.Protocol) {
if (reqt.isWitnessTable()) {
auto ref =
ProtocolConformanceRef(reqt.Protocol)
.subst(reqt.TypeParameter, archetype->getSubstitutions());
ProtocolConformanceRef(reqt.getProtocol())
.subst(reqt.getTypeParameter(), archetype->getSubstitutions());
args.push_back(emitWitnessTableRef(IGF, ty, ref));
} else {
assert(reqt.isMetadata());
args.push_back(IGF.emitAbstractTypeMetadataRef(ty));
}
types.push_back(args.back()->getType());
Expand Down
9 changes: 6 additions & 3 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ emitKeyPathComponent(IRGenModule &IGM,
enumerateGenericSignatureRequirements(
componentCanSig, [&](GenericRequirement reqt) {
auto substType =
reqt.TypeParameter.subst(subs)->getCanonicalType();
reqt.getTypeParameter().subst(subs)->getCanonicalType();

// FIXME: This seems wrong. We used to just mangle opened archetypes as
// their interface type. Let's make that explicit now.
Expand All @@ -896,14 +896,17 @@ emitKeyPathComponent(IRGenModule &IGM,
return None;
})->getCanonicalType();

if (!reqt.Protocol) {
if (reqt.isMetadata()) {
// Type requirement.
externalSubArgs.push_back(emitMetadataTypeRefForKeyPath(
IGM, substType, componentCanSig));
} else {
assert(reqt.isWitnessTable());

// Protocol requirement.
auto conformance = subs.lookupConformance(
reqt.TypeParameter->getCanonicalType(), reqt.Protocol);
reqt.getTypeParameter()->getCanonicalType(),
reqt.getProtocol());
externalSubArgs.push_back(IGM.emitWitnessTableRefString(
substType, conformance,
genericEnv ? genericEnv->getGenericSignature() : nullptr,
Expand Down
7 changes: 4 additions & 3 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4250,20 +4250,21 @@ namespace {
}

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

void addGenericWitnessTable(GenericRequirement requirement) {
auto conformance = genericSubstitutions().lookupConformance(
requirement.TypeParameter->getCanonicalType(), requirement.Protocol);
requirement.getTypeParameter()->getCanonicalType(),
requirement.getProtocol());
ProtocolConformance *concreteConformance = conformance.getConcrete();

llvm::Constant *addr;

Type argument = requirement.TypeParameter.subst(genericSubstitutions());
Type argument = requirement.getTypeParameter().subst(genericSubstitutions());
auto argumentNominal = argument->getAnyNominal();
if (argumentNominal && argumentNominal->isGenericContext()) {
// TODO: Statically specialize the witness table pattern for t's
Expand Down
Loading