[llvm] r367439 - [NFC][InstCombine] Add xor-or-icmp tests with icmp having extra uses

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 31 08:20:33 PDT 2019


Author: lebedevri
Date: Wed Jul 31 08:20:33 2019
New Revision: 367439

URL: http://llvm.org/viewvc/llvm-project?rev=367439&view=rev
Log:
[NFC][InstCombine] Add xor-or-icmp tests with icmp having extra uses

Currently InstCombiner::foldXorOfICmps() bailouts if the
ICMP it wants to invert has extra uses. As it can be seen
in the tests in previous commit, this is super unfortunate,
this is the single pattern that is left non-canonicalized.

We could analyze if we can also invert all the uses if said ICMP
at the same time, thus not bailing out there.
I'm not seeing any nicer alternative.

Added:
    llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll

Added: llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll?rev=367439&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll Wed Jul 31 08:20:33 2019
@@ -0,0 +1,165 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; These xor-of-icmps could be replaced with and-of-icmps, but %cond0 has extra
+; uses, so we don't consider it, even though some cases are freely invertible.
+
+; %cond0 is extra-used in select, which is freely invertible.
+define i1 @v0_select_of_consts(i32 %X, i32* %selected) {
+; CHECK-LABEL: @v0_select_of_consts(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND0]], i32 32767, i32 -32768
+; CHECK-NEXT:    store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 -32768
+  store i32 %select, i32* %selected
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+define i1 @v1_select_of_var_and_const(i32 %X, i32 %Y, i32* %selected) {
+; CHECK-LABEL: @v1_select_of_var_and_const(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND0]], i32 [[Y:%.*]], i32 -32768
+; CHECK-NEXT:    store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 %Y, i32 -32768
+  store i32 %select, i32* %selected
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+define i1 @v2_select_of_const_and_var(i32 %X, i32 %Y, i32* %selected) {
+; CHECK-LABEL: @v2_select_of_const_and_var(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND0]], i32 32767, i32 [[Y:%.*]]
+; CHECK-NEXT:    store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 %Y
+  store i32 %select, i32* %selected
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+
+; Branch is also freely invertible
+define i1 @v3_branch(i32 %X, i32* %dst0, i32* %dst1) {
+; CHECK-LABEL: @v3_branch(
+; CHECK-NEXT:  begin:
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    br i1 [[COND0]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    store i32 0, i32* [[DST0:%.*]], align 4
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    store i32 0, i32* [[DST1:%.*]], align 4
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+begin:
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  br i1 %cond0, label %bb0, label %bb1
+bb0:
+  store i32 0, i32* %dst0
+  br label %end
+bb1:
+  store i32 0, i32* %dst1
+  br label %end
+end:
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+
+; Can invert 'not'.
+define i1 @v4_not_store(i32 %X, i1* %not_cond) {
+; CHECK-LABEL: @v4_not_store(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[NOT_COND0:%.*]] = xor i1 [[COND0]], true
+; CHECK-NEXT:    store i1 [[NOT_COND0]], i1* [[NOT_COND:%.*]], align 1
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %not_cond0 = xor i1 %cond0, -1
+  store i1 %not_cond0, i1* %not_cond
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 -32768
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+
+; All extra uses are invertible.
+define i1 @v5_select_and_not(i32 %X, i32 %Y, i32* %selected, i1* %not_cond) {
+; CHECK-LABEL: @v5_select_and_not(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND0]], i32 32767, i32 [[Y:%.*]]
+; CHECK-NEXT:    [[NOT_COND0:%.*]] = xor i1 [[COND0]], true
+; CHECK-NEXT:    store i1 [[NOT_COND0]], i1* [[NOT_COND:%.*]], align 1
+; CHECK-NEXT:    store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 %Y
+  %not_cond0 = xor i1 %cond0, -1
+  store i1 %not_cond0, i1* %not_cond
+  store i32 %select, i32* %selected
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+
+; Not all extra uses are invertible.
+define i1 @n6_select_and_not(i32 %X, i32 %Y, i32* %selected, i1* %not_cond) {
+; CHECK-LABEL: @n6_select_and_not(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND0]], i32 32767, i32 [[Y:%.*]]
+; CHECK-NEXT:    store i1 [[COND0]], i1* [[NOT_COND:%.*]], align 1
+; CHECK-NEXT:    store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 %Y
+  store i1 %cond0, i1* %not_cond
+  store i32 %select, i32* %selected
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}
+
+; Not freely invertible, would require extra 'not' instruction.
+define i1 @n7_store(i32 %X, i1* %cond) {
+; CHECK-LABEL: @n7_store(
+; CHECK-NEXT:    [[COND0:%.*]] = icmp sgt i32 [[X:%.*]], 32767
+; CHECK-NEXT:    store i1 [[COND0]], i1* [[COND:%.*]], align 1
+; CHECK-NEXT:    [[COND1:%.*]] = icmp sgt i32 [[X]], -32768
+; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[COND0]], [[COND1]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cond0 = icmp sgt i32 %X, 32767
+  store i1 %cond0, i1* %cond
+  %cond1 = icmp sgt i32 %X, -32768
+  %select = select i1 %cond0, i32 32767, i32 -32768
+  %res = xor i1 %cond0, %cond1
+  ret i1 %res
+}




More information about the llvm-commits mailing list