Skip to content

Commit c39d86c

Browse files
Merge pull request #5501 from swiftwasm/main
[pull] swiftwasm from main
2 parents c6a1dbf + 2e484a1 commit c39d86c

File tree

306 files changed

+17349
-1766
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

306 files changed

+17349
-1766
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ swift_compiler_sources(Optimizer
1919
SimplifyInitEnumDataAddr.swift
2020
SimplifyLoad.swift
2121
SimplifyPartialApply.swift
22+
SimplifyRetainReleaseValue.swift
2223
SimplifyStrongRetainRelease.swift
2324
SimplifyStructExtract.swift
2425
SimplifyTupleExtract.swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
//===--- SimplifyRetainReleaseValue.swift ---------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
extension RetainValueInst : Simplifyable, SILCombineSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
// Remove pairs of
19+
// ```
20+
// release_value %0 // the release is before the retain!
21+
// retain_value %0
22+
// ```
23+
// which sometimes the ARC optimizations cannot do.
24+
//
25+
if optimizeReleaseRetainPair(context) {
26+
return
27+
}
28+
29+
// Replace
30+
// ```
31+
// %1 = enum #E.A, %0
32+
// retain_value %1
33+
// ```
34+
// with
35+
// ```
36+
// %1 = enum #E.A, %0 // maybe dead
37+
// retain_value %0
38+
// ```
39+
replaceOperandWithPayloadOfEnum(context)
40+
41+
// Remove if the operand is trivial (but not necessarily its type), e.g.
42+
// ```
43+
// %1 = value_to_bridge_object %0 : $UInt64
44+
// retain_value %1 : $Builtin.BridgeObject
45+
// ```
46+
if removeIfOperandIsTrivial(context) {
47+
return
48+
}
49+
50+
// Replace e.g.
51+
// ```
52+
// retain_value %1 : $SomeClass
53+
// ```
54+
// with
55+
// ```
56+
// strong_retain %1 : $SomeClass
57+
// ```
58+
replaceWithStrongOrUnownedRetain(context)
59+
}
60+
}
61+
62+
extension ReleaseValueInst : Simplifyable, SILCombineSimplifyable {
63+
func simplify(_ context: SimplifyContext) {
64+
65+
// Replace
66+
// ```
67+
// %1 = enum #E.A, %0
68+
// release_value %1
69+
// ```
70+
// with
71+
// ```
72+
// %1 = enum #E.A, %0 // maybe dead
73+
// release_value %0
74+
// ```
75+
replaceOperandWithPayloadOfEnum(context)
76+
77+
// Remove if the operand is trivial (but not necessarily its type), e.g.
78+
// ```
79+
// %1 = value_to_bridge_object %0 : $UInt64
80+
// release_value %1 : $Builtin.BridgeObject
81+
// ```
82+
if removeIfOperandIsTrivial(context) {
83+
return
84+
}
85+
86+
// Replace e.g.
87+
// ```
88+
// release_value %1 : $SomeClass
89+
// ```
90+
// with
91+
// ```
92+
// release_value %1 : $SomeClass
93+
// ```
94+
replaceWithStrongOrUnownedRelease(context)
95+
}
96+
}
97+
98+
private extension RetainValueInst {
99+
func optimizeReleaseRetainPair(_ context: SimplifyContext) -> Bool {
100+
if let prevInst = self.previous,
101+
let release = prevInst as? ReleaseValueInst,
102+
release.value == self.value {
103+
context.erase(instruction: release)
104+
context.erase(instruction: self)
105+
return true
106+
}
107+
return false
108+
}
109+
110+
func replaceWithStrongOrUnownedRetain(_ context: SimplifyContext) {
111+
if value.type.isReferenceCounted(in: parentFunction) {
112+
let builder = Builder(before: self, context)
113+
if value.type.isUnownedStorageType {
114+
builder.createUnownedRetain(operand: value)
115+
} else {
116+
builder.createStrongRetain(operand: value)
117+
}
118+
context.erase(instruction: self)
119+
}
120+
}
121+
}
122+
123+
private extension ReleaseValueInst {
124+
func replaceWithStrongOrUnownedRelease(_ context: SimplifyContext) {
125+
if value.type.isReferenceCounted(in: parentFunction) {
126+
let builder = Builder(before: self, context)
127+
if value.type.isUnownedStorageType {
128+
builder.createUnownedRelease(operand: value)
129+
} else {
130+
builder.createStrongRelease(operand: value)
131+
}
132+
context.erase(instruction: self)
133+
}
134+
}
135+
}
136+
137+
private extension UnaryInstruction {
138+
func replaceOperandWithPayloadOfEnum(_ context: SimplifyContext) {
139+
if let e = operand.value as? EnumInst,
140+
!e.type.isValueTypeWithDeinit,
141+
let payload = e.payload {
142+
operand.set(to: payload, context)
143+
}
144+
}
145+
146+
func removeIfOperandIsTrivial(_ context: SimplifyContext) -> Bool {
147+
if operand.value.isTrivial(context) {
148+
context.erase(instruction: self)
149+
return true
150+
}
151+
return false
152+
}
153+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ private func registerSwiftPasses() {
8787
registerForSILCombine(GlobalValueInst.self, { run(GlobalValueInst.self, $0) })
8888
registerForSILCombine(StrongRetainInst.self, { run(StrongRetainInst.self, $0) })
8989
registerForSILCombine(StrongReleaseInst.self, { run(StrongReleaseInst.self, $0) })
90+
registerForSILCombine(RetainValueInst.self, { run(RetainValueInst.self, $0) })
91+
registerForSILCombine(ReleaseValueInst.self, { run(ReleaseValueInst.self, $0) })
9092
registerForSILCombine(LoadInst.self, { run(LoadInst.self, $0) })
9193

9294
// Test passes

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

+37
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,43 @@ extension Value {
1616
var nonDebugUses: LazyFilterSequence<UseList> {
1717
uses.lazy.filter { !($0.instruction is DebugValueInst) }
1818
}
19+
20+
/// Walks over all fields of an aggregate and checks if a reference count
21+
/// operation for this value is required. This differs from a simple `Type.isTrivial`
22+
/// check, because it treats a value_to_bridge_object instruction as "trivial".
23+
/// It can also handle non-trivial enums with trivial cases.
24+
func isTrivial(_ context: some Context) -> Bool {
25+
if self is Undef {
26+
return true
27+
}
28+
var worklist = ValueWorklist(context)
29+
defer { worklist.deinitialize() }
30+
31+
worklist.pushIfNotVisited(self)
32+
while let v = worklist.pop() {
33+
if v.type.isTrivial(in: parentFunction) {
34+
continue
35+
}
36+
if v.type.isValueTypeWithDeinit {
37+
return false
38+
}
39+
switch v {
40+
case is ValueToBridgeObjectInst:
41+
break
42+
case is StructInst, is TupleInst:
43+
let inst = (v as! SingleValueInstruction)
44+
worklist.pushIfNotVisited(contentsOf: inst.operands.values.filter { !($0 is Undef) })
45+
case let en as EnumInst:
46+
if let payload = en.payload,
47+
!(payload is Undef) {
48+
worklist.pushIfNotVisited(payload)
49+
}
50+
default:
51+
return false
52+
}
53+
}
54+
return true
55+
}
1956
}
2057

2158
extension Builder {

SwiftCompilerSources/Sources/SIL/ApplySite.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ extension ApplySite {
8080
///
8181
/// This does not include the callee function operand.
8282
public var arguments: LazyMapSequence<OperandArray, Value> {
83-
argumentOperands.lazy.map { $0.value }
83+
argumentOperands.values
8484
}
8585

8686
public var substitutionMap: SubstitutionMap {

SwiftCompilerSources/Sources/SIL/Builder.swift

+12
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ public struct Builder {
136136
return notifyNew(release.getAs(StrongReleaseInst.self))
137137
}
138138

139+
@discardableResult
140+
public func createUnownedRetain(operand: Value) -> UnownedRetainInst {
141+
let retain = bridged.createUnownedRetain(operand.bridged)
142+
return notifyNew(retain.getAs(UnownedRetainInst.self))
143+
}
144+
145+
@discardableResult
146+
public func createUnownedRelease(operand: Value) -> UnownedReleaseInst {
147+
let release = bridged.createUnownedRelease(operand.bridged)
148+
return notifyNew(release.getAs(UnownedReleaseInst.self))
149+
}
150+
139151
public func createFunctionRef(_ function: Function) -> FunctionRefInst {
140152
let functionRef = bridged.createFunctionRef(function.bridged)
141153
return notifyNew(functionRef.getAs(FunctionRefInst.self))

SwiftCompilerSources/Sources/SIL/Instruction.swift

+11-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public class MultipleValueInstruction : Instruction {
197197
}
198198

199199
/// Instructions, which have a single operand.
200-
public protocol UnaryInstruction : AnyObject {
200+
public protocol UnaryInstruction : Instruction {
201201
var operands: OperandArray { get }
202202
var operand: Operand { get }
203203
}
@@ -306,14 +306,24 @@ final public class StrongRetainInst : RefCountingInst {
306306
public var instance: Value { operand.value }
307307
}
308308

309+
final public class UnownedRetainInst : RefCountingInst {
310+
public var instance: Value { operand.value }
311+
}
312+
309313
final public class RetainValueInst : RefCountingInst {
314+
public var value: Value { return operand.value }
310315
}
311316

312317
final public class StrongReleaseInst : RefCountingInst {
313318
public var instance: Value { operand.value }
314319
}
315320

321+
final public class UnownedReleaseInst : RefCountingInst {
322+
public var instance: Value { operand.value }
323+
}
324+
316325
final public class ReleaseValueInst : RefCountingInst {
326+
public var value: Value { return operand.value }
317327
}
318328

319329
final public class DestroyValueInst : Instruction, UnaryInstruction {

SwiftCompilerSources/Sources/SIL/Operand.swift

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public struct OperandArray : RandomAccessCollection, CustomReflectable {
7676
base: OptionalBridgedOperand(op: base.advancedBy(bounds.lowerBound).op),
7777
count: bounds.upperBound - bounds.lowerBound)
7878
}
79+
80+
public var values: LazyMapSequence<LazySequence<OperandArray>.Elements, Value> {
81+
self.lazy.map { $0.value }
82+
}
7983
}
8084

8185
public struct UseList : CollectionLikeSequence {

SwiftCompilerSources/Sources/SIL/Registration.swift

+2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ public func registerSILClasses() {
5454
register(EndApplyInst.self)
5555
register(AbortApplyInst.self)
5656
register(StrongRetainInst.self)
57+
register(UnownedRetainInst.self)
5758
register(RetainValueInst.self)
5859
register(StrongReleaseInst.self)
60+
register(UnownedReleaseInst.self)
5961
register(ReleaseValueInst.self)
6062
register(DestroyValueInst.self)
6163
register(DestroyAddrInst.self)

SwiftCompilerSources/Sources/SIL/Type.swift

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
3131
return !bridged.isNonTrivialOrContainsRawPointer(function.bridged.getFunction())
3232
}
3333

34+
/// True if this type is a value type (struct/enum) that requires deinitialization beyond
35+
/// destruction of its members.
36+
public var isValueTypeWithDeinit: Bool { bridged.isValueTypeWithDeinit() }
37+
3438
public func isLoadable(in function: Function) -> Bool {
3539
return bridged.isLoadable(function.bridged.getFunction())
3640
}
@@ -39,6 +43,10 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
3943
return bridged.isReferenceCounted(function.bridged.getFunction())
4044
}
4145

46+
public var isUnownedStorageType: Bool {
47+
return bridged.isUnownedStorageType()
48+
}
49+
4250
public var hasArchetype: Bool { bridged.hasArchetype() }
4351

4452
public var isNominal: Bool { bridged.getNominalOrBoundGenericNominal() != nil }

cmake/modules/AddPureSwift.cmake

+25-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ function(add_pure_swift_host_library name)
141141
set_property(TARGET ${name}
142142
PROPERTY BUILD_WITH_INSTALL_RPATH YES)
143143

144+
if(APSHL_SHARED AND CMAKE_SYSTEM_NAME STREQUAL Darwin)
145+
# Allow install_name_tool to update paths (for rdar://109473564)
146+
set_property(TARGET ${name} APPEND_STRING PROPERTY
147+
LINK_FLAGS " -Xlinker -headerpad_max_install_names")
148+
endif()
149+
144150
# Respect LLVM_COMMON_DEPENDS if it is set.
145151
#
146152
# LLVM_COMMON_DEPENDS if a global variable set in ./lib that provides targets
@@ -157,7 +163,7 @@ function(add_pure_swift_host_library name)
157163
add_custom_command(
158164
TARGET ${name}
159165
POST_BUILD
160-
COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $<TARGET_FILE:${name}> $<TARGET_OBJECTS:${name}>
166+
COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $<TARGET_FILE:${name}> $<TARGET_OBJECTS:${name}> "${SWIFT_HOST_LIBRARIES_DEST_DIR}/${name}.swiftmodule" "${CMAKE_CURRENT_BINARY_DIR}/${name}.swiftmodule"
161167
COMMAND_EXPAND_LISTS
162168
COMMENT "Update mtime of library outputs workaround")
163169

@@ -298,6 +304,24 @@ function(add_pure_swift_host_tool name)
298304
target_include_directories(${name} PUBLIC
299305
${SWIFT_HOST_LIBRARIES_DEST_DIR})
300306

307+
# Workaround to touch the library and its objects so that we don't
308+
# continually rebuild (again, see corresponding change in swift-syntax).
309+
add_custom_command(
310+
TARGET ${name}
311+
POST_BUILD
312+
COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $<TARGET_FILE:${name}> $<TARGET_OBJECTS:${name}>
313+
COMMAND_EXPAND_LISTS
314+
COMMENT "Update mtime of executable outputs workaround")
315+
316+
# Even worse hack - ${name}.swiftmodule is added as an output, even though
317+
# this is an executable target. Just touch it all the time to avoid having
318+
# to rebuild it every time.
319+
add_custom_command(
320+
TARGET ${name}
321+
POST_BUILD
322+
COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/${name}.swiftmodule"
323+
COMMAND_EXPAND_LISTS
324+
COMMENT "Update mtime of executable outputs workaround")
301325
# Export this target.
302326
set_property(GLOBAL APPEND PROPERTY SWIFT_EXPORTS ${name})
303327
endfunction()

docs/CppInteroperability/CppInteroperabilityManifesto.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
# ⚠️ Warning: document is out of date. ⚠️
44

5-
**This document has not had significant updates in the last three years. The goals and design outlined here do not necessarily reflect those established by the C++ Interop Work Group. For an up-to-date document, please see [the Forward Vision which is being developed here](https://github.com/zoecarver/swift/blob/docs/interop-roadmap/docs/CppInteroperability/ForwardVision.md).**
5+
**This document has not had significant updates in the last three years. The goals and design outlined here do not necessarily reflect those established by the C++ Interop Work Group. For an up-to-date document, please see [the Forward Vision document](https://github.com/apple/swift-evolution/blob/main/visions/using-swift-from-c%2B%2B.md).**
6+
7+
[** ‼️ Additionally, the official C++ interoperability documentation is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/)
68

79
This document discusses the design and tradeoffs for bidirectional API-level
810
interoperability between Swift and C++.

docs/CppInteroperability/CppInteroperabilityStatus.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[** ‼️ The official C++ interoperability documentation and status page is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/status)
2+
13
# C++ Interoperability Status
24

35
Swift has some experimental ability to interoperate with C++.

docs/CppInteroperability/GettingStartedWithC++Interop.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[** ‼️ The official C++ interoperability documentation is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/)
2+
13
# Getting started with C++ Interoperability
24

35
This document is designed to get you started with bidirectional API-level interoperability between Swift and C++.

docs/CppInteroperability/InteropOddities.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[** ‼️ The official C++ interoperability documentation is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/)
2+
13
# C++ Interoperability Oddities
24

35
C++ APIs may have slightly different behavior than other C++ APIs. This is a general catch-all document where these

0 commit comments

Comments
 (0)