Skip to content

Commit fb83d45

Browse files
committed
Merge pull request #2833 from jckarter/func-to-block-generic-params
2 parents eaa3201 + 9398ce9 commit fb83d45

File tree

13 files changed

+156
-31
lines changed

13 files changed

+156
-31
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,10 @@ class SILBuilder {
985985

986986
InitBlockStorageHeaderInst *
987987
createInitBlockStorageHeader(SILLocation Loc, SILValue BlockStorage,
988-
SILValue InvokeFunction, SILType BlockType) {
989-
return insert(new (F.getModule()) InitBlockStorageHeaderInst(
990-
getSILDebugLocation(Loc), BlockStorage, InvokeFunction, BlockType));
988+
SILValue InvokeFunction, SILType BlockType,
989+
ArrayRef<Substitution> Subs) {
990+
return insert(InitBlockStorageHeaderInst::create(F,
991+
getSILDebugLocation(Loc), BlockStorage, InvokeFunction, BlockType, Subs));
991992
}
992993

993994
MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype) {

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,8 @@ void SILCloner<ImplClass>::visitInitBlockStorageHeaderInst(
18771877
getOpLocation(Inst->getLoc()),
18781878
getOpValue(Inst->getBlockStorage()),
18791879
getOpValue(Inst->getInvokeFunction()),
1880-
getOpType(Inst->getType())));
1880+
getOpType(Inst->getType()),
1881+
getOpSubstitutions(Inst->getSubstitutions())));
18811882
}
18821883

18831884
template <typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3336,20 +3336,41 @@ class InitBlockStorageHeaderInst : public SILInstruction {
33363336
friend class SILBuilder;
33373337

33383338
enum { BlockStorage, InvokeFunction };
3339+
unsigned NumSubstitutions;
33393340
FixedOperandList<2> Operands;
3341+
3342+
Substitution *getSubstitutionsStorage() {
3343+
return reinterpret_cast<Substitution*>(Operands.asArray().end());
3344+
}
3345+
const Substitution *getSubstitutionsStorage() const {
3346+
return reinterpret_cast<const Substitution*>(Operands.asArray().end());
3347+
}
33403348

33413349
InitBlockStorageHeaderInst(SILDebugLocation DebugLoc, SILValue BlockStorage,
3342-
SILValue InvokeFunction, SILType BlockType)
3350+
SILValue InvokeFunction, SILType BlockType,
3351+
ArrayRef<Substitution> Subs)
33433352
: SILInstruction(ValueKind::InitBlockStorageHeaderInst, DebugLoc,
33443353
BlockType),
3345-
Operands(this, BlockStorage, InvokeFunction) {}
3346-
3354+
NumSubstitutions(Subs.size()),
3355+
Operands(this, BlockStorage, InvokeFunction) {
3356+
memcpy(getSubstitutionsStorage(), Subs.begin(),
3357+
sizeof(Subs[0]) * Subs.size());
3358+
}
3359+
3360+
static InitBlockStorageHeaderInst *create(SILFunction &F,
3361+
SILDebugLocation DebugLoc, SILValue BlockStorage,
3362+
SILValue InvokeFunction, SILType BlockType,
3363+
ArrayRef<Substitution> Subs);
33473364
public:
33483365
/// Get the block storage address to be initialized.
33493366
SILValue getBlockStorage() const { return Operands[BlockStorage].get(); }
33503367
/// Get the invoke function to form the block around.
33513368
SILValue getInvokeFunction() const { return Operands[InvokeFunction].get(); }
33523369

3370+
ArrayRef<Substitution> getSubstitutions() const {
3371+
return {getSubstitutionsStorage(), NumSubstitutions};
3372+
}
3373+
33533374
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
33543375
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
33553376

lib/Parse/ParseSIL.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,15 +3487,22 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
34873487
Identifier invoke, type;
34883488
SourceLoc invokeLoc, typeLoc;
34893489

3490-
SILValue invokeVal;
3490+
UnresolvedValueName invokeName;
3491+
SILType invokeTy;
3492+
GenericParamList *invokeGenericParams;
34913493

34923494
SILType blockType;
3495+
SmallVector<ParsedSubstitution, 4> parsedSubs;
3496+
34933497

34943498
if (parseTypedValueRef(Val, B) ||
34953499
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
34963500
parseSILIdentifier(invoke, invokeLoc,
34973501
diag::expected_tok_in_sil_instr, "invoke") ||
3498-
parseTypedValueRef(invokeVal, B) ||
3502+
parseValueName(invokeName) ||
3503+
parseApplySubstitutions(parsedSubs) ||
3504+
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
3505+
parseSILType(invokeTy, invokeGenericParams) ||
34993506
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
35003507
parseSILIdentifier(type, typeLoc,
35013508
diag::expected_tok_in_sil_instr, "type") ||
@@ -3512,8 +3519,21 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
35123519
return true;
35133520
}
35143521

3522+
auto invokeVal = getLocalValue(invokeName, invokeTy, InstLoc, B);
3523+
3524+
SmallVector<Substitution, 4> subs;
3525+
if (!parsedSubs.empty()) {
3526+
if (!invokeGenericParams) {
3527+
P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type);
3528+
return true;
3529+
}
3530+
if (getApplySubstitutionsFromParsed(*this, invokeGenericParams,
3531+
parsedSubs, subs))
3532+
return true;
3533+
}
3534+
35153535
ResultVal = B.createInitBlockStorageHeader(InstLoc, Val, invokeVal,
3516-
blockType);
3536+
blockType, subs);
35173537
break;
35183538
}
35193539
}

lib/SIL/SILInstructions.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,20 @@ BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
184184
sizeof(Substitution) * Subs.size());
185185
}
186186

187+
InitBlockStorageHeaderInst *
188+
InitBlockStorageHeaderInst::create(SILFunction &F,
189+
SILDebugLocation DebugLoc, SILValue BlockStorage,
190+
SILValue InvokeFunction, SILType BlockType,
191+
ArrayRef<Substitution> Subs) {
192+
void *Buffer = F.getModule().allocateInst(
193+
sizeof(InitBlockStorageHeaderInst) + sizeof(Substitution) * Subs.size(),
194+
alignof(InitBlockStorageHeaderInst));
195+
196+
return ::new (Buffer) InitBlockStorageHeaderInst(DebugLoc, BlockStorage,
197+
InvokeFunction, BlockType,
198+
Subs);
199+
}
200+
187201
ApplyInst::ApplyInst(SILDebugLocation Loc, SILValue Callee,
188202
SILType SubstCalleeTy, SILType Result,
189203
ArrayRef<Substitution> Subs, ArrayRef<SILValue> Args,

lib/SIL/SILPrinter.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,8 +1348,10 @@ class SILPrinter : public SILVisitor<SILPrinter> {
13481348
}
13491349
void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *IBSHI) {
13501350
*this << "init_block_storage_header " << getIDAndType(IBSHI->getBlockStorage())
1351-
<< ", invoke " << getIDAndType(IBSHI->getInvokeFunction())
1352-
<< ", type " << IBSHI->getType();
1351+
<< ", invoke " << getID(IBSHI->getInvokeFunction());
1352+
printSubstitutions(IBSHI->getSubstitutions());
1353+
*this << " : " << IBSHI->getInvokeFunction()->getType()
1354+
<< ", type " << IBSHI->getType();
13531355
}
13541356
void visitValueMetatypeInst(ValueMetatypeInst *MI) {
13551357
*this << "value_metatype " << MI->getType() << ", "

lib/SIL/SILVerifier.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2805,9 +2805,26 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
28052805
"invoke function operand must be a c function");
28062806
require(invokeTy->getParameters().size() >= 1,
28072807
"invoke function must take at least one parameter");
2808+
require(!invokeTy->getGenericSignature() ||
2809+
invokeTy->getExtInfo().isPseudogeneric(),
2810+
"invoke function must not take reified generic parameters");
2811+
2812+
if (auto sig = invokeTy->getGenericSignature()) {
2813+
require(sig->getGenericParams().size() ==
2814+
IBSHI->getSubstitutions().size(),
2815+
"instruction must provide substitutions matching invoke "
2816+
"function");
2817+
invokeTy = invokeTy->substGenericArgs(F.getModule(), M,
2818+
IBSHI->getSubstitutions());
2819+
} else {
2820+
require(IBSHI->getSubstitutions().empty(),
2821+
"instruction must not provide substitutions for non-polymorphic "
2822+
"invoke fn");
2823+
}
2824+
28082825
auto storageParam = invokeTy->getParameters()[0];
28092826
require(storageParam.getConvention() ==
2810-
ParameterConvention::Indirect_InoutAliasable,
2827+
ParameterConvention::Indirect_InoutAliasable,
28112828
"invoke function must take block storage as @inout_aliasable "
28122829
"parameter");
28132830
require(storageParam.getType() == storageTy,

lib/SILGen/SILGenBridging.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "SILGenFunction.h"
1414
#include "RValue.h"
1515
#include "Scope.h"
16+
#include "swift/AST/ArchetypeBuilder.h"
1617
#include "swift/AST/AST.h"
1718
#include "swift/AST/DiagnosticsSIL.h"
1819
#include "swift/AST/ForeignErrorConvention.h"
@@ -311,37 +312,57 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
311312
// Build the invoke function signature. The block will capture the original
312313
// function value.
313314
auto fnTy = fn.getType().castTo<SILFunctionType>();
315+
auto fnInterfaceTy = cast<SILFunctionType>(CanType(
316+
ArchetypeBuilder::mapTypeOutOfContext(SGM.M.getSwiftModule(),
317+
F.getContextGenericParams(),
318+
fnTy)));
319+
auto blockInterfaceTy = cast<SILFunctionType>(CanType(
320+
ArchetypeBuilder::mapTypeOutOfContext(SGM.M.getSwiftModule(),
321+
F.getContextGenericParams(),
322+
blockTy)));
323+
314324
auto storageTy = SILBlockStorageType::get(fnTy);
325+
auto storageInterfaceTy = SILBlockStorageType::get(fnInterfaceTy);
315326

316327
// Build the invoke function type.
317328
SmallVector<SILParameterInfo, 4> params;
318-
params.push_back(SILParameterInfo(storageTy,
329+
params.push_back(SILParameterInfo(storageInterfaceTy,
319330
ParameterConvention::Indirect_InoutAliasable));
320-
std::copy(blockTy->getParameters().begin(),
321-
blockTy->getParameters().end(),
331+
std::copy(blockInterfaceTy->getParameters().begin(),
332+
blockInterfaceTy->getParameters().end(),
322333
std::back_inserter(params));
323334

335+
// The block invoke function must be pseudogeneric. This should be OK for now
336+
// since a bridgeable function's parameters and returns should all be
337+
// trivially representable in ObjC so not need to exercise the type metadata.
338+
//
339+
// Ultimately we may need to capture generic parameters in block storage, but
340+
// that will require a redesign of the interface to support dependent-layout
341+
// context. Currently we don't capture anything directly into a block but a
342+
// Swift closure, but that's totally dumb.
324343
auto invokeTy =
325-
SILFunctionType::get(nullptr,
344+
SILFunctionType::get(F.getLoweredFunctionType()->getGenericSignature(),
326345
SILFunctionType::ExtInfo()
327346
.withRepresentation(SILFunctionType::Representation::
328-
CFunctionPointer),
347+
CFunctionPointer)
348+
.withIsPseudogeneric(),
329349
ParameterConvention::Direct_Unowned,
330350
params,
331-
blockTy->getAllResults(),
332-
blockTy->getOptionalErrorResult(),
351+
blockInterfaceTy->getAllResults(),
352+
blockInterfaceTy->getOptionalErrorResult(),
333353
getASTContext());
334354

335355
// Create the invoke function. Borrow the mangling scheme from reabstraction
336356
// thunks, which is what we are in spirit.
337-
auto thunk = SGM.getOrCreateReabstractionThunk(nullptr,
357+
auto thunk = SGM.getOrCreateReabstractionThunk(F.getContextGenericParams(),
338358
invokeTy,
339-
fnTy,
340-
blockTy,
359+
fnInterfaceTy,
360+
blockInterfaceTy,
341361
F.isFragile());
342362

343363
// Build it if necessary.
344364
if (thunk->empty()) {
365+
thunk->setContextGenericParams(F.getContextGenericParams());
345366
SILGenFunction thunkSGF(SGM, *thunk);
346367
auto loc = RegularLocation::getAutoGeneratedLocation();
347368
buildFuncToBlockInvokeBody(thunkSGF, loc, blockTy, storageTy, fnTy);
@@ -356,8 +377,10 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
356377
// reference.
357378
B.createStore(loc, fn.getValue(), capture);
358379
auto invokeFn = B.createFunctionRef(loc, thunk);
380+
359381
auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn,
360-
SILType::getPrimitiveObjectType(blockTy));
382+
SILType::getPrimitiveObjectType(blockTy),
383+
getForwardingSubstitutions());
361384

362385
// Copy the block so we have an independent heap object we can hand off.
363386
auto heapBlock = B.createCopyBlock(loc, stackBlock);

lib/Serialization/DeserializeSIL.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,8 +1760,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
17601760
break;
17611761
}
17621762
case ValueKind::InitBlockStorageHeaderInst: {
1763-
assert(ListOfValues.size() == 4 &&
1764-
"expected 6 values for InitBlockStorageHeader");
1763+
assert(ListOfValues.size() == 5 &&
1764+
"expected 5 values for InitBlockStorageHeader");
17651765
SILType blockTy
17661766
= getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
17671767

@@ -1774,9 +1774,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
17741774
SILValueCategory::Object);
17751775
SILValue invoke
17761776
= getLocalValue(ListOfValues[2], invokeTy);
1777+
1778+
unsigned NumSub = ListOfValues[4];
17771779

1780+
SmallVector<Substitution, 4> Substitutions;
1781+
while (NumSub--) {
1782+
auto sub = MF->maybeReadSubstitution(SILCursor);
1783+
assert(sub.hasValue() && "missing substitution");
1784+
Substitutions.push_back(*sub);
1785+
}
1786+
17781787
ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke,
1779-
blockTy);
1788+
blockTy, Substitutions);
17801789
break;
17811790
}
17821791
case ValueKind::UnreachableInst: {

lib/Serialization/SerializeSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,12 +1532,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
15321532
ListOfValues.push_back(
15331533
S.addTypeRef(IBSHI->getInvokeFunction()->getType().getSwiftRValueType()));
15341534
// Always a value, don't need to save category
1535+
ListOfValues.push_back(IBSHI->getSubstitutions().size());
15351536

15361537
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
15371538
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
15381539
S.addTypeRef(IBSHI->getType().getSwiftRValueType()),
15391540
(unsigned)IBSHI->getType().getCategory(),
15401541
ListOfValues);
1542+
S.writeSubstitutions(IBSHI->getSubstitutions(), SILAbbrCodes);
1543+
15411544
break;
15421545
}
15431546
case ValueKind::MarkUninitializedBehaviorInst:

test/Inputs/clang-importer-sdk/usr/include/objc_generics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
- (T __nonnull)objectAtIndexedSubscript:(uint16_t)i;
1414
- (void)setObject:(T __nonnull)object atIndexedSubscript:(uint16_t)i;
1515

16+
- (void)performBlockOnThings: (T __nonnull (^ __nonnull)(T __nonnull))block;
17+
- (T __nonnull (^ __nonnull)(T __nonnull))blockForPerformingOnThings;
18+
1619
@property (nonatomic) __nullable T propertyThing;
1720
@property (nonatomic) __nullable NSArray<T> *propertyArrayOfThings;
1821
@end

test/SILGen/objc_imported_generic.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public func genericPropertyOnAnyObject(o: AnyObject, b: Bool) -> AnyObject?? {
3737
return o.propertyThing
3838
}
3939

40+
// CHECK-LABEL: sil @_TF21objc_imported_generic26genericPropertyOnAnyObject
41+
// CHECK: dynamic_method_br %4 : $@opened([[TAG:.*]]) AnyObject, #GenericClass.propertyThing!getter.1.foreign, bb1
42+
// CHECK: bb1({{%.*}} : $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):
43+
4044
protocol ThingHolder {
4145
associatedtype Thing
4246

@@ -52,9 +56,16 @@ protocol ThingHolder {
5256

5357
extension GenericClass: ThingHolder {}
5458

55-
// CHECK-LABEL: sil @_TF21objc_imported_generic26genericPropertyOnAnyObject
56-
// CHECK: dynamic_method_br %4 : $@opened([[TAG:.*]]) AnyObject, #GenericClass.propertyThing!getter.1.foreign, bb1
57-
// CHECK: bb1({{%.*}} : $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):
59+
public func genericBlockBridging<T: AnyObject>(x: GenericClass<T>) {
60+
let block = x.blockForPerformingOnThings()
61+
x.performBlock(onThings: block)
62+
}
63+
64+
// CHECK-LABEL: sil @_TF21objc_imported_generic20genericBlockBridging
65+
// CHECK: [[BLOCK_TO_FUNC:%.*]] = function_ref @_TTRGRxs9AnyObjectrXFdCb_dx_ax_XFo_ox_ox_
66+
// CHECK: partial_apply [[BLOCK_TO_FUNC]]<T>
67+
// CHECK: [[FUNC_TO_BLOCK:%.*]] = function_ref @_TTRGRxs9AnyObjectrXFo_ox_ox_XFdCb_dx_ax_
68+
// CHECK: init_block_storage_header {{.*}} invoke [[FUNC_TO_BLOCK]]<T>
5869

5970
// CHECK-LABEL: sil @_TF21objc_imported_generic20arraysOfGenericParam
6071
public func arraysOfGenericParam<T: AnyObject>(y: Array<T>) {

test/SILGen/objc_thunks.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func registerAnsible() {
407407

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

410-
// 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) () -> ()>) -> ()
410+
// 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) () -> ()>) -> ()
411411
// CHECK: [[HEAP_BLOCK_IUO:%.*]] = copy_block %1
412412
// CHECK: select_enum [[HEAP_BLOCK_IUO]]
413413
// CHECK: bb1:

0 commit comments

Comments
 (0)