Skip to content
30 changes: 11 additions & 19 deletions include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace clang {

namespace swift {
namespace Lowering {
class FunctionParamGenerator;

/// A pattern for the abstraction of a value.
///
Expand Down Expand Up @@ -1501,29 +1502,20 @@ class AbstractionPattern {
/// parameters in the pattern.
unsigned getNumFunctionParams() const;

/// Perform a parallel visitation of the parameters of a function.
///
/// If this is a function pattern, calls handleScalar or
/// handleExpansion as appropriate for each parameter of the
/// original function, in order.
/// Traverses the parameters of a function, where this is the
/// abstraction pattern for the function (its "original type")
/// and the given parameters are the substituted formal parameters.
/// Calls the callback once for each parameter in the abstraction
/// pattern.
///
/// If this is not a function pattern, calls handleScalar for each
/// parameter of the substituted function type. Functions with
/// pack expansions cannot be abstracted legally this way.
/// parameter of the substituted function type. Note that functions
/// with pack expansions cannot be legally abstracted this way; it
/// is not possible in Swift's ABI to support this without some sort
/// of dynamic argument-forwarding thunk.
void forEachFunctionParam(AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalParam,
llvm::function_ref<void(unsigned origParamIndex,
unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origParamType,
AnyFunctionType::CanParam substParam)>
handleScalar,
llvm::function_ref<void(unsigned origParamIndex,
unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origExpansionType,
AnyFunctionType::CanParamArrayRef substParams)>
handleExpansion) const;
llvm::function_ref<void(FunctionParamGenerator &param)> function) const;

/// Given that the value being abstracted is optional, return the
/// abstraction pattern for its object type.
Expand Down
154 changes: 154 additions & 0 deletions include/swift/SIL/AbstractionPatternGenerators.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//===--- AbstractionPatternGenerators.h -------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines "generators" that can be used with an AbstractionPattern
// to do certain kinds of traversal without using callbacks.
// This can be useful when a traversal is required in parallel with
// some other traversal.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SIL_ABSTRACTIONPATTERNGENERATORS_H
#define SWIFT_SIL_ABSTRACTIONPATTERNGENERATORS_H

#include "swift/SIL/AbstractionPattern.h"

namespace swift {
namespace Lowering {

/// A generator for traversing the formal function parameters of a type
/// while properly respecting variadic generics.
class FunctionParamGenerator {
// The steady state of the generator.

/// The abstraction pattern of the entire function type. Set once
/// during construction.
AbstractionPattern origFunctionType;

/// The list of all substituted parameters to traverse. Set once
/// during construction.
AnyFunctionType::CanParamArrayRef allSubstParams;

/// The number of orig parameters to traverse. Set once during
/// construction.
unsigned numOrigParams;

/// The index of the current orig parameter.
/// Incremented during advance().
unsigned origParamIndex = 0;

/// The (start) index of the current subst parameters.
/// Incremented during advance().
unsigned substParamIndex = 0;

/// The number of subst parameters corresponding to the current
/// subst parameter.
unsigned numSubstParamsForOrigParam;

/// Whether the orig function type is opaque, i.e. does not permit us to
/// call getNumFunctionParams() and similar accessors. Set once during
/// construction.
bool origFunctionTypeIsOpaque;

/// Whether the current orig parameter is a pack expansion.
bool origParamIsExpansion;

/// The abstraction pattern of the current orig parameter.
/// If it is a pack expansion, this is the expansion type, not the
/// pattern type.
AbstractionPattern origParamType = AbstractionPattern::getInvalid();

/// Load the informaton for the current orig parameter into the
/// fields above for it.
void loadParameter() {
origParamType = origFunctionType.getFunctionParamType(origParamIndex);
origParamIsExpansion = origParamType.isPackExpansion();
numSubstParamsForOrigParam =
(origParamIsExpansion
? origParamType.getNumPackExpandedComponents()
: 1);
}

public:
FunctionParamGenerator(AbstractionPattern origFunctionType,
AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalOrigParam);

/// Is the traversal finished? If so, none of the getters below
/// are allowed to be called.
bool isFinished() const {
return origParamIndex == numOrigParams;
}

/// Advance to the next orig parameter.
void advance() {
assert(!isFinished());
origParamIndex++;
substParamIndex += numSubstParamsForOrigParam;
if (!isFinished()) loadParameter();
}

/// Return the index of the current orig parameter.
unsigned getOrigIndex() const {
assert(!isFinished());
return origParamIndex;
}

/// Return the index of the (first) subst parameter corresponding
/// to the current orig parameter.
unsigned getSubstIndex() const {
assert(!isFinished());
return origParamIndex;
}

/// Return the parameter flags for the current orig parameter.
ParameterTypeFlags getOrigFlags() const {
assert(!isFinished());
return (origFunctionTypeIsOpaque
? allSubstParams[substParamIndex].getParameterFlags()
: origFunctionType.getFunctionParamFlags(origParamIndex));
}

/// Return the type of the current orig parameter.
const AbstractionPattern &getOrigType() const {
assert(!isFinished());
return origParamType;
}

/// Return whether the current orig parameter type is a pack expansion.
bool isPackExpansion() const {
assert(!isFinished());
return origParamIsExpansion;
}

/// Return the substituted parameters corresponding to the current
/// orig parameter type. If the current orig parameter is not a
/// pack expansion, this will have exactly one element.
AnyFunctionType::CanParamArrayRef getSubstParams() const {
assert(!isFinished());
return allSubstParams.slice(substParamIndex, numSubstParamsForOrigParam);
}

/// Call this to finalize the traversal and assert that it was done
/// properly.
void finish() {
assert(isFinished() && "didn't finish the traversal");
assert(substParamIndex == allSubstParams.size() &&
"didn't exhaust subst parameters; possible missing subs on "
"orig function type");
}
};

} // end namespace Lowering
} // end namespace swift

#endif
7 changes: 7 additions & 0 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ class SILType {
return SILType(castTo<TupleType>().getElementType(index), getCategory());
}

/// Given that this is a pack type, return the lowered type of the
/// given pack element. The result will have the same value
/// category as the base type.
SILType getPackElementType(unsigned index) const {
return SILType(castTo<SILPackType>()->getElementType(index), getCategory());
}

/// Given that this is a pack expansion type, return the lowered type
/// of the pattern type. The result will have the same value category
/// as the base type.
Expand Down
102 changes: 40 additions & 62 deletions lib/SIL/IR/AbstractionPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/CanTypeVisitor.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/SIL/AbstractionPatternGenerators.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
Expand Down Expand Up @@ -1202,55 +1203,33 @@ unsigned AbstractionPattern::getNumFunctionParams() const {

void AbstractionPattern::
forEachFunctionParam(AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalParam,
llvm::function_ref<void(unsigned origParamIndex,
unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origParamType,
AnyFunctionType::CanParam substParam)>
handleScalar,
llvm::function_ref<void(unsigned origParamIndex,
unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origExpansionType,
AnyFunctionType::CanParamArrayRef substParams)>
handleExpansion) const {
// Honor ignoreFinalParam for the substituted parameters on all paths.
if (ignoreFinalParam) substParams = substParams.drop_back();

// If we don't have a function type, use the substituted type.
if (isTypeParameterOrOpaqueArchetype() ||
getKind() == Kind::OpaqueFunction ||
getKind() == Kind::OpaqueDerivativeFunction) {
for (auto substParamIndex : indices(substParams)) {
handleScalar(substParamIndex, substParamIndex,
substParams[substParamIndex].getParameterFlags(),
AbstractionPattern::getOpaque(),
substParams[substParamIndex]);
}
return;
bool ignoreFinalOrigParam,
llvm::function_ref<void(FunctionParamGenerator &param)> function) const {
FunctionParamGenerator generator(*this, substParams, ignoreFinalOrigParam);
for (; !generator.isFinished(); generator.advance()) {
function(generator);
}
generator.finish();
}

FunctionParamGenerator::FunctionParamGenerator(
AbstractionPattern origFunctionType,
AnyFunctionType::CanParamArrayRef substParams,
bool ignoreFinalOrigParam)
: origFunctionType(origFunctionType), allSubstParams(substParams) {
origFunctionTypeIsOpaque =
(origFunctionType.isTypeParameterOrOpaqueArchetype() ||
origFunctionType.isOpaqueFunctionOrOpaqueDerivativeFunction());

if (origFunctionTypeIsOpaque) {
numOrigParams = allSubstParams.size();
} else {
numOrigParams = origFunctionType.getNumFunctionParams();
if (ignoreFinalOrigParam)
numOrigParams--;
}

size_t numOrigParams = getNumFunctionParams();
if (ignoreFinalParam) numOrigParams--;

size_t substParamIndex = 0;
for (auto origParamIndex : range(numOrigParams)) {
auto origParamType = getFunctionParamType(origParamIndex);
if (origParamType.isPackExpansion()) {
unsigned numComponents = origParamType.getNumPackExpandedComponents();
handleExpansion(origParamIndex, substParamIndex,
getFunctionParamFlags(origParamIndex), origParamType,
substParams.slice(substParamIndex, numComponents));
substParamIndex += numComponents;
} else {
handleScalar(origParamIndex, substParamIndex,
getFunctionParamFlags(origParamIndex), origParamType,
substParams[substParamIndex]);
substParamIndex++;
}
}
assert(substParamIndex == substParams.size());
if (!isFinished()) loadParameter();
}

static CanType getOptionalObjectType(CanType type) {
Expand Down Expand Up @@ -2239,21 +2218,20 @@ class SubstFunctionTypePatternVisitor
};

pattern.forEachFunctionParam(func.getParams(), /*ignore self*/ false,
[&](unsigned origParamIndex, unsigned substParamIndex,
ParameterTypeFlags origFlags, AbstractionPattern origParamType,
AnyFunctionType::CanParam substParam) {
auto newParamTy = visit(substParam.getParameterType(), origParamType);
addParam(origFlags, newParamTy);
}, [&](unsigned origParamIndex, unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origExpansionType,
AnyFunctionType::CanParamArrayRef substParams) {
CanType candidateSubstType;
if (!substParams.empty())
candidateSubstType = substParams[0].getParameterType();
auto expansionType =
handlePackExpansion(origExpansionType, candidateSubstType);
addParam(origFlags, expansionType);
[&](FunctionParamGenerator &param) {
if (!param.isPackExpansion()) {
auto newParamTy = visit(param.getSubstParams()[0].getParameterType(),
param.getOrigType());
addParam(param.getOrigFlags(), newParamTy);
} else {
auto substParams = param.getSubstParams();
CanType candidateSubstType;
if (!substParams.empty())
candidateSubstType = substParams[0].getParameterType();
auto expansionType =
handlePackExpansion(param.getOrigType(), candidateSubstType);
addParam(param.getOrigFlags(), expansionType);
}
});

if (yieldType) {
Expand Down
24 changes: 13 additions & 11 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/AbstractionPatternGenerators.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
Expand Down Expand Up @@ -1569,22 +1570,22 @@ class DestructureInputs {
maybeAddForeignParameters();

// Process all the non-self parameters.
origType.forEachFunctionParam(params, hasSelf,
[&](unsigned origParamIndex, unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origParamType,
AnyFunctionType::CanParam substParam) {
origType.forEachFunctionParam(params.drop_back(hasSelf ? 1 : 0),
/*ignore final orig param*/ hasSelf,
[&](FunctionParamGenerator &param) {
// If the parameter is not a pack expansion, just pull off the
// next parameter and destructure it in parallel with the abstraction
// pattern for the type.
visit(origParamType, substParam, /*forSelf*/false);
}, [&](unsigned origParamIndex, unsigned substParamIndex,
ParameterTypeFlags origFlags,
AbstractionPattern origExpansionType,
AnyFunctionType::CanParamArrayRef substParams) {
if (!param.isPackExpansion()) {
visit(param.getOrigType(), param.getSubstParams()[0],
/*forSelf*/false);
return;
}

// Otherwise, collect the substituted components into a pack.
auto origExpansionType = param.getOrigType();
SmallVector<CanType, 8> packElts;
for (auto substParam : substParams) {
for (auto substParam : param.getSubstParams()) {
auto substParamType = substParam.getParameterType();
auto origParamType =
origExpansionType.getPackExpansionComponentType(substParamType);
Expand All @@ -1597,6 +1598,7 @@ class DestructureInputs {
SILPackType::ExtInfo extInfo(/*address*/ indirect);
auto packTy = SILPackType::get(TC.Context, extInfo, packElts);

auto origFlags = param.getOrigFlags();
addPackParameter(packTy, origFlags.getValueOwnership(),
origFlags.isNoDerivative());
});
Expand Down
Loading