Skip to content

Commit 7ebcb7b

Browse files
committed
[Interop][SwiftToCxx] Implement enum case switching
1 parent 2c425f0 commit 7ebcb7b

File tree

8 files changed

+645
-28
lines changed

8 files changed

+645
-28
lines changed

include/swift/IRGen/IRABIDetailsProvider.h

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

16+
#include "swift/AST/Decl.h"
1617
#include "swift/AST/Type.h"
1718
#include "clang/AST/CharUnits.h"
1819
#include "llvm/ADT/Optional.h"
@@ -93,6 +94,10 @@ class IRABIDetailsProvider {
9394
/// access function.
9495
FunctionABISignature getTypeMetadataAccessFunctionSignature();
9596

97+
/// Returns EnumElementDecls (enum cases) in their declaration order with
98+
/// their tag indices from the given EnumDecl
99+
std::map<EnumElementDecl *, unsigned> getEnumTagMapping(EnumDecl *ED);
100+
96101
private:
97102
std::unique_ptr<IRABIDetailsProviderImpl> impl;
98103
};

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "swift/IRGen/IRABIDetailsProvider.h"
1414
#include "FixedTypeInfo.h"
15+
#include "GenEnum.h"
1516
#include "GenType.h"
1617
#include "IRGen.h"
1718
#include "IRGenModule.h"
@@ -122,6 +123,19 @@ class IRABIDetailsProviderImpl {
122123
return {returnTy, {paramTy}};
123124
}
124125

126+
std::map<EnumElementDecl *, unsigned> getEnumTagMapping(EnumDecl *ED) {
127+
std::map<EnumElementDecl *, unsigned> elements;
128+
auto &enumImplStrat = getEnumImplStrategy(
129+
IGM, ED->getDeclaredType()->getCanonicalType());
130+
131+
for (auto *element : ED->getAllElements()) {
132+
auto tagIdx = enumImplStrat.getTagIndex(element);
133+
elements.insert({element, tagIdx});
134+
}
135+
136+
return elements;
137+
}
138+
125139
private:
126140
Lowering::TypeConverter typeConverter;
127141
// Default silOptions are sufficient, as we don't need to generated SIL.
@@ -162,3 +176,8 @@ IRABIDetailsProvider::FunctionABISignature
162176
IRABIDetailsProvider::getTypeMetadataAccessFunctionSignature() {
163177
return impl->getTypeMetadataAccessFunctionSignature();
164178
}
179+
180+
std::map<EnumElementDecl *, unsigned>
181+
IRABIDetailsProvider::getEnumTagMapping(EnumDecl *ED) {
182+
return impl->getEnumTagMapping(ED);
183+
}

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "PrimitiveTypeMapping.h"
1616
#include "PrintClangFunction.h"
1717
#include "PrintClangValueType.h"
18+
#include "SwiftToClangInteropContext.h"
1819

1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/ASTMangler.h"
@@ -31,6 +32,7 @@
3132
#include "swift/AST/TypeCheckRequests.h"
3233
#include "swift/AST/TypeVisitor.h"
3334
#include "swift/IDE/CommentConversion.h"
35+
#include "swift/IRGen/IRABIDetailsProvider.h"
3436
#include "swift/IRGen/Linking.h"
3537
#include "swift/Parse/Lexer.h"
3638
#include "swift/Parse/Parser.h"
@@ -384,30 +386,65 @@ class DeclAndTypePrinter::Implementation
384386
os << "@end\n";
385387
}
386388

389+
void visitEnumDeclCxx(EnumDecl *ED) {
390+
// FIXME: Print enum's availability
391+
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
392+
owningPrinter.typeMapping,
393+
owningPrinter.interopContext);
394+
printer.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
395+
ClangSyntaxPrinter syntaxPrinter(os);
396+
auto elementTagMapping =
397+
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
398+
399+
os << " enum class cases {\n";
400+
for (const auto &pair : elementTagMapping) {
401+
os << " ";
402+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
403+
os << ",\n";
404+
}
405+
os << " };\n"; // enum class cases' closing bracket
406+
407+
if (elementTagMapping.empty()) {
408+
os << "\n";
409+
return;
410+
}
411+
412+
// Printing operator cases()
413+
os << " inline operator cases() const {\n";
414+
os << " switch (_getEnumTag()) {\n";
415+
for (const auto &pair : elementTagMapping) {
416+
if (pair == *elementTagMapping.crbegin()) {
417+
os << " case " << pair.second << ": default: return cases::";
418+
} else {
419+
os << " case " << pair.second << ": return cases::";
420+
}
421+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
422+
os << ";\n";
423+
}
424+
os << " }\n"; // switch's closing bracket
425+
os << " }\n"; // operator cases()'s closing bracket
426+
427+
// Printing predicates
428+
for (const auto &pair : elementTagMapping) {
429+
os << " inline bool is";
430+
auto name = pair.first->getNameStr().str();
431+
name[0] = std::toupper(name[0]);
432+
os << name << "() const {\n";
433+
os << " return *this == cases::";
434+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
435+
os << ";\n }\n";
436+
}
437+
os << "\n";
438+
});
439+
os << outOfLineDefinitions;
440+
outOfLineDefinitions.clear();
441+
}
442+
387443
void visitEnumDecl(EnumDecl *ED) {
388444
printDocumentationComment(ED);
389445

390446
if (outputLang == OutputLanguageMode::Cxx) {
391-
// FIXME: Print enum's availability
392-
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
393-
owningPrinter.typeMapping,
394-
owningPrinter.interopContext);
395-
printer.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
396-
ClangSyntaxPrinter syntaxPrinter(os);
397-
os << " enum class cases {";
398-
llvm::interleaveComma(
399-
ED->getAllCases(), os, [&](const EnumCaseDecl *caseDecl) {
400-
llvm::interleaveComma(caseDecl->getElements(), os,
401-
[&](const EnumElementDecl *elementDecl) {
402-
os << "\n ";
403-
syntaxPrinter.printIdentifier(
404-
elementDecl->getNameStr());
405-
});
406-
});
407-
os << "\n };\n";
408-
});
409-
os << outOfLineDefinitions;
410-
outOfLineDefinitions.clear();
447+
visitEnumDeclCxx(ED);
411448
return;
412449
}
413450

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,25 @@ void ClangValueTypePrinter::printValueTypeDecl(
202202
os << ".getOpaquePointer()";
203203
os << "; }\n";
204204
os << "\n";
205-
205+
// Print out helper function for getting enum tag for enum type
206+
if (isa<EnumDecl>(typeDecl)) {
207+
// FIXME: (tongjie) return type should be unsigned
208+
os << " inline int _getEnumTag() const {\n";
209+
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
210+
<< "::";
211+
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
212+
os << ";\n";
213+
os << " auto *vwTable = ";
214+
printer.printValueWitnessTableAccessFromTypeMetadata("metadata");
215+
os << ";\n";
216+
os << " const auto *enumVWTable = reinterpret_cast<";
217+
ClangSyntaxPrinter(os).printSwiftImplQualifier();
218+
os << "EnumValueWitnessTable";
219+
os << " *>(vwTable);\n";
220+
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
221+
"metadata._0);\n";
222+
os << " }\n";
223+
}
206224
// Print out the storage for the value type.
207225
os << " ";
208226
if (isOpaqueLayout) {

lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ static void printKnownType(
6262
printKnownStruct(typeMapping, os, name, typeRecord);
6363
}
6464

65-
static void printValueWitnessTableFunctionType(raw_ostream &os, StringRef name,
66-
StringRef returnType,
67-
std::string paramTypes,
68-
uint16_t ptrauthDisc) {
69-
os << "using ValueWitness" << name << "Ty = " << returnType
65+
static void
66+
printValueWitnessTableFunctionType(raw_ostream &os, StringRef prefix,
67+
StringRef name, StringRef returnType,
68+
std::string paramTypes,
69+
uint16_t ptrauthDisc) {
70+
os << "using " << prefix << name << "Ty = " << returnType
7071
<< "(* __ptrauth_swift_value_witness_function_pointer(" << ptrauthDisc
7172
<< "))(" << paramTypes << ");\n";
7273
}
@@ -87,7 +88,7 @@ static void printValueWitnessTable(raw_ostream &os) {
8788
membersOS << " " << type << " " << #lowerId << ";\n";
8889
#define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \
8990
printValueWitnessTableFunctionType( \
90-
os, #upperId, returnType, makeParams paramTypes, \
91+
os, "ValueWitness", #upperId, returnType, makeParams paramTypes, \
9192
SpecialPointerAuthDiscriminators::upperId); \
9293
membersOS << " ValueWitness" << #upperId << "Ty _Nonnull " << #lowerId \
9394
<< ";\n";
@@ -102,7 +103,32 @@ static void printValueWitnessTable(raw_ostream &os) {
102103
#define VOID_TYPE "void"
103104
#include "swift/ABI/ValueWitness.def"
104105

105-
os << "\nstruct ValueWitnessTable {\n" << membersOS.str() << "};\n";
106+
os << "\nstruct ValueWitnessTable {\n" << membersOS.str() << "};\n\n";
107+
membersOS.str().clear();
108+
109+
#define WANT_ONLY_ENUM_VALUE_WITNESSES
110+
#define DATA_VALUE_WITNESS(lowerId, upperId, type) \
111+
membersOS << " " << type << " " << #lowerId << ";\n";
112+
#define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \
113+
printValueWitnessTableFunctionType( \
114+
os, "EnumValueWitness", #upperId, returnType, makeParams paramTypes, \
115+
SpecialPointerAuthDiscriminators::upperId); \
116+
membersOS << " EnumValueWitness" << #upperId << "Ty _Nonnull " << #lowerId \
117+
<< ";\n";
118+
#define MUTABLE_VALUE_TYPE "void * _Nonnull"
119+
#define IMMUTABLE_VALUE_TYPE "const void * _Nonnull"
120+
#define MUTABLE_BUFFER_TYPE "void * _Nonnull"
121+
#define IMMUTABLE_BUFFER_TYPE "const void * _Nonnull"
122+
#define TYPE_TYPE "void * _Nonnull"
123+
#define SIZE_TYPE "size_t"
124+
#define INT_TYPE "int"
125+
#define UINT_TYPE "unsigned"
126+
#define VOID_TYPE "void"
127+
#include "swift/ABI/ValueWitness.def"
128+
129+
os << "\nstruct EnumValueWitnessTable {\n"
130+
<< " ValueWitnessTable vwTable;\n"
131+
<< membersOS.str() << "};\n\n";
106132
}
107133

108134
static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx,

test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@
4747
// CHECK-NEXT: unsigned extraInhabitantCount;
4848
// CHECK-NEXT: };
4949
// CHECK-EMPTY:
50+
// CHECK-NEXT: using EnumValueWitnessGetEnumTagTy = int(* __ptrauth_swift_value_witness_function_pointer(41909))(const void * _Nonnull, void * _Nonnull);
51+
// CHECK-NEXT: using EnumValueWitnessDestructiveProjectEnumDataTy = void(* __ptrauth_swift_value_witness_function_pointer(1053))(void * _Nonnull, void * _Nonnull);
52+
// CHECK-NEXT: using EnumValueWitnessDestructiveInjectEnumTagTy = void(* __ptrauth_swift_value_witness_function_pointer(45796))(void * _Nonnull, unsigned, void * _Nonnull);
53+
// CHECK-EMPTY:
54+
// CHECK-NEXT: struct EnumValueWitnessTable {
55+
// CHECK-NEXT: ValueWitnessTable vwTable;
56+
// CHECK-NEXT: EnumValueWitnessGetEnumTagTy _Nonnull getEnumTag;
57+
// CHECK-NEXT: EnumValueWitnessDestructiveProjectEnumDataTy _Nonnull destructiveProjectEnumData;
58+
// CHECK-NEXT: EnumValueWitnessDestructiveInjectEnumTagTy _Nonnull destructiveInjectEnumTag;
59+
// CHECK-NEXT: };
60+
// CHECK-EMPTY:
61+
// CHECK-EMPTY:
5062
// CHECK-NEXT: #ifdef __cplusplus
5163
// CHECK-NEXT: }
5264
// CHECK-NEXT: #endif

0 commit comments

Comments
 (0)