Skip to content

SILGen: Propagate generic types through func-to-block invoke functions. #2833

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 1 commit into from
Jun 2, 2016
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
7 changes: 4 additions & 3 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -985,9 +985,10 @@ class SILBuilder {

InitBlockStorageHeaderInst *
createInitBlockStorageHeader(SILLocation Loc, SILValue BlockStorage,
SILValue InvokeFunction, SILType BlockType) {
return insert(new (F.getModule()) InitBlockStorageHeaderInst(
getSILDebugLocation(Loc), BlockStorage, InvokeFunction, BlockType));
SILValue InvokeFunction, SILType BlockType,
ArrayRef<Substitution> Subs) {
return insert(InitBlockStorageHeaderInst::create(F,
getSILDebugLocation(Loc), BlockStorage, InvokeFunction, BlockType, Subs));
}

MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype) {
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,8 @@ void SILCloner<ImplClass>::visitInitBlockStorageHeaderInst(
getOpLocation(Inst->getLoc()),
getOpValue(Inst->getBlockStorage()),
getOpValue(Inst->getInvokeFunction()),
getOpType(Inst->getType())));
getOpType(Inst->getType()),
getOpSubstitutions(Inst->getSubstitutions())));
}

template <typename ImplClass>
Expand Down
27 changes: 24 additions & 3 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3336,20 +3336,41 @@ class InitBlockStorageHeaderInst : public SILInstruction {
friend class SILBuilder;

enum { BlockStorage, InvokeFunction };
unsigned NumSubstitutions;
FixedOperandList<2> Operands;

Substitution *getSubstitutionsStorage() {
return reinterpret_cast<Substitution*>(Operands.asArray().end());
}
const Substitution *getSubstitutionsStorage() const {
return reinterpret_cast<const Substitution*>(Operands.asArray().end());
}

InitBlockStorageHeaderInst(SILDebugLocation DebugLoc, SILValue BlockStorage,
SILValue InvokeFunction, SILType BlockType)
SILValue InvokeFunction, SILType BlockType,
ArrayRef<Substitution> Subs)
: SILInstruction(ValueKind::InitBlockStorageHeaderInst, DebugLoc,
BlockType),
Operands(this, BlockStorage, InvokeFunction) {}

NumSubstitutions(Subs.size()),
Operands(this, BlockStorage, InvokeFunction) {
memcpy(getSubstitutionsStorage(), Subs.begin(),
sizeof(Subs[0]) * Subs.size());
}

static InitBlockStorageHeaderInst *create(SILFunction &F,
SILDebugLocation DebugLoc, SILValue BlockStorage,
SILValue InvokeFunction, SILType BlockType,
ArrayRef<Substitution> Subs);
public:
/// Get the block storage address to be initialized.
SILValue getBlockStorage() const { return Operands[BlockStorage].get(); }
/// Get the invoke function to form the block around.
SILValue getInvokeFunction() const { return Operands[InvokeFunction].get(); }

ArrayRef<Substitution> getSubstitutions() const {
return {getSubstitutionsStorage(), NumSubstitutions};
}

ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }

Expand Down
26 changes: 23 additions & 3 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3487,15 +3487,22 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
Identifier invoke, type;
SourceLoc invokeLoc, typeLoc;

SILValue invokeVal;
UnresolvedValueName invokeName;
SILType invokeTy;
GenericParamList *invokeGenericParams;

SILType blockType;
SmallVector<ParsedSubstitution, 4> parsedSubs;


if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(invoke, invokeLoc,
diag::expected_tok_in_sil_instr, "invoke") ||
parseTypedValueRef(invokeVal, B) ||
parseValueName(invokeName) ||
parseApplySubstitutions(parsedSubs) ||
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(invokeTy, invokeGenericParams) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(type, typeLoc,
diag::expected_tok_in_sil_instr, "type") ||
Expand All @@ -3512,8 +3519,21 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
return true;
}

auto invokeVal = getLocalValue(invokeName, invokeTy, InstLoc, B);

SmallVector<Substitution, 4> subs;
if (!parsedSubs.empty()) {
if (!invokeGenericParams) {
P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
if (getApplySubstitutionsFromParsed(*this, invokeGenericParams,
parsedSubs, subs))
return true;
}

ResultVal = B.createInitBlockStorageHeader(InstLoc, Val, invokeVal,
blockType);
blockType, subs);
break;
}
}
Expand Down
14 changes: 14 additions & 0 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,20 @@ BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
sizeof(Substitution) * Subs.size());
}

InitBlockStorageHeaderInst *
InitBlockStorageHeaderInst::create(SILFunction &F,
SILDebugLocation DebugLoc, SILValue BlockStorage,
SILValue InvokeFunction, SILType BlockType,
ArrayRef<Substitution> Subs) {
void *Buffer = F.getModule().allocateInst(
sizeof(InitBlockStorageHeaderInst) + sizeof(Substitution) * Subs.size(),
alignof(InitBlockStorageHeaderInst));

return ::new (Buffer) InitBlockStorageHeaderInst(DebugLoc, BlockStorage,
InvokeFunction, BlockType,
Subs);
}

ApplyInst::ApplyInst(SILDebugLocation Loc, SILValue Callee,
SILType SubstCalleeTy, SILType Result,
ArrayRef<Substitution> Subs, ArrayRef<SILValue> Args,
Expand Down
6 changes: 4 additions & 2 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,8 +1348,10 @@ class SILPrinter : public SILVisitor<SILPrinter> {
}
void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *IBSHI) {
*this << "init_block_storage_header " << getIDAndType(IBSHI->getBlockStorage())
<< ", invoke " << getIDAndType(IBSHI->getInvokeFunction())
<< ", type " << IBSHI->getType();
<< ", invoke " << getID(IBSHI->getInvokeFunction());
printSubstitutions(IBSHI->getSubstitutions());
*this << " : " << IBSHI->getInvokeFunction()->getType()
<< ", type " << IBSHI->getType();
}
void visitValueMetatypeInst(ValueMetatypeInst *MI) {
*this << "value_metatype " << MI->getType() << ", "
Expand Down
19 changes: 18 additions & 1 deletion lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2805,9 +2805,26 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"invoke function operand must be a c function");
require(invokeTy->getParameters().size() >= 1,
"invoke function must take at least one parameter");
require(!invokeTy->getGenericSignature() ||
invokeTy->getExtInfo().isPseudogeneric(),
"invoke function must not take reified generic parameters");

if (auto sig = invokeTy->getGenericSignature()) {
require(sig->getGenericParams().size() ==
IBSHI->getSubstitutions().size(),
"instruction must provide substitutions matching invoke "
"function");
invokeTy = invokeTy->substGenericArgs(F.getModule(), M,
IBSHI->getSubstitutions());
} else {
require(IBSHI->getSubstitutions().empty(),
"instruction must not provide substitutions for non-polymorphic "
"invoke fn");
}

auto storageParam = invokeTy->getParameters()[0];
require(storageParam.getConvention() ==
ParameterConvention::Indirect_InoutAliasable,
ParameterConvention::Indirect_InoutAliasable,
"invoke function must take block storage as @inout_aliasable "
"parameter");
require(storageParam.getType() == storageTy,
Expand Down
45 changes: 34 additions & 11 deletions lib/SILGen/SILGenBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "SILGenFunction.h"
#include "RValue.h"
#include "Scope.h"
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/AST.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/ForeignErrorConvention.h"
Expand Down Expand Up @@ -311,37 +312,57 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
// Build the invoke function signature. The block will capture the original
// function value.
auto fnTy = fn.getType().castTo<SILFunctionType>();
auto fnInterfaceTy = cast<SILFunctionType>(CanType(
ArchetypeBuilder::mapTypeOutOfContext(SGM.M.getSwiftModule(),
F.getContextGenericParams(),
fnTy)));
auto blockInterfaceTy = cast<SILFunctionType>(CanType(
ArchetypeBuilder::mapTypeOutOfContext(SGM.M.getSwiftModule(),
F.getContextGenericParams(),
blockTy)));

auto storageTy = SILBlockStorageType::get(fnTy);
auto storageInterfaceTy = SILBlockStorageType::get(fnInterfaceTy);

// Build the invoke function type.
SmallVector<SILParameterInfo, 4> params;
params.push_back(SILParameterInfo(storageTy,
params.push_back(SILParameterInfo(storageInterfaceTy,
ParameterConvention::Indirect_InoutAliasable));
std::copy(blockTy->getParameters().begin(),
blockTy->getParameters().end(),
std::copy(blockInterfaceTy->getParameters().begin(),
blockInterfaceTy->getParameters().end(),
std::back_inserter(params));

// The block invoke function must be pseudogeneric. This should be OK for now
// since a bridgeable function's parameters and returns should all be
// trivially representable in ObjC so not need to exercise the type metadata.
//
// Ultimately we may need to capture generic parameters in block storage, but
// that will require a redesign of the interface to support dependent-layout
// context. Currently we don't capture anything directly into a block but a
// Swift closure, but that's totally dumb.
auto invokeTy =
SILFunctionType::get(nullptr,
SILFunctionType::get(F.getLoweredFunctionType()->getGenericSignature(),
SILFunctionType::ExtInfo()
.withRepresentation(SILFunctionType::Representation::
CFunctionPointer),
CFunctionPointer)
.withIsPseudogeneric(),
ParameterConvention::Direct_Unowned,
params,
blockTy->getAllResults(),
blockTy->getOptionalErrorResult(),
blockInterfaceTy->getAllResults(),
blockInterfaceTy->getOptionalErrorResult(),
getASTContext());

// Create the invoke function. Borrow the mangling scheme from reabstraction
// thunks, which is what we are in spirit.
auto thunk = SGM.getOrCreateReabstractionThunk(nullptr,
auto thunk = SGM.getOrCreateReabstractionThunk(F.getContextGenericParams(),
invokeTy,
fnTy,
blockTy,
fnInterfaceTy,
blockInterfaceTy,
F.isFragile());

// Build it if necessary.
if (thunk->empty()) {
thunk->setContextGenericParams(F.getContextGenericParams());
SILGenFunction thunkSGF(SGM, *thunk);
auto loc = RegularLocation::getAutoGeneratedLocation();
buildFuncToBlockInvokeBody(thunkSGF, loc, blockTy, storageTy, fnTy);
Expand All @@ -356,8 +377,10 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
// reference.
B.createStore(loc, fn.getValue(), capture);
auto invokeFn = B.createFunctionRef(loc, thunk);

auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn,
SILType::getPrimitiveObjectType(blockTy));
SILType::getPrimitiveObjectType(blockTy),
getForwardingSubstitutions());

// Copy the block so we have an independent heap object we can hand off.
auto heapBlock = B.createCopyBlock(loc, stackBlock);
Expand Down
15 changes: 12 additions & 3 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1760,8 +1760,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
break;
}
case ValueKind::InitBlockStorageHeaderInst: {
assert(ListOfValues.size() == 4 &&
"expected 6 values for InitBlockStorageHeader");
assert(ListOfValues.size() == 5 &&
"expected 5 values for InitBlockStorageHeader");
SILType blockTy
= getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);

Expand All @@ -1774,9 +1774,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
SILValueCategory::Object);
SILValue invoke
= getLocalValue(ListOfValues[2], invokeTy);

unsigned NumSub = ListOfValues[4];

SmallVector<Substitution, 4> Substitutions;
while (NumSub--) {
auto sub = MF->maybeReadSubstitution(SILCursor);
assert(sub.hasValue() && "missing substitution");
Substitutions.push_back(*sub);
}

ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke,
blockTy);
blockTy, Substitutions);
break;
}
case ValueKind::UnreachableInst: {
Expand Down
3 changes: 3 additions & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1532,12 +1532,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
ListOfValues.push_back(
S.addTypeRef(IBSHI->getInvokeFunction()->getType().getSwiftRValueType()));
// Always a value, don't need to save category
ListOfValues.push_back(IBSHI->getSubstitutions().size());

SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(IBSHI->getType().getSwiftRValueType()),
(unsigned)IBSHI->getType().getCategory(),
ListOfValues);
S.writeSubstitutions(IBSHI->getSubstitutions(), SILAbbrCodes);

break;
}
case ValueKind::MarkUninitializedBehaviorInst:
Expand Down
3 changes: 3 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
- (T __nonnull)objectAtIndexedSubscript:(uint16_t)i;
- (void)setObject:(T __nonnull)object atIndexedSubscript:(uint16_t)i;

- (void)performBlockOnThings: (T __nonnull (^ __nonnull)(T __nonnull))block;
- (T __nonnull (^ __nonnull)(T __nonnull))blockForPerformingOnThings;

@property (nonatomic) __nullable T propertyThing;
@property (nonatomic) __nullable NSArray<T> *propertyArrayOfThings;
@end
Expand Down
17 changes: 14 additions & 3 deletions test/SILGen/objc_imported_generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public func genericPropertyOnAnyObject(o: AnyObject, b: Bool) -> AnyObject?? {
return o.propertyThing
}

// CHECK-LABEL: sil @_TF21objc_imported_generic26genericPropertyOnAnyObject
// CHECK: dynamic_method_br %4 : $@opened([[TAG:.*]]) AnyObject, #GenericClass.propertyThing!getter.1.foreign, bb1
// CHECK: bb1({{%.*}} : $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):

protocol ThingHolder {
associatedtype Thing

Expand All @@ -52,9 +56,16 @@ protocol ThingHolder {

extension GenericClass: ThingHolder {}

// CHECK-LABEL: sil @_TF21objc_imported_generic26genericPropertyOnAnyObject
// CHECK: dynamic_method_br %4 : $@opened([[TAG:.*]]) AnyObject, #GenericClass.propertyThing!getter.1.foreign, bb1
// CHECK: bb1({{%.*}} : $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):
public func genericBlockBridging<T: AnyObject>(x: GenericClass<T>) {
let block = x.blockForPerformingOnThings()
x.performBlock(onThings: block)
}

// CHECK-LABEL: sil @_TF21objc_imported_generic20genericBlockBridging
// CHECK: [[BLOCK_TO_FUNC:%.*]] = function_ref @_TTRGRxs9AnyObjectrXFdCb_dx_ax_XFo_ox_ox_
// CHECK: partial_apply [[BLOCK_TO_FUNC]]<T>
// CHECK: [[FUNC_TO_BLOCK:%.*]] = function_ref @_TTRGRxs9AnyObjectrXFo_ox_ox_XFdCb_dx_ax_
// CHECK: init_block_storage_header {{.*}} invoke [[FUNC_TO_BLOCK]]<T>

// CHECK-LABEL: sil @_TF21objc_imported_generic20arraysOfGenericParam
public func arraysOfGenericParam<T: AnyObject>(y: Array<T>) {
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/objc_thunks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ func registerAnsible() {

// FIXME: would be nice if we didn't need to re-abstract as much here.

// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFo_oGSqFT_T____XFdCb_dGSqbT_T____ : $@convention(c) (@inout_aliasable @block_storage @callee_owned (@owned Optional<() -> ()>) -> (), Optional<@convention(block) () -> ()>) -> ()
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFo_oGSqFT_T____XFdCb_dGSqbT_T____ : $@convention(c) @pseudogeneric (@inout_aliasable @block_storage @callee_owned (@owned Optional<() -> ()>) -> (), Optional<@convention(block) () -> ()>) -> ()
// CHECK: [[HEAP_BLOCK_IUO:%.*]] = copy_block %1
// CHECK: select_enum [[HEAP_BLOCK_IUO]]
// CHECK: bb1:
Expand Down