mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SwiftCompilerSources: move SIL-related datastructures from the Optimizer to the SIL module
This commit is contained in:
@@ -7,11 +7,6 @@
|
||||
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
|
||||
swift_compiler_sources(Optimizer
|
||||
BasicBlockRange.swift
|
||||
DeadEndBlocks.swift
|
||||
FunctionUses.swift
|
||||
InstructionRange.swift
|
||||
ReachableBlocks.swift
|
||||
Set.swift
|
||||
Stack.swift
|
||||
Worklist.swift)
|
||||
ReachableBlocks.swift)
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SIL
|
||||
|
||||
let getAccessBaseTest = FunctionTest("swift_get_access_base") {
|
||||
function, arguments, context in
|
||||
let address = arguments.takeValue()
|
||||
|
||||
@@ -904,3 +904,29 @@ let interiorLivenessTest = FunctionTest("interior_liveness_swift") {
|
||||
defer { boundary.deinitialize() }
|
||||
print(boundary)
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Move this to InstructionRange.swift when computeLinearLiveness is in the SIL module.
|
||||
//
|
||||
let rangeOverlapsPathTest = FunctionTest("range_overlaps_path") {
|
||||
function, arguments, context in
|
||||
let rangeValue = arguments.takeValue()
|
||||
print("Range of: \(rangeValue)")
|
||||
var range = computeLinearLiveness(for: rangeValue, context)
|
||||
defer { range.deinitialize() }
|
||||
let pathInst = arguments.takeInstruction()
|
||||
print("Path begin: \(pathInst)")
|
||||
if let pathBegin = pathInst as? ScopedInstruction {
|
||||
for end in pathBegin.endInstructions {
|
||||
print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end, context))
|
||||
}
|
||||
return
|
||||
}
|
||||
if let pathValue = pathInst as? SingleValueInstruction, pathValue.ownership == .owned {
|
||||
for end in pathValue.uses.endingLifetime {
|
||||
print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end.instruction, context))
|
||||
}
|
||||
return
|
||||
}
|
||||
print("Test specification error: not a scoped or owned instruction: \(pathInst)")
|
||||
}
|
||||
|
||||
@@ -35,5 +35,6 @@ add_swift_compiler_module(SIL
|
||||
VTable.swift
|
||||
WitnessTable.swift)
|
||||
|
||||
add_subdirectory(DataStructures)
|
||||
add_subdirectory(Utilities)
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SIL
|
||||
|
||||
/// A range of basic blocks.
|
||||
///
|
||||
/// The `BasicBlockRange` defines a range from a dominating "begin" block to one or more "end" blocks.
|
||||
@@ -46,16 +44,16 @@ import SIL
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
public struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
|
||||
/// The dominating begin block.
|
||||
let begin: BasicBlock
|
||||
public let begin: BasicBlock
|
||||
|
||||
/// The inclusive range, i.e. the exclusive range plus the end blocks.
|
||||
private(set) var inclusiveRange: Stack<BasicBlock>
|
||||
|
||||
public private(set) var inclusiveRange: Stack<BasicBlock>
|
||||
|
||||
/// The exclusive range, i.e. not containing the end blocks.
|
||||
var range: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
public var range: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
inclusiveRange.lazy.filter { contains($0) }
|
||||
}
|
||||
|
||||
@@ -66,7 +64,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
private var inExclusiveRange: BasicBlockSet
|
||||
private var worklist: BasicBlockWorklist
|
||||
|
||||
init(begin: BasicBlock, _ context: some Context) {
|
||||
public init(begin: BasicBlock, _ context: some Context) {
|
||||
self.begin = begin
|
||||
self.inclusiveRange = Stack(context)
|
||||
self.inserted = Stack(context)
|
||||
@@ -81,7 +79,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
/// Returns true if the begin-block is reached during backward propagation.
|
||||
/// Usually this is not relevant, but InstructionRange needs this information.
|
||||
@discardableResult
|
||||
mutating func insert(_ block: BasicBlock) -> Bool {
|
||||
public mutating func insert(_ block: BasicBlock) -> Bool {
|
||||
if wasInserted.insert(block) {
|
||||
inserted.append(block)
|
||||
}
|
||||
@@ -103,22 +101,22 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Insert a sequence of potential end blocks.
|
||||
mutating func insert<S: Sequence>(contentsOf other: S) where S.Element == BasicBlock {
|
||||
public mutating func insert<S: Sequence>(contentsOf other: S) where S.Element == BasicBlock {
|
||||
for block in other {
|
||||
insert(block)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the exclusive range contains `block`.
|
||||
func contains(_ block: BasicBlock) -> Bool { inExclusiveRange.contains(block) }
|
||||
|
||||
public func contains(_ block: BasicBlock) -> Bool { inExclusiveRange.contains(block) }
|
||||
|
||||
/// Returns true if the inclusive range contains `block`.
|
||||
func inclusiveRangeContains (_ block: BasicBlock) -> Bool {
|
||||
public func inclusiveRangeContains (_ block: BasicBlock) -> Bool {
|
||||
worklist.hasBeenPushed(block)
|
||||
}
|
||||
|
||||
/// Returns true if the range is valid and that's iff the begin block dominates all blocks of the range.
|
||||
var isValid: Bool {
|
||||
public var isValid: Bool {
|
||||
let entry = begin.parentFunction.entryBlock
|
||||
return begin == entry ||
|
||||
// If any block in the range is not dominated by `begin`, the range propagates back to the entry block.
|
||||
@@ -126,12 +124,12 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Returns the end blocks.
|
||||
var ends: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
public var ends: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
inserted.lazy.filter { !contains($0) }
|
||||
}
|
||||
|
||||
/// Returns the exit blocks.
|
||||
var exits: LazySequence<FlattenSequence<
|
||||
public var exits: LazySequence<FlattenSequence<
|
||||
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
|
||||
LazyFilterSequence<SuccessorArray>>>> {
|
||||
range.flatMap {
|
||||
@@ -142,11 +140,11 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Returns the interior blocks.
|
||||
var interiors: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
public var interiors: LazyFilterSequence<Stack<BasicBlock>> {
|
||||
inserted.lazy.filter { contains($0) && $0 != begin }
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
return (isValid ? "" : "<invalid>\n") +
|
||||
"""
|
||||
begin: \(begin.name)
|
||||
@@ -159,7 +157,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
worklist.deinitialize()
|
||||
inExclusiveRange.deinitialize()
|
||||
wasInserted.deinitialize()
|
||||
@@ -0,0 +1,14 @@
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
|
||||
swift_compiler_sources(SIL
|
||||
BasicBlockRange.swift
|
||||
InstructionRange.swift
|
||||
Set.swift
|
||||
Stack.swift
|
||||
Worklist.swift)
|
||||
@@ -10,8 +10,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SIL
|
||||
|
||||
/// A range of instructions.
|
||||
///
|
||||
/// The `InstructionRange` defines a range from a dominating "begin" instruction to one or more "end" instructions.
|
||||
@@ -38,29 +36,29 @@ import SIL
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
|
||||
public struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
|
||||
/// The underlying block range.
|
||||
private(set) var blockRange: BasicBlockRange
|
||||
public private(set) var blockRange: BasicBlockRange
|
||||
|
||||
private var insertedInsts: InstructionSet
|
||||
|
||||
// For efficiency, this set does not include instructions in blocks which are not the begin or any end block.
|
||||
private var inExclusiveRange: InstructionSet
|
||||
|
||||
init(begin beginInst: Instruction, _ context: some Context) {
|
||||
public init(begin beginInst: Instruction, _ context: some Context) {
|
||||
self = InstructionRange(beginBlock: beginInst.parentBlock, context)
|
||||
self.inExclusiveRange.insert(beginInst)
|
||||
}
|
||||
|
||||
// Note: 'ends' are simply the instructions to insert in the range. 'self.ends' might not return the same sequence
|
||||
// as this 'ends' argument because 'self.ends' will not include block exits.
|
||||
init<S: Sequence>(begin beginInst: Instruction, ends: S, _ context: some Context) where S.Element: Instruction {
|
||||
public init<S: Sequence>(begin beginInst: Instruction, ends: S, _ context: some Context) where S.Element: Instruction {
|
||||
self = InstructionRange(begin: beginInst, context)
|
||||
insert(contentsOf: ends)
|
||||
}
|
||||
|
||||
init(for value: Value, _ context: some Context) {
|
||||
public init(for value: Value, _ context: some Context) {
|
||||
if let inst = value.definingInstruction {
|
||||
self = InstructionRange(begin: inst, context)
|
||||
} else if let arg = value as? Argument {
|
||||
@@ -77,7 +75,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Insert a potential end instruction.
|
||||
mutating func insert(_ inst: Instruction) {
|
||||
public mutating func insert(_ inst: Instruction) {
|
||||
insertedInsts.insert(inst)
|
||||
insertIntoRange(instructions: ReverseInstructionList(first: inst.previous))
|
||||
if blockRange.insert(inst.parentBlock) {
|
||||
@@ -90,14 +88,14 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Insert a sequence of potential end instructions.
|
||||
mutating func insert<S: Sequence>(contentsOf other: S) where S.Element: Instruction {
|
||||
public mutating func insert<S: Sequence>(contentsOf other: S) where S.Element: Instruction {
|
||||
for inst in other {
|
||||
insert(inst)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the exclusive range contains `inst`.
|
||||
func contains(_ inst: Instruction) -> Bool {
|
||||
public func contains(_ inst: Instruction) -> Bool {
|
||||
if inExclusiveRange.contains(inst) {
|
||||
return true
|
||||
}
|
||||
@@ -106,37 +104,37 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// Returns true if the inclusive range contains `inst`.
|
||||
func inclusiveRangeContains (_ inst: Instruction) -> Bool {
|
||||
public func inclusiveRangeContains (_ inst: Instruction) -> Bool {
|
||||
contains(inst) || insertedInsts.contains(inst)
|
||||
}
|
||||
|
||||
/// Returns the end instructions.
|
||||
///
|
||||
/// Warning: this returns `begin` if no instructions were inserted.
|
||||
var ends: LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>, Instruction> {
|
||||
public var ends: LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>, Instruction> {
|
||||
blockRange.ends.map {
|
||||
$0.instructions.reversed().first(where: { insertedInsts.contains($0)})!
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the exit blocks.
|
||||
var exitBlocks: LazySequence<FlattenSequence<
|
||||
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
|
||||
public var exitBlocks: LazySequence<FlattenSequence<
|
||||
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
|
||||
LazyFilterSequence<SuccessorArray>>>> {
|
||||
blockRange.exits
|
||||
}
|
||||
|
||||
/// Returns the exit instructions.
|
||||
var exits: LazyMapSequence<LazySequence<FlattenSequence<
|
||||
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
|
||||
public var exits: LazyMapSequence<LazySequence<FlattenSequence<
|
||||
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
|
||||
LazyFilterSequence<SuccessorArray>>>>,
|
||||
Instruction> {
|
||||
blockRange.exits.lazy.map { $0.instructions.first! }
|
||||
}
|
||||
|
||||
/// Returns the interior instructions.
|
||||
var interiors: LazySequence<FlattenSequence<
|
||||
LazyMapSequence<Stack<BasicBlock>,
|
||||
public var interiors: LazySequence<FlattenSequence<
|
||||
LazyMapSequence<Stack<BasicBlock>,
|
||||
LazyFilterSequence<ReverseInstructionList>>>> {
|
||||
blockRange.inserted.lazy.flatMap {
|
||||
var include = blockRange.contains($0)
|
||||
@@ -151,7 +149,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
}
|
||||
|
||||
var begin: Instruction? {
|
||||
public var begin: Instruction? {
|
||||
blockRange.begin.instructions.first(where: inExclusiveRange.contains)
|
||||
}
|
||||
|
||||
@@ -163,7 +161,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
return (blockRange.isValid ? "" : "<invalid>\n") +
|
||||
"""
|
||||
begin: \(begin?.description ?? blockRange.begin.name)
|
||||
@@ -174,7 +172,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
inExclusiveRange.deinitialize()
|
||||
insertedInsts.deinitialize()
|
||||
blockRange.deinitialize()
|
||||
@@ -182,7 +180,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
|
||||
}
|
||||
|
||||
extension InstructionRange {
|
||||
enum PathOverlap {
|
||||
public enum PathOverlap {
|
||||
// range: ---
|
||||
// | pathBegin
|
||||
// | |
|
||||
@@ -226,7 +224,7 @@ extension InstructionRange {
|
||||
/// Returns .containsBegin, if this range has the same begin and end as the path.
|
||||
///
|
||||
/// Precondition: `begin` dominates `end`.
|
||||
func overlaps(pathBegin: Instruction, pathEnd: Instruction, _ context: some Context) -> PathOverlap {
|
||||
public func overlaps(pathBegin: Instruction, pathEnd: Instruction, _ context: some Context) -> PathOverlap {
|
||||
assert(pathBegin != pathEnd, "expect an exclusive path")
|
||||
if contains(pathBegin) {
|
||||
// Note: pathEnd != self.begin here since self.contains(pathBegin)
|
||||
@@ -277,25 +275,3 @@ extension InstructionRange {
|
||||
}
|
||||
}
|
||||
|
||||
let rangeOverlapsPathTest = FunctionTest("range_overlaps_path") {
|
||||
function, arguments, context in
|
||||
let rangeValue = arguments.takeValue()
|
||||
print("Range of: \(rangeValue)")
|
||||
var range = computeLinearLiveness(for: rangeValue, context)
|
||||
defer { range.deinitialize() }
|
||||
let pathInst = arguments.takeInstruction()
|
||||
print("Path begin: \(pathInst)")
|
||||
if let pathBegin = pathInst as? ScopedInstruction {
|
||||
for end in pathBegin.endInstructions {
|
||||
print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end, context))
|
||||
}
|
||||
return
|
||||
}
|
||||
if let pathValue = pathInst as? SingleValueInstruction, pathValue.ownership == .owned {
|
||||
for end in pathValue.uses.endingLifetime {
|
||||
print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end.instruction, context))
|
||||
}
|
||||
return
|
||||
}
|
||||
print("Test specification error: not a scoped or owned instruction: \(pathInst)")
|
||||
}
|
||||
@@ -10,10 +10,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SIL
|
||||
import OptimizerBridging
|
||||
import SILBridging
|
||||
|
||||
protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren {
|
||||
public protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren {
|
||||
associatedtype Element
|
||||
|
||||
init(_ context: some Context)
|
||||
@@ -31,31 +30,31 @@ protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren {
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct BasicBlockSet : IntrusiveSet {
|
||||
public struct BasicBlockSet : IntrusiveSet {
|
||||
|
||||
private let context: BridgedContext
|
||||
private let bridged: BridgedBasicBlockSet
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.context = context._bridged
|
||||
self.bridged = self.context.allocBasicBlockSet()
|
||||
}
|
||||
|
||||
func contains(_ block: BasicBlock) -> Bool {
|
||||
public func contains(_ block: BasicBlock) -> Bool {
|
||||
bridged.contains(block.bridged)
|
||||
}
|
||||
|
||||
/// Returns true if `block` was not contained in the set before inserting.
|
||||
@discardableResult
|
||||
mutating func insert(_ block: BasicBlock) -> Bool {
|
||||
public mutating func insert(_ block: BasicBlock) -> Bool {
|
||||
bridged.insert(block.bridged)
|
||||
}
|
||||
|
||||
mutating func erase(_ block: BasicBlock) {
|
||||
public mutating func erase(_ block: BasicBlock) {
|
||||
bridged.erase(block.bridged)
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
let function = bridged.getFunction().function
|
||||
let blockNames = function.blocks.enumerated().filter { contains($0.1) }
|
||||
.map { "bb\($0.0)"}
|
||||
@@ -63,7 +62,7 @@ struct BasicBlockSet : IntrusiveSet {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
context.freeBasicBlockSet(bridged)
|
||||
}
|
||||
}
|
||||
@@ -76,31 +75,31 @@ struct BasicBlockSet : IntrusiveSet {
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct ValueSet : IntrusiveSet {
|
||||
public struct ValueSet : IntrusiveSet {
|
||||
|
||||
private let context: BridgedContext
|
||||
private let bridged: BridgedNodeSet
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.context = context._bridged
|
||||
self.bridged = self.context.allocNodeSet()
|
||||
}
|
||||
|
||||
func contains(_ value: Value) -> Bool {
|
||||
public func contains(_ value: Value) -> Bool {
|
||||
bridged.containsValue(value.bridged)
|
||||
}
|
||||
|
||||
/// Returns true if `value` was not contained in the set before inserting.
|
||||
@discardableResult
|
||||
mutating func insert(_ value: Value) -> Bool {
|
||||
public mutating func insert(_ value: Value) -> Bool {
|
||||
bridged.insertValue(value.bridged)
|
||||
}
|
||||
|
||||
mutating func erase(_ value: Value) {
|
||||
public mutating func erase(_ value: Value) {
|
||||
bridged.eraseValue(value.bridged)
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
let function = bridged.getFunction().function
|
||||
var d = "{\n"
|
||||
for block in function.blocks {
|
||||
@@ -122,7 +121,7 @@ struct ValueSet : IntrusiveSet {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
context.freeNodeSet(bridged)
|
||||
}
|
||||
}
|
||||
@@ -135,31 +134,31 @@ struct ValueSet : IntrusiveSet {
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct SpecificInstructionSet<InstType: Instruction> : IntrusiveSet {
|
||||
public struct SpecificInstructionSet<InstType: Instruction> : IntrusiveSet {
|
||||
|
||||
private let context: BridgedContext
|
||||
private let bridged: BridgedNodeSet
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.context = context._bridged
|
||||
self.bridged = self.context.allocNodeSet()
|
||||
}
|
||||
|
||||
func contains(_ inst: InstType) -> Bool {
|
||||
public func contains(_ inst: InstType) -> Bool {
|
||||
bridged.containsInstruction(inst.bridged)
|
||||
}
|
||||
|
||||
/// Returns true if `inst` was not contained in the set before inserting.
|
||||
@discardableResult
|
||||
mutating func insert(_ inst: InstType) -> Bool {
|
||||
public mutating func insert(_ inst: InstType) -> Bool {
|
||||
bridged.insertInstruction(inst.bridged)
|
||||
}
|
||||
|
||||
mutating func erase(_ inst: InstType) {
|
||||
public mutating func erase(_ inst: InstType) {
|
||||
bridged.eraseInstruction(inst.bridged)
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
let function = bridged.getFunction().function
|
||||
var d = "{\n"
|
||||
for i in function.instructions {
|
||||
@@ -172,27 +171,27 @@ struct SpecificInstructionSet<InstType: Instruction> : IntrusiveSet {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
context.freeNodeSet(bridged)
|
||||
}
|
||||
}
|
||||
|
||||
/// An `InstructionSet` which also provides a `count` property.
|
||||
struct SpecificInstructionSetWithCount<InstType: Instruction> : IntrusiveSet {
|
||||
private(set) var count = 0
|
||||
public struct SpecificInstructionSetWithCount<InstType: Instruction> : IntrusiveSet {
|
||||
public private(set) var count = 0
|
||||
private var underlyingSet: SpecificInstructionSet<InstType>
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.underlyingSet = SpecificInstructionSet(context)
|
||||
}
|
||||
|
||||
func contains(_ inst: InstType) -> Bool { underlyingSet.contains(inst) }
|
||||
public func contains(_ inst: InstType) -> Bool { underlyingSet.contains(inst) }
|
||||
|
||||
var isEmpty: Bool { count == 0 }
|
||||
public var isEmpty: Bool { count == 0 }
|
||||
|
||||
/// Returns true if `inst` was not contained in the set before inserting.
|
||||
@discardableResult
|
||||
mutating func insert(_ inst: InstType) -> Bool {
|
||||
public mutating func insert(_ inst: InstType) -> Bool {
|
||||
if underlyingSet.insert(inst) {
|
||||
count += 1
|
||||
return true
|
||||
@@ -200,7 +199,7 @@ struct SpecificInstructionSetWithCount<InstType: Instruction> : IntrusiveSet {
|
||||
return false
|
||||
}
|
||||
|
||||
mutating func erase(_ inst: InstType) {
|
||||
public mutating func erase(_ inst: InstType) {
|
||||
if underlyingSet.contains(inst) {
|
||||
count -= 1
|
||||
assert(count >= 0)
|
||||
@@ -208,13 +207,13 @@ struct SpecificInstructionSetWithCount<InstType: Instruction> : IntrusiveSet {
|
||||
underlyingSet.erase(inst)
|
||||
}
|
||||
|
||||
var description: String { underlyingSet.description }
|
||||
public var description: String { underlyingSet.description }
|
||||
|
||||
mutating func deinitialize() { underlyingSet.deinitialize() }
|
||||
public mutating func deinitialize() { underlyingSet.deinitialize() }
|
||||
}
|
||||
|
||||
typealias InstructionSet = SpecificInstructionSet<Instruction>
|
||||
typealias InstructionSetWithCount = SpecificInstructionSetWithCount<Instruction>
|
||||
public typealias InstructionSet = SpecificInstructionSet<Instruction>
|
||||
public typealias InstructionSetWithCount = SpecificInstructionSetWithCount<Instruction>
|
||||
|
||||
/// A set of operands.
|
||||
///
|
||||
@@ -224,31 +223,31 @@ typealias InstructionSetWithCount = SpecificInstructionSetWithCount<Instruction>
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct OperandSet : IntrusiveSet {
|
||||
public struct OperandSet : IntrusiveSet {
|
||||
|
||||
private let context: BridgedContext
|
||||
private let bridged: BridgedOperandSet
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.context = context._bridged
|
||||
self.bridged = self.context.allocOperandSet()
|
||||
}
|
||||
|
||||
func contains(_ operand: Operand) -> Bool {
|
||||
public func contains(_ operand: Operand) -> Bool {
|
||||
bridged.contains(operand.bridged)
|
||||
}
|
||||
|
||||
/// Returns true if `inst` was not contained in the set before inserting.
|
||||
@discardableResult
|
||||
mutating func insert(_ operand: Operand) -> Bool {
|
||||
public mutating func insert(_ operand: Operand) -> Bool {
|
||||
bridged.insert(operand.bridged)
|
||||
}
|
||||
|
||||
mutating func erase(_ operand: Operand) {
|
||||
public mutating func erase(_ operand: Operand) {
|
||||
bridged.erase(operand.bridged)
|
||||
}
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
let function = bridged.getFunction().function
|
||||
var d = "{\n"
|
||||
for inst in function.instructions {
|
||||
@@ -263,13 +262,13 @@ struct OperandSet : IntrusiveSet {
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
context.freeOperandSet(bridged)
|
||||
}
|
||||
}
|
||||
|
||||
extension InstructionSet {
|
||||
mutating func insert<I: Instruction>(contentsOf source: some Sequence<I>) {
|
||||
public mutating func insert<I: Instruction>(contentsOf source: some Sequence<I>) {
|
||||
for inst in source {
|
||||
_ = insert(inst)
|
||||
}
|
||||
@@ -277,13 +276,13 @@ extension InstructionSet {
|
||||
}
|
||||
|
||||
extension IntrusiveSet {
|
||||
mutating func insert(contentsOf source: some Sequence<Element>) {
|
||||
public mutating func insert(contentsOf source: some Sequence<Element>) {
|
||||
for element in source {
|
||||
_ = insert(element)
|
||||
}
|
||||
}
|
||||
|
||||
init(insertContentsOf source: some Sequence<Element>, _ context: some Context) {
|
||||
public init(insertContentsOf source: some Sequence<Element>, _ context: some Context) {
|
||||
self.init(context)
|
||||
insert(contentsOf: source)
|
||||
}
|
||||
@@ -10,8 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import OptimizerBridging
|
||||
import SIL
|
||||
import SILBridging
|
||||
|
||||
/// A very efficient implementation of a stack, which can also be iterated over.
|
||||
///
|
||||
@@ -24,7 +23,7 @@ import SIL
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct Stack<Element> : CollectionLikeSequence {
|
||||
public struct Stack<Element> : CollectionLikeSequence {
|
||||
|
||||
private let bridgedContext: BridgedContext
|
||||
private var firstSlab = BridgedContext.Slab(nil)
|
||||
@@ -50,13 +49,13 @@ struct Stack<Element> : CollectionLikeSequence {
|
||||
return UnsafeMutableRawPointer(slab.data!).assumingMemoryBound(to: Element.self) + index
|
||||
}
|
||||
|
||||
struct Iterator : IteratorProtocol {
|
||||
public struct Iterator : IteratorProtocol {
|
||||
var slab: BridgedContext.Slab
|
||||
var index: Int
|
||||
let lastSlab: BridgedContext.Slab
|
||||
let endIndex: Int
|
||||
|
||||
mutating func next() -> Element? {
|
||||
public mutating func next() -> Element? {
|
||||
let end = (slab.data == lastSlab.data ? endIndex : slabCapacity)
|
||||
|
||||
guard index < end else { return nil }
|
||||
@@ -72,21 +71,21 @@ struct Stack<Element> : CollectionLikeSequence {
|
||||
}
|
||||
}
|
||||
|
||||
init(_ context: some Context) { self.bridgedContext = context._bridged }
|
||||
public init(_ context: some Context) { self.bridgedContext = context._bridged }
|
||||
|
||||
func makeIterator() -> Iterator {
|
||||
public func makeIterator() -> Iterator {
|
||||
return Iterator(slab: firstSlab, index: 0, lastSlab: lastSlab, endIndex: endIndex)
|
||||
}
|
||||
|
||||
var first: Element? {
|
||||
public var first: Element? {
|
||||
isEmpty ? nil : Stack.element(in: firstSlab, at: 0)
|
||||
}
|
||||
|
||||
var last: Element? {
|
||||
public var last: Element? {
|
||||
isEmpty ? nil : Stack.element(in: lastSlab, at: endIndex &- 1)
|
||||
}
|
||||
|
||||
mutating func push(_ element: Element) {
|
||||
public mutating func push(_ element: Element) {
|
||||
if endIndex >= Stack.slabCapacity {
|
||||
lastSlab = allocate(after: lastSlab)
|
||||
endIndex = 0
|
||||
@@ -100,17 +99,17 @@ struct Stack<Element> : CollectionLikeSequence {
|
||||
}
|
||||
|
||||
/// The same as `push` to provide an Array-like append API.
|
||||
mutating func append(_ element: Element) { push(element) }
|
||||
public mutating func append(_ element: Element) { push(element) }
|
||||
|
||||
mutating func append<S: Sequence>(contentsOf other: S) where S.Element == Element {
|
||||
public mutating func append<S: Sequence>(contentsOf other: S) where S.Element == Element {
|
||||
for elem in other {
|
||||
append(elem)
|
||||
}
|
||||
}
|
||||
|
||||
var isEmpty: Bool { return endIndex == 0 }
|
||||
|
||||
mutating func pop() -> Element? {
|
||||
public var isEmpty: Bool { return endIndex == 0 }
|
||||
|
||||
public mutating func pop() -> Element? {
|
||||
if isEmpty {
|
||||
return nil
|
||||
}
|
||||
@@ -133,12 +132,12 @@ struct Stack<Element> : CollectionLikeSequence {
|
||||
return elem
|
||||
}
|
||||
|
||||
mutating func removeAll() {
|
||||
public mutating func removeAll() {
|
||||
while pop() != nil { }
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() { removeAll() }
|
||||
public mutating func deinitialize() { removeAll() }
|
||||
}
|
||||
|
||||
extension Stack {
|
||||
@@ -10,8 +10,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SIL
|
||||
|
||||
/// A utility for processing entities in a worklist.
|
||||
///
|
||||
/// A `Worklist` is basically a combination of a stack and a set.
|
||||
@@ -20,20 +18,20 @@ import SIL
|
||||
/// This type should be a move-only type, but unfortunately we don't have move-only
|
||||
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
|
||||
/// destruct this data structure, e.g. in a `defer {}` block.
|
||||
struct Worklist<Set: IntrusiveSet> : CustomStringConvertible, NoReflectionChildren {
|
||||
typealias Element = Set.Element
|
||||
public struct Worklist<Set: IntrusiveSet> : CustomStringConvertible, NoReflectionChildren {
|
||||
public typealias Element = Set.Element
|
||||
private var worklist: Stack<Element>
|
||||
private var pushedElements: Set
|
||||
|
||||
init(_ context: some Context) {
|
||||
public init(_ context: some Context) {
|
||||
self.worklist = Stack(context)
|
||||
self.pushedElements = Set(context)
|
||||
}
|
||||
|
||||
mutating func pop() -> Element? { return worklist.pop() }
|
||||
public mutating func pop() -> Element? { return worklist.pop() }
|
||||
|
||||
/// Pop and allow the popped element to be pushed again to the worklist.
|
||||
mutating func popAndForget() -> Element? {
|
||||
public mutating func popAndForget() -> Element? {
|
||||
if let element = worklist.pop() {
|
||||
pushedElements.erase(element)
|
||||
return element
|
||||
@@ -41,24 +39,24 @@ struct Worklist<Set: IntrusiveSet> : CustomStringConvertible, NoReflectionChildr
|
||||
return nil
|
||||
}
|
||||
|
||||
mutating func pushIfNotVisited(_ element: Element) {
|
||||
public mutating func pushIfNotVisited(_ element: Element) {
|
||||
if pushedElements.insert(element) {
|
||||
worklist.append(element)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func pushIfNotVisited<S: Sequence>(contentsOf other: S) where S.Element == Element {
|
||||
public mutating func pushIfNotVisited<S: Sequence>(contentsOf other: S) where S.Element == Element {
|
||||
for element in other {
|
||||
pushIfNotVisited(element)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if \p element was pushed to the worklist, regardless if it's already popped or not.
|
||||
func hasBeenPushed(_ element: Element) -> Bool { pushedElements.contains(element) }
|
||||
public func hasBeenPushed(_ element: Element) -> Bool { pushedElements.contains(element) }
|
||||
|
||||
var isEmpty: Bool { worklist.isEmpty }
|
||||
public var isEmpty: Bool { worklist.isEmpty }
|
||||
|
||||
var description: String {
|
||||
public var description: String {
|
||||
"""
|
||||
worklist: \(worklist)
|
||||
pushed: \(pushedElements)
|
||||
@@ -66,20 +64,20 @@ struct Worklist<Set: IntrusiveSet> : CustomStringConvertible, NoReflectionChildr
|
||||
}
|
||||
|
||||
/// TODO: once we have move-only types, make this a real deinit.
|
||||
mutating func deinitialize() {
|
||||
public mutating func deinitialize() {
|
||||
pushedElements.deinitialize()
|
||||
worklist.deinitialize()
|
||||
}
|
||||
}
|
||||
|
||||
typealias BasicBlockWorklist = Worklist<BasicBlockSet>
|
||||
typealias InstructionWorklist = Worklist<InstructionSet>
|
||||
typealias SpecificInstructionWorklist<InstType: Instruction> = Worklist<SpecificInstructionSet<InstType>>
|
||||
typealias ValueWorklist = Worklist<ValueSet>
|
||||
typealias OperandWorklist = Worklist<OperandSet>
|
||||
public typealias BasicBlockWorklist = Worklist<BasicBlockSet>
|
||||
public typealias InstructionWorklist = Worklist<InstructionSet>
|
||||
public typealias SpecificInstructionWorklist<InstType: Instruction> = Worklist<SpecificInstructionSet<InstType>>
|
||||
public typealias ValueWorklist = Worklist<ValueSet>
|
||||
public typealias OperandWorklist = Worklist<OperandSet>
|
||||
|
||||
extension InstructionWorklist {
|
||||
mutating func pushPredecessors(of inst: Instruction, ignoring ignoreInst: Instruction) {
|
||||
public mutating func pushPredecessors(of inst: Instruction, ignoring ignoreInst: Instruction) {
|
||||
if let prev = inst.previous {
|
||||
if prev != ignoreInst {
|
||||
pushIfNotVisited(prev)
|
||||
@@ -94,7 +92,7 @@ extension InstructionWorklist {
|
||||
}
|
||||
}
|
||||
|
||||
mutating func pushSuccessors(of inst: Instruction, ignoring ignoreInst: Instruction) {
|
||||
public mutating func pushSuccessors(of inst: Instruction, ignoring ignoreInst: Instruction) {
|
||||
if let succ = inst.next {
|
||||
if succ != ignoreInst {
|
||||
pushIfNotVisited(succ)
|
||||
@@ -111,34 +109,36 @@ extension InstructionWorklist {
|
||||
}
|
||||
|
||||
/// A worklist for `Function`s.
|
||||
struct FunctionWorklist {
|
||||
public struct FunctionWorklist {
|
||||
|
||||
// The current functions in the worklist.
|
||||
private(set) var functions = Array<Function>()
|
||||
public private(set) var functions = Array<Function>()
|
||||
|
||||
// All functions which were ever pushed to the worklist.
|
||||
private var pushedFunctions = Set<Function>()
|
||||
|
||||
mutating func pushIfNotVisited(_ function: Function) {
|
||||
public init() {}
|
||||
|
||||
public mutating func pushIfNotVisited(_ function: Function) {
|
||||
if pushedFunctions.insert(function).inserted {
|
||||
functions.append(function)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func pushIfNotVisited<S: Sequence>(contentsOf functions: S) where S.Element == Function {
|
||||
public mutating func pushIfNotVisited<S: Sequence>(contentsOf functions: S) where S.Element == Function {
|
||||
for f in functions {
|
||||
pushIfNotVisited(f)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func pop() -> Function? {
|
||||
public mutating func pop() -> Function? {
|
||||
return functions.popLast()
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `ValueWorklist`, but allows pushing `Value`s from different functions -
|
||||
/// at the cost of a less efficient implementation.
|
||||
struct CrossFunctionValueWorklist {
|
||||
public struct CrossFunctionValueWorklist {
|
||||
|
||||
// The current values in the worklist.
|
||||
private(set) var values = Array<Value>()
|
||||
@@ -146,27 +146,27 @@ struct CrossFunctionValueWorklist {
|
||||
// All values which were ever pushed to the worklist.
|
||||
private var pushedValues = Set<ObjectIdentifier>(minimumCapacity: 8)
|
||||
|
||||
init() {
|
||||
public init() {
|
||||
values.reserveCapacity(8)
|
||||
}
|
||||
|
||||
mutating func pop() -> Value? {
|
||||
public mutating func pop() -> Value? {
|
||||
return values.popLast()
|
||||
}
|
||||
|
||||
mutating func pushIfNotVisited(_ value: Value) {
|
||||
public mutating func pushIfNotVisited(_ value: Value) {
|
||||
if pushedValues.insert(ObjectIdentifier(value)).inserted {
|
||||
values.append(value)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func pushIfNotVisited<S: Sequence>(contentsOf values: S) where S.Element == Value {
|
||||
public mutating func pushIfNotVisited<S: Sequence>(contentsOf values: S) where S.Element == Value {
|
||||
for value in values {
|
||||
pushIfNotVisited(value)
|
||||
}
|
||||
}
|
||||
|
||||
func hasBeenPushed(_ value: Value) -> Bool {
|
||||
public func hasBeenPushed(_ value: Value) -> Bool {
|
||||
return pushedValues.contains(ObjectIdentifier(value))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user