Skip to content

Commit 0509a05

Browse files
committed
SwiftCompilerSources: improve APIs for UseList
Make filter APIs for UseList chainable by adding them to Sequence where Element == Operand For example, it allows to write: ``` let singleUse = value.uses.ignoreDebugUses.ignoreUsers(ofType: EndAccessInst.self).singleUse ``` Also, add `UseList.getSingleUser(notOfType:)`
1 parent eb597cb commit 0509a05

File tree

10 files changed

+54
-95
lines changed

10 files changed

+54
-95
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/NamedReturnValueOptimization.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ let namedReturnValueOptimization = FunctionPass(name: "named-return-value-optimi
6161
/// Returns a copy_addr which copies from an alloc_stack to the `outArg` at the end of the function.
6262
///
6363
private func findCopyForNRVO(for outArg: FunctionArgument) -> CopyAddrInst? {
64-
guard let singleArgUse = outArg.uses.singleNonDebugUse,
64+
guard let singleArgUse = outArg.uses.ignoreDebugUses.singleUse,
6565
let copyToArg = singleArgUse.instruction as? CopyAddrInst else {
6666
return nil
6767
}
@@ -106,7 +106,7 @@ private func findCopyForNRVO(for outArg: FunctionArgument) -> CopyAddrInst? {
106106
}
107107

108108
private func performNRVO(with copy: CopyAddrInst, _ context: FunctionPassContext) {
109-
copy.source.uses.replaceAllExceptDealloc(with: copy.destination, context)
109+
copy.source.replaceAllUsesExceptDealloc(with: copy.destination, context)
110110
assert(copy.source == copy.destination)
111111
context.erase(instruction: copy)
112112
}
@@ -122,10 +122,8 @@ private func isAnyInstructionWritingToMemory(after: Instruction) -> Bool {
122122
return false
123123
}
124124

125-
private extension UseList {
126-
func replaceAllExceptDealloc(with replacement: Value, _ context: some MutatingContext) {
127-
for use in self where !(use.instruction is Deallocation) {
128-
use.set(to: replacement, context)
129-
}
125+
private extension Value {
126+
func replaceAllUsesExceptDealloc(with replacement: Value, _ context: some MutatingContext) {
127+
uses.lazy.filter{!($0.instruction is Deallocation)}.replaceAll(with: replacement, context)
130128
}
131129
}

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBeginCOWMutation.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private extension BeginCOWMutationInst {
5959
if !isEmptyCOWSingleton(instance) {
6060
return
6161
}
62-
if uniquenessResult.nonDebugUses.isEmpty {
62+
if uniquenessResult.uses.ignoreDebugUses.isEmpty {
6363
/// Don't create an integer_literal which would be dead. This would result
6464
/// in an infinite loop in SILCombine.
6565
return
@@ -70,15 +70,15 @@ private extension BeginCOWMutationInst {
7070
}
7171

7272
func optimizeEmptyBeginEndPair(_ context: SimplifyContext) -> Bool {
73-
if !uniquenessResult.nonDebugUses.isEmpty {
73+
if !uniquenessResult.uses.ignoreDebugUses.isEmpty {
7474
return false
7575
}
7676
let buffer = instanceResult
77-
if buffer.nonDebugUses.contains(where: { !($0.instruction is EndCOWMutationInst) }) {
77+
if buffer.uses.ignoreDebugUses.contains(where: { !($0.instruction is EndCOWMutationInst) }) {
7878
return false
7979
}
8080

81-
for use in buffer.nonDebugUses {
81+
for use in buffer.uses.ignoreDebugUses {
8282
let endCOW = use.instruction as! EndCOWMutationInst
8383
endCOW.uses.replaceAll(with: instance, context)
8484
context.erase(instruction: endCOW)
@@ -88,13 +88,13 @@ private extension BeginCOWMutationInst {
8888
}
8989

9090
func optimizeEmptyEndBeginPair(_ context: SimplifyContext) -> Bool {
91-
if !uniquenessResult.nonDebugUses.isEmpty {
91+
if !uniquenessResult.uses.ignoreDebugUses.isEmpty {
9292
return false
9393
}
9494
guard let endCOW = instance as? EndCOWMutationInst else {
9595
return false
9696
}
97-
if endCOW.nonDebugUses.contains(where: { $0.instruction != self }) {
97+
if endCOW.uses.ignoreDebugUses.contains(where: { $0.instruction != self }) {
9898
return false
9999
}
100100

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyDestructure.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ extension DestructureStructInst : OnoneSimplifyable {
8787
private func tryReplaceConstructDestructPair(construct: SingleValueInstruction,
8888
destruct: MultipleValueInstruction,
8989
_ context: SimplifyContext) {
90-
let singleUse = context.preserveDebugInfo ? construct.uses.singleUse : construct.uses.singleNonDebugUse
90+
let singleUse = context.preserveDebugInfo ? construct.uses.singleUse : construct.uses.ignoreDebugUses.singleUse
9191
let canEraseFirst = singleUse?.instruction == destruct
9292

9393
if !canEraseFirst && construct.parentFunction.hasOwnership && construct.ownership == .owned {

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ extension LoadInst : OnoneSimplifyable, SILCombineSimplifyable {
197197
if context.preserveDebugInfo {
198198
return !uses.contains { !($0.instruction is DestroyValueInst) }
199199
} else {
200-
return !nonDebugUses.contains { !($0.instruction is DestroyValueInst) }
200+
return !uses.ignoreDebugUses.contains { !($0.instruction is DestroyValueInst) }
201201
}
202202
}
203203
}

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyRefCasts.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private extension UnaryInstruction {
6565
}
6666

6767
func tryReplaceSource(withOperandOf inst: SingleValueInstruction, _ context: SimplifyContext) -> Bool {
68-
let singleUse = context.preserveDebugInfo ? inst.uses.singleUse : inst.uses.singleNonDebugUse
68+
let singleUse = context.preserveDebugInfo ? inst.uses.singleUse : inst.uses.ignoreDebugUses.singleUse
6969
let canEraseInst = singleUse?.instruction == self
7070
let replacement = inst.operands[0].value
7171

SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,14 @@ private extension Value {
265265
var singleUseValue: any Value = self
266266
var path = SmallProjectionPath()
267267
while true {
268-
guard let use = singleUseValue.uses.singleRelevantUse else {
268+
// The initializer value of a global can contain access instructions if it references another
269+
// global variable by address, e.g.
270+
// var p = Point(x: 10, y: 20)
271+
// let o = UnsafePointer(&p)
272+
// Therefore ignore the `end_access` use of a `begin_access`.
273+
let relevantUses = singleUseValue.uses.ignoreDebugUses.ignoreUsers(ofType: EndAccessInst.self)
274+
275+
guard let use = relevantUses.singleUse else {
269276
return nil
270277
}
271278

@@ -383,27 +390,3 @@ fileprivate struct FunctionWorklist {
383390
}
384391
}
385392
}
386-
387-
private extension UseList {
388-
var singleRelevantUse: Operand? {
389-
var singleUse: Operand?
390-
for use in self {
391-
switch use.instruction {
392-
case is DebugValueInst,
393-
// The initializer value of a global can contain access instructions if it references another
394-
// global variable by address, e.g.
395-
// var p = Point(x: 10, y: 20)
396-
// let o = UnsafePointer(&p)
397-
// Therefore ignore the `end_access` use of a `begin_access`.
398-
is EndAccessInst:
399-
continue
400-
default:
401-
if singleUse != nil {
402-
return nil
403-
}
404-
singleUse = use
405-
}
406-
}
407-
return singleUse
408-
}
409-
}

SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,7 @@ private struct StackProtectionOptimization {
365365
let builder = Builder(after: beginAccess, location: beginAccess.location.autoGenerated, context)
366366
let temporary = builder.createAllocStack(beginAccess.type)
367367

368-
for use in beginAccess.uses where !(use.instruction is EndAccessInst) {
369-
use.instruction.setOperand(at: use.index, to: temporary, context)
370-
}
368+
beginAccess.uses.ignoreUsers(ofType: EndAccessInst.self).replaceAll(with: temporary, context)
371369

372370
for endAccess in beginAccess.endInstructions {
373371
let endBuilder = Builder(before: endAccess, location: endAccess.location.autoGenerated, context)

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ extension AllocRefInstBase {
448448
}
449449
}
450450

451-
extension UseList {
451+
extension Sequence where Element == Operand {
452452
func replaceAll(with replacement: Value, _ context: some MutatingContext) {
453453
for use in self {
454454
use.set(to: replacement, context)

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ import SIL
1414
import OptimizerBridging
1515

1616
extension Value {
17-
var nonDebugUses: LazyFilterSequence<UseList> {
18-
uses.lazy.filter { !($0.instruction is DebugValueInst) }
19-
}
20-
2117
var lookThroughBorrow: Value {
2218
if let beginBorrow = self as? BeginBorrowInst {
2319
return beginBorrow.borrowedValue.lookThroughBorrow
@@ -206,7 +202,7 @@ extension Instruction {
206202
}
207203

208204
var isTriviallyDeadIgnoringDebugUses: Bool {
209-
if results.contains(where: { !$0.uses.isEmptyIgnoringDebugUses }) {
205+
if results.contains(where: { !$0.uses.ignoreDebugUses.isEmpty }) {
210206
return false
211207
}
212208
return self.canBeRemovedIfNotUsed
@@ -320,32 +316,6 @@ extension LoadInst {
320316
}
321317
}
322318

323-
324-
extension UseList {
325-
var singleNonDebugUse: Operand? {
326-
var singleUse: Operand?
327-
for use in self {
328-
if use.instruction is DebugValueInst {
329-
continue
330-
}
331-
if singleUse != nil {
332-
return nil
333-
}
334-
singleUse = use
335-
}
336-
return singleUse
337-
}
338-
339-
var isEmptyIgnoringDebugUses: Bool {
340-
for use in self {
341-
if !(use.instruction is DebugValueInst) {
342-
return false
343-
}
344-
}
345-
return true
346-
}
347-
}
348-
349319
extension SmallProjectionPath {
350320
/// Returns true if the path only contains projections which can be materialized as
351321
/// SIL struct or tuple projection instructions - for values or addresses.
@@ -421,7 +391,7 @@ extension SimplifyContext {
421391
/// The operation is not done if it would require to insert a copy due to keep ownership correct.
422392
func tryReplaceRedundantInstructionPair(first: SingleValueInstruction, second: SingleValueInstruction,
423393
with replacement: Value) {
424-
let singleUse = preserveDebugInfo ? first.uses.singleUse : first.uses.singleNonDebugUse
394+
let singleUse = preserveDebugInfo ? first.uses.singleUse : first.uses.ignoreDebugUses.singleUse
425395
let canEraseFirst = singleUse?.instruction == second
426396

427397
if !canEraseFirst && first.parentFunction.hasOwnership && replacement.ownership == .owned {

SwiftCompilerSources/Sources/SIL/Operand.swift

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,33 +115,43 @@ public struct UseList : CollectionLikeSequence {
115115
self.firstOpPtr = firstOpPtr
116116
}
117117

118-
public var singleUse: Operand? {
119-
if let op = firstOpPtr.operand {
120-
if op.getNextUse().operand != nil {
121-
return nil
122-
}
123-
return Operand(bridged: op)
124-
}
125-
return nil
118+
public func makeIterator() -> Iterator {
119+
return Iterator(currentOpPtr: firstOpPtr)
126120
}
121+
}
127122

128-
public func getSingleUser<I: Instruction>(ofType: I.Type) -> I? {
129-
var result: I? = nil
130-
for use in self {
131-
if let user = use.instruction as? I {
132-
if result != nil {
133-
return nil
134-
}
135-
result = user
123+
extension Sequence where Element == Operand {
124+
public var singleUse: Operand? {
125+
var result: Operand? = nil
126+
for op in self {
127+
if result != nil {
128+
return nil
136129
}
130+
result = op
137131
}
138132
return result
139133
}
140134

141135
public var isSingleUse: Bool { singleUse != nil }
142136

143-
public func makeIterator() -> Iterator {
144-
return Iterator(currentOpPtr: firstOpPtr)
137+
public var ignoreDebugUses: LazyFilterSequence<Self> {
138+
self.lazy.filter { !($0.instruction is DebugValueInst) }
139+
}
140+
141+
public func filterUsers<I: Instruction>(ofType: I.Type) -> LazyFilterSequence<Self> {
142+
self.lazy.filter { $0.instruction is I }
143+
}
144+
145+
public func ignoreUsers<I: Instruction>(ofType: I.Type) -> LazyFilterSequence<Self> {
146+
self.lazy.filter { !($0.instruction is I) }
147+
}
148+
149+
public func getSingleUser<I: Instruction>(ofType: I.Type) -> I? {
150+
filterUsers(ofType: I.self).singleUse?.instruction as? I
151+
}
152+
153+
public func getSingleUser<I: Instruction>(notOfType: I.Type) -> Instruction? {
154+
ignoreUsers(ofType: I.self).singleUse?.instruction
145155
}
146156
}
147157

0 commit comments

Comments
 (0)