Generalize and fix SinkAddressProjections.

Fixes a potential real bug in the case that SinkAddressProjections moves
projections without notifying SimplifyCFG of the change. This could
fail to update Analyses (probably won't break anything in practice).

Introduce SILInstruction::isPure. Among other things, this can tell
you if it's safe to duplicate instructions at their
uses. SinkAddressProjections should check this before sinking uses. I
couldn't find a way to expose this as a real bug, but it is a
theoretical bug.

Add the SinkAddressProjections functionality to the BasicBlockCloner
utility. Enable address projection sinking for all BasicBlockCloner
clients (the four different kinds of jump-threading that use it). This
brings the compiler much closer to banning all address phis.

The "bugs" were originally introduced a week ago here:

commit f22371bf0b (fork/fix-address-phi, fix-address-phi)
Author: Andrew Trick <atrick@apple.com>
Date:   Tue Sep 17 16:45:51 2019

    Add SIL SinkAddressProjections utility to avoid address phis.

    Enable this utility during jump-threading in SimplifyCFG.

    Ultimately, the SIL verifier should prevent all address-phis and we'll
    need to use this utility in a few more places.

    Fixes <rdar://problem/55320867> SIL verification failed: Unknown
    formal access pattern: storage
This commit is contained in:
Andrew Trick
2019-09-30 13:56:17 -07:00
parent 1ca57e06d7
commit 38c29e231e
9 changed files with 373 additions and 141 deletions

View File

@@ -43,8 +43,8 @@ public class C<R> {
let r : R
init(_ _r: R) { r = _r }
// SIL: // C.f<A>(_:)
// IR: define {{.*}} @"$s1A1CC1fyyqd__lF"
// SIL-LABEL: // C.f<A>(_:)
// IR-LABEL: define {{.*}} @"$s1A1CC1fyyqd__lF"
#sourceLocation(file: "f.swift", line: 1)
public func f<S>(_ s: S) {
// SIL: debug_value_addr %0 : $*S, let, name "s", argno 1,{{.*}} scope [[F]]
@@ -57,7 +57,13 @@ public class C<R> {
// IR: call {{.*}}3use
#sourceLocation(file: "f.swift", line: 2)
g(s)
// IR: dbg.value({{.*}}, metadata ![[GR_T:[0-9]+]]
// Jump-threading removes the basic block containing debug_value
// "t" before the second call to `g(r)`. When this happens, the
// ref_element_addr in that removed block is left with a single
// debug_value use, so they are both deleted. This means we have
// no debug value for "t" in the call to `g(r)`.
// dbg.value({{.*}}, metadata ![[GR_T:[0-9]+]]
// IR: dbg.value({{.*}}, metadata ![[GR_U:[0-9]+]]
// IR: call {{.*}}3use
#sourceLocation(file: "f.swift", line: 3)
@@ -81,6 +87,8 @@ public class C<R> {
g(false)
}
}
// SIL-LABEL: } // end sil function '$s1A1CC1fyyqd__lF'
// IR-LABEL: ret void
// IR: ![[BOOL:[0-9]+]] = !DICompositeType({{.*}}name: "Bool"
// IR: ![[LET_BOOL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[BOOL]])
@@ -96,9 +104,12 @@ public class C<R> {
// IR: ![[SP_GS_T]] = {{.*}}linkageName: "$s1A1gyyxlFqd___Ti5"
// IR: ![[GS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GS_U:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]])
// IR: ![[SP_GS_U]] = {{.*}}linkageName: "$s1A1hyyxlFqd___Ti5"
// IR: ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]])
// Debug info for this variable is removed. See the note above the call to g(r).
// ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]])
// S has the same generic parameter numbering s T and U.
// IR: ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF"
// ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF"
// IR: ![[GR_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GR_U:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]])
// IR: ![[SP_GR_U]] = {{.*}}linkageName: "$s1A1hyyxlF"
// IR: ![[GRS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GRS_T:[0-9]+]], {{.*}}type: ![[LET_TUPLE:[0-9]+]]