[interop][SwiftToCxx] emit swift type metadata access function declaration for structs

This commit is contained in:
Alex Lorenz
2022-06-13 08:04:53 -07:00
parent f6f677f6ca
commit 9254c47b2c
13 changed files with 284 additions and 5 deletions

View File

@@ -17,6 +17,7 @@
#include "clang/AST/CharUnits.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <cstdint>
#include <memory>
#include <utility>
@@ -67,6 +68,31 @@ public:
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
callback);
/// An representation of a single type, or a C struct with multiple members
/// with specified types. The C struct is expected to be passed via swiftcc
/// functions.
class TypeRecordABIRepresentation {
public:
ArrayRef<Type> getMembers() const { return members; }
using MemberVectorTy = SmallVector<Type, 4>;
private:
friend class IRABIDetailsProviderImpl;
TypeRecordABIRepresentation(MemberVectorTy members) : members(members) {}
MemberVectorTy members;
};
struct FunctionABISignature {
TypeRecordABIRepresentation returnType;
SmallVector<TypeRecordABIRepresentation, 4> parameterTypes;
};
/// Returns the function signature that is used for the the type metadata
/// access function.
FunctionABISignature getTypeMetadataAccessFunctionSignature();
private:
std::unique_ptr<IRABIDetailsProviderImpl> impl;
};

View File

@@ -107,6 +107,21 @@ public:
return hasError;
}
IRABIDetailsProvider::FunctionABISignature
getTypeMetadataAccessFunctionSignature() {
auto &ctx = IGM.getSwiftModule()->getASTContext();
llvm::StructType *responseTy = IGM.getTypeMetadataResponseTy();
IRABIDetailsProvider::TypeRecordABIRepresentation::MemberVectorTy members;
for (auto *elementTy : responseTy->elements())
members.push_back(*getPrimitiveTypeFromLLVMType(ctx, elementTy));
auto returnTy =
IRABIDetailsProvider::TypeRecordABIRepresentation(std::move(members));
auto paramTy = IRABIDetailsProvider::TypeRecordABIRepresentation(
{*getPrimitiveTypeFromLLVMType(ctx,
IGM.getTypeMetadataRequestParamTy())});
return {returnTy, {paramTy}};
}
private:
Lowering::TypeConverter typeConverter;
// Default silOptions are sufficient, as we don't need to generated SIL.
@@ -142,3 +157,8 @@ bool IRABIDetailsProvider::enumerateDirectPassingRecordMembers(
callback) {
return impl->enumerateDirectPassingRecordMembers(t, callback);
}
IRABIDetailsProvider::FunctionABISignature
IRABIDetailsProvider::getTypeMetadataAccessFunctionSignature() {
return impl->getTypeMetadataAccessFunctionSignature();
}

View File

@@ -7,6 +7,7 @@ add_swift_host_library(swiftPrintAsClang STATIC
PrintAsClang.cpp
PrintClangFunction.cpp
PrintClangValueType.cpp
PrintSwiftToClangCoreScaffold.cpp
SwiftToClangInteropContext.cpp)
target_link_libraries(swiftPrintAsClang PRIVATE
swiftAST

View File

@@ -72,6 +72,21 @@ void ClangSyntaxPrinter::printNamespace(
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter);
}
void ClangSyntaxPrinter::printExternC(
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
os << "#ifdef __cplusplus\n";
os << "extern \"C\" {\n";
os << "#endif\n\n";
bodyPrinter(os);
os << "\n#ifdef __cplusplus\n";
os << "}\n";
os << "#endif\n";
}
void ClangSyntaxPrinter::printSwiftImplQualifier() const {
os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
}
void ClangSyntaxPrinter::printNullability(
Optional<OptionalTypeKind> kind, NullabilityPrintKind printKind) const {
if (!kind)

View File

@@ -55,6 +55,13 @@ public:
printNamespace(StringRef name,
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
/// Print an extern C block with given body.
void
printExternC(llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
/// Print the `swift::_impl::` namespace qualifier.
void printSwiftImplQualifier() const;
/// Where nullability information should be printed.
enum class NullabilityPrintKind {
Before,

View File

@@ -16,6 +16,7 @@
#include "DeclAndTypePrinter.h"
#include "OutputLanguageMode.h"
#include "PrimitiveTypeMapping.h"
#include "PrintSwiftToClangCoreScaffold.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Module.h"
@@ -138,6 +139,8 @@ public:
access, outputLang),
outputLangMode(outputLang) {}
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
/// Returns true if we added the decl's module to the import set, false if
/// the decl is a local decl.
///
@@ -659,9 +662,14 @@ void swift::printModuleContentsAsCxx(
std::string modulePrologueBuf;
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
ModuleWriter(moduleOS, prologueOS, imports, M, interopContext,
getRequiredAccess(M), OutputLanguageMode::Cxx)
.write();
ModuleWriter writer(moduleOS, prologueOS, imports, M, interopContext,
getRequiredAccess(M), OutputLanguageMode::Cxx);
writer.write();
os << "#ifndef SWIFT_PRINTED_CORE\n";
os << "#define SWIFT_PRINTED_CORE\n";
printSwiftToClangCoreScaffold(interopContext, writer.getTypeMapping(), os);
os << "#endif\n";
// FIXME: refactor.
if (!prologueOS.str().empty()) {

View File

@@ -21,6 +21,7 @@
#include "swift/AST/TypeVisitor.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/IRGen/IRABIDetailsProvider.h"
#include "swift/IRGen/Linking.h"
#include "llvm/ADT/STLExtras.h"
using namespace swift;
@@ -59,6 +60,22 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
os << "};\n\n";
}
void printCTypeMetadataTypeFunction(raw_ostream &os,
const NominalTypeDecl *typeDecl) {
os << "// Type metadata accessor for " << typeDecl->getNameStr() << "\n";
auto entity = irgen::LinkEntity::forTypeMetadataAccessFunction(
typeDecl->getDeclaredType()->getCanonicalType());
os << "SWIFT_EXTERN ";
ClangSyntaxPrinter printer(os);
printer.printSwiftImplQualifier();
os << "MetadataResponseTy ";
entity.mangle(os);
os << '(';
printer.printSwiftImplQualifier();
os << "MetadataRequestTy)";
os << " SWIFT_NOEXCEPT SWIFT_CALL;\n\n";
}
void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
auto typeSizeAlign =
interopContext.getIrABIDetails().getTypeSizeAlignment(SD);
@@ -78,7 +95,11 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
[&](raw_ostream &os) {
os << "class ";
printCxxImplClassName(os, SD);
os << ";\n";
os << ";\n\n";
// Print out special functions, like functions that
// access type metadata.
printCTypeMetadataTypeFunction(os, SD);
});
// Print out the C++ class itself.

View File

@@ -0,0 +1,88 @@
//===--- PrintSwiftToClangCoreScaffold.cpp - Print core decls ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 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
//
//===----------------------------------------------------------------------===//
#include "PrintSwiftToClangCoreScaffold.h"
#include "ClangSyntaxPrinter.h"
#include "PrimitiveTypeMapping.h"
#include "SwiftToClangInteropContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "swift/IRGen/IRABIDetailsProvider.h"
using namespace swift;
static void printKnownCType(Type t, PrimitiveTypeMapping &typeMapping,
raw_ostream &os) {
auto info =
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
assert(info.hasValue() && "not a known type");
os << info->name;
if (info->canBeNullable)
os << " _Null_unspecified";
}
static void printKnownStruct(
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
assert(typeRecord.getMembers().size() > 1);
os << "struct " << name << " {\n";
for (const auto &ty : llvm::enumerate(typeRecord.getMembers())) {
os << " ";
printKnownCType(ty.value(), typeMapping, os);
os << " _" << ty.index() << ";\n";
}
os << "};\n";
}
static void printKnownTypedef(
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
assert(typeRecord.getMembers().size() == 1);
os << "typedef ";
printKnownCType(typeRecord.getMembers()[0], typeMapping, os);
os << " " << name << ";\n";
}
static void printKnownType(
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
if (typeRecord.getMembers().size() == 1)
return printKnownTypedef(typeMapping, os, name, typeRecord);
printKnownStruct(typeMapping, os, name, typeRecord);
}
static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx,
PrimitiveTypeMapping &typeMapping,
raw_ostream &os) {
os << "// Swift type metadata response type.\n";
// Print out the type metadata structure.
auto funcSig = ctx.getIrABIDetails().getTypeMetadataAccessFunctionSignature();
printKnownType(typeMapping, os, "MetadataResponseTy", funcSig.returnType);
assert(funcSig.parameterTypes.size() == 1);
os << "// Swift type metadata request type.\n";
printKnownType(typeMapping, os, "MetadataRequestTy",
funcSig.parameterTypes[0]);
}
void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
PrimitiveTypeMapping &typeMapping,
raw_ostream &os) {
ClangSyntaxPrinter printer(os);
printer.printNamespace("swift", [&](raw_ostream &) {
printer.printNamespace(
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &) {
printer.printExternC([&](raw_ostream &os) {
printTypeMetadataResponseType(ctx, typeMapping, os);
});
});
});
}

View File

@@ -0,0 +1,31 @@
//===--- PrintSwiftToClangCoreScaffold.h - Print core decls -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
#define SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
#include "llvm/Support/raw_ostream.h"
namespace swift {
class PrimitiveTypeMapping;
class SwiftToClangInteropContext;
/// Print out the core declarations required by C/C++ that are part of the core
/// Swift stdlib code.
void printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
PrimitiveTypeMapping &typeMapping,
llvm::raw_ostream &os);
} // end namespace swift
#endif

View File

@@ -0,0 +1,19 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
// RUN: %FileCheck %s < %t/core.h
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
// REQUIRES: PTRSIZE=64
// CHECK: namespace swift {
// CHECK: namespace _impl {
// CHECK: // Swift type metadata response type.
// CHECK-NEXT: struct MetadataResponseTy {
// CHECK-NEXT: void * _Null_unspecified _0;
// CHECK-NEXT: uint64_t _1;
// CHECK-NEXT: };
// CHECK-NEXT: // Swift type metadata request type.
// CHECK-NEXT: typedef uint64_t MetadataRequestTy;

View File

@@ -0,0 +1,35 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
// RUN: %FileCheck %s < %t/core.h
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
// CHECK: #ifndef SWIFT_PRINTED_CORE
// CHECK-NEXT: #define SWIFT_PRINTED_CORE
// CHECK-NEXT: namespace swift {
// CHECK-EMPTY:
// CHECK-NEXT: namespace _impl {
// CHECK-EMPTY:
// CHECK-NEXT: #ifdef __cplusplus
// CHECK-NEXT: extern "C" {
// CHECK-NEXT: #endif
// CHECK-EMPTY:
// CHECK-NEXT: // Swift type metadata response type.
// CHECK-NEXT: struct MetadataResponseTy {
// CHECK-NEXT: void * _Null_unspecified _0;
// CHECK-NEXT: uint{{.*}}_t _1;
// CHECK-NEXT: };
// CHECK-NEXT: // Swift type metadata request type.
// CHECK-NEXT: typedef uint{{.*}}_t MetadataRequestTy;
// CHECK-EMPTY:
// CHECK-NEXT: #ifdef __cplusplus
// CHECK-NEXT: }
// CHECK-NEXT: #endif
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace _impl
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace swift
// CHECK-EMPTY:
// CHECK-NEXT: #endif

View File

@@ -13,6 +13,10 @@
// CHECK-EMPTY:
// CHECK-NEXT: class _impl_StructWithIntField;
// CHECK-EMPTY:
// CHECK-NEXT: // Type metadata accessor for StructWithIntField
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $s7Structs18StructWithIntFieldVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: }
// CHECK: class StructWithIntField final {

View File

@@ -70,7 +70,11 @@
// CHECK-LABEL: #if defined(__OBJC__)
// CHECK-NEXT: #endif
// CHECK-NEXT: #if defined(__cplusplus)
// CHECK-NEXT: namespace empty {
// CHECK-NEXT: #ifndef SWIFT_PRINTED_CORE
// CHECK: } // namespace swift
// CHECK-EMPTY:
// CHECK-NEXT: #endif
// CHECK: namespace empty {
// CHECK: } // namespace empty
// CHECK: #endif