Files
clang-p2996/llvm/test/Transforms/Util/MemorySSA/cyclicphi.ll
George Burgess IV 82ee942a8c [MemorySSA] Change how the walker views/walks visited phis.
This patch teaches the caching MemorySSA walker a few things:

1. Not to walk Phis we've walked before. It seems that we tried to do
   this before, but it didn't work so well in cases like:

define void @foo() {
  %1 = alloca i8
  %2 = alloca i8
  br label %begin

begin:
  ; 3 = MemoryPhi({%0,liveOnEntry},{%end,2})
  ; 1 = MemoryDef(3)
  store i8 0, i8* %2
  br label %end

end:
  ; MemoryUse(?)
  load i8, i8* %1
  ; 2 = MemoryDef(1)
  store i8 0, i8* %2
  br label %begin
}

Because we wouldn't put Phis in Q.Visited until we tried to visit them.
So, when trying to optimize MemoryUse(?):
  - We would visit 3 above
    - ...Which would make us put {%0,liveOnEntry} in Q.Visited
    - ...Which would make us visit {%0,liveOnEntry}
    - ...Which would make us put {%end,2} in Q.Visited
    - ...Which would make us visit {%end,2}
      - ...Which would make us visit 3
        - ...Which would realize we've already visited everything in 3
        - ...Which would make us conservatively return 3.

In the added test-case, (@looped_visitedonlyonce) this behavior would
cause us to give incorrect results. Specifically, we'd visit 4 twice
in the same query, but on the second visit, we'd skip while.cond because
it had been visited, visit if.then/if.then2, and cache "1" as the
clobbering def on the way back.

2. If we try to walk the defs of a {Phi,MemLoc} and see it has been
   visited before, just hand back the Phi we're trying to optimize.

I promise this isn't as terrible as it seems. :)

We now insert {Phi,MemLoc} pairs just before walking the Phi's upward
defs. So, we check the cache for the {Phi,MemLoc} pair before checking
if we've already walked the Phi.

The {Phi,MemLoc} pair is (almost?) always guaranteed to have a cache
entry if we've already fully walked it, because we cache as we go.

So, if the {Phi,MemLoc} pair isn't in cache, either:
 (a) we must be in the process of visiting it (in which case, we can't
     give a better answer in a cache-as-we-go DFS walker)

 (b) we visited it, but didn't cache it on the way back (...which seems
     to require `ModifyingAccess` to not dominate `StartingAccess`,
     so I'm 99% sure that would be an error. If it's not an error, I
     haven't been able to get it to happen locally, so I suspect it's
     rare.)

- - - - -

As a consequence of this change, we no longer skip upward defs of phis,
so we can kill the `VisitedOnlyOne` check. This gives us better accuracy
than we had before, at the cost of potentially doing a bit more work
when we have a loop.

llvm-svn: 264814
2016-03-30 00:26:26 +00:00

124 lines
4.7 KiB
LLVM

; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s
%struct.hoge = type { i32, %struct.widget }
%struct.widget = type { i64 }
define hidden void @quux(%struct.hoge *%f) align 2 {
%tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
%tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1
%tmp25 = bitcast %struct.widget* %tmp24 to i64**
br label %bb26
bb26: ; preds = %bb77, %0
; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2})
; CHECK-NEXT: br i1 undef, label %bb68, label %bb77
br i1 undef, label %bb68, label %bb77
bb68: ; preds = %bb26
; CHECK: MemoryUse(liveOnEntry)
; CHECK-NEXT: %tmp69 = load i64, i64* null, align 8
%tmp69 = load i64, i64* null, align 8
; CHECK: 1 = MemoryDef(3)
; CHECK-NEXT: store i64 %tmp69, i64* %tmp, align 8
store i64 %tmp69, i64* %tmp, align 8
br label %bb77
bb77: ; preds = %bb68, %bb26
; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1})
; CHECK: MemoryUse(2)
; CHECK-NEXT: %tmp78 = load i64*, i64** %tmp25, align 8
%tmp78 = load i64*, i64** %tmp25, align 8
%tmp79 = getelementptr inbounds i64, i64* %tmp78, i64 undef
br label %bb26
}
; CHECK-LABEL: define void @quux_skip
define void @quux_skip(%struct.hoge* noalias %f, i64* noalias %g) align 2 {
%tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
%tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1
%tmp25 = bitcast %struct.widget* %tmp24 to i64**
br label %bb26
bb26: ; preds = %bb77, %0
; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2})
; CHECK-NEXT: br i1 undef, label %bb68, label %bb77
br i1 undef, label %bb68, label %bb77
bb68: ; preds = %bb26
; CHECK: MemoryUse(3)
; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8
%tmp69 = load i64, i64* %g, align 8
; CHECK: 1 = MemoryDef(3)
; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8
store i64 %tmp69, i64* %g, align 8
br label %bb77
bb77: ; preds = %bb68, %bb26
; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1})
; FIXME: This should be MemoryUse(liveOnEntry)
; CHECK: MemoryUse(3)
; CHECK-NEXT: %tmp78 = load i64*, i64** %tmp25, align 8
%tmp78 = load i64*, i64** %tmp25, align 8
br label %bb26
}
; CHECK-LABEL: define void @quux_dominated
define void @quux_dominated(%struct.hoge* noalias %f, i64* noalias %g) align 2 {
%tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
%tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1
%tmp25 = bitcast %struct.widget* %tmp24 to i64**
br label %bb26
bb26: ; preds = %bb77, %0
; CHECK: 4 = MemoryPhi({%0,liveOnEntry},{bb77,2})
; CHECK: MemoryUse(4)
; CHECK-NEXT: load i64*, i64** %tmp25, align 8
load i64*, i64** %tmp25, align 8
br i1 undef, label %bb68, label %bb77
bb68: ; preds = %bb26
; CHECK: MemoryUse(4)
; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8
%tmp69 = load i64, i64* %g, align 8
; CHECK: 1 = MemoryDef(4)
; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8
store i64 %tmp69, i64* %g, align 8
br label %bb77
bb77: ; preds = %bb68, %bb26
; CHECK: 3 = MemoryPhi({bb26,4},{bb68,1})
; CHECK: 2 = MemoryDef(3)
; CHECK-NEXT: store i64* null, i64** %tmp25, align 8
store i64* null, i64** %tmp25, align 8
br label %bb26
}
; CHECK-LABEL: define void @quux_nodominate
define void @quux_nodominate(%struct.hoge* noalias %f, i64* noalias %g) align 2 {
%tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
%tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1
%tmp25 = bitcast %struct.widget* %tmp24 to i64**
br label %bb26
bb26: ; preds = %bb77, %0
; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2})
; CHECK: MemoryUse(liveOnEntry)
; CHECK-NEXT: load i64*, i64** %tmp25, align 8
load i64*, i64** %tmp25, align 8
br i1 undef, label %bb68, label %bb77
bb68: ; preds = %bb26
; CHECK: MemoryUse(3)
; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8
%tmp69 = load i64, i64* %g, align 8
; CHECK: 1 = MemoryDef(3)
; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8
store i64 %tmp69, i64* %g, align 8
br label %bb77
bb77: ; preds = %bb68, %bb26
; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1})
; CHECK-NEXT: br label %bb26
br label %bb26
}