mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
134 lines
4.2 KiB
Swift
134 lines
4.2 KiB
Swift
//===--- SimplifyBeginCOWMutation.swift - Simplify begin_cow_mutation -----===//
|
|
//
|
|
// 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 https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SIL
|
|
|
|
extension BeginCOWMutationInst : Simplifiable, SILCombineSimplifiable {
|
|
func simplify(_ context: SimplifyContext) {
|
|
|
|
/// The buffer of an empty Array/Set/Dictionary singleton is known to be not
|
|
/// unique. Replace the uniqueness result of such a
|
|
/// `begin_cow_mutation` with a zero `integer_literal`, e.g.
|
|
///
|
|
/// %3 = global_addr @_swiftEmptyArrayStorage
|
|
/// %4 = address_to_pointer %3
|
|
/// %5 = raw_pointer_to_ref %4
|
|
/// %6 = unchecked_ref_cast %5
|
|
/// (%u, %b) = begin_cow_mutation %6
|
|
/// ->
|
|
/// [...]
|
|
/// (%not_used, %b) = begin_cow_mutation %6
|
|
/// %u = integer_literal $Builtin.Int1, 0
|
|
///
|
|
optimizeEmptySingleton(context)
|
|
|
|
/// If the only use of the `begin_cow_instruction` is an `end_cow_instruction`,
|
|
/// remove the pair, e.g.
|
|
///
|
|
/// (%u, %b) = begin_cow_mutation %0 : $Buffer
|
|
/// %e = end_cow_mutation %b : $Buffer
|
|
///
|
|
if optimizeEmptyBeginEndPair(context) {
|
|
return
|
|
}
|
|
|
|
/// If the operand of the `begin_cow_instruction` is an `end_cow_instruction`,
|
|
/// which has no other uses, remove the pair, e.g.
|
|
///
|
|
/// %e = end_cow_mutation %0 : $Buffer
|
|
/// (%u, %b) = begin_cow_mutation %e : $Buffer
|
|
///
|
|
if optimizeEmptyEndBeginPair(context) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension BeginCOWMutationInst {
|
|
|
|
func optimizeEmptySingleton(_ context: SimplifyContext) {
|
|
if !isEmptyCOWSingleton(instance) {
|
|
return
|
|
}
|
|
if uniquenessResult.uses.ignoreDebugUses.isEmpty {
|
|
/// Don't create an integer_literal which would be dead. This would result
|
|
/// in an infinite loop in SILCombine.
|
|
return
|
|
}
|
|
let builder = Builder(before: self, location: location, context)
|
|
let zero = builder.createIntegerLiteral(0, type: uniquenessResult.type);
|
|
uniquenessResult.uses.replaceAll(with: zero, context)
|
|
}
|
|
|
|
func optimizeEmptyBeginEndPair(_ context: SimplifyContext) -> Bool {
|
|
if !uniquenessResult.uses.ignoreDebugUses.isEmpty {
|
|
return false
|
|
}
|
|
let buffer = instanceResult
|
|
guard buffer.uses.ignoreDebugUses.allSatisfy({
|
|
if let endCOW = $0.instruction as? EndCOWMutationInst {
|
|
return !endCOW.doKeepUnique
|
|
}
|
|
return false
|
|
}) else
|
|
{
|
|
return false
|
|
}
|
|
|
|
for use in buffer.uses.ignoreDebugUses {
|
|
let endCOW = use.instruction as! EndCOWMutationInst
|
|
endCOW.replace(with: instance, context)
|
|
}
|
|
context.erase(instructionIncludingDebugUses: self)
|
|
return true
|
|
}
|
|
|
|
func optimizeEmptyEndBeginPair(_ context: SimplifyContext) -> Bool {
|
|
if !uniquenessResult.uses.ignoreDebugUses.isEmpty {
|
|
return false
|
|
}
|
|
guard let endCOW = instance as? EndCOWMutationInst,
|
|
!endCOW.doKeepUnique else {
|
|
return false
|
|
}
|
|
if endCOW.uses.ignoreDebugUses.contains(where: { $0.instruction != self }) {
|
|
return false
|
|
}
|
|
|
|
instanceResult.uses.replaceAll(with: endCOW.instance, context)
|
|
context.erase(instructionIncludingDebugUses: self)
|
|
context.erase(instructionIncludingDebugUses: endCOW)
|
|
return true
|
|
}
|
|
}
|
|
|
|
private func isEmptyCOWSingleton(_ value: Value) -> Bool {
|
|
var v = value
|
|
while true {
|
|
switch v {
|
|
case is UncheckedRefCastInst,
|
|
is UpcastInst,
|
|
is RawPointerToRefInst,
|
|
is AddressToPointerInst,
|
|
is CopyValueInst:
|
|
v = (v as! UnaryInstruction).operand.value
|
|
case let globalAddr as GlobalAddrInst:
|
|
let name = globalAddr.global.name
|
|
return name == "_swiftEmptyArrayStorage" ||
|
|
name == "_swiftEmptyDictionarySingleton" ||
|
|
name == "_swiftEmptySetSingleton"
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|