Skip to content

Commit 0b664c6

Browse files
committed
use EnumImplStrategy to get tag index mapping and improve test cases
1 parent e8e2a0f commit 0b664c6

File tree

5 files changed

+93
-38
lines changed

5 files changed

+93
-38
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: 17 additions & 23 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"
@@ -391,53 +393,45 @@ class DeclAndTypePrinter::Implementation
391393
owningPrinter.interopContext);
392394
printer.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
393395
ClangSyntaxPrinter syntaxPrinter(os);
394-
llvm::SmallVector<const EnumElementDecl *> elements;
396+
auto elementTagMapping =
397+
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
395398

396399
os << " enum class cases {\n";
397-
for (const auto *caseDecl : ED->getAllCases()) {
398-
for (const auto *element : caseDecl->getElements()) {
399-
os << " ";
400-
syntaxPrinter.printIdentifier(element->getNameStr());
401-
elements.push_back(element);
402-
os << ",\n";
403-
}
400+
for (const auto &pair : elementTagMapping) {
401+
os << " ";
402+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
403+
os << ",\n";
404404
}
405405
os << " };\n"; // enum class cases' closing bracket
406406

407-
if (elements.size() == 0) {
407+
if (elementTagMapping.size() == 0) {
408408
os << "\n";
409409
return;
410410
}
411411

412-
// Rearrange cases so that they match their tag values
413-
llvm::stable_sort(elements, [&](const auto *e1, const auto *e2) {
414-
return e1->hasAssociatedValues() && !e2->hasAssociatedValues();
415-
});
416-
417412
// Printing operator cases()
418413
os << " inline operator cases() const {\n";
419414
os << " switch (_getEnumTag()) {\n";
420-
for (unsigned i = 0; i < elements.size(); ++i) {
421-
if (i != elements.size() - 1) {
422-
os << " case " << i << ": return cases::";
415+
for (const auto &pair : elementTagMapping) {
416+
if (pair == *elementTagMapping.crbegin()) {
417+
os << " case " << pair.second << ": default: return cases::";
423418
} else {
424-
os << " case " << i << ": default: return cases::";
419+
os << " case " << pair.second << ": return cases::";
425420
}
426-
syntaxPrinter.printIdentifier(elements[i]->getNameStr());
421+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
427422
os << ";\n";
428423
}
429424
os << " }\n"; // switch's closing bracket
430425
os << " }\n"; // operator cases()'s closing bracket
431426

432427
// Printing predicates
433-
for (const auto *element : elements) {
428+
for (const auto &pair : elementTagMapping) {
434429
os << " inline bool is";
435-
auto name = element->getNameStr().str();
436-
// TODO: (tongjie) maybe find a reliable way for upper case conversion
430+
auto name = pair.first->getNameStr().str();
437431
name[0] = std::toupper(name[0]);
438432
os << name << "() const {\n";
439433
os << " return *this == cases::";
440-
syntaxPrinter.printIdentifier(element->getNameStr());
434+
syntaxPrinter.printIdentifier(pair.first->getNameStr());
441435
os << ";\n }\n";
442436
}
443437
os << "\n";

test/Interop/SwiftToCxx/enums/enum-cxx-clike-enum-case-functions-execution.cpp renamed to test/Interop/SwiftToCxx/enums/swift-enum-case-functions-execution.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend %S/enum-cxx-clike-enum-case-functions.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h
3+
// RUN: %target-swift-frontend %S/swift-enum-case-functions.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h
44

55
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o
6-
// RUN: %target-interop-build-swift %S/enum-cxx-clike-enum-case-functions.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain
6+
// RUN: %target-interop-build-swift %S/swift-enum-case-functions.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain
77

88
// RUN: %target-codesign %t/swift-enums-execution
99
// RUN: %target-run %t/swift-enums-execution
1010

1111
// REQUIRES: executable_test
12+
// UNSUPPORTED: CPU=arm64e
1213

1314
#include <cassert>
1415
#include "enums.h"

test/Interop/SwiftToCxx/enums/enum-cxx-clike-enum-case-functions.swift renamed to test/Interop/SwiftToCxx/enums/swift-enum-case-functions.swift

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function)
66

7-
// Use enums from docs/ABI/TypeLayout.rst to test various mappings between tag values and cases
7+
// test case-related member functions: operator cases() and isXYZ predicates
88

99
public enum DataCase { case one(_ x: Int) }
1010

@@ -181,25 +181,37 @@ public func checkIntDoubleOrBignum(_ x: IntDoubleOrBignum, tag: Int) -> Bool {
181181
// CHECK-NEXT: inline bool isThree() const {
182182
// CHECK-NEXT: return *this == cases::three;
183183
// CHECK-NEXT: }
184+
// CHECK: inline int _getEnumTag() const {
185+
// CHECK-NEXT: auto metadata = _impl::$s5Enums9CLikeEnumOMa(0);
186+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
187+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
188+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
189+
// CHECK-NEXT: }
184190

185191
// CHECK: class CharOrSectionMarker final {
186192

187193
// CHECK: inline operator cases() const {
188194
// CHECK-NEXT: switch (_getEnumTag()) {
189-
// CHECK-NEXT: case 0: return cases::Char;
190195
// CHECK-NEXT: case 1: return cases::Paragraph;
196+
// CHECK-NEXT: case 0: return cases::Char;
191197
// CHECK-NEXT: case 2: default: return cases::Chapter;
192198
// CHECK-NEXT: }
193199
// CHECK-NEXT: }
194-
// CHECK-NEXT: inline bool isChar() const {
195-
// CHECK-NEXT: return *this == cases::Char;
196-
// CHECK-NEXT: }
197200
// CHECK-NEXT: inline bool isParagraph() const {
198201
// CHECK-NEXT: return *this == cases::Paragraph;
199202
// CHECK-NEXT: }
203+
// CHECK-NEXT: inline bool isChar() const {
204+
// CHECK-NEXT: return *this == cases::Char;
205+
// CHECK-NEXT: }
200206
// CHECK-NEXT: inline bool isChapter() const {
201207
// CHECK-NEXT: return *this == cases::Chapter;
202208
// CHECK-NEXT: }
209+
// CHECK: inline int _getEnumTag() const {
210+
// CHECK-NEXT: auto metadata = _impl::$s5Enums19CharOrSectionMarkerOMa(0);
211+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
212+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
213+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
214+
// CHECK-NEXT: }
203215

204216
// CHECK: class DataCase final {
205217

@@ -211,6 +223,12 @@ public func checkIntDoubleOrBignum(_ x: IntDoubleOrBignum, tag: Int) -> Bool {
211223
// CHECK-NEXT: inline bool isOne() const {
212224
// CHECK-NEXT: return *this == cases::one;
213225
// CHECK-NEXT: }
226+
// CHECK: inline int _getEnumTag() const {
227+
// CHECK-NEXT: auto metadata = _impl::$s5Enums8DataCaseOMa(0);
228+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
229+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
230+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
231+
// CHECK-NEXT: }
214232

215233
// CHECK: class IntDoubleOrBignum final {
216234

@@ -230,38 +248,53 @@ public func checkIntDoubleOrBignum(_ x: IntDoubleOrBignum, tag: Int) -> Bool {
230248
// CHECK-NEXT: inline bool isBignum() const {
231249
// CHECK-NEXT: return *this == cases::Bignum;
232250
// CHECK-NEXT: }
251+
// CHECK: inline int _getEnumTag() const {
252+
// CHECK-NEXT: auto metadata = _impl::$s5Enums17IntDoubleOrBignumOMa(0);
253+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
254+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
255+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
256+
// CHECK-NEXT: }
233257

234258
// CHECK: class IntOrInfinity final {
235259

236260
// CHECK: inline operator cases() const {
237261
// CHECK-NEXT: switch (_getEnumTag()) {
238-
// CHECK-NEXT: case 0: return cases::Int;
239262
// CHECK-NEXT: case 1: return cases::NegInfinity;
263+
// CHECK-NEXT: case 0: return cases::Int;
240264
// CHECK-NEXT: case 2: default: return cases::PosInfinity;
241265
// CHECK-NEXT: }
242266
// CHECK-NEXT: }
243-
// CHECK-NEXT: inline bool isInt() const {
244-
// CHECK-NEXT: return *this == cases::Int;
245-
// CHECK-NEXT: }
246267
// CHECK-NEXT: inline bool isNegInfinity() const {
247268
// CHECK-NEXT: return *this == cases::NegInfinity;
248269
// CHECK-NEXT: }
270+
// CHECK-NEXT: inline bool isInt() const {
271+
// CHECK-NEXT: return *this == cases::Int;
272+
// CHECK-NEXT: }
249273
// CHECK-NEXT: inline bool isPosInfinity() const {
250274
// CHECK-NEXT: return *this == cases::PosInfinity;
251275
// CHECK-NEXT: }
276+
// CHECK: inline int _getEnumTag() const {
277+
// CHECK-NEXT: auto metadata = _impl::$s5Enums13IntOrInfinityOMa(0);
278+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
279+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
280+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
281+
// CHECK-NEXT: }
252282

253283
// CHECK: class TerminalChar final {
254284

255285
// CHECK: inline operator cases() const {
256286
// CHECK-NEXT: switch (_getEnumTag()) {
287+
// CHECK-NEXT: case 4: return cases::Cursor;
257288
// CHECK-NEXT: case 0: return cases::Plain;
258289
// CHECK-NEXT: case 1: return cases::Bold;
259290
// CHECK-NEXT: case 2: return cases::Underline;
260291
// CHECK-NEXT: case 3: return cases::Blink;
261-
// CHECK-NEXT: case 4: return cases::Cursor;
262292
// CHECK-NEXT: case 5: default: return cases::Empty;
263293
// CHECK-NEXT: }
264294
// CHECK-NEXT: }
295+
// CHECK-NEXT: inline bool isCursor() const {
296+
// CHECK-NEXT: return *this == cases::Cursor;
297+
// CHECK-NEXT: }
265298
// CHECK-NEXT: inline bool isPlain() const {
266299
// CHECK-NEXT: return *this == cases::Plain;
267300
// CHECK-NEXT: }
@@ -274,9 +307,12 @@ public func checkIntDoubleOrBignum(_ x: IntDoubleOrBignum, tag: Int) -> Bool {
274307
// CHECK-NEXT: inline bool isBlink() const {
275308
// CHECK-NEXT: return *this == cases::Blink;
276309
// CHECK-NEXT: }
277-
// CHECK-NEXT: inline bool isCursor() const {
278-
// CHECK-NEXT: return *this == cases::Cursor;
279-
// CHECK-NEXT: }
280310
// CHECK-NEXT: inline bool isEmpty() const {
281311
// CHECK-NEXT: return *this == cases::Empty;
282312
// CHECK-NEXT: }
313+
// CHECK: inline int _getEnumTag() const {
314+
// CHECK-NEXT: auto metadata = _impl::$s5Enums12TerminalCharOMa(0);
315+
// CHECK-NEXT: auto *vwTable = *(reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1);
316+
// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast<swift::_impl::EnumValueWitnessTable *>(vwTable);
317+
// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0);
318+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)