Skip to content

Commit 6517817

Browse files
committed
ComputeSideEffects: handle program termination functions which are defined in the same module
This case was neglected. The fix can result in better side effect analysis, e.g. in the stdlib core module.
1 parent 86c30d6 commit 6517817

File tree

3 files changed

+41
-7
lines changed

3 files changed

+41
-7
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ let computeSideEffects = FunctionPass(name: "compute-side-effects") {
7070

7171
// Finally replace the function's side effects.
7272
context.modifyEffects(in: function) { (effects: inout FunctionEffects) in
73-
effects.sideEffects = SideEffects(arguments: collectedEffects.argumentEffects, global: collectedEffects.globalEffects)
73+
let globalEffects = function.isProgramTerminationPoint ?
74+
collectedEffects.globalEffects.forProgramTerminationPoints
75+
: collectedEffects.globalEffects
76+
effects.sideEffects = SideEffects(arguments: collectedEffects.argumentEffects, global: globalEffects)
7477
}
7578
}
7679

SwiftCompilerSources/Sources/SIL/Effects.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,7 @@ extension Function {
161161
break
162162
}
163163
if isProgramTerminationPoint {
164-
// We can ignore any memory writes in a program termination point, because it's not relevant
165-
// for the caller. But we need to consider memory reads, otherwise preceding memory writes
166-
// would be eliminated by dead-store-elimination in the caller. E.g. String initialization
167-
// for error strings which are printed by the program termination point.
168-
// Regarding ownership: a program termination point must not touch any reference counted objects.
169-
return SideEffects.GlobalEffects(memory: SideEffects.Memory(read: true))
164+
return SideEffects.GlobalEffects.worstEffects.forProgramTerminationPoints
170165
}
171166
var result = SideEffects.GlobalEffects.worstEffects
172167
switch effectAttribute {
@@ -568,6 +563,18 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
568563
return result
569564
}
570565

566+
/// Effects with all effects removed which are not relevant for program termination points (like `fatalError`).
567+
public var forProgramTerminationPoints: GlobalEffects {
568+
// We can ignore any memory writes in a program termination point, because it's not relevant
569+
// for the caller. But we need to consider memory reads, otherwise preceding memory writes
570+
// would be eliminated by dead-store-elimination in the caller. E.g. String initialization
571+
// for error strings which are printed by the program termination point.
572+
// Regarding ownership: a program termination point must not touch any reference counted objects.
573+
// Also, the deinit-barrier effect is not relevant because functions like `fatalError` and `exit` are
574+
// not accessing objects (except strings).
575+
return GlobalEffects(memory: Memory(read: memory.read))
576+
}
577+
571578
public static var worstEffects: GlobalEffects {
572579
GlobalEffects(memory: .worstEffects, ownership: .worstEffects, allocates: true, isDeinitBarrier: true)
573580
}

test/SILOptimizer/side_effects.sil

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,13 @@ bb0(%0 : $*X):
680680
return %r : $()
681681
}
682682

683+
sil [_semantics "programtermination_point"] @exitfunc_defined : $@convention(thin) () -> Never {
684+
bb0:
685+
%u = function_ref @unknown_func : $@convention(thin) () -> ()
686+
%a = apply %u() : $@convention(thin) () -> ()
687+
unreachable
688+
}
689+
683690
// CHECK-LABEL: sil @call_noreturn
684691
// CHECK-NEXT: [global: read]
685692
// CHECK-NEXT: {{^[^[]}}
@@ -697,6 +704,23 @@ bb2:
697704
return %r : $()
698705
}
699706

707+
// CHECK-LABEL: sil @call_defined_noreturn
708+
// CHECK-NEXT: [global: read]
709+
// CHECK-NEXT: {{^[^[]}}
710+
sil @call_defined_noreturn : $@convention(thin) () -> () {
711+
bb0:
712+
cond_br undef, bb1, bb2
713+
714+
bb1:
715+
%u = function_ref @exitfunc_defined : $@convention(thin) () -> Never
716+
%a = apply %u() : $@convention(thin) () -> Never
717+
unreachable
718+
719+
bb2:
720+
%r = tuple ()
721+
return %r : $()
722+
}
723+
700724
// CHECK-LABEL: sil @call_readnone
701725
// CHECK-NEXT: [global: copy,deinit_barrier]
702726
// CHECK-NEXT: {{^[^[]}}

0 commit comments

Comments
 (0)