Skip to content

Setup code for Clang types in SIL. #33541

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
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
13 changes: 13 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ namespace swift {
class BoundGenericType;
class ClangModuleLoader;
class ClangNode;
class ClangTypeConverter;
class ConcreteDeclRef;
class ConstructorDecl;
class Decl;
Expand Down Expand Up @@ -586,6 +587,10 @@ class ASTContext final {
Type getBridgedToObjC(const DeclContext *dc, Type type,
Type *bridgedValueType = nullptr) const;

private:
ClangTypeConverter &getClangTypeConverter();

public:
/// Get the Clang type corresponding to a Swift function type.
///
/// \param params The function parameters.
Expand All @@ -595,6 +600,14 @@ class ASTContext final {
getClangFunctionType(ArrayRef<AnyFunctionType::Param> params, Type resultTy,
FunctionTypeRepresentation trueRep);

/// Get the canonical Clang type corresponding to a SIL function type.
///
/// SIL analog of \c ASTContext::getClangFunctionType .
const clang::Type *
getCanonicalClangFunctionType(
ArrayRef<SILParameterInfo> params, Optional<SILResultInfo> result,
SILFunctionType::Representation trueRep);

/// Get the Swift declaration that a Clang declaration was exported from,
/// if applicable.
const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl);
Expand Down
55 changes: 25 additions & 30 deletions include/swift/AST/ExtInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,8 @@ class ASTExtInfoBuilder {

using Representation = FunctionTypeRepresentation;

static void assertIsFunctionType(const clang::Type *);

ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
: bits(bits), clangTypeInfo(clangTypeInfo) {
// TODO: [clang-function-type-serialization] Once we start serializing
// the Clang type, we should also assert that the pointer is non-null.
auto Rep = Representation(bits & RepresentationMask);
if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type)
assertIsFunctionType(clangTypeInfo.type);
}
: bits(bits), clangTypeInfo(clangTypeInfo) {}

public:
// Constructor with all defaults.
Expand Down Expand Up @@ -254,10 +246,7 @@ class ASTExtInfoBuilder {
DifferentiabilityKind::NonDifferentiable;
}

/// Get the underlying ClangTypeInfo value if it is not the default value.
Optional<ClangTypeInfo> getClangTypeInfo() const {
return clangTypeInfo.empty() ? Optional<ClangTypeInfo>() : clangTypeInfo;
}
ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }

constexpr SILFunctionTypeRepresentation getSILRepresentation() const {
unsigned rawRep = bits & RepresentationMask;
Expand Down Expand Up @@ -404,9 +393,7 @@ class ASTExtInfo {

constexpr bool isDifferentiable() const { return builder.isDifferentiable(); }

Optional<ClangTypeInfo> getClangTypeInfo() const {
return builder.getClangTypeInfo();
}
ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); }

constexpr bool hasSelfParam() const { return builder.hasSelfParam(); }

Expand Down Expand Up @@ -518,20 +505,32 @@ class SILExtInfoBuilder {
SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
: bits(bits), clangTypeInfo(clangTypeInfo) {}

static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
bool isNoEscape, bool isAsync,
DifferentiabilityKind diffKind) {
return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
(isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) |
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert that diffKind fits inside DifferentiabilityMask?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, should we do this consistently for all the fields? For example, representation takes two bits. I imagine we could have a Last = 3 case there (and a Last = 2 case for DifferentiabilityKind) and then have a static_assert(std::bit_width(DifferentiabilityKind::Last) == std::bit_width(DifferentiabilityMask)).

Copy link
Contributor Author

@varungandhi-apple varungandhi-apple Aug 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Leaving this open for discussion. Will fix this in a follow-up PR based on what you think about the question ^.)

DifferentiabilityMask);
}

public:
// Constructor with all defaults.
SILExtInfoBuilder() : bits(0), clangTypeInfo(ClangTypeInfo(nullptr)) {}
SILExtInfoBuilder() : SILExtInfoBuilder(0, ClangTypeInfo(nullptr)) {}

// Constructor for polymorphic type.
SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
bool isAsync, DifferentiabilityKind diffKind,
const clang::Type *type)
: SILExtInfoBuilder(
((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
(isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) |
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
DifferentiabilityMask),
ClangTypeInfo(type)) {}
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isAsync,
diffKind),
ClangTypeInfo(type)) {}

SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric)
: SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric,
info.isNoEscape(), info.isAsync(),
info.getDifferentiabilityKind()),
info.getClangTypeInfo()) {}

void checkInvariants() const;

Expand Down Expand Up @@ -566,10 +565,8 @@ class SILExtInfoBuilder {
DifferentiabilityKind::NonDifferentiable;
}

/// Get the underlying ClangTypeInfo value if it is not the default value.
Optional<ClangTypeInfo> getClangTypeInfo() const {
return clangTypeInfo.empty() ? Optional<ClangTypeInfo>() : clangTypeInfo;
}
/// Get the underlying ClangTypeInfo value.
ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }

constexpr bool hasSelfParam() const {
switch (getRepresentation()) {
Expand Down Expand Up @@ -697,9 +694,7 @@ class SILExtInfo {

constexpr bool isDifferentiable() const { return builder.isDifferentiable(); }

Optional<ClangTypeInfo> getClangTypeInfo() const {
return builder.getClangTypeInfo();
}
ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); }

constexpr bool hasSelfParam() const { return builder.hasSelfParam(); }

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2872,7 +2872,7 @@ class AnyFunctionType : public TypeBase {
unsigned NumParams, ExtInfo Info)
: TypeBase(Kind, CanTypeContext, properties), Output(Output) {
Bits.AnyFunctionType.ExtInfoBits = Info.getBits();
Bits.AnyFunctionType.HasClangTypeInfo = Info.getClangTypeInfo().hasValue();
Bits.AnyFunctionType.HasClangTypeInfo = !Info.getClangTypeInfo().empty();
Bits.AnyFunctionType.NumParams = NumParams;
assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!");
// The use of both assert() and static_assert() is intentional.
Expand Down
1 change: 0 additions & 1 deletion include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,6 @@ class TypeConverter {
/// Given a function type, yield its bridged formal type.
CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern,
CanAnyFunctionType fnType,
AnyFunctionType::ExtInfo extInfo,
Bridgeability bridging);

/// Given a referenced value and the substituted formal type of a
Expand Down
35 changes: 24 additions & 11 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3131,16 +3131,16 @@ FunctionType *FunctionType::get(ArrayRef<AnyFunctionType::Param> params,
return funcTy;
}

Optional<ClangTypeInfo> clangTypeInfo = info.getClangTypeInfo();
auto clangTypeInfo = info.getClangTypeInfo();

size_t allocSize = totalSizeToAlloc<AnyFunctionType::Param, ClangTypeInfo>(
params.size(), clangTypeInfo.hasValue() ? 1 : 0);
params.size(), clangTypeInfo.empty() ? 0 : 1);
void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena);

bool isCanonical = isFunctionTypeCanonical(params, result);
if (clangTypeInfo.hasValue()) {
if (!clangTypeInfo.empty()) {
if (ctx.LangOpts.UseClangFunctionTypes)
isCanonical &= clangTypeInfo->type->isCanonicalUnqualified();
isCanonical &= clangTypeInfo.getType()->isCanonicalUnqualified();
else
isCanonical = false;
}
Expand All @@ -3162,8 +3162,8 @@ FunctionType::FunctionType(ArrayRef<AnyFunctionType::Param> params,
std::uninitialized_copy(params.begin(), params.end(),
getTrailingObjects<AnyFunctionType::Param>());
auto clangTypeInfo = info.getClangTypeInfo();
if (clangTypeInfo.hasValue())
*getTrailingObjects<ClangTypeInfo>() = clangTypeInfo.getValue();
if (!clangTypeInfo.empty())
*getTrailingObjects<ClangTypeInfo>() = clangTypeInfo;
}

void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID,
Expand Down Expand Up @@ -4457,16 +4457,29 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
return Type();
}

const clang::Type *
ASTContext::getClangFunctionType(ArrayRef<AnyFunctionType::Param> params,
Type resultTy,
FunctionTypeRepresentation trueRep) {
ClangTypeConverter &ASTContext::getClangTypeConverter() {
auto &impl = getImpl();
if (!impl.Converter) {
auto *cml = getClangModuleLoader();
impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target);
}
return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep);
return impl.Converter.getValue();
}

const clang::Type *
ASTContext::getClangFunctionType(ArrayRef<AnyFunctionType::Param> params,
Type resultTy,
FunctionTypeRepresentation trueRep) {
return getClangTypeConverter().getFunctionType(params, resultTy, trueRep);
}

const clang::Type *
ASTContext::getCanonicalClangFunctionType(
ArrayRef<SILParameterInfo> params,
Optional<SILResultInfo> result,
SILFunctionType::Representation trueRep) {
auto *ty = getClangTypeConverter().getFunctionType(params, result, trueRep);
return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr;
}

const Decl *
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,7 +3629,7 @@ void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) {
auto *cml = Ctx.getClangModuleLoader();
SmallString<64> buf;
llvm::raw_svector_ostream os(buf);
info.getClangTypeInfo().getValue().printType(cml, os);
info.getClangTypeInfo().printType(cml, os);
Printer << ", cType: " << QuotedString(os.str());
}

Expand Down Expand Up @@ -4054,7 +4054,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case SILFunctionType::Representation::CFunctionPointer:
Printer << "c";
// [TODO: Clang-type-plumbing] Remove the second check.
if (printNameOnly || !info.getClangTypeInfo().hasValue())
if (printNameOnly || info.getClangTypeInfo().empty())
break;
printCType(Ctx, Printer, info);
break;
Expand Down Expand Up @@ -4120,7 +4120,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case SILFunctionType::Representation::CFunctionPointer:
Printer << "c";
// [TODO: Clang-type-plumbing] Remove the second check.
if (printNameOnly || !info.getClangTypeInfo().hasValue())
if (printNameOnly || info.getClangTypeInfo().empty())
break;
printCType(Ctx, Printer, info);
break;
Expand Down
62 changes: 60 additions & 2 deletions lib/AST/ClangTypeConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,57 @@ const clang::Type *ClangTypeConverter::getFunctionType(
llvm_unreachable("invalid representation");
}

const clang::Type *ClangTypeConverter::getFunctionType(
ArrayRef<SILParameterInfo> params, Optional<SILResultInfo> result,
SILFunctionType::Representation repr) {

// Using the interface type is sufficient as type parameters get mapped to
// `id`, since ObjC lightweight generics use type erasure. (See also: SE-0057)
auto resultClangTy = result.hasValue()
? convert(result.getValue().getInterfaceType())
: ClangASTContext.VoidTy;

if (resultClangTy.isNull())
return nullptr;

SmallVector<clang::FunctionProtoType::ExtParameterInfo, 4> extParamInfos;
SmallVector<clang::QualType, 4> paramsClangTy;
bool someParamIsConsumed = false;
for (auto &p : params) {
auto pc = convert(p.getInterfaceType());
if (pc.isNull())
return nullptr;
clang::FunctionProtoType::ExtParameterInfo extParamInfo;
if (p.isConsumed()) {
someParamIsConsumed = true;
extParamInfo = extParamInfo.withIsConsumed(true);
}
extParamInfos.push_back(extParamInfo);
paramsClangTy.push_back(pc);
}

clang::FunctionProtoType::ExtProtoInfo info(clang::CallingConv::CC_C);
if (someParamIsConsumed)
info.ExtParameterInfos = extParamInfos.begin();
auto fn = ClangASTContext.getFunctionType(resultClangTy, paramsClangTy, info);
if (fn.isNull())
return nullptr;

switch (repr) {
case SILFunctionType::Representation::CFunctionPointer:
return ClangASTContext.getPointerType(fn).getTypePtr();
case SILFunctionType::Representation::Block:
return ClangASTContext.getBlockPointerType(fn).getTypePtr();
case SILFunctionType::Representation::Thick:
case SILFunctionType::Representation::Thin:
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::WitnessMethod:
case SILFunctionType::Representation::Closure:
llvm_unreachable("Expected a C-compatible representation.");
}
}

clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC,
StringRef memberName) {
auto memberTypeDecl = cast<TypeDecl>(
Expand Down Expand Up @@ -576,12 +627,19 @@ clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) {
}

clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) {
llvm::report_fatal_error("Expected only AST types but found a SIL function.");
// We must've already computed it before if applicable.
return clang::QualType(type->getClangTypeInfo().getType(), 0);
}

clang::QualType
ClangTypeConverter::visitSILBlockStorageType(SILBlockStorageType *type) {
llvm::report_fatal_error("Expected only AST types but found a SIL block.");
// We'll select (void)(^)(). This isn't correct for all blocks, but block
// storage type should only be converted for function signature lowering,
// where the parameter types do not matter.
auto &clangCtx = ClangASTContext;
auto fnTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy);
auto blockTy = clangCtx.getBlockPointerType(fnTy);
return clangCtx.getCanonicalType(blockTy);
}

clang::QualType
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ClangTypeConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class ClangTypeConverter :
ArrayRef<AnyFunctionType::Param> params, Type resultTy,
AnyFunctionType::Representation repr);

/// Compute the C function type for a SIL function type.
const clang::Type *getFunctionType(
ArrayRef<SILParameterInfo> params, Optional<SILResultInfo> result,
SILFunctionType::Representation repr);

/// Check whether the given Clang declaration is an export of a Swift
/// declaration introduced by this converter, and if so, return the original
/// Swift declaration.
Expand Down
35 changes: 19 additions & 16 deletions lib/AST/ExtInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@

#include "clang/AST/Type.h"

static void assertIsFunctionType(const clang::Type *type) {
#ifndef NDEBUG
if (!(type->isFunctionPointerType() || type->isBlockPointerType() ||
type->isFunctionReferenceType())) {
llvm::SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
os << "Expected a Clang function type wrapped in a pointer type or "
<< "a block pointer type but found:\n";
type->dump(os);
llvm_unreachable(os.str().data());
}
#endif
}

namespace swift {

// MARK: - ClangTypeInfo
Expand Down Expand Up @@ -53,23 +67,12 @@ void ClangTypeInfo::dump(llvm::raw_ostream &os) const {

// MARK: - ASTExtInfoBuilder

void ASTExtInfoBuilder::assertIsFunctionType(const clang::Type *type) {
#ifndef NDEBUG
if (!(type->isFunctionPointerType() || type->isBlockPointerType() ||
type->isFunctionReferenceType())) {
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
os << "Expected a Clang function type wrapped in a pointer type or "
<< "a block pointer type but found:\n";
type->dump(os);
llvm_unreachable(os.str().data());
}
#endif
return;
}

void ASTExtInfoBuilder::checkInvariants() const {
// TODO: Add validation checks here while making sure things don't blow up.
// TODO: [clang-function-type-serialization] Once we start serializing
// the Clang type, we should also assert that the pointer is non-null.
auto Rep = Representation(bits & RepresentationMask);
if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type)
assertIsFunctionType(clangTypeInfo.type);
}

// MARK: - ASTExtInfo
Expand Down
Loading