Files
swift-mirror/include/swift/SILOptimizer/Utils/Existential.h
Andrew Trick 118a725d96 Generalize and cleanup code for existential specialization.
Generalizes the ConcreteExistentialInfo abstraction so it can be used
both by the ExistentialSpecializer and SILCombine, allowing redundant
code in ExistentialSpecializer.cpp to be deleted.

Splits OpenedArchetypeInfo from ConcreteExistentialInfo. Adds a
ConcreteOpenedArchetypeInfo convenience wrapper around them both, for
use wherever we were originally using ConcreteExistentialInfo.

Splits getAddressOfStackInit into getStackInitInst, This is cleaner and
allows both the ExistentialSpecializer and SILCombine to handle more
interesting cases in the future, like unconditional_checked_cast.

Creates utilities, initializeSubstitutionMap, and
initializeConcreteTypeDef to simplify an generalize
ConcreteExistentialInfo.

While rewriting ExistentialSpecializer to use the new
abstraction, I fixed a latent bug in which is was using a SIL
argument index as a function type parameter index (this would
have broken up if/when we decide to enable calls with indirect
results).
2019-01-02 08:44:37 -08:00

140 lines
5.5 KiB
C++

//===--- Existential.h - Existential related Analyses. -------*- 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_SILOPTIMIZER_UTILS_EXISTENTIAL_H
#define SWIFT_SILOPTIMIZER_UTILS_EXISTENTIAL_H
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h"
namespace swift {
/// Record information about an opened archetype.
///
/// This is used to determine whether a generic call argument originates from
/// an opened existential. For example:
/// %o = open_existential_ref %e : $P & Q to $@opened("PQ") P & Q
/// %r = apply %f<@opened("PQ") P & Q>(%o)
/// : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q>
/// (@guaranteed τ_0_0) -> @owned τ_0_0
///
/// When successfull, ConcreteExistentialInfo can be used to determine the
/// concrete type of the opened existential.
struct OpenedArchetypeInfo {
ArchetypeType *OpenedArchetype = nullptr;
// The opened value.
SingleValueInstruction *OpenedArchetypeValue;
// The existential value.
SILValue ExistentialValue;
// True if the openedValue is copied from another stack location
bool isOpenedValueCopied = false;
// Construct a valid instance if the given use originates from a recognizable
// OpenedArchetype instruction.
OpenedArchetypeInfo(Operand &use);
bool isValid() const {
assert(!OpenedArchetype || (OpenedArchetypeValue && ExistentialValue));
return OpenedArchetype;
}
};
/// Record conformance and concrete type info derived from an init_existential
/// value that is reopened before it's use. This is useful for finding the
/// concrete type of an apply's self argument. For example, an important pattern
/// for a class existential is:
///
/// %e = init_existential_ref %c : $C : $C, $P & Q
/// %o = open_existential_ref %e : $P & Q to $@opened("PQ") P & Q
/// %r = apply %f<@opened("PQ") P & Q>(%o)
/// : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q>
/// (@guaranteed τ_0_0) -> @owned τ_0_0
struct ConcreteExistentialInfo {
// The existential type of the self argument before it is opened,
// produced by an init_existential.
CanType ExistentialType;
// The concrete type of self from the init_existential. `$C` above.
CanType ConcreteType;
// The concrete value used to initialize the opened existential.
// `%c` in the above comment.
SILValue ConcreteValue;
// True if the ConcreteValue is copied from another stack location
bool isConcreteValueCopied = false;
// When ConcreteType is itself an opened existential, record the type
// definition. May be nullptr for a valid AppliedConcreteType.
SingleValueInstruction *ConcreteTypeDef = nullptr;
// The Substitution map derived from the init_existential.
// This maps a single generic parameter to the replacement ConcreteType
// and includes the full list of existential conformances.
// signature: <P & Q>, replacement: $C : conformances: [$P, $Q]
SubstitutionMap ExistentialSubs;
// Search for a recognized pattern in which the given existential value is
// initialized to a concrete type. Constructs a valid ConcreteExistentialInfo
// object if successfull.
ConcreteExistentialInfo(SILValue existential, SILInstruction *user);
// This constructor initializes a ConcreteExistentialInfo based on already
// known ConcreteType and ProtocolDecl pair.
ConcreteExistentialInfo(SILValue existential, SILInstruction *user,
CanType ConcreteType, ProtocolDecl *Protocol);
/// For scenerios where ConcreteExistentialInfo is created using a known
/// ConcreteType and ProtocolDecl, the ConcreteValue can be null.
bool isValid() const { return ConcreteType && !ExistentialSubs.empty(); }
// Do a conformance lookup on ConcreteType with the given requirement, P. If P
// is satisfiable based on the existential's conformance, return the new
// conformance on P. Otherwise return None.
Optional<ProtocolConformanceRef>
lookupExistentialConformance(ProtocolDecl *P) const {
CanType selfTy = P->getSelfInterfaceType()->getCanonicalType();
return ExistentialSubs.lookupConformance(selfTy, P);
}
private:
void initializeSubstitutionMap(
ArrayRef<ProtocolConformanceRef> ExistentialConformances, SILModule *M);
void initializeConcreteTypeDef(SILInstruction *typeConversionInst);
};
// Convenience for tracking both the OpenedArchetypeInfo and
// ConcreteExistentialInfo from the same SILValue.
struct ConcreteOpenedExistentialInfo {
OpenedArchetypeInfo OAI;
// If CEI has a value, it must be valid.
Optional<ConcreteExistentialInfo> CEI;
ConcreteOpenedExistentialInfo(Operand &use);
// Provide a whole module type-inferred ConcreteType to fall back on if the
// concrete type cannot be determined from data flow.
ConcreteOpenedExistentialInfo(Operand &use, CanType concreteType,
ProtocolDecl *protocol);
bool isValid() const {
if (!CEI)
return false;
assert(CEI->isValid());
return true;
}
};
} // end namespace swift
#endif