From 1eaac255e2a7f54e7a8cf00cec8b024440cad9e6 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 12 Oct 2024 15:13:47 -0600 Subject: [PATCH 1/2] Add pre-commit tests --- llvm/test/Transforms/InstCombine/sext-and.ll | 236 +++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/sext-and.ll diff --git a/llvm/test/Transforms/InstCombine/sext-and.ll b/llvm/test/Transforms/InstCombine/sext-and.ll new file mode 100644 index 0000000000000..377805391b92c --- /dev/null +++ b/llvm/test/Transforms/InstCombine/sext-and.ll @@ -0,0 +1,236 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +declare void @use(i8) + +define i1 @fold_sext_to_and(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp eq i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and1(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and1( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 1 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp ne i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and2(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and2( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 2 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 1073741826 + %3 = icmp eq i32 %2, 2 + ret i1 %3 +} + +define i1 @fold_sext_to_and3(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and3( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 2 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 1073741826 + %3 = icmp ne i32 %2, 2 + ret i1 %3 +} + +define i1 @fold_sext_to_and_multi_use(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_multi_use( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: call void @use(i32 [[TMP1]]) +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + call void @use(i32 %1) + %2 = and i32 %1, -2147483647 + %3 = icmp eq i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_multi_use1(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_multi_use1( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: call void @use(i32 [[TMP1]]) +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 1 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + call void @use(i32 %1) + %2 = and i32 %1, -2147483647 + %3 = icmp ne i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_multi_use2(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_multi_use2( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: call void @use(i32 [[TMP1]]) +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 2 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + call void @use(i32 %1) + %2 = and i32 %1, 1073741826 + %3 = icmp eq i32 %2, 2 + ret i1 %3 +} + +define i1 @fold_sext_to_and_multi_use3(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_multi_use3( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 +; CHECK-NEXT: call void @use(i32 [[TMP1]]) +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 2 +; CHECK-NEXT: ret i1 [[TMP3]] +; + %1 = sext i8 %x to i32 + call void @use(i32 %1) + %2 = and i32 %1, 1073741826 + %3 = icmp ne i32 %2, 2 + ret i1 %3 +} + +; Negative tests + +define i1 @fold_sext_to_and_wrong(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 false +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp eq i32 %2, -1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong2(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong2( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 false +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp eq i32 %2, 128 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong3(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong3( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 false +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 128 + %3 = icmp eq i32 %2, -2147483648 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong4(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong4( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 false +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 128 + %3 = icmp eq i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong5(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong5( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 false +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -256 + %3 = icmp eq i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong6(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong6( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 true +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp ne i32 %2, -1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong7(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong7( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 true +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -2147483647 + %3 = icmp ne i32 %2, 128 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong8(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong8( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 true +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 128 + %3 = icmp ne i32 %2, -2147483648 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong9(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong9( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 true +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, 128 + %3 = icmp ne i32 %2, 1 + ret i1 %3 +} + +define i1 @fold_sext_to_and_wrong10(i8 %x) { +; CHECK-LABEL: define i1 @fold_sext_to_and_wrong10( +; CHECK-SAME: i8 [[X:%.*]]) { +; CHECK-NEXT: ret i1 true +; + %1 = sext i8 %x to i32 + %2 = and i32 %1, -256 + %3 = icmp ne i32 %2, 1 + ret i1 %3 +} From 1ddd277ddf9daf62c737f571ae530c692d12a4e1 Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 24 Oct 2024 21:06:30 -0600 Subject: [PATCH 2/2] Apply transformation --- .../InstCombine/InstCombineCompares.cpp | 26 ++++++++++++++ llvm/test/Transforms/InstCombine/load-cmp.ll | 4 +-- llvm/test/Transforms/InstCombine/sext-and.ll | 36 +++++++++---------- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 6bb39cabb0988..680e39f03902e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -7716,6 +7716,32 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) { if (Instruction *Res = foldReductionIdiom(I, Builder, DL)) return Res; + { + Value *A; + const APInt *C1, *C2; + ICmpInst::Predicate Pred = I.getPredicate(); + if (ICmpInst::isEquality(Pred)) { + // sext(a) & c1 == c2 --> a & c3 == trunc(c2) + // sext(a) & c1 != c2 --> a & c3 != trunc(c2) + if (match(Op0, m_And(m_SExt(m_Value(A)), m_APInt(C1))) && + match(Op1, m_APInt(C2))) { + Type *InputTy = A->getType(); + unsigned InputBitWidth = InputTy->getScalarSizeInBits(); + // c2 must be non-negative at the bitwidth of a. + if (C2->getActiveBits() < InputBitWidth) { + APInt TruncC1 = C1->trunc(InputBitWidth); + // Check if there are 1s in C1 high bits of size InputBitWidth. + if (C1->uge(APInt::getOneBitSet(C1->getBitWidth(), InputBitWidth))) + TruncC1.setBit(InputBitWidth - 1); + Value *AndInst = Builder.CreateAnd(A, TruncC1); + return new ICmpInst( + Pred, AndInst, + ConstantInt::get(InputTy, C2->trunc(InputBitWidth))); + } + } + } + } + return Changed ? &I : nullptr; } diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll index 8e39fe33cded8..12be81b8f815d 100644 --- a/llvm/test/Transforms/InstCombine/load-cmp.ll +++ b/llvm/test/Transforms/InstCombine/load-cmp.ll @@ -312,9 +312,7 @@ define i1 @test10_struct_arr_i64(i64 %x) { define i1 @test10_struct_arr_noinbounds_i16(i16 %x) { ; CHECK-LABEL: @test10_struct_arr_noinbounds_i16( -; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 268435455 -; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP2]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[X:%.*]], 1 ; CHECK-NEXT: ret i1 [[R]] ; %p = getelementptr [4 x %Foo], ptr @GStructArr, i32 0, i16 %x, i32 2 diff --git a/llvm/test/Transforms/InstCombine/sext-and.ll b/llvm/test/Transforms/InstCombine/sext-and.ll index 377805391b92c..e08bbbd83d884 100644 --- a/llvm/test/Transforms/InstCombine/sext-and.ll +++ b/llvm/test/Transforms/InstCombine/sext-and.ll @@ -6,9 +6,8 @@ declare void @use(i8) define i1 @fold_sext_to_and(i8 %x) { ; CHECK-LABEL: define i1 @fold_sext_to_and( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 -; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -127 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -20,9 +19,8 @@ define i1 @fold_sext_to_and(i8 %x) { define i1 @fold_sext_to_and1(i8 %x) { ; CHECK-LABEL: define i1 @fold_sext_to_and1( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 -; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -127 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -34,9 +32,8 @@ define i1 @fold_sext_to_and1(i8 %x) { define i1 @fold_sext_to_and2(i8 %x) { ; CHECK-LABEL: define i1 @fold_sext_to_and2( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 -; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -126 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP1]], 2 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -48,9 +45,8 @@ define i1 @fold_sext_to_and2(i8 %x) { define i1 @fold_sext_to_and3(i8 %x) { ; CHECK-LABEL: define i1 @fold_sext_to_and3( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 -; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -126 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP1]], 2 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -64,8 +60,8 @@ define i1 @fold_sext_to_and_multi_use(i8 %x) { ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 -; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X]], -127 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP2]], 1 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -80,8 +76,8 @@ define i1 @fold_sext_to_and_multi_use1(i8 %x) { ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -2147483647 -; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X]], -127 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP2]], 1 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -96,8 +92,8 @@ define i1 @fold_sext_to_and_multi_use2(i8 %x) { ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 -; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X]], -126 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP2]], 2 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32 @@ -112,8 +108,8 @@ define i1 @fold_sext_to_and_multi_use3(i8 %x) { ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1073741826 -; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X]], -126 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i8 [[TMP2]], 2 ; CHECK-NEXT: ret i1 [[TMP3]] ; %1 = sext i8 %x to i32