SwiftCompilerSources: add a few enum related APIs in Type and Builder

* `Type.getEnumCases`
* `Builder.createUncheckedTakeEnumDataAddr`
* `Builder.createSwitchEnumAddr`
This commit is contained in:
Erik Eckstein
2023-11-09 13:39:41 +01:00
parent 263f4d4cde
commit 6f6c0a5608
5 changed files with 147 additions and 22 deletions

View File

@@ -215,6 +215,12 @@ public struct Builder {
return notifyNew(ued.getAs(UncheckedEnumDataInst.self)) return notifyNew(ued.getAs(UncheckedEnumDataInst.self))
} }
public func createUncheckedTakeEnumDataAddr(enumAddress: Value,
caseIndex: Int) -> UncheckedTakeEnumDataAddrInst {
let uteda = bridged.createUncheckedTakeEnumDataAddr(enumAddress.bridged, caseIndex)
return notifyNew(uteda.getAs(UncheckedTakeEnumDataAddrInst.self))
}
public func createEnum(caseIndex: Int, payload: Value?, enumType: Type) -> EnumInst { public func createEnum(caseIndex: Int, payload: Value?, enumType: Type) -> EnumInst {
let enumInst = bridged.createEnum(caseIndex, payload.bridged, enumType.bridged) let enumInst = bridged.createEnum(caseIndex, payload.bridged, enumType.bridged)
return notifyNew(enumInst.getAs(EnumInst.self)) return notifyNew(enumInst.getAs(EnumInst.self))
@@ -236,6 +242,17 @@ public struct Builder {
return notifyNew(se.getAs(SwitchEnumInst.self)) return notifyNew(se.getAs(SwitchEnumInst.self))
} }
@discardableResult
public func createSwitchEnumAddr(enumAddress: Value,
cases: [(Int, BasicBlock)],
defaultBlock: BasicBlock? = nil) -> SwitchEnumAddrInst {
let se = cases.withUnsafeBufferPointer { caseBuffer in
bridged.createSwitchEnumAddrInst(enumAddress.bridged, defaultBlock.bridged,
caseBuffer.baseAddress, caseBuffer.count)
}
return notifyNew(se.getAs(SwitchEnumAddrInst.self))
}
@discardableResult @discardableResult
public func createBranch(to destBlock: BasicBlock, arguments: [Value] = []) -> BranchInst { public func createBranch(to destBlock: BasicBlock, arguments: [Value] = []) -> BranchInst {
return arguments.withBridgedValues { valuesRef in return arguments.withBridgedValues { valuesRef in

View File

@@ -100,6 +100,16 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
return NominalFieldsArray(type: self, function: function) return NominalFieldsArray(type: self, function: function)
} }
/// Can only be used if the type is in fact an enum type.
/// Returns nil if the enum is a resilient type because in this case the complete list
/// of cases is not known.
public func getEnumCases(in function: Function) -> EnumCases? {
if nominal.isResilient(in: function) {
return nil
}
return EnumCases(enumType: self, function: function)
}
public typealias MetatypeRepresentation = BridgedType.MetatypeRepresentation public typealias MetatypeRepresentation = BridgedType.MetatypeRepresentation
public func instanceTypeOfMetatype(in function: Function) -> Type { public func instanceTypeOfMetatype(in function: Function) -> Type {
@@ -199,6 +209,36 @@ public struct NominalFieldsArray : RandomAccessCollection, FormattedLikeArray {
} }
} }
public struct EnumCase {
public let payload: Type?
public let index: Int
}
public struct EnumCases : CollectionLikeSequence, IteratorProtocol {
fileprivate let enumType: Type
fileprivate let function: Function
private var caseIterator: BridgedType.EnumElementIterator
private var caseIndex = 0
fileprivate init(enumType: Type, function: Function) {
self.enumType = enumType
self.function = function
self.caseIterator = enumType.bridged.getFirstEnumCaseIterator()
}
public mutating func next() -> EnumCase? {
if !enumType.bridged.isEndCaseIterator(caseIterator) {
defer {
caseIterator = caseIterator.getNext()
caseIndex += 1
}
return EnumCase(payload: enumType.bridged.getEnumCasePayload(caseIterator, function.bridged).typeOrNil,
index: caseIndex)
}
return nil
}
}
public struct TupleElementArray : RandomAccessCollection, FormattedLikeArray { public struct TupleElementArray : RandomAccessCollection, FormattedLikeArray {
fileprivate let type: Type fileprivate let type: Type

View File

@@ -78,6 +78,22 @@ struct BridgedType {
Is Is
}; };
struct EnumElementIterator {
uint64_t storage[4];
#ifdef USED_IN_CPP_SOURCE
EnumElementIterator(swift::EnumDecl::ElementRange::iterator i) {
static_assert(sizeof(EnumElementIterator) >= sizeof(swift::EnumDecl::ElementRange::iterator));
*reinterpret_cast<swift::EnumDecl::ElementRange::iterator *>(&storage) = i;
}
swift::EnumDecl::ElementRange::iterator unbridged() const {
return *reinterpret_cast<const swift::EnumDecl::ElementRange::iterator *>(&storage);
}
#endif
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE EnumElementIterator getNext() const;
};
#ifdef USED_IN_CPP_SOURCE #ifdef USED_IN_CPP_SOURCE
BridgedType(swift::SILType t) : opaqueValue(t.getOpaqueValue()) {} BridgedType(swift::SILType t) : opaqueValue(t.getOpaqueValue()) {}
@@ -128,6 +144,9 @@ struct BridgedType {
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFieldType(SwiftInt idx, BridgedFunction f) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFieldType(SwiftInt idx, BridgedFunction f) const;
BRIDGED_INLINE SwiftInt getFieldIdxOfNominalType(BridgedStringRef name) const; BRIDGED_INLINE SwiftInt getFieldIdxOfNominalType(BridgedStringRef name) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getFieldName(SwiftInt idx) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getFieldName(SwiftInt idx) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE EnumElementIterator getFirstEnumCaseIterator() const;
BRIDGED_INLINE bool isEndCaseIterator(EnumElementIterator i) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getEnumCasePayload(EnumElementIterator i, BridgedFunction f) const;
BRIDGED_INLINE SwiftInt getNumTupleElements() const; BRIDGED_INLINE SwiftInt getNumTupleElements() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getTupleElementType(SwiftInt idx) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getTupleElementType(SwiftInt idx) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFunctionTypeWithNoEscape(bool withNoEscape) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFunctionTypeWithNoEscape(bool withNoEscape) const;
@@ -898,11 +917,16 @@ struct BridgedBuilder{
BridgedSubstitutionMap subMap, BridgedSubstitutionMap subMap,
BridgedValueArray arguments, bool isNonThrowing, bool isNonAsync, BridgedValueArray arguments, bool isNonThrowing, bool isNonAsync,
BridgedGenericSpecializationInformation specInfo) const; BridgedGenericSpecializationInformation specInfo) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createSwitchEnumInst(BridgedValue enumVal, SWIFT_IMPORT_UNSAFE BridgedInstruction createSwitchEnumInst(BridgedValue enumVal,
OptionalBridgedBasicBlock defaultBlock,
const void * _Nullable enumCases, SwiftInt numEnumCases) const;
SWIFT_IMPORT_UNSAFE BridgedInstruction createSwitchEnumAddrInst(BridgedValue enumAddr,
OptionalBridgedBasicBlock defaultBlock, OptionalBridgedBasicBlock defaultBlock,
const void * _Nullable enumCases, SwiftInt numEnumCases) const; const void * _Nullable enumCases, SwiftInt numEnumCases) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedEnumData(BridgedValue enumVal, SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedEnumData(BridgedValue enumVal,
SwiftInt caseIdx, BridgedType resultType) const; SwiftInt caseIdx, BridgedType resultType) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedTakeEnumDataAddr(BridgedValue enumAddr,
SwiftInt caseIdx) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEnum(SwiftInt caseIdx, OptionalBridgedValue payload, SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEnum(SwiftInt caseIdx, OptionalBridgedValue payload,
BridgedType resultType) const; BridgedType resultType) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createThinToThickFunction(BridgedValue fn, SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createThinToThickFunction(BridgedValue fn,

View File

@@ -44,6 +44,10 @@ SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
// BridgedType // BridgedType
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
BridgedType::EnumElementIterator BridgedType::EnumElementIterator::getNext() const {
return EnumElementIterator(std::next(unbridged()));
}
BridgedOwnedString BridgedType::getDebugDescription() const { BridgedOwnedString BridgedType::getDebugDescription() const {
return BridgedOwnedString(unbridged().getDebugDescription()); return BridgedOwnedString(unbridged().getDebugDescription());
} }
@@ -216,6 +220,23 @@ BridgedStringRef BridgedType::getFieldName(SwiftInt idx) const {
return unbridged().getFieldName(idx); return unbridged().getFieldName(idx);
} }
BridgedType::EnumElementIterator BridgedType::getFirstEnumCaseIterator() const {
swift::EnumDecl *enumDecl = unbridged().getEnumOrBoundGenericEnum();
return EnumElementIterator(enumDecl->getAllElements().begin());
}
bool BridgedType::isEndCaseIterator(EnumElementIterator i) const {
swift::EnumDecl *enumDecl = unbridged().getEnumOrBoundGenericEnum();
return i.unbridged() == enumDecl->getAllElements().end();
}
BridgedType BridgedType::getEnumCasePayload(EnumElementIterator i, BridgedFunction f) const {
swift::EnumElementDecl *elt = *i.unbridged();
if (elt->hasAssociatedValues())
return unbridged().getEnumElementType(elt, f.getFunction());
return swift::SILType();
}
SwiftInt BridgedType::getNumTupleElements() const { SwiftInt BridgedType::getNumTupleElements() const {
return unbridged().getNumTupleElements(); return unbridged().getNumTupleElements();
} }
@@ -1338,27 +1359,6 @@ BridgedInstruction BridgedBuilder::createApply(BridgedValue function, BridgedSub
arguments.getValues(argValues), applyOpts, specInfo.data)}; arguments.getValues(argValues), applyOpts, specInfo.data)};
} }
BridgedInstruction BridgedBuilder::createSwitchEnumInst(BridgedValue enumVal, OptionalBridgedBasicBlock defaultBlock,
const void * _Nullable enumCases, SwiftInt numEnumCases) const {
using BridgedCase = const std::pair<SwiftInt, BridgedBasicBlock>;
llvm::ArrayRef<BridgedCase> cases(static_cast<BridgedCase *>(enumCases),
(unsigned)numEnumCases);
llvm::SmallDenseMap<SwiftInt, swift::EnumElementDecl *> mappedElements;
swift::SILValue en = enumVal.getSILValue();
swift::EnumDecl *enumDecl = en->getType().getEnumOrBoundGenericEnum();
for (auto elemWithIndex : llvm::enumerate(enumDecl->getAllElements())) {
mappedElements[elemWithIndex.index()] = elemWithIndex.value();
}
llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16> convertedCases;
for (auto c : cases) {
assert(mappedElements.count(c.first) && "wrong enum element index");
convertedCases.push_back({mappedElements[c.first], c.second.unbridged()});
}
return {unbridged().createSwitchEnum(regularLoc(), enumVal.getSILValue(),
defaultBlock.unbridged(),
convertedCases)};
}
BridgedInstruction BridgedBuilder::createUncheckedEnumData(BridgedValue enumVal, SwiftInt caseIdx, BridgedInstruction BridgedBuilder::createUncheckedEnumData(BridgedValue enumVal, SwiftInt caseIdx,
BridgedType resultType) const { BridgedType resultType) const {
swift::SILValue en = enumVal.getSILValue(); swift::SILValue en = enumVal.getSILValue();
@@ -1367,6 +1367,11 @@ BridgedInstruction BridgedBuilder::createUncheckedEnumData(BridgedValue enumVal,
en->getType().getEnumElement(caseIdx), resultType.unbridged())}; en->getType().getEnumElement(caseIdx), resultType.unbridged())};
} }
BridgedInstruction BridgedBuilder::createUncheckedTakeEnumDataAddr(BridgedValue enumAddr, SwiftInt caseIdx) const {
swift::SILValue en = enumAddr.getSILValue();
return {unbridged().createUncheckedTakeEnumDataAddr(regularLoc(), en, en->getType().getEnumElement(caseIdx))};
}
BridgedInstruction BridgedBuilder::createEnum(SwiftInt caseIdx, OptionalBridgedValue payload, BridgedInstruction BridgedBuilder::createEnum(SwiftInt caseIdx, OptionalBridgedValue payload,
BridgedType resultType) const { BridgedType resultType) const {
swift::EnumElementDecl *caseDecl = swift::EnumElementDecl *caseDecl =

View File

@@ -444,3 +444,42 @@ bool BridgedInstruction::mayBeDeinitBarrierNotConsideringSideEffects() const {
return ::mayBeDeinitBarrierNotConsideringSideEffects(unbridged()); return ::mayBeDeinitBarrierNotConsideringSideEffects(unbridged());
} }
//===----------------------------------------------------------------------===//
// BridgedBuilder
//===----------------------------------------------------------------------===//
static llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16>
convertCases(SILType enumTy, const void * _Nullable enumCases, SwiftInt numEnumCases) {
using BridgedCase = const std::pair<SwiftInt, BridgedBasicBlock>;
llvm::ArrayRef<BridgedCase> cases(static_cast<BridgedCase *>(enumCases),
(unsigned)numEnumCases);
llvm::SmallDenseMap<SwiftInt, swift::EnumElementDecl *> mappedElements;
swift::EnumDecl *enumDecl = enumTy.getEnumOrBoundGenericEnum();
for (auto elemWithIndex : llvm::enumerate(enumDecl->getAllElements())) {
mappedElements[elemWithIndex.index()] = elemWithIndex.value();
}
llvm::SmallVector<std::pair<swift::EnumElementDecl *, swift::SILBasicBlock *>, 16> convertedCases;
for (auto c : cases) {
assert(mappedElements.count(c.first) && "wrong enum element index");
convertedCases.push_back({mappedElements[c.first], c.second.unbridged()});
}
return convertedCases;
}
BridgedInstruction BridgedBuilder::createSwitchEnumInst(BridgedValue enumVal, OptionalBridgedBasicBlock defaultBlock,
const void * _Nullable enumCases, SwiftInt numEnumCases) const {
return {unbridged().createSwitchEnum(regularLoc(),
enumVal.getSILValue(),
defaultBlock.unbridged(),
convertCases(enumVal.getSILValue()->getType(), enumCases, numEnumCases))};
}
BridgedInstruction BridgedBuilder::createSwitchEnumAddrInst(BridgedValue enumAddr,
OptionalBridgedBasicBlock defaultBlock,
const void * _Nullable enumCases,
SwiftInt numEnumCases) const {
return {unbridged().createSwitchEnumAddr(regularLoc(),
enumAddr.getSILValue(),
defaultBlock.unbridged(),
convertCases(enumAddr.getSILValue()->getType(), enumCases, numEnumCases))};
}