Skip to content

Commit 6f6c0a5

Browse files
committed
SwiftCompilerSources: add a few enum related APIs in Type and Builder
* `Type.getEnumCases` * `Builder.createUncheckedTakeEnumDataAddr` * `Builder.createSwitchEnumAddr`
1 parent 263f4d4 commit 6f6c0a5

File tree

5 files changed

+147
-22
lines changed

5 files changed

+147
-22
lines changed

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ public struct Builder {
215215
return notifyNew(ued.getAs(UncheckedEnumDataInst.self))
216216
}
217217

218+
public func createUncheckedTakeEnumDataAddr(enumAddress: Value,
219+
caseIndex: Int) -> UncheckedTakeEnumDataAddrInst {
220+
let uteda = bridged.createUncheckedTakeEnumDataAddr(enumAddress.bridged, caseIndex)
221+
return notifyNew(uteda.getAs(UncheckedTakeEnumDataAddrInst.self))
222+
}
223+
218224
public func createEnum(caseIndex: Int, payload: Value?, enumType: Type) -> EnumInst {
219225
let enumInst = bridged.createEnum(caseIndex, payload.bridged, enumType.bridged)
220226
return notifyNew(enumInst.getAs(EnumInst.self))
@@ -236,6 +242,17 @@ public struct Builder {
236242
return notifyNew(se.getAs(SwitchEnumInst.self))
237243
}
238244

245+
@discardableResult
246+
public func createSwitchEnumAddr(enumAddress: Value,
247+
cases: [(Int, BasicBlock)],
248+
defaultBlock: BasicBlock? = nil) -> SwitchEnumAddrInst {
249+
let se = cases.withUnsafeBufferPointer { caseBuffer in
250+
bridged.createSwitchEnumAddrInst(enumAddress.bridged, defaultBlock.bridged,
251+
caseBuffer.baseAddress, caseBuffer.count)
252+
}
253+
return notifyNew(se.getAs(SwitchEnumAddrInst.self))
254+
}
255+
239256
@discardableResult
240257
public func createBranch(to destBlock: BasicBlock, arguments: [Value] = []) -> BranchInst {
241258
return arguments.withBridgedValues { valuesRef in

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
100100
return NominalFieldsArray(type: self, function: function)
101101
}
102102

103+
/// Can only be used if the type is in fact an enum type.
104+
/// Returns nil if the enum is a resilient type because in this case the complete list
105+
/// of cases is not known.
106+
public func getEnumCases(in function: Function) -> EnumCases? {
107+
if nominal.isResilient(in: function) {
108+
return nil
109+
}
110+
return EnumCases(enumType: self, function: function)
111+
}
112+
103113
public typealias MetatypeRepresentation = BridgedType.MetatypeRepresentation
104114

105115
public func instanceTypeOfMetatype(in function: Function) -> Type {
@@ -199,6 +209,36 @@ public struct NominalFieldsArray : RandomAccessCollection, FormattedLikeArray {
199209
}
200210
}
201211

212+
public struct EnumCase {
213+
public let payload: Type?
214+
public let index: Int
215+
}
216+
217+
public struct EnumCases : CollectionLikeSequence, IteratorProtocol {
218+
fileprivate let enumType: Type
219+
fileprivate let function: Function
220+
private var caseIterator: BridgedType.EnumElementIterator
221+
private var caseIndex = 0
222+
223+
fileprivate init(enumType: Type, function: Function) {
224+
self.enumType = enumType
225+
self.function = function
226+
self.caseIterator = enumType.bridged.getFirstEnumCaseIterator()
227+
}
228+
229+
public mutating func next() -> EnumCase? {
230+
if !enumType.bridged.isEndCaseIterator(caseIterator) {
231+
defer {
232+
caseIterator = caseIterator.getNext()
233+
caseIndex += 1
234+
}
235+
return EnumCase(payload: enumType.bridged.getEnumCasePayload(caseIterator, function.bridged).typeOrNil,
236+
index: caseIndex)
237+
}
238+
return nil
239+
}
240+
}
241+
202242
public struct TupleElementArray : RandomAccessCollection, FormattedLikeArray {
203243
fileprivate let type: Type
204244

include/swift/SIL/SILBridging.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ struct BridgedType {
7878
Is
7979
};
8080

81+
struct EnumElementIterator {
82+
uint64_t storage[4];
83+
84+
#ifdef USED_IN_CPP_SOURCE
85+
EnumElementIterator(swift::EnumDecl::ElementRange::iterator i) {
86+
static_assert(sizeof(EnumElementIterator) >= sizeof(swift::EnumDecl::ElementRange::iterator));
87+
*reinterpret_cast<swift::EnumDecl::ElementRange::iterator *>(&storage) = i;
88+
}
89+
swift::EnumDecl::ElementRange::iterator unbridged() const {
90+
return *reinterpret_cast<const swift::EnumDecl::ElementRange::iterator *>(&storage);
91+
}
92+
#endif
93+
94+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE EnumElementIterator getNext() const;
95+
};
96+
8197
#ifdef USED_IN_CPP_SOURCE
8298
BridgedType(swift::SILType t) : opaqueValue(t.getOpaqueValue()) {}
8399

@@ -128,6 +144,9 @@ struct BridgedType {
128144
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFieldType(SwiftInt idx, BridgedFunction f) const;
129145
BRIDGED_INLINE SwiftInt getFieldIdxOfNominalType(BridgedStringRef name) const;
130146
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getFieldName(SwiftInt idx) const;
147+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE EnumElementIterator getFirstEnumCaseIterator() const;
148+
BRIDGED_INLINE bool isEndCaseIterator(EnumElementIterator i) const;
149+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getEnumCasePayload(EnumElementIterator i, BridgedFunction f) const;
131150
BRIDGED_INLINE SwiftInt getNumTupleElements() const;
132151
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getTupleElementType(SwiftInt idx) const;
133152
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFunctionTypeWithNoEscape(bool withNoEscape) const;
@@ -898,11 +917,16 @@ struct BridgedBuilder{
898917
BridgedSubstitutionMap subMap,
899918
BridgedValueArray arguments, bool isNonThrowing, bool isNonAsync,
900919
BridgedGenericSpecializationInformation specInfo) const;
901-
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createSwitchEnumInst(BridgedValue enumVal,
920+
SWIFT_IMPORT_UNSAFE BridgedInstruction createSwitchEnumInst(BridgedValue enumVal,
921+
OptionalBridgedBasicBlock defaultBlock,
922+
const void * _Nullable enumCases, SwiftInt numEnumCases) const;
923+
SWIFT_IMPORT_UNSAFE BridgedInstruction createSwitchEnumAddrInst(BridgedValue enumAddr,
902924
OptionalBridgedBasicBlock defaultBlock,
903925
const void * _Nullable enumCases, SwiftInt numEnumCases) const;
904926
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedEnumData(BridgedValue enumVal,
905927
SwiftInt caseIdx, BridgedType resultType) const;
928+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedTakeEnumDataAddr(BridgedValue enumAddr,
929+
SwiftInt caseIdx) const;
906930
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEnum(SwiftInt caseIdx, OptionalBridgedValue payload,
907931
BridgedType resultType) const;
908932
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createThinToThickFunction(BridgedValue fn,

include/swift/SIL/SILBridgingImpl.h

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
4444
// BridgedType
4545
//===----------------------------------------------------------------------===//
4646

47+
BridgedType::EnumElementIterator BridgedType::EnumElementIterator::getNext() const {
48+
return EnumElementIterator(std::next(unbridged()));
49+
}
50+
4751
BridgedOwnedString BridgedType::getDebugDescription() const {
4852
return BridgedOwnedString(unbridged().getDebugDescription());
4953
}
@@ -216,6 +220,23 @@ BridgedStringRef BridgedType::getFieldName(SwiftInt idx) const {
216220
return unbridged().getFieldName(idx);
217221
}
218222

223+
BridgedType::EnumElementIterator BridgedType::getFirstEnumCaseIterator() const {
224+
swift::EnumDecl *enumDecl = unbridged().getEnumOrBoundGenericEnum();
225+
return EnumElementIterator(enumDecl->getAllElements().begin());
226+
}
227+
228+
bool BridgedType::isEndCaseIterator(EnumElementIterator i) const {
229+
swift::EnumDecl *enumDecl = unbridged().getEnumOrBoundGenericEnum();
230+
return i.unbridged() == enumDecl->getAllElements().end();
231+
}
232+
233+
BridgedType BridgedType::getEnumCasePayload(EnumElementIterator i, BridgedFunction f) const {
234+
swift::EnumElementDecl *elt = *i.unbridged();
235+
if (elt->hasAssociatedValues())
236+
return unbridged().getEnumElementType(elt, f.getFunction());
237+
return swift::SILType();
238+
}
239+
219240
SwiftInt BridgedType::getNumTupleElements() const {
220241
return unbridged().getNumTupleElements();
221242
}
@@ -1338,27 +1359,6 @@ BridgedInstruction BridgedBuilder::createApply(BridgedValue function, BridgedSub
13381359
arguments.getValues(argValues), applyOpts, specInfo.data)};
13391360
}
13401361

1341-
BridgedInstruction BridgedBuilder::createSwitchEnumInst(BridgedValue enumVal, OptionalBridgedBasicBlock defaultBlock,
1342-
const void * _Nullable enumCases, SwiftInt numEnumCases) const {
1343-
using BridgedCase = const std::pair<SwiftInt, BridgedBasicBlock>;
1344-
llvm::ArrayRef<BridgedCase> cases(static_cast<BridgedCase *>(enumCases),
1345-
(unsigned)numEnumCases);
1346-
llvm::SmallDenseMap<SwiftInt, swift::EnumElementDecl *> mappedElements;
1347-
swift::SILValue en = enumVal.getSILValue();
1348-
swift::EnumDecl *enumDecl = en->getType().getEnumOrBoundGenericEnum();
1349-
for (auto elemWithIndex : llvm::enumerate(enumDecl->getAllElements())) {
1350-
mappedElements[elemWithIndex.index()] = elemWithIndex.value();
1351-
}
1352-
llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16> convertedCases;
1353-
for (auto c : cases) {
1354-
assert(mappedElements.count(c.first) && "wrong enum element index");
1355-
convertedCases.push_back({mappedElements[c.first], c.second.unbridged()});
1356-
}
1357-
return {unbridged().createSwitchEnum(regularLoc(), enumVal.getSILValue(),
1358-
defaultBlock.unbridged(),
1359-
convertedCases)};
1360-
}
1361-
13621362
BridgedInstruction BridgedBuilder::createUncheckedEnumData(BridgedValue enumVal, SwiftInt caseIdx,
13631363
BridgedType resultType) const {
13641364
swift::SILValue en = enumVal.getSILValue();
@@ -1367,6 +1367,11 @@ BridgedInstruction BridgedBuilder::createUncheckedEnumData(BridgedValue enumVal,
13671367
en->getType().getEnumElement(caseIdx), resultType.unbridged())};
13681368
}
13691369

1370+
BridgedInstruction BridgedBuilder::createUncheckedTakeEnumDataAddr(BridgedValue enumAddr, SwiftInt caseIdx) const {
1371+
swift::SILValue en = enumAddr.getSILValue();
1372+
return {unbridged().createUncheckedTakeEnumDataAddr(regularLoc(), en, en->getType().getEnumElement(caseIdx))};
1373+
}
1374+
13701375
BridgedInstruction BridgedBuilder::createEnum(SwiftInt caseIdx, OptionalBridgedValue payload,
13711376
BridgedType resultType) const {
13721377
swift::EnumElementDecl *caseDecl =

lib/SIL/Utils/SILBridging.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,42 @@ bool BridgedInstruction::mayBeDeinitBarrierNotConsideringSideEffects() const {
444444
return ::mayBeDeinitBarrierNotConsideringSideEffects(unbridged());
445445
}
446446

447+
//===----------------------------------------------------------------------===//
448+
// BridgedBuilder
449+
//===----------------------------------------------------------------------===//
450+
451+
static llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16>
452+
convertCases(SILType enumTy, const void * _Nullable enumCases, SwiftInt numEnumCases) {
453+
using BridgedCase = const std::pair<SwiftInt, BridgedBasicBlock>;
454+
llvm::ArrayRef<BridgedCase> cases(static_cast<BridgedCase *>(enumCases),
455+
(unsigned)numEnumCases);
456+
llvm::SmallDenseMap<SwiftInt, swift::EnumElementDecl *> mappedElements;
457+
swift::EnumDecl *enumDecl = enumTy.getEnumOrBoundGenericEnum();
458+
for (auto elemWithIndex : llvm::enumerate(enumDecl->getAllElements())) {
459+
mappedElements[elemWithIndex.index()] = elemWithIndex.value();
460+
}
461+
llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16> convertedCases;
462+
for (auto c : cases) {
463+
assert(mappedElements.count(c.first) && "wrong enum element index");
464+
convertedCases.push_back({mappedElements[c.first], c.second.unbridged()});
465+
}
466+
return convertedCases;
467+
}
468+
469+
BridgedInstruction BridgedBuilder::createSwitchEnumInst(BridgedValue enumVal, OptionalBridgedBasicBlock defaultBlock,
470+
const void * _Nullable enumCases, SwiftInt numEnumCases) const {
471+
return {unbridged().createSwitchEnum(regularLoc(),
472+
enumVal.getSILValue(),
473+
defaultBlock.unbridged(),
474+
convertCases(enumVal.getSILValue()->getType(), enumCases, numEnumCases))};
475+
}
476+
477+
BridgedInstruction BridgedBuilder::createSwitchEnumAddrInst(BridgedValue enumAddr,
478+
OptionalBridgedBasicBlock defaultBlock,
479+
const void * _Nullable enumCases,
480+
SwiftInt numEnumCases) const {
481+
return {unbridged().createSwitchEnumAddr(regularLoc(),
482+
enumAddr.getSILValue(),
483+
defaultBlock.unbridged(),
484+
convertCases(enumAddr.getSILValue()->getType(), enumCases, numEnumCases))};
485+
}

0 commit comments

Comments
 (0)