Skip to content

Optimizer: some improvements for alias analysis in several utilities #75689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ struct AliasAnalysis {
if destroy.destroyedValue.type.isNoEscapeFunction {
return .noEffects
}
if destroy.isDeadEnd {
// We don't have to take deinit effects into acount for a `destroy_value [dead_end]`.
// Such destroys are lowered to no-ops and will not call any deinit.
return .noEffects
}
return defaultEffects(of: destroy, on: memLoc)

default:
Expand Down Expand Up @@ -569,11 +574,7 @@ private enum MemoryLocation {
var isLetValue: Bool {
switch self {
case .memoryAddress(let addr):
switch addr.accessBase {
case .global(let global): return global.isLet
case .class(let rea): return rea.fieldIsLet
default: return false
}
return addr.accessBase.isLet
case .modifyAccessScope:
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
switch uacUse.instruction {
case is IsUniqueInst:
break
case is LoadInst, is LoadBorrowInst:
case is LoadInst, is LoadBorrowInst, is ApplyInst, is TryApplyInst:
if followLoads(at: path) {
return .abortWalk
}
Expand Down
10 changes: 0 additions & 10 deletions SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -625,16 +625,6 @@ private struct EscapesToValueVisitor : EscapeVisitor {
}

extension Function {
var globalOfGlobalInitFunction: GlobalVariable? {
if isGlobalInitFunction,
let ret = returnInstruction,
let atp = ret.returnedValue as? AddressToPointerInst,
let ga = atp.address as? GlobalAddrInst {
return ga.global
}
return nil
}

var initializedGlobal: GlobalVariable? {
if !isGlobalInitOnceFunction {
return nil
Expand Down
5 changes: 5 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ final public class UnmanagedAutoreleaseValueInst : RefCountingInst {}

final public class DestroyValueInst : Instruction, UnaryInstruction {
public var destroyedValue: Value { operand.value }

/// True if this `destroy_value` is inside a dead-end block is only needed to formally
/// end the lifetime of its operand.
/// Such `destroy_value` instructions are lowered to no-ops.
public var isDeadEnd: Bool { bridged.DestroyValueInst_isDeadEnd() }
}

final public class DestroyAddrInst : Instruction, UnaryInstruction {
Expand Down
26 changes: 26 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,17 @@ private extension PointerToAddressInst {
}
return walker.result
}

var resultOfGlobalAddressorCall: GlobalVariable? {
if isStrict,
let apply = pointer as? ApplyInst,
let callee = apply.referencedFunction,
let global = callee.globalOfGlobalInitFunction
{
return global
}
return nil
}
}

/// The `EnclosingScope` of an access is the innermost `begin_access`
Expand Down Expand Up @@ -507,6 +518,9 @@ private struct AccessPathWalker : AddressUseDefWalker {
if let p2ai = address as? PointerToAddressInst {
if let originatingAddr = p2ai.originatingAddress {
return walkUp(address: originatingAddr, path: path)
} else if let global = p2ai.resultOfGlobalAddressorCall {
self.result = AccessPath(base: .global(global), projectionPath: path.projectionPath)
return .continueWalk
} else {
self.result = AccessPath(base: .pointer(p2ai), projectionPath: path.projectionPath)
return .continueWalk
Expand Down Expand Up @@ -628,3 +642,15 @@ extension ValueUseDefWalker where Path == SmallProjectionPath {
}
}
}

extension Function {
public var globalOfGlobalInitFunction: GlobalVariable? {
if isGlobalInitFunction,
let ret = returnInstruction,
let atp = ret.returnedValue as? AddressToPointerInst,
let ga = atp.address as? GlobalAddrInst {
return ga.global
}
return nil
}
}
1 change: 1 addition & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ struct BridgedInstruction {

BRIDGED_INLINE SwiftInt ProjectBoxInst_fieldIndex() const;
BRIDGED_INLINE bool EndCOWMutationInst_doKeepUnique() const;
BRIDGED_INLINE bool DestroyValueInst_isDeadEnd() const;
BRIDGED_INLINE SwiftInt EnumInst_caseIndex() const;
BRIDGED_INLINE SwiftInt UncheckedEnumDataInst_caseIndex() const;
BRIDGED_INLINE SwiftInt InitEnumDataAddrInst_caseIndex() const;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/SIL/SILBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,10 @@ bool BridgedInstruction::EndCOWMutationInst_doKeepUnique() const {
return getAs<swift::EndCOWMutationInst>()->doKeepUnique();
}

bool BridgedInstruction::DestroyValueInst_isDeadEnd() const {
return getAs<swift::DestroyValueInst>()->isDeadEnd();
}

SwiftInt BridgedInstruction::EnumInst_caseIndex() const {
return getAs<swift::EnumInst>()->getCaseIndex();
}
Expand Down
79 changes: 79 additions & 0 deletions test/SILOptimizer/accessutils.sil
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,85 @@ bb0:

sil_global @global1 : $Int64
sil_global @global2 : $Int64
sil_global @somePointer : $Builtin.RawPointer

sil [global_init] [ossa] @addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer {
bb0:
%0 = global_addr @global1 : $*Int64
%1 = address_to_pointer %0 : $*Int64 to $Builtin.RawPointer
return %1 : $Builtin.RawPointer
}

sil [global_init] [ossa] @external_addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer

sil [global_init] [ossa] @wrong_addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer {
bb0:
%0 = global_addr @somePointer : $*Builtin.RawPointer
%1 = load [trivial] %0 : $*Builtin.RawPointer
return %1 : $Builtin.RawPointer
}

// CHECK-LABEL: Accesses for testSimpleGlobal
// CHECK-NEXT: Value: %0 = global_addr @global1 : $*Int64
// CHECK-NEXT: Scope: base
// CHECK-NEXT: Base: global - @global1
// CHECK-NEXT: Path: ""
// CHECK-NEXT: no Storage paths
// CHECK-NEXT: End accesses for testSimpleGlobal
sil [ossa] @testSimpleGlobal : $@convention(thin) () -> Int64 {
bb0:
%0 = global_addr @global1 : $*Int64
%1 = load [trivial] %0 : $*Int64
return %1 : $Int64
}

// CHECK-LABEL: Accesses for testGlobalViaAddressor
// CHECK-NEXT: Value: %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
// CHECK-NEXT: Scope: base
// CHECK-NEXT: Base: global - @global1
// CHECK-NEXT: Path: ""
// CHECK-NEXT: no Storage paths
// CHECK-NEXT: End accesses for testGlobalViaAddressor
sil [ossa] @testGlobalViaAddressor : $@convention(thin) () -> Int64 {
bb0:
%0 = function_ref @addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer
%1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
%3 = load [trivial] %2 : $*Int64
return %3 : $Int64
}

// CHECK-LABEL: Accesses for testGlobalViaUnknwonAddressor
// CHECK-NEXT: Value: %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
// CHECK-NEXT: Scope: base
// CHECK-NEXT: Base: pointer - %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
// CHECK-NEXT: Path: ""
// CHECK-NEXT: no Storage paths
// CHECK-NEXT: End accesses for testGlobalViaUnknwonAddressor
sil [ossa] @testGlobalViaUnknwonAddressor : $@convention(thin) () -> Int64 {
bb0:
%0 = function_ref @external_addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer
%1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
%3 = load [trivial] %2 : $*Int64
return %3 : $Int64
}

// CHECK-LABEL: Accesses for testGlobalViaWrongAddressor
// CHECK-NEXT: Value: %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
// CHECK-NEXT: Scope: base
// CHECK-NEXT: Base: pointer - %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
// CHECK-NEXT: Path: ""
// CHECK-NEXT: no Storage paths
// CHECK-NEXT: End accesses for testGlobalViaWrongAddressor
sil [ossa] @testGlobalViaWrongAddressor : $@convention(thin) () -> Int64 {
bb0:
%0 = function_ref @wrong_addressor_of_global1 : $@convention(thin) () -> Builtin.RawPointer
%1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64
%3 = load [trivial] %2 : $*Int64
return %3 : $Int64
}

sil @coro : $@yield_once @convention(thin) () -> @yields @inout Int64

Expand Down
35 changes: 19 additions & 16 deletions test/SILOptimizer/addr_escape_info.sil
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ sil @non_escaping_class_argument : $@convention(thin) (@guaranteed X) -> () {
sil @inout_class_argument : $@convention(thin) (@inout X) -> () {
[%0: noescape **]
}
sil @inout_class_argument2 : $@convention(thin) (@inout XandIntClass) -> () {
[%0: noescape **]
}
sil @inout_class_argument3 : $@convention(thin) (@inout XandIntClass) -> @error Error {
[%0: noescape **]
}
sil @container_argument : $@convention(thin) (@guaranteed Container) -> ()
sil @take_closure_as_addr : $@convention(thin) (@in @callee_guaranteed () -> ()) -> ()
sil @take_closure_as_addr_noescape : $@convention(thin) (@in @callee_guaranteed () -> ()) -> () {
Expand Down Expand Up @@ -813,6 +819,9 @@ bb0(%0 : @owned $X):

// CHECK-LABEL: Address escape information for test_unchecked_addr_cast:
// CHECK: value: %1 = alloc_stack $X
// CHECK: ==> %10 = apply %9(%4) : $@convention(thin) (@inout XandIntClass) -> ()
// CHECK: ==> try_apply %11(%4) : $@convention(thin) (@inout XandIntClass) -> @error any Error, normal bb1, error bb2
// CHECK: - %15 = apply %14() : $@convention(thin) () -> ()
// CHECK-NEXT: End function test_unchecked_addr_cast
sil [ossa] @test_unchecked_addr_cast : $@convention(thin) (@owned X) -> @owned XandIntClass {
bb0(%0 : @owned $X):
Expand All @@ -824,25 +833,19 @@ bb0(%0 : @owned $X):
%6 = load_borrow %4 : $*XandIntClass
end_borrow %6 : $XandIntClass
%8 = load [take] %4 : $*XandIntClass
%9 = function_ref @inout_class_argument2 : $@convention(thin) (@inout XandIntClass) -> ()
%10 = apply %9(%4) : $@convention(thin) (@inout XandIntClass) -> ()
%11 = function_ref @inout_class_argument3 : $@convention(thin) (@inout XandIntClass) -> @error Error
try_apply %11(%4) : $@convention(thin) (@inout XandIntClass) -> @error Error, normal bb1, error bb2

bb1(%13 : $()):
%14 = function_ref @no_arguments : $@convention(thin) () -> ()
%15 = apply %14() : $@convention(thin) () -> ()
dealloc_stack %1 : $*X
return %8 : $XandIntClass
}

// CHECK-LABEL: Address escape information for test_unchecked_addr_cast_escaping:
// CHECK: value: %1 = alloc_stack $X
// CHECK-NEXT: ==> %6 = apply %5(%4) : $@convention(thin) (@inout X) -> ()
// CHECK-NEXT: End function test_unchecked_addr_cast_escaping
sil [ossa] @test_unchecked_addr_cast_escaping : $@convention(thin) (@owned XandIntClass) -> () {
bb0(%0 : @owned $XandIntClass):
%1 = alloc_stack $XandIntClass
store %0 to [init] %1 : $*XandIntClass
fix_lifetime %1 : $*XandIntClass
%4 = unchecked_addr_cast %1 : $*XandIntClass to $*X
%5 = function_ref @inout_class_argument : $@convention(thin) (@inout X) -> ()
%6 = apply %5(%4) : $@convention(thin) (@inout X) -> ()
dealloc_stack %1 : $*XandIntClass
%8 = tuple ()
return %8 : $()
bb2(%17 : $Error):
unreachable
}

// CHECK-LABEL: Address escape information for test_store_borrow:
Expand Down
14 changes: 14 additions & 0 deletions test/SILOptimizer/escape_info.sil
Original file line number Diff line number Diff line change
Expand Up @@ -1457,3 +1457,17 @@ bb0:
%3 = unchecked_ref_cast %1 : $Derived to $X
return %2 : $X
}

// CHECK-LABEL: Escape information for test_unchecked_addr_cast:
// CHECK: global: %1 = alloc_ref $X
// CHECK: End function test_unchecked_addr_cast
sil @test_unchecked_addr_cast : $@convention(thin) () -> @owned Builtin.RawPointer {
bb0:
%0 = alloc_stack $X
%1 = alloc_ref $X
store %1 to %0 : $*X
%3 = unchecked_addr_cast %0 : $*X to $*Builtin.RawPointer
%4 = load %3 : $*Builtin.RawPointer
dealloc_stack %0 : $*X
return %4 : $Builtin.RawPointer
}
Loading