To eliminate a store, we must ensure that it is not accessed before the
killing def on any path to a function exit. Currently we use
post-dominance to ensure that the killing def is executed on each path
from the killed def. But this excludes cases where there are no other
reads before another overwriting def on other paths. An example can be
found below. The first store (store i32 1, i32* %P) is dead, but neither
of the killing stores post-dominate it.
This patch adds support for such cases in a relatively straight-forward
way. When checking for read clobbers, we already traverse explore all
uses. If there are any reads before clobbering writes along any path to
an exit, we will check them. We can stop adding uses to the worklist for
MemoryDefs that completely overwrite the original location.
The only remaining problem is accesses after returning from the
function. But I think we can make those reads explicit in the MemorySSA
by introducing an additonal MemoryUse that clobbers all locations
visible to the caller at each exit. With those additional MemoryUses,
the existing algorithms should handle those cases naturally as well.
Currently the patch uses a hack to create those MemoryUses: it just
introduces a readonly function call at the end of each function and
treats it as clobbering all objects may visible to the caller. If the
solution makes sense, I'll find a proper solution for the hack.
define void @test4(i32* noalias %P, i1 %c1) {
store i32 1, i32* %P br i1 %c1, label %bb1, label %bb2
bb1:
store i32 0, i32* %P br label %bb5
bb2:
store i32 3, i32* %P br label %bb5
bb5:
call void @use(i32* %P) ret void
}
clang-format-diff not found in user's PATH; not linting file.