From fbb694bcdee1e2d3246b66b048efcc56dbbb58e5 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Fri, 12 Aug 2022 13:13:11 +0200 Subject: [PATCH] Swift SIL: add bridging for witness and default witness tables --- .../PassManager/ModulePassContext.swift | 36 ++++++ .../Sources/SIL/CMakeLists.txt | 4 +- .../Sources/SIL/WitnessTable.swift | 114 ++++++++++++++++++ include/swift/SIL/SILBridging.h | 38 +++++- include/swift/SIL/SILBridgingUtils.h | 16 +++ include/swift/SIL/SILDefaultWitnessTable.h | 2 + include/swift/SIL/SILWitnessTable.h | 2 + .../swift/SILOptimizer/OptimizerBridging.h | 8 ++ lib/SIL/Utils/SILBridging.cpp | 61 ++++++++++ lib/SILOptimizer/PassManager/PassManager.cpp | 34 ++++++ 10 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 SwiftCompilerSources/Sources/SIL/WitnessTable.swift diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift index 71572927f20..511457ffa84 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift @@ -47,6 +47,34 @@ struct ModulePassContext { } } + struct WitnessTableList : CollectionLikeSequence, IteratorProtocol { + private var currentTable: WitnessTable? + + fileprivate init(first: WitnessTable?) { currentTable = first } + + mutating func next() -> WitnessTable? { + if let t = currentTable { + currentTable = PassContext_nextWitnessTableInModule(t.bridged).table + return t + } + return nil + } + } + + struct DefaultWitnessTableList : CollectionLikeSequence, IteratorProtocol { + private var currentTable: DefaultWitnessTable? + + fileprivate init(first: DefaultWitnessTable?) { currentTable = first } + + mutating func next() -> DefaultWitnessTable? { + if let t = currentTable { + currentTable = PassContext_nextDefaultWitnessTableInModule(t.bridged).table + return t + } + return nil + } + } + var functions: FunctionList { FunctionList(first: PassContext_firstFunctionInModule(_bridged).function) } @@ -55,6 +83,14 @@ struct ModulePassContext { VTableArray(bridged: PassContext_getVTables(_bridged)) } + var witnessTables: WitnessTableList { + WitnessTableList(first: PassContext_firstWitnessTableInModule(_bridged).table) + } + + var defaultWitnessTables: DefaultWitnessTableList { + DefaultWitnessTableList(first: PassContext_firstDefaultWitnessTableInModule(_bridged).table) + } + /// Run a closure with a `PassContext` for a function, which allows to modify that function. /// /// Only a single `transform` can be alive at the same time, i.e. it's not allowed to nest diff --git a/SwiftCompilerSources/Sources/SIL/CMakeLists.txt b/SwiftCompilerSources/Sources/SIL/CMakeLists.txt index d69d492bcd1..dd737835f5b 100644 --- a/SwiftCompilerSources/Sources/SIL/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/SIL/CMakeLists.txt @@ -26,5 +26,5 @@ add_swift_compiler_module(SIL Type.swift Utils.swift Value.swift - VTable.swift) - + VTable.swift + WitnessTable.swift) diff --git a/SwiftCompilerSources/Sources/SIL/WitnessTable.swift b/SwiftCompilerSources/Sources/SIL/WitnessTable.swift new file mode 100644 index 00000000000..3d110c9908f --- /dev/null +++ b/SwiftCompilerSources/Sources/SIL/WitnessTable.swift @@ -0,0 +1,114 @@ +//===--- WitnessTable.swift -----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SILBridging + +public struct WitnessTable : CustomStringConvertible, CustomReflectable { + public let bridged: BridgedWitnessTable + + public init(bridged: BridgedWitnessTable) { self.bridged = bridged } + + public struct Entry : CustomStringConvertible, CustomReflectable { + fileprivate let bridged: BridgedWitnessTableEntry + + public enum Kind { + case method + case associatedType + case associatedTypeProtocol + case baseProtocol + } + + public var kind: Kind { + switch SILWitnessTableEntry_getKind(bridged) { + case SILWitnessTableEntry_Method: return .method + case SILWitnessTableEntry_AssociatedType: return .associatedType + case SILWitnessTableEntry_AssociatedTypeProtocol: return .associatedTypeProtocol + case SILWitnessTableEntry_BaseProtocol: return .baseProtocol + default: + fatalError("unknown witness table kind") + } + } + + public var methodFunction: Function? { + assert(kind == .method) + return SILWitnessTableEntry_getMethodFunction(bridged).function + } + + public var description: String { + let stdString = SILWitnessTableEntry_debugDescription(bridged) + return String(_cxxString: stdString) + } + + public var customMirror: Mirror { Mirror(self, children: []) } + } + + public struct EntryArray : BridgedRandomAccessCollection { + fileprivate let bridged: BridgedArrayRef + + public var startIndex: Int { return 0 } + public var endIndex: Int { return Int(bridged.numElements) } + + public subscript(_ index: Int) -> Entry { + precondition(index >= 0 && index < endIndex) + return Entry(bridged: BridgedWitnessTableEntry(ptr: bridged.data! + index &* BridgedWitnessTableEntrySize)) + } + } + + public var entries: EntryArray { + EntryArray(bridged: SILWitnessTable_getEntries(bridged)) + } + + public var description: String { + let stdString = SILWitnessTable_debugDescription(bridged) + return String(_cxxString: stdString) + } + + public var customMirror: Mirror { Mirror(self, children: []) } +} + +public struct DefaultWitnessTable : CustomStringConvertible, CustomReflectable { + public let bridged: BridgedDefaultWitnessTable + + public init(bridged: BridgedDefaultWitnessTable) { self.bridged = bridged } + + public typealias Entry = WitnessTable.Entry + public typealias EntryArray = WitnessTable.EntryArray + + public var entries: EntryArray { + EntryArray(bridged: SILDefaultWitnessTable_getEntries(bridged)) + } + + public var description: String { + let stdString = SILDefaultWitnessTable_debugDescription(bridged) + return String(_cxxString: stdString) + } + + public var customMirror: Mirror { Mirror(self, children: []) } +} + +extension OptionalBridgedWitnessTable { + public var table: WitnessTable? { + if let p = ptr { + return WitnessTable(bridged: BridgedWitnessTable(ptr: p)) + } + return nil + } +} + +extension OptionalBridgedDefaultWitnessTable { + public var table: DefaultWitnessTable? { + if let p = ptr { + return DefaultWitnessTable(bridged: BridgedDefaultWitnessTable(ptr: p)) + } + return nil + } +} diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 0e308ab5e27..1496f269bf8 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -24,7 +24,8 @@ SWIFT_BEGIN_NULLABILITY_ANNOTATIONS enum { BridgedOperandSize = 4 * sizeof(uintptr_t), BridgedSuccessorSize = 4 * sizeof(uintptr_t) + sizeof(uint64_t), - BridgedVTableEntrySize = 5 * sizeof(uintptr_t) + BridgedVTableEntrySize = 5 * sizeof(uintptr_t), + BridgedWitnessTableEntrySize = 5 * sizeof(uintptr_t) }; enum ChangeNotificationKind { @@ -77,6 +78,33 @@ typedef struct { const void * _Nonnull ptr; } BridgedVTableEntry; +typedef struct { + const void * _Nonnull ptr; +} BridgedWitnessTable; + +typedef struct { + const void * _Nullable ptr; +} OptionalBridgedWitnessTable; + +typedef struct { + const void * _Nonnull ptr; +} BridgedDefaultWitnessTable; + +typedef struct { + const void * _Nullable ptr; +} OptionalBridgedDefaultWitnessTable; + +typedef struct { + const void * _Nonnull ptr; +} BridgedWitnessTableEntry; + +typedef enum { + SILWitnessTableEntry_Method, + SILWitnessTableEntry_AssociatedType, + SILWitnessTableEntry_AssociatedTypeProtocol, + SILWitnessTableEntry_BaseProtocol +} SILWitnessTableEntryKind; + typedef struct { SwiftObject obj; } BridgedFunction; @@ -247,6 +275,14 @@ BridgedArrayRef SILVTable_getEntries(BridgedVTable vTable); std::string SILVTableEntry_debugDescription(BridgedVTableEntry entry); BridgedFunction SILVTableEntry_getFunction(BridgedVTableEntry entry); +std::string SILWitnessTable_debugDescription(BridgedWitnessTable table); +BridgedArrayRef SILWitnessTable_getEntries(BridgedWitnessTable table); +std::string SILDefaultWitnessTable_debugDescription(BridgedDefaultWitnessTable table); +BridgedArrayRef SILDefaultWitnessTable_getEntries(BridgedDefaultWitnessTable table); +std::string SILWitnessTableEntry_debugDescription(BridgedWitnessTableEntry entry); +SILWitnessTableEntryKind SILWitnessTableEntry_getKind(BridgedWitnessTableEntry entry); +OptionalBridgedFunction SILWitnessTableEntry_getMethodFunction(BridgedWitnessTableEntry entry); + OptionalBridgedBasicBlock SILBasicBlock_next(BridgedBasicBlock block); OptionalBridgedBasicBlock SILBasicBlock_previous(BridgedBasicBlock block); BridgedFunction SILBasicBlock_getFunction(BridgedBasicBlock block); diff --git a/include/swift/SIL/SILBridgingUtils.h b/include/swift/SIL/SILBridgingUtils.h index 5f66d56051c..7da0e24b6e2 100644 --- a/include/swift/SIL/SILBridgingUtils.h +++ b/include/swift/SIL/SILBridgingUtils.h @@ -17,6 +17,8 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILGlobalVariable.h" #include "swift/SIL/SILVTable.h" +#include "swift/SIL/SILWitnessTable.h" +#include "swift/SIL/SILDefaultWitnessTable.h" #include "llvm/ADT/StringRef.h" #include @@ -93,6 +95,20 @@ inline const SILVTableEntry *castToVTableEntry(BridgedVTableEntry entry) { return static_cast(entry.ptr); } +inline const SILWitnessTable *castToWitnessTable(BridgedWitnessTable table) { + return static_cast(table.ptr); +} + +inline const SILDefaultWitnessTable * +castToDefaultWitnessTable(BridgedDefaultWitnessTable table) { + return static_cast(table.ptr); +} + +inline const SILWitnessTable::Entry * +castToWitnessTableEntry(BridgedWitnessTableEntry entry) { + return static_cast(entry.ptr); +} + inline ValueOwnershipKind castToOwnership(BridgedOwnership ownership) { switch (ownership) { case Ownership_Unowned: return OwnershipKind::Unowned; diff --git a/include/swift/SIL/SILDefaultWitnessTable.h b/include/swift/SIL/SILDefaultWitnessTable.h index aeed5f89827..8fc0072174f 100644 --- a/include/swift/SIL/SILDefaultWitnessTable.h +++ b/include/swift/SIL/SILDefaultWitnessTable.h @@ -105,6 +105,8 @@ public: ~SILDefaultWitnessTable(); + SILModule &getModule() const { return Mod; } + /// Return true if this is a declaration with no body. bool isDeclaration() const { return IsDeclaration; } diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h index 92c0efbe5a0..3a3cbb74550 100644 --- a/include/swift/SIL/SILWitnessTable.h +++ b/include/swift/SIL/SILWitnessTable.h @@ -223,6 +223,8 @@ public: RootProtocolConformance *conformance); ~SILWitnessTable(); + + SILModule &getModule() const { return Mod; } /// Return the AST ProtocolConformance this witness table represents. RootProtocolConformance *getConformance() const { diff --git a/include/swift/SILOptimizer/OptimizerBridging.h b/include/swift/SILOptimizer/OptimizerBridging.h index afcc017154e..53405267adc 100644 --- a/include/swift/SILOptimizer/OptimizerBridging.h +++ b/include/swift/SILOptimizer/OptimizerBridging.h @@ -172,6 +172,14 @@ PassContext_firstFunctionInModule(BridgedPassContext context); OptionalBridgedFunction PassContext_nextFunctionInModule(BridgedFunction function); BridgedVTableArray PassContext_getVTables(BridgedPassContext context); +OptionalBridgedWitnessTable +PassContext_firstWitnessTableInModule(BridgedPassContext context); +OptionalBridgedWitnessTable +PassContext_nextWitnessTableInModule(BridgedWitnessTable table); +OptionalBridgedDefaultWitnessTable +PassContext_firstDefaultWitnessTableInModule(BridgedPassContext context); +OptionalBridgedDefaultWitnessTable +PassContext_nextDefaultWitnessTableInModule(BridgedDefaultWitnessTable table); OptionalBridgedFunction PassContext_loadFunction(BridgedPassContext context, llvm::StringRef name); diff --git a/lib/SIL/Utils/SILBridging.cpp b/lib/SIL/Utils/SILBridging.cpp index 170d8870333..10b1f5e16e0 100644 --- a/lib/SIL/Utils/SILBridging.cpp +++ b/lib/SIL/Utils/SILBridging.cpp @@ -581,6 +581,67 @@ BridgedFunction SILVTableEntry_getFunction(BridgedVTableEntry entry) { return {castToVTableEntry(entry)->getImplementation()}; } +//===----------------------------------------------------------------------===// +// SILVWitnessTable, SILDefaultWitnessTable +//===----------------------------------------------------------------------===// + +static_assert(BridgedWitnessTableEntrySize == sizeof(SILWitnessTable::Entry), + "wrong bridged WitnessTable entry size"); + +std::string SILWitnessTable_debugDescription(BridgedWitnessTable table) { + std::string str; + llvm::raw_string_ostream os(str); + castToWitnessTable(table)->print(os); + str.pop_back(); // Remove trailing newline. + return str; +} + +BridgedArrayRef SILWitnessTable_getEntries(BridgedWitnessTable table) { + auto entries = castToWitnessTable(table)->getEntries(); + return {(const unsigned char *)entries.data(), entries.size()}; +} + +std::string SILDefaultWitnessTable_debugDescription(BridgedDefaultWitnessTable table) { + std::string str; + llvm::raw_string_ostream os(str); + castToDefaultWitnessTable(table)->print(os); + str.pop_back(); // Remove trailing newline. + return str; +} + +BridgedArrayRef SILDefaultWitnessTable_getEntries(BridgedDefaultWitnessTable table) { + auto entries = castToDefaultWitnessTable(table)->getEntries(); + return {(const unsigned char *)entries.data(), entries.size()}; +} + +std::string SILWitnessTableEntry_debugDescription(BridgedWitnessTableEntry entry) { + std::string str; + llvm::raw_string_ostream os(str); + castToWitnessTableEntry(entry)->print(os, /*verbose=*/ false, + PrintOptions::printSIL()); + str.pop_back(); // Remove trailing newline. + return str; +} + +SILWitnessTableEntryKind SILWitnessTableEntry_getKind(BridgedWitnessTableEntry entry) { + switch (castToWitnessTableEntry(entry)->getKind()) { + case SILWitnessTable::Method: + return SILWitnessTableEntry_Method; + case SILWitnessTable::AssociatedType: + return SILWitnessTableEntry_AssociatedType; + case SILWitnessTable::AssociatedTypeProtocol: + return SILWitnessTableEntry_AssociatedTypeProtocol; + case SILWitnessTable::BaseProtocol: + return SILWitnessTableEntry_BaseProtocol; + default: + llvm_unreachable("wrong witness table entry kind"); + } +} + +OptionalBridgedFunction SILWitnessTableEntry_getMethodFunction(BridgedWitnessTableEntry entry) { + return {castToWitnessTableEntry(entry)->getMethodWitness().Witness}; +} + //===----------------------------------------------------------------------===// // SILInstruction //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index 9ead83915b1..47a1a3225d4 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -1579,6 +1579,40 @@ BridgedVTableArray PassContext_getVTables(BridgedPassContext context) { return {(const BridgedVTable *)vTables.data(), vTables.size()}; } +OptionalBridgedWitnessTable +PassContext_firstWitnessTableInModule(BridgedPassContext context) { + SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule(); + if (mod->getWitnessTables().empty()) + return {nullptr}; + return {&*mod->getWitnessTables().begin()}; +} + +OptionalBridgedWitnessTable +PassContext_nextWitnessTableInModule(BridgedWitnessTable table) { + auto *t = castToWitnessTable(table); + auto nextIter = std::next(t->getIterator()); + if (nextIter == t->getModule().getWitnessTables().end()) + return {nullptr}; + return {&*nextIter}; +} + +OptionalBridgedDefaultWitnessTable +PassContext_firstDefaultWitnessTableInModule(BridgedPassContext context) { + SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule(); + if (mod->getDefaultWitnessTables().empty()) + return {nullptr}; + return {&*mod->getDefaultWitnessTables().begin()}; +} + +OptionalBridgedDefaultWitnessTable +PassContext_nextDefaultWitnessTableInModule(BridgedDefaultWitnessTable table) { + auto *t = castToDefaultWitnessTable(table); + auto nextIter = std::next(t->getIterator()); + if (nextIter == t->getModule().getDefaultWitnessTables().end()) + return {nullptr}; + return {&*nextIter}; +} + OptionalBridgedFunction PassContext_loadFunction(BridgedPassContext context, StringRef name) { SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();