llvm/test/Transforms/InstCombine/zext-or-icmp.ll
Tobias Grosser dd5930fbf7 [InstCombine] Refactor optimization of zext(or(icmp, icmp)) to enable more aggressive cast-folding
Summary:
InstCombine unfolds expressions of the form `zext(or(icmp, icmp))` to `or(zext(icmp), zext(icmp))` such that in a later iteration of InstCombine the exposed `zext(icmp)` instructions can be optimized. We now combine this unfolding and the subsequent `zext(icmp)` optimization to be performed together. Since the unfolding doesn't happen separately anymore, we also again enable the folding of `logic(cast(icmp), cast(icmp))` expressions to `cast(logic(icmp, icmp))` which had been disabled due to its interference with the unfolding transformation.

Tested via `make check` and `lnt`.

Background
==========

For a better understanding on how it came to this change we subsequently summarize its history. In commit r275989 we've already tried to enable the folding of `logic(cast(icmp), cast(icmp))` to `cast(logic(icmp, icmp))` which had to be reverted in r276106 because it could lead to an endless loop in InstCombine (also see http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160718/374347.html). The root of this problem is that in `visitZExt()` in InstCombineCasts.cpp there also exists a reverse of the above folding transformation, that unfolds `zext(or(icmp, icmp))` to `or(zext(icmp), zext(icmp))` in order to expose `zext(icmp)` operations which would then possibly be eliminated by subsequent iterations of InstCombine. However, before these `zext(icmp)` would be eliminated the folding from r275989 could kick in and cause InstCombine to endlessly switch back and forth between the folding and the unfolding transformation. This is the reason why we now combine the `zext`-unfolding and the elimination of the exposed `zext(icmp)` to happen at one go because this enables us to still allow the cast-folding in `logic(cast(icmp), cast(icmp))` without entering an endless loop again.

Details on the submitted changes
================================

- In `visitZExt()` we combine the unfolding and optimization of `zext` instructions.
- In `transformZExtICmp()` we have to use `Builder->CreateIntCast()` instead of `CastInst::CreateIntegerCast()` to make sure that the new `CastInst` is inserted in a `BasicBlock`. The new calls to `transformZExtICmp()` that we introduce in `visitZExt()` would otherwise cause according assertions to be triggered (in our case this happend, for example, with lnt for the MultiSource/Applications/sqlite3 and SingleSource/Regression/C++/EH/recursive-throw tests). The subsequent usage of `replaceInstUsesWith()` is necessary to ensure that the new `CastInst` replaces the `ZExtInst` accordingly.
- In InstCombineAndOrXor.cpp we again allow the folding of casts on `icmp` instructions.
- The instruction order in the optimized IR for the zext-or-icmp.ll test case is different with the introduced changes.
- The test cases in zext.ll have been adopted from the reverted commits r275989 and r276105.

Reviewers: grosser, majnemer, spatel

Subscribers: eli.friedman, majnemer, llvm-commits

Differential Revision: https://reviews.llvm.org/D22864

Contributed-by: Matthias Reisinger <d412vv1n@gmail.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@277635 91177308-0d34-0410-b5e6-96231b3b80d8
2016-08-03 19:30:35 +00:00

22 lines
626 B
LLVM

; RUN: opt < %s -instcombine -S | FileCheck %s
; Remove an icmp by using its operand in the subsequent logic directly.
define i8 @zext_or_icmp_icmp(i8 %a, i8 %b) {
%mask = and i8 %a, 1
%toBool1 = icmp eq i8 %mask, 0
%toBool2 = icmp eq i8 %b, 0
%bothCond = or i1 %toBool1, %toBool2
%zext = zext i1 %bothCond to i8
ret i8 %zext
; CHECK-LABEL: zext_or_icmp_icmp(
; CHECK-NEXT: %mask = and i8 %a, 1
; CHECK-NEXT: %toBool2 = icmp eq i8 %b, 0
; CHECK-NEXT: %toBool22 = zext i1 %toBool2 to i8
; CHECK-NEXT: %1 = xor i8 %mask, 1
; CHECK-NEXT: %zext = or i8 %1, %toBool22
; CHECK-NEXT: ret i8 %zext
}