From 264ac878b26e90fe446aba9163d714d28d05bd8d Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 28 Apr 2011 16:58:40 +0000 Subject: [PATCH] InstCombine: Merge "(trunc x) == C1 & (and x, CA) == C2" into a single and+icmp. This happens when GVN widens loads. Part of PR6627. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@130405 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineAndOrXor.cpp | 36 +++++++++++++++++++ test/Transforms/InstCombine/merge-icmp.ll | 29 +++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 test/Transforms/InstCombine/merge-icmp.ll diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 980a42b8f41..0cbb1fe9ec1 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -769,6 +769,42 @@ Value *InstCombiner::FoldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS) { return Builder->CreateICmp(LHSCC, NewOr, LHSCst); } } + + // (trunc x) == C1 & (and x, CA) == C2 -> (and CA|CMAX) == C1|C2 + // where CMAX is the all ones value for the truncated type, + // iff the lower bits of CA are zero. + if (LHSCC == RHSCC && ICmpInst::isEquality(LHSCC) && + LHS->hasOneUse() && RHS->hasOneUse()) { + Value *V; + ConstantInt *AndCst, *SmallCst = 0, *BigCst = 0; + + // (trunc x) == C1 & (and x, CA) == C2 + if (match(Val2, m_Trunc(m_Value(V))) && + match(Val, m_And(m_Specific(V), m_ConstantInt(AndCst)))) { + SmallCst = RHSCst; + BigCst = LHSCst; + } + // (and x, CA) == C2 & (trunc x) == C1 + else if (match(Val, m_Trunc(m_Value(V))) && + match(Val2, m_And(m_Specific(V), m_ConstantInt(AndCst)))) { + SmallCst = LHSCst; + BigCst = RHSCst; + } + + if (SmallCst && BigCst) { + unsigned BigBitSize = BigCst->getType()->getBitWidth(); + unsigned SmallBitSize = SmallCst->getType()->getBitWidth(); + + // Check that the low bits are zero. + APInt Low = APInt::getLowBitsSet(BigBitSize, SmallBitSize); + if ((Low & AndCst->getValue()) == 0) { + Value *NewAnd = Builder->CreateAnd(V, Low | AndCst->getValue()); + APInt N = SmallCst->getValue().zext(BigBitSize) | BigCst->getValue(); + Value *NewVal = ConstantInt::get(AndCst->getType()->getContext(), N); + return Builder->CreateICmp(LHSCC, NewAnd, NewVal); + } + } + } // From here on, we only handle: // (icmp1 A, C1) & (icmp2 A, C2) --> something simpler. diff --git a/test/Transforms/InstCombine/merge-icmp.ll b/test/Transforms/InstCombine/merge-icmp.ll new file mode 100644 index 00000000000..00020b157e0 --- /dev/null +++ b/test/Transforms/InstCombine/merge-icmp.ll @@ -0,0 +1,29 @@ +; RUN: opt -S -instcombine < %s | FileCheck %s + +define i1 @test1(i16* %x) { + %load = load i16* %x, align 4 + %trunc = trunc i16 %load to i8 + %cmp1 = icmp eq i8 %trunc, 127 + %and = and i16 %load, -256 + %cmp2 = icmp eq i16 %and, 17664 + %or = and i1 %cmp1, %cmp2 + ret i1 %or +; CHECK: @test1 +; CHECK-NEXT: load i16 +; CHECK-NEXT: icmp eq i16 %load, 17791 +; CHECK-NEXT: ret i1 +} + +define i1 @test2(i16* %x) { + %load = load i16* %x, align 4 + %and = and i16 %load, -256 + %cmp1 = icmp eq i16 %and, 32512 + %trunc = trunc i16 %load to i8 + %cmp2 = icmp eq i8 %trunc, 69 + %or = and i1 %cmp1, %cmp2 + ret i1 %or +; CHECK: @test2 +; CHECK-NEXT: load i16 +; CHECK-NEXT: icmp eq i16 %load, 32581 +; CHECK-NEXT: ret i1 +} -- 2.34.1