This patch attempts to eliminate redundant loads whose addresses are dependent upon a select instruction.
First, look for patterns such as:
(load (gep (select (cond, ptr_a, ptr_b)) idx0, idx1, ..., idxN)) (load (gep ptr_op, (select (cond, idx_a, idx_b)), idx1 ..., idxN)) (load (gep ptr_op, idx0, (select (cond, idx_a, idx_b)), ..., idxN))
Then find similar loads and perform a transformation such as:
Constant zero index with different pointer operands:
a = (load (gep ptr_a 0 0)) b = (load (gep ptr_b 0 0)) c = (load (gep (select (cond, ptr_a, ptr_b)) 0 0)) --> a = (load (gep ptr_a, 0, 0)) b = (load (gep ptr_b, 0, 0)) c = (select (cond, a, b))
and
GEPs differ by only a single index:
a = (load (gep ptr_op, idx, idx_a)) b = (load (gep ptr_op, idx, idx_b)) c = (load (gep ptr_op, idx, (select (cond, idx_a, idx_b)))) --> a = (load (gep ptr_op, idx, idx_a)) b = (load (gep ptr_op, idx, idx_b)) c = (select (cond, a, b))
See the PR for additional information.
http://llvm.org/bugs/show_bug.cgi?id=21052
This work is based on a patch done by Tilmann Scheller (attached to PR21052).
Basically, I moved the patch from InstCombine to GVN, so I would have dependency information. I also made the solution a bit more general.
This is a WIP, but I wanted to get some feedback before continuing. After considering the suggestions from Nick L. and David M. (see the bug report), I didn't see how those suggestions would benefit this patch (at least not in local scope).
Here are the tasks that remain:
- Use use-def and def-use chains rather than iterate over instructions.
- Allow the base load to be fed by stores as well as loads.
- Perform additional correctness/perf testing.
Please feel free to comment.
Chad
Another way you might be able to phrase this would be to ask GVN if it had a value which would be CSEd with a newly created GEP at the current instruction.