Skip to content

Commit 6cc8359

Browse files
authored
Merge pull request swiftlang#59318 from hyp/eng/struct-interop-pass-return
[interop][SwiftToCxx] pass / return Swift struct values between C/C++…
2 parents 64bd784 + 550de96 commit 6cc8359

26 files changed

+1379
-54
lines changed

include/swift/IRGen/IRABIDetailsProvider.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@
1313
#ifndef SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
1414
#define SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
1515

16+
#include "swift/AST/Type.h"
17+
#include "clang/AST/CharUnits.h"
1618
#include "llvm/ADT/Optional.h"
19+
#include "llvm/ADT/STLExtras.h"
1720
#include <cstdint>
1821
#include <memory>
1922
#include <utility>
2023

2124
namespace swift {
2225

26+
class ASTContext;
2327
class IRGenOptions;
2428
class ModuleDecl;
2529
class NominalTypeDecl;
@@ -45,6 +49,24 @@ class IRABIDetailsProvider {
4549
llvm::Optional<SizeAndAlignment>
4650
getTypeSizeAlignment(const NominalTypeDecl *TD);
4751

52+
/// Returns true if the given type should be passed indirectly into a swiftcc
53+
/// function.
54+
bool shouldPassIndirectly(Type t);
55+
56+
/// Returns true if the given type should be returned indirectly from a
57+
/// swiftcc function.
58+
bool shouldReturnIndirectly(Type t);
59+
60+
/// Enumerates all of the members of the underlying record in terms of their
61+
/// primitive types that needs to be stored in a Clang/LLVM record when this
62+
/// type is passed or returned directly to/from swiftcc function.
63+
///
64+
/// Returns true if an error occurred when a particular member can't be
65+
/// represented with an AST type.
66+
bool enumerateDirectPassingRecordMembers(
67+
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
68+
callback);
69+
4870
private:
4971
std::unique_ptr<IRABIDetailsProviderImpl> impl;
5072
};

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,45 @@
1515
#include "GenType.h"
1616
#include "IRGen.h"
1717
#include "IRGenModule.h"
18+
#include "NativeConventionSchema.h"
1819

1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/IRGenOptions.h"
2122
#include "swift/AST/Types.h"
2223
#include "swift/SIL/SILModule.h"
24+
#include "clang/CodeGen/ModuleBuilder.h"
25+
#include "clang/CodeGen/SwiftCallingConv.h"
26+
#include "llvm/IR/DerivedTypes.h"
2327

2428
using namespace swift;
2529
using namespace irgen;
2630

31+
static Optional<Type> getPrimitiveTypeFromLLVMType(ASTContext &ctx,
32+
const llvm::Type *type) {
33+
if (const auto *intType = dyn_cast<llvm::IntegerType>(type)) {
34+
switch (intType->getBitWidth()) {
35+
case 8:
36+
return ctx.getUInt8Type();
37+
case 16:
38+
return ctx.getUInt16Type();
39+
case 32:
40+
return ctx.getUInt32Type();
41+
case 64:
42+
return ctx.getUInt64Type();
43+
default:
44+
return None;
45+
}
46+
} else if (type->isFloatTy()) {
47+
return ctx.getFloatType();
48+
} else if (type->isDoubleTy()) {
49+
return ctx.getDoubleType();
50+
} else if (type->isPointerTy()) {
51+
return ctx.getOpaquePointerType();
52+
}
53+
// FIXME: Handle vector type.
54+
return None;
55+
}
56+
2757
namespace swift {
2858

2959
class IRABIDetailsProviderImpl {
@@ -44,6 +74,39 @@ class IRABIDetailsProviderImpl {
4474
fixedTI->getFixedAlignment().getValue()};
4575
}
4676

77+
bool shouldPassIndirectly(Type type) {
78+
auto *TI = &IGM.getTypeInfoForUnlowered(type);
79+
NativeConventionSchema schema(IGM, TI, /*isResult=*/false);
80+
return schema.requiresIndirect();
81+
}
82+
83+
bool shouldReturnIndirectly(Type type) {
84+
if (type->isVoid())
85+
return false;
86+
auto *TI = &IGM.getTypeInfoForUnlowered(type);
87+
NativeConventionSchema schema(IGM, TI, /*isResult=*/true);
88+
return schema.requiresIndirect();
89+
}
90+
91+
bool enumerateDirectPassingRecordMembers(
92+
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
93+
callback) {
94+
auto *TI = &IGM.getTypeInfoForUnlowered(t);
95+
NativeConventionSchema schema(IGM, TI, /*isResult=*/false);
96+
bool hasError = false;
97+
schema.enumerateComponents(
98+
[&](clang::CharUnits offset, clang::CharUnits end, llvm::Type *type) {
99+
auto primitiveType = getPrimitiveTypeFromLLVMType(
100+
IGM.getSwiftModule()->getASTContext(), type);
101+
if (!primitiveType) {
102+
hasError = true;
103+
return;
104+
}
105+
callback(offset, end, *primitiveType);
106+
});
107+
return hasError;
108+
}
109+
47110
private:
48111
Lowering::TypeConverter typeConverter;
49112
// Default silOptions are sufficient, as we don't need to generated SIL.
@@ -65,3 +128,17 @@ llvm::Optional<IRABIDetailsProvider::SizeAndAlignment>
65128
IRABIDetailsProvider::getTypeSizeAlignment(const NominalTypeDecl *TD) {
66129
return impl->getTypeSizeAlignment(TD);
67130
}
131+
132+
bool IRABIDetailsProvider::shouldPassIndirectly(Type t) {
133+
return impl->shouldPassIndirectly(t);
134+
}
135+
136+
bool IRABIDetailsProvider::shouldReturnIndirectly(Type t) {
137+
return impl->shouldReturnIndirectly(t);
138+
}
139+
140+
bool IRABIDetailsProvider::enumerateDirectPassingRecordMembers(
141+
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
142+
callback) {
143+
return impl->enumerateDirectPassingRecordMembers(t, callback);
144+
}

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "ClangSyntaxPrinter.h"
14+
#include "swift/AST/Module.h"
1415

1516
using namespace swift;
1617
using namespace cxx_synthesis;
@@ -43,6 +44,10 @@ void ClangSyntaxPrinter::printIdentifier(StringRef name) {
4344
os << '_';
4445
}
4546

47+
void ClangSyntaxPrinter::printModuleNameCPrefix(const ModuleDecl &mod) {
48+
os << mod.getName().str() << '_';
49+
}
50+
4651
/// Print a C++ namespace declaration with the give name and body.
4752
void ClangSyntaxPrinter::printNamespace(
4853
llvm::function_ref<void(raw_ostream &OS)> namePrinter,

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
namespace swift {
2222

23+
class ModuleDecl;
24+
2325
namespace cxx_synthesis {
2426

2527
/// Return the name of the implementation namespace that is used to hide
@@ -37,6 +39,10 @@ class ClangSyntaxPrinter {
3739
/// trailing underscore.
3840
void printIdentifier(StringRef name);
3941

42+
/// Print the C-style prefix for the given module name, that's used for
43+
/// C type names inside the module.
44+
void printModuleNameCPrefix(const ModuleDecl &mod);
45+
4046
/// Print a C++ namespace declaration with the give name and body.
4147
void
4248
printNamespace(llvm::function_ref<void(raw_ostream &OS)> namePrinter,

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,9 @@ class DeclAndTypePrinter::Implementation
332332
if (outputLang != OutputLanguageMode::Cxx)
333333
return;
334334
// FIXME: Print struct's availability.
335-
ClangValueTypePrinter printer(os, owningPrinter.interopContext);
335+
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
336+
owningPrinter.typeMapping,
337+
owningPrinter.interopContext);
336338
printer.printStructDecl(SD);
337339
}
338340

@@ -834,7 +836,9 @@ class DeclAndTypePrinter::Implementation
834836

835837
os << "SWIFT_EXTERN ";
836838

837-
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
839+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
840+
owningPrinter.typeMapping,
841+
owningPrinter.interopContext);
838842
funcPrinter.printFunctionSignature(
839843
FD, funcABI.getSymbolName(), resultTy,
840844
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto);
@@ -873,7 +877,9 @@ class DeclAndTypePrinter::Implementation
873877
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
874878

875879
os << "inline ";
876-
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
880+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
881+
owningPrinter.typeMapping,
882+
owningPrinter.interopContext);
877883
funcPrinter.printFunctionSignature(
878884
FD, FD->getName().getBaseIdentifier().get(), resultTy,
879885
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CxxInlineThunk);
@@ -882,27 +888,8 @@ class DeclAndTypePrinter::Implementation
882888
printFunctionClangAttributes(FD, funcTy);
883889
printAvailability(FD);
884890
os << " {\n";
885-
os << " return " << cxx_synthesis::getCxxImplNamespaceName()
886-
<< "::" << funcABI.getSymbolName() << '(';
887-
888-
auto params = FD->getParameters();
889-
if (params->size()) {
890-
size_t index = 1;
891-
interleaveComma(*params, os, [&](const ParamDecl *param) {
892-
if (param->isInOut()) {
893-
os << "&";
894-
}
895-
896-
if (param->hasName()) {
897-
ClangSyntaxPrinter(os).printIdentifier(param->getName().str());
898-
} else {
899-
os << "_" << index;
900-
}
901-
++index;
902-
});
903-
}
904-
905-
os << ");\n";
891+
funcPrinter.printCxxThunkBody(funcABI.getSymbolName(), resultTy,
892+
FD->getParameters());
906893
os << "}\n";
907894
}
908895

@@ -1112,8 +1099,11 @@ class DeclAndTypePrinter::Implementation
11121099
if (outputLang == OutputLanguageMode::Cxx) {
11131100
// Emit the underlying C signature that matches the Swift ABI
11141101
// in the generated C++ implementation prologue for the module.
1115-
auto funcABI = getModuleProloguePrinter()
1102+
std::string cFuncDecl;
1103+
llvm::raw_string_ostream cFuncPrologueOS(cFuncDecl);
1104+
auto funcABI = Implementation(cFuncPrologueOS, owningPrinter, outputLang)
11161105
.printSwiftABIFunctionSignatureAsCxxFunction(FD);
1106+
owningPrinter.prologueOS << cFuncPrologueOS.str();
11171107
printAbstractFunctionAsCxxFunctionThunk(FD, funcABI);
11181108
return;
11191109
}

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ class ModuleWriter {
265265
forwardDeclare(ED);
266266
} else if (isa<AbstractTypeParamDecl>(TD)) {
267267
llvm_unreachable("should not see type params here");
268+
} else if (isa<StructDecl>(TD)) {
269+
// FIXME: add support here.
270+
return;
268271
} else {
269272
assert(false && "unknown local type decl");
270273
}
@@ -668,13 +671,15 @@ void swift::printModuleContentsAsCxx(
668671
M.ValueDecl::getName().print(os);
669672
os << " {\n";
670673
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << " {\n";
674+
os << "extern \"C\" {\n";
671675
os << "#endif\n\n";
672676

673677
os << prologueOS.str();
674678

675679
os << "\n#ifdef __cplusplus\n";
676680
os << "}\n";
677681
os << "}\n";
682+
os << "}\n";
678683
}
679684

680685
// Construct a C++ namespace for the module.

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,14 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
8989
[&] {
9090
out << "#include <cstdint>\n"
9191
"#include <cstddef>\n"
92-
"#include <cstdbool>\n";
92+
"#include <cstdbool>\n"
93+
"#include <cstring>\n";
9394
},
9495
[&] {
9596
out << "#include <stdint.h>\n"
9697
"#include <stddef.h>\n"
97-
"#include <stdbool.h>\n";
98+
"#include <stdbool.h>\n"
99+
"#include <string.h>\n";
98100
});
99101
out << "\n"
100102
"#if !defined(SWIFT_TYPEDEFS)\n"
@@ -301,6 +303,7 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
301303
out << "#endif\n";
302304
};
303305
emitMacro("SWIFT_CALL", "__attribute__((swiftcall))");
306+
emitMacro("SWIFT_INDIRECT_RESULT", "__attribute__((swift_indirect_result))");
304307
// SWIFT_NOEXCEPT applies 'noexcept' in C++ mode only.
305308
emitCxxConditional(
306309
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },

0 commit comments

Comments
 (0)