Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
88103a7
[InstructionDeleter] Add fixLifetime argument.
nate-chandler May 4, 2023
5ab9a00
[CanonicalizeGuaranteedValue] Cleared everything.
nate-chandler May 4, 2023
e5e1481
[CanonGuaranteedValue] Rewrite fwds in place.
nate-chandler May 4, 2023
ea10281
[CanonGuaranteedValue] Don't insert fwd destroy.
nate-chandler May 4, 2023
ec4bf2e
Augment `abitypes.swift` to support testing on watch simulator...
edymtt May 2, 2023
270125b
Handle a gap while matching SIL patterns for hoisting array bound checks
meg-gupta May 2, 2023
3ee4668
[CodeComplete] Fix a nullptr crash
ahoppen May 9, 2023
5024955
[CodeCompletion] Fix another test that was causing an assertion failu…
ahoppen May 10, 2023
3d555a4
refactor two swift passes
eeckstein May 10, 2023
5e26417
Augment abitypes.swift to support testing on watch simulator... (#65768)
edymtt May 10, 2023
6c299ad
Merge pull request #65573 from meg-gupta/abcoptfix
meg-gupta May 10, 2023
0f25f02
[Macros] Improve diagnostics for missing macro implementation (#65814)
rxwei May 10, 2023
a0ec3f4
Revert "Relax test"
adrian-prantl May 10, 2023
b74cdf1
Derive the SILDebugScope for a variable declaration from its owning A…
adrian-prantl May 9, 2023
27731bd
IRGen: Another fix for compiling LLVM opaque pointers
aschwaighofer May 10, 2023
7260c3b
Merge pull request #65818 from ahoppen/ahoppen/stress-tester-fixes
ahoppen May 10, 2023
12e1db4
[move-only] Ensure that resilient deinits take their self argument as…
gottesmm May 9, 2023
7d7c929
[move-only] Teach the move only object checker how to handle concrete…
gottesmm May 5, 2023
59fdfad
[move-only] Spill noncopyable types that are objects using store_borr…
gottesmm May 5, 2023
e76f3f9
Change test to use ~Copyable syntax.
gottesmm May 10, 2023
0f6a0ed
add even more test coverage for parsing `~Copyable`
kavon May 10, 2023
8ab43a4
Merge pull request #65821 from eeckstein/refactor-swift-passes
swift-ci May 10, 2023
3e5347c
Merge pull request #65784 from adrian-prantl/108940570
adrian-prantl May 11, 2023
b723958
[AST] Added language feature for @_eagerMove.
nate-chandler May 10, 2023
edb08da
GenericSpecializer: fix the function convention if specialization rem…
eeckstein Mar 30, 2023
8ea848a
PerformanceDiagnostics: fix missing diagnostics
eeckstein Mar 31, 2023
7709a9a
don't verify the SIL module during de-serialization
eeckstein Mar 31, 2023
9326da0
allow deleting dead non-escaping closures in OSSA
eeckstein Apr 4, 2023
5e2e7e3
SIL Bridging: use `bool` for boolean properties
eeckstein Apr 6, 2023
85052a1
deprecate the -experimental-performance-annotations option
eeckstein Apr 18, 2023
4dcd91a
Swift SIL: add all deallocation instructions and let them conform to …
eeckstein May 9, 2023
08e75f2
Swift SIL: add the `Operand.set` API
eeckstein May 9, 2023
92a17f8
Optimizer: extract the NamedReturnValueOptimization from CopyForwardi…
eeckstein Apr 6, 2023
6eff928
Swift Optimizer: add a message to an assert
eeckstein Apr 19, 2023
46abfa8
tests: fix check lines in the simplify_unchecked_enum_data.sil test
eeckstein Apr 19, 2023
6488da9
SILOptimizer: don't copy move-only partial_apply arguments to tempora…
eeckstein May 9, 2023
82734b6
Swift Optimizer: simplification for apply, try_apply, begin_apply and…
eeckstein May 9, 2023
b916906
Swift SIL: add some APIs
eeckstein May 9, 2023
1355e94
Simplification: simplify `builtin "canBeClass"` and `builtin "assert_…
eeckstein May 9, 2023
dc3cb18
Swift Optimizer: add the MandatoryPerformanceOptimizations pass
eeckstein May 9, 2023
dfce8c2
Optimizer: replace the MandatoryGenericSpecializer with the Mandatory…
eeckstein May 10, 2023
13108d6
SILOptimizer: remove the obsolete MandatoryGenericSpecializer pass
eeckstein May 10, 2023
6877778
Merge pull request #65820 from eeckstein/performance-annotations
swift-ci May 11, 2023
3d146b8
Merge pull request #65686 from nate-chandler/canonicalize-guaranteed-…
nate-chandler May 11, 2023
8a611bf
Merge pull request #65836 from aschwaighofer/one_more_opaque_pointer_fix
aschwaighofer May 11, 2023
6d13bf1
SIL Optimizer: handle dead-end infinite loops in StackNesting
eeckstein May 11, 2023
4d8dab0
Merge pull request #65845 from nate-chandler/eagermove_language_feature
nate-chandler May 11, 2023
a6c4744
[sil-optimizer] Add LLVM_DEBUG statements to escaping capture diagnos…
gottesmm May 11, 2023
a4fcdd8
[move-only] Fix a thinko where we are treating inout convention as a …
gottesmm May 9, 2023
81a09b3
When using a store_borrow for borrowed things, make sure to only stor…
gottesmm May 11, 2023
46d99e4
Merge pull request #65858 from eeckstein/fix-stack-nesting
eeckstein May 11, 2023
290ede8
Merge pull request #65862 from gottesmm/pr-dd102ff2567b101537297f1755…
swift-ci May 11, 2023
dc73b5a
Merge pull request #65864 from gottesmm/pr-cfee502eb154203b1fda427c5c…
gottesmm May 11, 2023
5b5b55f
Merge pull request #65842 from gottesmm/more-resilient-stuff
gottesmm May 11, 2023
72df1fc
Merge pull request #65873 from kavon/more-test-coverage-without-copyable
swift-ci May 12, 2023
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 @@ -14,6 +14,7 @@ swift_compiler_sources(Optimizer
InitializeStaticGlobals.swift
ObjCBridgingOptimization.swift
MergeCondFails.swift
NamedReturnValueOptimization.swift
ReleaseDevirtualizer.swift
SimplificationPasses.swift
StackPromotion.swift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ let initializeStaticGlobalsPass = FunctionPass(name: "initialize-static-globals"
return
}

guard let (allocInst, storeToGlobal) = function.getGlobalInitialization() else {
guard let (allocInst, storeToGlobal) = getGlobalInitialization(of: function) else {
return
}

Expand All @@ -62,69 +62,69 @@ let initializeStaticGlobalsPass = FunctionPass(name: "initialize-static-globals"
context.erase(instruction: storeToGlobal)
}

private extension Function {
/// Analyses the global initializer function and returns the `alloc_global` and `store`
/// instructions which initialize the global.
///
/// The function's single basic block must contain following code pattern:
/// ```
/// alloc_global @the_global
/// %a = global_addr @the_global
/// %i = some_const_initializer_insts
/// store %i to %a
/// ```
func getGlobalInitialization() -> (allocInst: AllocGlobalInst, storeToGlobal: StoreInst)? {
/// Analyses the global initializer function and returns the `alloc_global` and `store`
/// instructions which initialize the global.
///
/// The function's single basic block must contain following code pattern:
/// ```
/// alloc_global @the_global
/// %a = global_addr @the_global
/// %i = some_const_initializer_insts
/// store %i to %a
/// ```
private func getGlobalInitialization(of function: Function) -> (allocInst: AllocGlobalInst, storeToGlobal: StoreInst)? {

guard let block = singleBlock else {
return nil
}
guard let block = function.singleBlock else {
return nil
}

var allocInst: AllocGlobalInst? = nil
var globalAddr: GlobalAddrInst? = nil
var store: StoreInst? = nil
var allocInst: AllocGlobalInst? = nil
var globalAddr: GlobalAddrInst? = nil
var store: StoreInst? = nil

for inst in block.instructions {
switch inst {
case is ReturnInst,
is DebugValueInst,
is DebugStepInst:
break
case let agi as AllocGlobalInst:
if allocInst != nil {
return nil
}
allocInst = agi
case let ga as GlobalAddrInst:
if globalAddr != nil {
return nil
}
guard let agi = allocInst, agi.global == ga.global else {
return nil
}
globalAddr = ga
case let si as StoreInst:
if store != nil {
return nil
}
guard let ga = globalAddr else {
return nil
}
if si.destination != ga {
return nil
}
store = si
default:
if !inst.isValidInStaticInitializerOfGlobal {
return nil
}
for inst in block.instructions {
switch inst {
case is ReturnInst,
is DebugValueInst,
is DebugStepInst:
break
case let agi as AllocGlobalInst:
if allocInst != nil {
return nil
}
allocInst = agi
case let ga as GlobalAddrInst:
if globalAddr != nil {
return nil
}
guard let agi = allocInst, agi.global == ga.global else {
return nil
}
globalAddr = ga
case let si as StoreInst:
if store != nil {
return nil
}
guard let ga = globalAddr else {
return nil
}
if si.destination != ga {
return nil
}
store = si
default:
if !inst.isValidInStaticInitializerOfGlobal {
return nil
}
}
if let store = store {
return (allocInst: allocInst!, storeToGlobal: store)
}
return nil
}
if let store = store {
return (allocInst: allocInst!, storeToGlobal: store)
}
return nil
}

private extension Function {
var singleBlock: BasicBlock? {
let block = entryBlock
if block.next != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//===--- NamedReturnValueOptimization.swift --------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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

/// Removes a `copy_addr` to an indirect out argument by replacing the source of the copy
/// (which must be an `alloc_stack`) with the out argument itself.
///
/// The following SIL pattern will be optimized:
///
/// sil @foo : $@convention(thin) <T> () -> @out T {
/// bb0(%0 : $*T):
/// %2 = alloc_stack $T
/// ...
/// copy_addr %some_value to [init] %2 // or any other writes to %2
/// ...
/// bbN:
/// copy_addr [take] %2 to [init] %0 : $*T // the only use of %0
/// ... // no writes
/// return
///
/// to:
///
/// sil @foo : $@convention(thin) <T> (@out T) -> () {
/// bb0(%0 : $*T):
/// %2 = alloc_stack $T // is dead now
/// ...
/// copy_addr %some_value to [init] %0
/// ...
/// bbN:
/// ...
/// return
///
/// This optimization can be done because we know that:
/// * The out argument dominates all uses of the copy_addr's source (because it's a function argument).
/// * It's not aliased (by definition). We can't allow aliases to be accessed between the initialization and the return.
///
/// This pass shouldn't run before serialization. It might prevent predictable memory optimizations
/// in a caller after inlining, because the memory location (the out argument = an alloc_stack in the caller)
/// might be written multiple times after this optimization.
///
let namedReturnValueOptimization = FunctionPass(name: "named-return-value-optimization") {
(function: Function, context: FunctionPassContext) in

for outArg in function.arguments[0..<function.numIndirectResultArguments] {
if let copyToArg = findCopyForNRVO(for: outArg) {
performNRVO(with: copyToArg, context)
}
}
}

/// Returns a copy_addr which copies from an alloc_stack to the `outArg` at the end of the function.
///
private func findCopyForNRVO(for outArg: FunctionArgument) -> CopyAddrInst? {
guard let singleArgUse = outArg.uses.singleNonDebugUse,
let copyToArg = singleArgUse.instruction as? CopyAddrInst else {
return nil
}

assert(singleArgUse == copyToArg.destinationOperand,
"single use of out-argument cannot be the source of a copy")

// Don't perform NRVO unless the copy is a [take]. This is the easiest way
// to determine that the local variable has ownership of its value and ensures
// that removing a copy is a reference count neutral operation. For example,
// this copy can't be trivially eliminated without adding a retain.
// sil @f : $@convention(thin) (@guaranteed T) -> @out T
// bb0(%in : $*T, %out : $T):
// %local = alloc_stack $T
// store %in to %local : $*T
// copy_addr %local to [init] %out : $*T
if !copyToArg.isTakeOfSrc {
return nil
}

guard let sourceStackAlloc = copyToArg.source as? AllocStackInst else {
return nil
}

// NRVO for alloc_stack [dynamic_lifetime] will invalidate OSSA invariants.
if sourceStackAlloc.hasDynamicLifetime && copyToArg.parentFunction.hasOwnership {
return nil
}

if !(copyToArg.parentBlock.terminator is ReturnInst) {
return nil
}

// This check is overly conservative, because we only need to check if the source
// of the copy is not written to. But the copy to the out argument is usually the last
// instruction of the function, so it doesn't matter.
if isAnyInstructionWritingToMemory(after: copyToArg) {
return nil
}

return copyToArg
}

private func performNRVO(with copy: CopyAddrInst, _ context: FunctionPassContext) {
copy.source.uses.replaceAllExceptDealloc(with: copy.destination, context)
assert(copy.source == copy.destination)
context.erase(instruction: copy)
}

private func isAnyInstructionWritingToMemory(after: Instruction) -> Bool {
var followingInst = after.next
while let fi = followingInst {
if fi.mayWriteToMemory && !(fi is DeallocStackInst) {
return true
}
followingInst = fi.next
}
return false
}

private extension UseList {
func replaceAllExceptDealloc(with replacement: Value, _ context: some MutatingContext) {
for use in self where !(use.instruction is Deallocation) {
use.set(to: replacement, context)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ let lateOnoneSimplificationPass = FunctionPass(name: "late-onone-simplification"
//===--------------------------------------------------------------------===//


private func runSimplification(on function: Function, _ context: FunctionPassContext,
preserveDebugInfo: Bool,
_ simplify: (Instruction, SimplifyContext) -> ()) {
func runSimplification(on function: Function, _ context: FunctionPassContext,
preserveDebugInfo: Bool,
_ simplify: (Instruction, SimplifyContext) -> ()) {
var worklist = InstructionWorklist(context)
defer { worklist.deinitialize() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ swift_compiler_sources(Optimizer
SimplifyDestructure.swift
SimplifyGlobalValue.swift
SimplifyLoad.swift
SimplifyPartialApply.swift
SimplifyStrongRetainRelease.swift
SimplifyStructExtract.swift
SimplifyTupleExtract.swift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,18 @@ import SIL

extension ApplyInst : OnoneSimplifyable {
func simplify(_ context: SimplifyContext) {
tryReplaceTrivialApplyOfPartialApply(context)
_ = context.tryDevirtualize(apply: self, isMandatory: false)
}
}

private extension ApplyInst {
func tryReplaceTrivialApplyOfPartialApply(_ context: SimplifyContext) {
guard let pa = callee as? PartialApplyInst else {
return
}

if pa.referencedFunction == nil {
return
}

// Currently we don't handle generic closures. For Onone this is good enough.
// TODO: handle it once we replace the SILCombine simplification with this.
if !allArgumentsAreTrivial(arguments) {
return
}

if !allArgumentsAreTrivial(pa.arguments) {
return
}

if !substitutionMap.isEmpty {
return
}

let allArgs = Array<Value>(arguments) + Array<Value>(pa.arguments)
let builder = Builder(before: self, context)
let newApply = builder.createApply(function: pa.callee, pa.substitutionMap, arguments: allArgs,
isNonThrowing: isNonThrowing, isNonAsync: isNonAsync,
specializationInfo: specializationInfo)
uses.replaceAll(with: newApply, context)
context.erase(instruction: self)

if context.tryDeleteDeadClosure(closure: pa) {
context.notifyInvalidatedStackNesting()
}
extension TryApplyInst : OnoneSimplifyable {
func simplify(_ context: SimplifyContext) {
_ = context.tryDevirtualize(apply: self, isMandatory: false)
}
}

private func allArgumentsAreTrivial(_ args: LazyMapSequence<OperandArray, Value>) -> Bool {
return !args.contains { !$0.hasTrivialType }
extension BeginApplyInst : OnoneSimplifyable {
func simplify(_ context: SimplifyContext) {
_ = context.tryDevirtualize(apply: self, isMandatory: false)
}
}
Loading