Skip to content

Commit 9254c47

Browse files
committed
[interop][SwiftToCxx] emit swift type metadata access function declaration for structs
1 parent f6f677f commit 9254c47

13 files changed

+284
-5
lines changed

include/swift/IRGen/IRABIDetailsProvider.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/CharUnits.h"
1818
#include "llvm/ADT/Optional.h"
1919
#include "llvm/ADT/STLExtras.h"
20+
#include "llvm/ADT/SmallVector.h"
2021
#include <cstdint>
2122
#include <memory>
2223
#include <utility>
@@ -67,6 +68,31 @@ class IRABIDetailsProvider {
6768
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
6869
callback);
6970

71+
/// An representation of a single type, or a C struct with multiple members
72+
/// with specified types. The C struct is expected to be passed via swiftcc
73+
/// functions.
74+
class TypeRecordABIRepresentation {
75+
public:
76+
ArrayRef<Type> getMembers() const { return members; }
77+
78+
using MemberVectorTy = SmallVector<Type, 4>;
79+
80+
private:
81+
friend class IRABIDetailsProviderImpl;
82+
TypeRecordABIRepresentation(MemberVectorTy members) : members(members) {}
83+
84+
MemberVectorTy members;
85+
};
86+
87+
struct FunctionABISignature {
88+
TypeRecordABIRepresentation returnType;
89+
SmallVector<TypeRecordABIRepresentation, 4> parameterTypes;
90+
};
91+
92+
/// Returns the function signature that is used for the the type metadata
93+
/// access function.
94+
FunctionABISignature getTypeMetadataAccessFunctionSignature();
95+
7096
private:
7197
std::unique_ptr<IRABIDetailsProviderImpl> impl;
7298
};

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ class IRABIDetailsProviderImpl {
107107
return hasError;
108108
}
109109

110+
IRABIDetailsProvider::FunctionABISignature
111+
getTypeMetadataAccessFunctionSignature() {
112+
auto &ctx = IGM.getSwiftModule()->getASTContext();
113+
llvm::StructType *responseTy = IGM.getTypeMetadataResponseTy();
114+
IRABIDetailsProvider::TypeRecordABIRepresentation::MemberVectorTy members;
115+
for (auto *elementTy : responseTy->elements())
116+
members.push_back(*getPrimitiveTypeFromLLVMType(ctx, elementTy));
117+
auto returnTy =
118+
IRABIDetailsProvider::TypeRecordABIRepresentation(std::move(members));
119+
auto paramTy = IRABIDetailsProvider::TypeRecordABIRepresentation(
120+
{*getPrimitiveTypeFromLLVMType(ctx,
121+
IGM.getTypeMetadataRequestParamTy())});
122+
return {returnTy, {paramTy}};
123+
}
124+
110125
private:
111126
Lowering::TypeConverter typeConverter;
112127
// Default silOptions are sufficient, as we don't need to generated SIL.
@@ -142,3 +157,8 @@ bool IRABIDetailsProvider::enumerateDirectPassingRecordMembers(
142157
callback) {
143158
return impl->enumerateDirectPassingRecordMembers(t, callback);
144159
}
160+
161+
IRABIDetailsProvider::FunctionABISignature
162+
IRABIDetailsProvider::getTypeMetadataAccessFunctionSignature() {
163+
return impl->getTypeMetadataAccessFunctionSignature();
164+
}

lib/PrintAsClang/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_swift_host_library(swiftPrintAsClang STATIC
77
PrintAsClang.cpp
88
PrintClangFunction.cpp
99
PrintClangValueType.cpp
10+
PrintSwiftToClangCoreScaffold.cpp
1011
SwiftToClangInteropContext.cpp)
1112
target_link_libraries(swiftPrintAsClang PRIVATE
1213
swiftAST

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ void ClangSyntaxPrinter::printNamespace(
7272
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter);
7373
}
7474

75+
void ClangSyntaxPrinter::printExternC(
76+
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
77+
os << "#ifdef __cplusplus\n";
78+
os << "extern \"C\" {\n";
79+
os << "#endif\n\n";
80+
bodyPrinter(os);
81+
os << "\n#ifdef __cplusplus\n";
82+
os << "}\n";
83+
os << "#endif\n";
84+
}
85+
86+
void ClangSyntaxPrinter::printSwiftImplQualifier() const {
87+
os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
88+
}
89+
7590
void ClangSyntaxPrinter::printNullability(
7691
Optional<OptionalTypeKind> kind, NullabilityPrintKind printKind) const {
7792
if (!kind)

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ class ClangSyntaxPrinter {
5555
printNamespace(StringRef name,
5656
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
5757

58+
/// Print an extern C block with given body.
59+
void
60+
printExternC(llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
61+
62+
/// Print the `swift::_impl::` namespace qualifier.
63+
void printSwiftImplQualifier() const;
64+
5865
/// Where nullability information should be printed.
5966
enum class NullabilityPrintKind {
6067
Before,

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "DeclAndTypePrinter.h"
1717
#include "OutputLanguageMode.h"
1818
#include "PrimitiveTypeMapping.h"
19+
#include "PrintSwiftToClangCoreScaffold.h"
1920

2021
#include "swift/AST/ExistentialLayout.h"
2122
#include "swift/AST/Module.h"
@@ -138,6 +139,8 @@ class ModuleWriter {
138139
access, outputLang),
139140
outputLangMode(outputLang) {}
140141

142+
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
143+
141144
/// Returns true if we added the decl's module to the import set, false if
142145
/// the decl is a local decl.
143146
///
@@ -659,9 +662,14 @@ void swift::printModuleContentsAsCxx(
659662
std::string modulePrologueBuf;
660663
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
661664

662-
ModuleWriter(moduleOS, prologueOS, imports, M, interopContext,
663-
getRequiredAccess(M), OutputLanguageMode::Cxx)
664-
.write();
665+
ModuleWriter writer(moduleOS, prologueOS, imports, M, interopContext,
666+
getRequiredAccess(M), OutputLanguageMode::Cxx);
667+
writer.write();
668+
669+
os << "#ifndef SWIFT_PRINTED_CORE\n";
670+
os << "#define SWIFT_PRINTED_CORE\n";
671+
printSwiftToClangCoreScaffold(interopContext, writer.getTypeMapping(), os);
672+
os << "#endif\n";
665673

666674
// FIXME: refactor.
667675
if (!prologueOS.str().empty()) {

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/TypeVisitor.h"
2222
#include "swift/ClangImporter/ClangImporter.h"
2323
#include "swift/IRGen/IRABIDetailsProvider.h"
24+
#include "swift/IRGen/Linking.h"
2425
#include "llvm/ADT/STLExtras.h"
2526

2627
using namespace swift;
@@ -59,6 +60,22 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
5960
os << "};\n\n";
6061
}
6162

63+
void printCTypeMetadataTypeFunction(raw_ostream &os,
64+
const NominalTypeDecl *typeDecl) {
65+
os << "// Type metadata accessor for " << typeDecl->getNameStr() << "\n";
66+
auto entity = irgen::LinkEntity::forTypeMetadataAccessFunction(
67+
typeDecl->getDeclaredType()->getCanonicalType());
68+
os << "SWIFT_EXTERN ";
69+
ClangSyntaxPrinter printer(os);
70+
printer.printSwiftImplQualifier();
71+
os << "MetadataResponseTy ";
72+
entity.mangle(os);
73+
os << '(';
74+
printer.printSwiftImplQualifier();
75+
os << "MetadataRequestTy)";
76+
os << " SWIFT_NOEXCEPT SWIFT_CALL;\n\n";
77+
}
78+
6279
void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
6380
auto typeSizeAlign =
6481
interopContext.getIrABIDetails().getTypeSizeAlignment(SD);
@@ -78,7 +95,11 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
7895
[&](raw_ostream &os) {
7996
os << "class ";
8097
printCxxImplClassName(os, SD);
81-
os << ";\n";
98+
os << ";\n\n";
99+
100+
// Print out special functions, like functions that
101+
// access type metadata.
102+
printCTypeMetadataTypeFunction(os, SD);
82103
});
83104

84105
// Print out the C++ class itself.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===--- PrintSwiftToClangCoreScaffold.cpp - Print core decls ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "PrintSwiftToClangCoreScaffold.h"
14+
#include "ClangSyntaxPrinter.h"
15+
#include "PrimitiveTypeMapping.h"
16+
#include "SwiftToClangInteropContext.h"
17+
#include "swift/AST/Decl.h"
18+
#include "swift/AST/Type.h"
19+
#include "swift/IRGen/IRABIDetailsProvider.h"
20+
21+
using namespace swift;
22+
23+
static void printKnownCType(Type t, PrimitiveTypeMapping &typeMapping,
24+
raw_ostream &os) {
25+
auto info =
26+
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
27+
assert(info.hasValue() && "not a known type");
28+
os << info->name;
29+
if (info->canBeNullable)
30+
os << " _Null_unspecified";
31+
}
32+
33+
static void printKnownStruct(
34+
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
35+
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
36+
assert(typeRecord.getMembers().size() > 1);
37+
os << "struct " << name << " {\n";
38+
for (const auto &ty : llvm::enumerate(typeRecord.getMembers())) {
39+
os << " ";
40+
printKnownCType(ty.value(), typeMapping, os);
41+
os << " _" << ty.index() << ";\n";
42+
}
43+
os << "};\n";
44+
}
45+
46+
static void printKnownTypedef(
47+
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
48+
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
49+
assert(typeRecord.getMembers().size() == 1);
50+
os << "typedef ";
51+
printKnownCType(typeRecord.getMembers()[0], typeMapping, os);
52+
os << " " << name << ";\n";
53+
}
54+
55+
static void printKnownType(
56+
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
57+
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
58+
if (typeRecord.getMembers().size() == 1)
59+
return printKnownTypedef(typeMapping, os, name, typeRecord);
60+
printKnownStruct(typeMapping, os, name, typeRecord);
61+
}
62+
63+
static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx,
64+
PrimitiveTypeMapping &typeMapping,
65+
raw_ostream &os) {
66+
os << "// Swift type metadata response type.\n";
67+
// Print out the type metadata structure.
68+
auto funcSig = ctx.getIrABIDetails().getTypeMetadataAccessFunctionSignature();
69+
printKnownType(typeMapping, os, "MetadataResponseTy", funcSig.returnType);
70+
assert(funcSig.parameterTypes.size() == 1);
71+
os << "// Swift type metadata request type.\n";
72+
printKnownType(typeMapping, os, "MetadataRequestTy",
73+
funcSig.parameterTypes[0]);
74+
}
75+
76+
void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
77+
PrimitiveTypeMapping &typeMapping,
78+
raw_ostream &os) {
79+
ClangSyntaxPrinter printer(os);
80+
printer.printNamespace("swift", [&](raw_ostream &) {
81+
printer.printNamespace(
82+
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &) {
83+
printer.printExternC([&](raw_ostream &os) {
84+
printTypeMetadataResponseType(ctx, typeMapping, os);
85+
});
86+
});
87+
});
88+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--- PrintSwiftToClangCoreScaffold.h - Print core decls -----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
14+
#define SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
15+
16+
#include "llvm/Support/raw_ostream.h"
17+
18+
namespace swift {
19+
20+
class PrimitiveTypeMapping;
21+
class SwiftToClangInteropContext;
22+
23+
/// Print out the core declarations required by C/C++ that are part of the core
24+
/// Swift stdlib code.
25+
void printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
26+
PrimitiveTypeMapping &typeMapping,
27+
llvm::raw_ostream &os);
28+
29+
} // end namespace swift
30+
31+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
3+
// RUN: %FileCheck %s < %t/core.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
6+
7+
// REQUIRES: PTRSIZE=64
8+
9+
// CHECK: namespace swift {
10+
11+
// CHECK: namespace _impl {
12+
13+
// CHECK: // Swift type metadata response type.
14+
// CHECK-NEXT: struct MetadataResponseTy {
15+
// CHECK-NEXT: void * _Null_unspecified _0;
16+
// CHECK-NEXT: uint64_t _1;
17+
// CHECK-NEXT: };
18+
// CHECK-NEXT: // Swift type metadata request type.
19+
// CHECK-NEXT: typedef uint64_t MetadataRequestTy;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
3+
// RUN: %FileCheck %s < %t/core.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
6+
7+
8+
// CHECK: #ifndef SWIFT_PRINTED_CORE
9+
// CHECK-NEXT: #define SWIFT_PRINTED_CORE
10+
// CHECK-NEXT: namespace swift {
11+
// CHECK-EMPTY:
12+
// CHECK-NEXT: namespace _impl {
13+
// CHECK-EMPTY:
14+
// CHECK-NEXT: #ifdef __cplusplus
15+
// CHECK-NEXT: extern "C" {
16+
// CHECK-NEXT: #endif
17+
// CHECK-EMPTY:
18+
// CHECK-NEXT: // Swift type metadata response type.
19+
// CHECK-NEXT: struct MetadataResponseTy {
20+
// CHECK-NEXT: void * _Null_unspecified _0;
21+
// CHECK-NEXT: uint{{.*}}_t _1;
22+
// CHECK-NEXT: };
23+
// CHECK-NEXT: // Swift type metadata request type.
24+
// CHECK-NEXT: typedef uint{{.*}}_t MetadataRequestTy;
25+
// CHECK-EMPTY:
26+
// CHECK-NEXT: #ifdef __cplusplus
27+
// CHECK-NEXT: }
28+
// CHECK-NEXT: #endif
29+
// CHECK-EMPTY:
30+
// CHECK-NEXT: } // namespace _impl
31+
// CHECK-EMPTY:
32+
// CHECK-EMPTY:
33+
// CHECK-NEXT: } // namespace swift
34+
// CHECK-EMPTY:
35+
// CHECK-NEXT: #endif

test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
// CHECK-EMPTY:
1414
// CHECK-NEXT: class _impl_StructWithIntField;
1515
// CHECK-EMPTY:
16+
// CHECK-NEXT: // Type metadata accessor for StructWithIntField
17+
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $s7Structs18StructWithIntFieldVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
18+
// CHECK-EMPTY:
19+
// CHECK-EMPTY:
1620
// CHECK-NEXT: }
1721

1822
// CHECK: class StructWithIntField final {

test/PrintAsCxx/empty.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@
7070
// CHECK-LABEL: #if defined(__OBJC__)
7171
// CHECK-NEXT: #endif
7272
// CHECK-NEXT: #if defined(__cplusplus)
73-
// CHECK-NEXT: namespace empty {
73+
// CHECK-NEXT: #ifndef SWIFT_PRINTED_CORE
74+
// CHECK: } // namespace swift
75+
// CHECK-EMPTY:
76+
// CHECK-NEXT: #endif
77+
// CHECK: namespace empty {
7478
// CHECK: } // namespace empty
7579
// CHECK: #endif
7680

0 commit comments

Comments
 (0)