From: Roman Lebedev Date: Wed, 31 Jul 2019 15:20:33 +0000 (+0000) Subject: [NFC][InstCombine] Add xor-or-icmp tests with icmp having extra uses X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8d76284599c4bc995c037b524b107ee0e902dcdb;p=platform%2Fupstream%2Fllvm.git [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. llvm-svn: 367439 --- diff --git a/llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll b/llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll new file mode 100644 index 0000000..1364b4a --- /dev/null +++ b/llvm/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll @@ -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 +}