Skip to content

Commit 5f45820

Browse files
[AST] Store Clang type in SILFunctionType for @convention(c) functions.
1 parent bfa2f98 commit 5f45820

File tree

10 files changed

+192
-89
lines changed

10 files changed

+192
-89
lines changed

include/swift/AST/Types.h

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444

4545
namespace clang {
4646
class Type;
47-
class FunctionType;
4847
} // namespace clang
4948

5049
namespace llvm {
@@ -2947,6 +2946,7 @@ class AnyFunctionType : public TypeBase {
29472946
friend ExtInfo;
29482947
friend class AnyFunctionType;
29492948
friend class FunctionType;
2949+
friend class SILUncommonInfo;
29502950
// We preserve a full clang::Type *, not a clang::FunctionType * as:
29512951
// 1. We need to keep sugar in case we need to present an error to the user.
29522952
// 2. The actual type being stored is [ignoring sugar] either a
@@ -3917,6 +3917,24 @@ namespace Lowering {
39173917
class TypeConverter;
39183918
};
39193919

3920+
class SILUncommonInfo {
3921+
friend class SILFunctionType;
3922+
3923+
// Invariant: The FunctionType is canonical.
3924+
// We store a clang::FunctionType * instead of a clang::CanQualType to
3925+
// avoid depending on the Clang AST in this header.
3926+
const clang::Type *ClangFunctionType;
3927+
3928+
bool empty() const { return !ClangFunctionType; }
3929+
SILUncommonInfo(const clang::Type *type) : ClangFunctionType(type) {}
3930+
SILUncommonInfo(AnyFunctionType::ExtInfo::Uncommon uncommon);
3931+
3932+
public:
3933+
/// Analog of AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType.
3934+
void printClangFunctionType(ClangModuleLoader *cml,
3935+
llvm::raw_ostream &os) const;
3936+
};
3937+
39203938
/// SILFunctionType - The lowered type of a function value, suitable
39213939
/// for use by SIL.
39223940
///
@@ -3925,7 +3943,8 @@ namespace Lowering {
39253943
/// function parameter and result types.
39263944
class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
39273945
private llvm::TrailingObjects<SILFunctionType, SILParameterInfo,
3928-
SILResultInfo, SILYieldInfo, CanType> {
3946+
SILResultInfo, SILYieldInfo, CanType,
3947+
SILUncommonInfo> {
39293948
friend TrailingObjects;
39303949

39313950
size_t numTrailingObjects(OverloadToken<SILParameterInfo>) const {
@@ -3944,6 +3963,10 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
39443963
return hasResultCache() ? 2 : 0;
39453964
}
39463965

3966+
size_t numTrailingObjects(OverloadToken<SILUncommonInfo>) const {
3967+
return Bits.SILFunctionType.HasUncommonInfo ? 1 : 0;
3968+
}
3969+
39473970
public:
39483971
using Language = SILFunctionLanguage;
39493972
using Representation = SILFunctionTypeRepresentation;
@@ -3968,27 +3991,31 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
39683991

39693992
unsigned Bits; // Naturally sized for speed.
39703993

3971-
class Uncommon {
3972-
friend ExtInfo;
3973-
friend class SILFunctionType;
3974-
3975-
// Invariant: The FunctionType is canonical.
3976-
// We store a clang::FunctionType * instead of a clang::CanQualType to
3977-
// avoid depending on the Clang AST in this header.
3978-
const clang::FunctionType *ClangFunctionType;
3994+
// For symmetry with AnyFunctionType::Uncommon
3995+
using Uncommon = SILUncommonInfo;
39793996

3980-
bool empty() const { return !ClangFunctionType; }
3981-
Uncommon(const clang::FunctionType *type) : ClangFunctionType(type) {}
3997+
Uncommon Other;
39823998

3983-
public:
3984-
/// Analog of AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType.
3985-
void printClangFunctionType(ClangModuleLoader *cml,
3986-
llvm::raw_ostream &os) const;
3987-
};
3999+
static void assertIsFunctionType(const clang::Type *);
39884000

3989-
Uncommon Other;
4001+
ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) {
4002+
auto Rep = Representation(Bits & RepresentationMask);
4003+
// TODO: [clang-function-type-serialization] Once we start serializing
4004+
// the Clang type, we should also assert that the pointer is non-null.
4005+
if ((Rep == Representation::CFunctionPointer) && Other.ClangFunctionType)
4006+
assertIsFunctionType(Other.ClangFunctionType);
4007+
}
39904008

3991-
ExtInfo(unsigned Bits, Uncommon Other) : Bits(Bits), Other(Other) {}
4009+
static constexpr unsigned makeBits(Representation rep,
4010+
bool isPseudogeneric,
4011+
bool isNoEscape,
4012+
DifferentiabilityKind diffKind) {
4013+
return ((unsigned) rep)
4014+
| (isPseudogeneric ? PseudogenericMask : 0)
4015+
| (isNoEscape ? NoEscapeMask : 0)
4016+
| (((unsigned)diffKind << DifferentiabilityMaskOffset)
4017+
& DifferentiabilityMask);
4018+
}
39924019

39934020
friend class SILFunctionType;
39944021
public:
@@ -3998,15 +4025,21 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
39984025
// Constructor for polymorphic type.
39994026
ExtInfo(Representation rep, bool isPseudogeneric, bool isNoEscape,
40004027
DifferentiabilityKind diffKind,
4001-
const clang::FunctionType *type)
4002-
: ExtInfo(((unsigned) rep)
4003-
| (isPseudogeneric ? PseudogenericMask : 0)
4004-
| (isNoEscape ? NoEscapeMask : 0)
4005-
| (((unsigned)diffKind << DifferentiabilityMaskOffset)
4006-
& DifferentiabilityMask),
4028+
const clang::Type *type)
4029+
: ExtInfo(makeBits(rep, isPseudogeneric, isNoEscape, diffKind),
40074030
Uncommon(type)) {
40084031
}
40094032

4033+
ExtInfo(AnyFunctionType::ExtInfo info, bool isPseudogeneric)
4034+
: ExtInfo(makeBits(info.getSILRepresentation(),
4035+
isPseudogeneric,
4036+
info.isNoEscape(),
4037+
info.getDifferentiabilityKind()),
4038+
info.getUncommonInfo().hasValue()
4039+
? Uncommon(info.getUncommonInfo().getValue())
4040+
: Uncommon(nullptr)) {
4041+
}
4042+
40104043
static ExtInfo getThin() {
40114044
return ExtInfo(Representation::Thin, false, false,
40124045
DifferentiabilityKind::NonDifferentiable, nullptr);
@@ -4093,6 +4126,9 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
40934126
return ExtInfo(NoEscape ? (Bits | NoEscapeMask) : (Bits & ~NoEscapeMask),
40944127
Other);
40954128
}
4129+
ExtInfo withClangFunctionType(const clang::Type *type) const {
4130+
return ExtInfo(Bits, Uncommon(type));
4131+
}
40964132

40974133
std::pair<unsigned, const void *> getFuncAttrKey() const {
40984134
return std::make_pair(Bits, Other.ClangFunctionType);
@@ -4388,7 +4424,7 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
43884424
return WitnessMethodConformance;
43894425
}
43904426

4391-
const clang::FunctionType *getClangFunctionType() const;
4427+
const clang::Type *getClangFunctionType() const;
43924428

43934429
ExtInfo getExtInfo() const {
43944430
return ExtInfo(Bits.SILFunctionType.ExtInfoBits, getClangFunctionType());

lib/AST/ASTContext.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3158,7 +3158,13 @@ ArrayRef<Requirement> GenericFunctionType::getRequirements() const {
31583158
return Signature->getRequirements();
31593159
}
31603160

3161-
void SILFunctionType::ExtInfo::Uncommon::printClangFunctionType(
3161+
SILUncommonInfo::SILUncommonInfo(AnyFunctionType::ExtInfo::Uncommon uncommon) {
3162+
auto *ty = uncommon.ClangFunctionType;
3163+
ClangFunctionType = ty ? ty->getCanonicalTypeInternal().getTypePtr()
3164+
: nullptr;
3165+
}
3166+
3167+
void SILUncommonInfo::printClangFunctionType(
31623168
ClangModuleLoader *cml, llvm::raw_ostream &os) const {
31633169
cml->printClangType(ClangFunctionType, os);
31643170
}
@@ -3224,11 +3230,11 @@ SILFunctionType::SILFunctionType(
32243230

32253231
Bits.SILFunctionType.HasErrorResult = errorResult.hasValue();
32263232
Bits.SILFunctionType.ExtInfoBits = ext.Bits;
3227-
Bits.SILFunctionType.HasUncommonInfo = false;
32283233
// The use of both assert() and static_assert() below is intentional.
32293234
assert(Bits.SILFunctionType.ExtInfoBits == ext.Bits && "Bits were dropped!");
32303235
static_assert(ExtInfo::NumMaskBits == NumSILExtInfoBits,
32313236
"ExtInfo and SILFunctionTypeBitfields must agree on bit size");
3237+
Bits.SILFunctionType.HasUncommonInfo = ext.getUncommonInfo().hasValue();
32323238
Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind);
32333239
NumParameters = params.size();
32343240
if (coroutineKind == SILCoroutineKind::None) {
@@ -3261,6 +3267,9 @@ SILFunctionType::SILFunctionType(
32613267
getMutableFormalResultsCache() = CanType();
32623268
getMutableAllResultsCache() = CanType();
32633269
}
3270+
if (auto uncommon = ext.getUncommonInfo())
3271+
*getTrailingObjects<ExtInfo::Uncommon>() = uncommon.getValue();
3272+
32643273
#ifndef NDEBUG
32653274
if (ext.getRepresentation() == Representation::WitnessMethod)
32663275
assert(!WitnessMethodConformance.isInvalid() &&
@@ -3360,6 +3369,10 @@ CanSILFunctionType SILFunctionType::get(
33603369
assert(coroutineKind != SILCoroutineKind::None || yields.empty());
33613370
assert(!ext.isPseudogeneric() || genericSig);
33623371

3372+
// FIXME: [clang-function-type-serialization] Don't drop the Clang type...
3373+
if (!ctx.LangOpts.UseClangFunctionTypes)
3374+
ext = ext.withClangFunctionType(nullptr);
3375+
33633376
llvm::FoldingSetNodeID id;
33643377
SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params,
33653378
yields, normalResults, errorResult,
@@ -3376,10 +3389,11 @@ CanSILFunctionType SILFunctionType::get(
33763389

33773390
// See [SILFunctionType-layout]
33783391
bool hasResultCache = normalResults.size() > 1;
3379-
size_t bytes =
3380-
totalSizeToAlloc<SILParameterInfo, SILResultInfo, SILYieldInfo, CanType>(
3392+
size_t bytes = totalSizeToAlloc<SILParameterInfo, SILResultInfo, SILYieldInfo,
3393+
CanType, SILFunctionType::ExtInfo::Uncommon>(
33813394
params.size(), normalResults.size() + (errorResult ? 1 : 0),
3382-
yields.size(), hasResultCache ? 2 : 0);
3395+
yields.size(), hasResultCache ? 2 : 0,
3396+
ext.getUncommonInfo().hasValue() ? 1 : 0);
33833397

33843398
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));
33853399

lib/AST/ASTDemangler.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,12 +488,6 @@ Type ASTBuilder::createImplFunctionType(
488488
break;
489489
}
490490

491-
// TODO: [store-sil-clang-function-type]
492-
auto einfo = SILFunctionType::ExtInfo(
493-
representation, flags.isPseudogeneric(), !flags.isEscaping(),
494-
DifferentiabilityKind::NonDifferentiable,
495-
/*clangFunctionType*/ nullptr);
496-
497491
llvm::SmallVector<SILParameterInfo, 8> funcParams;
498492
llvm::SmallVector<SILYieldInfo, 8> funcYields;
499493
llvm::SmallVector<SILResultInfo, 8> funcResults;
@@ -516,6 +510,26 @@ Type ASTBuilder::createImplFunctionType(
516510
auto conv = getResultConvention(errorResult->getConvention());
517511
funcErrorResult.emplace(type, conv);
518512
}
513+
514+
const clang::Type *clangFnType = nullptr;
515+
auto incompleteExtInfo = SILFunctionType::ExtInfo(
516+
SILFunctionType::Representation::Thick, flags.isPseudogeneric(),
517+
!flags.isEscaping(), DifferentiabilityKind::NonDifferentiable,
518+
clangFnType);
519+
520+
if (representation == SILFunctionType::Representation::CFunctionPointer) {
521+
assert(funcResults.size() <= 1 && funcYields.size() == 0
522+
&& "@convention(c) functions have at most 1 result and 0 yields.");
523+
auto result = funcResults.empty() ? Optional<SILResultInfo>()
524+
: funcResults[0];
525+
auto &Context = getASTContext();
526+
clangFnType = Context.getCanonicalClangFunctionType(funcParams, result,
527+
incompleteExtInfo,
528+
representation);
529+
}
530+
auto einfo = incompleteExtInfo.withRepresentation(representation)
531+
.withClangFunctionType(clangFnType);
532+
519533
return SILFunctionType::get(genericSig, einfo, funcCoroutineKind,
520534
funcCalleeConvention, funcParams, funcYields,
521535
funcResults, funcErrorResult,

lib/AST/Type.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3229,8 +3229,7 @@ void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType(
32293229
cml->printClangType(ClangFunctionType, os);
32303230
}
32313231

3232-
void
3233-
AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
3232+
static void assertIsFunctionType(const clang::Type *type) {
32343233
#ifndef NDEBUG
32353234
if (!(type->isFunctionPointerType() || type->isBlockPointerType())) {
32363235
SmallString<256> buf;
@@ -3244,6 +3243,10 @@ AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
32443243
return;
32453244
}
32463245

3246+
void AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
3247+
::assertIsFunctionType(type);
3248+
}
3249+
32473250
const clang::Type *AnyFunctionType::getClangFunctionType() const {
32483251
switch (getKind()) {
32493252
case TypeKind::Function:
@@ -3261,9 +3264,16 @@ const clang::Type *AnyFunctionType::getCanonicalClangFunctionType() const {
32613264
return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr;
32623265
}
32633266

3264-
// TODO: [store-sil-clang-function-type]
3265-
const clang::FunctionType *SILFunctionType::getClangFunctionType() const {
3266-
return nullptr;
3267+
void SILFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
3268+
::assertIsFunctionType(type);
3269+
}
3270+
3271+
const clang::Type *SILFunctionType::getClangFunctionType() const {
3272+
if (!Bits.SILFunctionType.HasUncommonInfo)
3273+
return nullptr;
3274+
auto *type = getTrailingObjects<ExtInfo::Uncommon>()->ClangFunctionType;
3275+
assert(type && "If the pointer was null, we shouldn't have stored it.");
3276+
return type;
32673277
}
32683278

32693279
FunctionType *

lib/ClangImporter/ImportType.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,11 @@ namespace {
416416

417417
if (pointeeQualType->isFunctionType()) {
418418
auto funcTy = pointeeType->castTo<FunctionType>();
419-
return {
420-
FunctionType::get(funcTy->getParams(), funcTy->getResult(),
421-
funcTy->getExtInfo()
422-
.withRepresentation(
419+
auto extInfo = funcTy->getExtInfo().withRepresentation(
423420
AnyFunctionType::Representation::CFunctionPointer)
424-
.withClangFunctionType(type)),
421+
.withClangFunctionType(type);
422+
return {
423+
FunctionType::get(funcTy->getParams(), funcTy->getResult(), extInfo),
425424
ImportHint::CFunctionPointer
426425
};
427426
}

lib/SIL/SILFunctionType.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,10 +1266,7 @@ static CanSILFunctionType getSILFunctionType(
12661266

12671267
// NOTE: SILFunctionType::ExtInfo doesn't track everything that
12681268
// AnyFunctionType::ExtInfo tracks. For example: 'throws' or 'auto-closure'
1269-
auto silExtInfo = SILFunctionType::ExtInfo()
1270-
.withRepresentation(extInfo.getSILRepresentation())
1271-
.withIsPseudogeneric(pseudogeneric)
1272-
.withNoEscape(extInfo.isNoEscape());
1269+
SILFunctionType::ExtInfo silExtInfo(extInfo, pseudogeneric);
12731270

12741271
// Build the substituted generic signature we extracted.
12751272
bool impliedSignature = false;

lib/SILGen/SILGen.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,6 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess,
452452

453453
SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
454454
ASTContext &C = getASTContext();
455-
auto extInfo = SILFunctionType::ExtInfo()
456-
.withRepresentation(SILFunctionType::Representation::CFunctionPointer);
457455

458456
// Use standard library types if we have them; otherwise, fall back to
459457
// builtins.
@@ -484,13 +482,19 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
484482
SILParameterInfo(PtrPtrInt8Ty, ParameterConvention::Direct_Unowned),
485483
};
486484

485+
SILResultInfo results[] = {SILResultInfo(Int32Ty, ResultConvention::Unowned)};
486+
487+
auto rep = SILFunctionType::Representation::CFunctionPointer;
488+
auto incompleteExtInfo = SILFunctionType::ExtInfo();
489+
auto *clangTy = C.getCanonicalClangFunctionType(params, results[0],
490+
incompleteExtInfo, rep);
491+
auto extInfo = incompleteExtInfo.withRepresentation(rep)
492+
.withClangFunctionType(clangTy);
493+
487494
CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo,
488495
SILCoroutineKind::None,
489496
ParameterConvention::Direct_Unowned,
490-
params, /*yields*/ {},
491-
SILResultInfo(Int32Ty,
492-
ResultConvention::Unowned),
493-
None,
497+
params, /*yields*/ {}, results, None,
494498
SubstitutionMap(), false,
495499
C);
496500

lib/SILGen/SILGenBridging.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,16 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
541541
blockInterfaceTy->getParameters().end(),
542542
std::back_inserter(params));
543543

544-
auto extInfo =
545-
SILFunctionType::ExtInfo()
546-
.withRepresentation(SILFunctionType::Representation::CFunctionPointer);
544+
auto results = blockInterfaceTy->getResults();
545+
auto incompleteExtInfo = SILFunctionType::ExtInfo();
546+
auto *clangFnType = getASTContext().getCanonicalClangFunctionType(
547+
params, results.empty() ? Optional<SILResultInfo>() : results[0],
548+
incompleteExtInfo,
549+
SILFunctionType::Representation::CFunctionPointer);
550+
551+
auto extInfo = incompleteExtInfo
552+
.withRepresentation(SILFunctionType::Representation::CFunctionPointer)
553+
.withClangFunctionType(clangFnType);
547554

548555
CanGenericSignature genericSig;
549556
GenericEnvironment *genericEnv = nullptr;
@@ -568,8 +575,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
568575

569576
auto invokeTy = SILFunctionType::get(
570577
genericSig, extInfo, SILCoroutineKind::None,
571-
ParameterConvention::Direct_Unowned, params,
572-
/*yields*/ {}, blockInterfaceTy->getResults(),
578+
ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results,
573579
blockInterfaceTy->getOptionalErrorResult(), SubstitutionMap(), false,
574580
getASTContext());
575581

0 commit comments

Comments
 (0)