@@ -31,15 +31,6 @@ public struct FunctionEffects : CustomStringConvertible, NoReflectionChildren {
31
31
self . sideEffects = nil
32
32
}
33
33
34
- /// The "accumulated" side-effects of the function, which includes the global effects and
35
- /// all argument effects.
36
- public var accumulatedSideEffects : SideEffects . GlobalEffects {
37
- if let sideEffects = sideEffects {
38
- return sideEffects. accumulatedEffects
39
- }
40
- return . worstEffects
41
- }
42
-
43
34
public var description : String {
44
35
var numArgEffects = escapeEffects. arguments. reduce ( 0 , { max ( $0, $1. argumentIndex) } ) + 1
45
36
if let sideEffects = sideEffects {
@@ -70,14 +61,77 @@ public struct FunctionEffects : CustomStringConvertible, NoReflectionChildren {
70
61
71
62
extension Function {
72
63
73
- /// The global side effects of the function which are defined by attributes.
64
+ /// Returns the global side effects of the function.
65
+ public func getSideEffects( ) -> SideEffects . GlobalEffects {
66
+ if let sideEffects = effects. sideEffects {
67
+ /// There are computed side effects.
68
+ return sideEffects. accumulatedEffects
69
+ } else {
70
+
71
+ var effects = definedGlobalEffects
72
+
73
+ // Even a `[readnone]` function can read from indirect arguments.
74
+ if ( 0 ..< numArguments) . contains ( where: { getArgumentConvention ( for: $0) . isIndirectIn} ) {
75
+ effects. memory. read = true
76
+ }
77
+ // Even `[readnone]` and `[readonly]` functions write to indirect results.
78
+ if numIndirectResultArguments > 0 {
79
+ effects. memory. write = true
80
+ }
81
+ return effects
82
+ }
83
+ }
84
+
85
+ /// Returns the side effects for a function argument.
74
86
///
75
- /// This API should be used if there are no derived side-effects available, i.e. `effects.sideEffects` is nil.
76
- /// It returns "worstEffects" unless an effect attribute (e.g. `[readnone]`) is set for the function.
77
- public var definedSideEffects : SideEffects . GlobalEffects {
87
+ /// The `argument` can be a function argument in this function or an apply argument in a caller.
88
+ public func getSideEffects( forArgument argument: ProjectedValue ,
89
+ atIndex argumentIndex: Int ,
90
+ withConvention convention: ArgumentConvention ) -> SideEffects . GlobalEffects {
91
+ if let sideEffects = effects. sideEffects {
92
+ /// There are computed side effects.
93
+ var result = SideEffects . GlobalEffects ( )
94
+ let argEffect = sideEffects. getArgumentEffects ( for: argumentIndex)
95
+ if let effectPath = argEffect. read, effectPath. mayOverlap ( with: argument. path) {
96
+ result. memory. read = true
97
+ }
98
+ if let effectPath = argEffect. write, effectPath. mayOverlap ( with: argument. path) {
99
+ result. memory. write = true
100
+ }
101
+ if let effectPath = argEffect. copy, effectPath. mayOverlap ( with: argument. path) {
102
+ result. ownership. copy = true
103
+ }
104
+ if let effectPath = argEffect. destroy, effectPath. mayOverlap ( with: argument. path) {
105
+ result. ownership. destroy = true
106
+ }
107
+ return result
108
+ } else {
109
+ /// Even for defined effects, there might be additional effects due to the argument conventions.
110
+ var result = definedGlobalEffects
111
+ if convention. isIndirectIn {
112
+ // Even a `[readnone]` function can read from an indirect argument.
113
+ result. memory. read = true
114
+ } else if convention == . indirectOut {
115
+ // Even `[readnone]` and `[readonly]` functions write to indirect results.
116
+ result. memory. write = true
117
+ }
118
+ return result. restrictedTo ( argument: argument, withConvention: convention)
119
+ }
120
+ }
121
+
122
+ /// Global effect of the function, defined by effect attributes.
123
+ public var definedGlobalEffects : SideEffects . GlobalEffects {
124
+ switch name {
125
+ case " _swift_stdlib_malloc_size " , " _swift_stdlib_has_malloc_size " :
126
+ // These C runtime functions, which are used in the array implementation, have defined effects.
127
+ return SideEffects . GlobalEffects ( memory: SideEffects . Memory ( read: true ) )
128
+ default :
129
+ break
130
+ }
78
131
var result = SideEffects . GlobalEffects. worstEffects
79
132
switch effectAttribute {
80
133
case . none:
134
+ // The common case: there is no effect attribute, so we have to assume the worst effects.
81
135
break
82
136
case . readNone:
83
137
result. memory. read = false
@@ -421,9 +475,9 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
421
475
}
422
476
423
477
/// Removes effects, which cannot occur for an `argument` value with a given `convention`.
424
- public func restrictedTo( argument: Value , withConvention convention: ArgumentConvention ) -> GlobalEffects {
478
+ public func restrictedTo( argument: ProjectedValue , withConvention convention: ArgumentConvention ) -> GlobalEffects {
425
479
var result = self
426
- let isTrivial = argument. type . isTrivial ( in : argument . function )
480
+ let isTrivial = argument. value . hasTrivialNonPointerType
427
481
if isTrivial {
428
482
// There cannot be any ownership effects on trivial arguments.
429
483
result. ownership = SideEffects . Ownership ( )
@@ -439,14 +493,19 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
439
493
result. ownership. copy = false
440
494
result. ownership. destroy = false
441
495
442
- // Note that `directGuaranteed` still has a "destroy" effect, because an object stored in
443
- // a class property could be destroyed.
444
- case . directOwned, . directUnowned, . directGuaranteed:
496
+ case . directGuaranteed:
497
+ // Note that `directGuaranteed` still has a "destroy" effect, because an object stored in
498
+ // a class property could be destroyed.
499
+ if argument. path. hasNoClassProjection {
500
+ result. ownership. destroy = false
501
+ }
502
+ fallthrough
503
+ case . directOwned, . directUnowned:
445
504
if isTrivial {
446
505
// Trivial direct arguments cannot have class properties which could be loaded from/stored to.
447
506
result. memory = SideEffects . Memory ( )
448
507
}
449
- break
508
+
450
509
case . indirectInout, . indirectInoutAliasable:
451
510
break
452
511
}
0 commit comments