From 6c84f7ad2dbba5d1afa26a4929c3b032ae9e7e10 Mon Sep 17 00:00:00 2001 From: Nadav Rotem Date: Tue, 12 Nov 2013 22:38:59 +0000 Subject: [PATCH] Fold (iszero(A&K1) | iszero(A&K2)) -> (A&(K1|K2)) != (K1|K2) if we know that K1 and K2 are 'one-hot' (only one bit is on). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194525 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineAndOrXor.cpp | 53 +++++++++++++++++-- test/Transforms/InstCombine/onehot_merge.ll | 35 ++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 test/Transforms/InstCombine/onehot_merge.ll diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 98a7b2df4d7..9603f220781 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1543,10 +1543,60 @@ static Instruction *MatchSelectFromAndOr(Value *A, Value *B, return 0; } +/// IsSingleBitValue - Returns true for "one-hot" values (values where at most +/// one bit can be set). +static bool IsOneHotValue(Value *V) { + // Match 1<(V)) + if (BO->getOpcode() == Instruction::Shl) { + ConstantInt *One = dyn_cast(BO->getOperand(0)); + return One && One->isOne(); + } + + // Check for power of two integer constants. + if (ConstantInt *K = dyn_cast(V)) + return K->getValue().isPowerOf2(); + + return false; +} + /// FoldOrOfICmps - Fold (icmp)|(icmp) if possible. Value *InstCombiner::FoldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS) { ICmpInst::Predicate LHSCC = LHS->getPredicate(), RHSCC = RHS->getPredicate(); + // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) + // if K1 and K2 are a one-bit mask. + ConstantInt *LHSCst = dyn_cast(LHS->getOperand(1)); + ConstantInt *RHSCst = dyn_cast(RHS->getOperand(1)); + + if (LHS->getPredicate() == ICmpInst::ICMP_EQ && LHSCst && LHSCst->isZero() && + RHS->getPredicate() == ICmpInst::ICMP_EQ && RHSCst && RHSCst->isZero()) { + + BinaryOperator *LAnd = dyn_cast(LHS->getOperand(0)); + BinaryOperator *RAnd = dyn_cast(RHS->getOperand(0)); + if (LAnd && RAnd && LAnd->hasOneUse() && RHS->hasOneUse() && + LAnd->getOpcode() == Instruction::And && + RAnd->getOpcode() == Instruction::And) { + + Value *Mask = 0; + Value *Masked = 0; + if (LAnd->getOperand(0) == RAnd->getOperand(0) && + IsOneHotValue(LAnd->getOperand(1)) && + IsOneHotValue(RAnd->getOperand(1))) { + Mask = Builder->CreateOr(LAnd->getOperand(1), RAnd->getOperand(1)); + Masked = Builder->CreateAnd(LAnd->getOperand(0), Mask); + } else if (LAnd->getOperand(1) == RAnd->getOperand(1) && + IsOneHotValue(LAnd->getOperand(0)) && + IsOneHotValue(RAnd->getOperand(0))) { + Mask = Builder->CreateOr(LAnd->getOperand(0), RAnd->getOperand(0)); + Masked = Builder->CreateAnd(LAnd->getOperand(1), Mask); + } + + if (Masked) + return Builder->CreateICmp(ICmpInst::ICMP_NE, Masked, Mask); + } + } + // (icmp1 A, B) | (icmp2 A, B) --> (icmp3 A, B) if (PredicatesFoldable(LHSCC, RHSCC)) { if (LHS->getOperand(0) == RHS->getOperand(1) && @@ -1567,9 +1617,6 @@ Value *InstCombiner::FoldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS) { return V; Value *Val = LHS->getOperand(0), *Val2 = RHS->getOperand(0); - ConstantInt *LHSCst = dyn_cast(LHS->getOperand(1)); - ConstantInt *RHSCst = dyn_cast(RHS->getOperand(1)); - if (LHS->hasOneUse() || RHS->hasOneUse()) { // (icmp eq B, 0) | (icmp ult A, B) -> (icmp ule A, B-1) // (icmp eq B, 0) | (icmp ugt B, A) -> (icmp ule A, B-1) diff --git a/test/Transforms/InstCombine/onehot_merge.ll b/test/Transforms/InstCombine/onehot_merge.ll new file mode 100644 index 00000000000..51f955c2c24 --- /dev/null +++ b/test/Transforms/InstCombine/onehot_merge.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +;CHECK: @and_consts +;CHECK: and i32 %k, 12 +;CHECK: icmp ne i32 %0, 12 +;CHECK: ret +define i1 @and_consts(i32 %k, i32 %c1, i32 %c2) { +bb: + %tmp1 = and i32 4, %k + %tmp2 = icmp eq i32 %tmp1, 0 + %tmp5 = and i32 8, %k + %tmp6 = icmp eq i32 %tmp5, 0 + %or = or i1 %tmp2, %tmp6 + ret i1 %or +} + +;CHECK: @foo1_and +;CHECK: shl i32 1, %c1 +;CHECK-NEXT: shl i32 1, %c2 +;CHECK-NEXT: or i32 +;CHECK-NEXT: and i32 +;CHECK-NEXT: icmp ne i32 %1, %0 +;CHECK: ret +define i1 @foo1_and(i32 %k, i32 %c1, i32 %c2) { +bb: + %tmp = shl i32 1, %c1 + %tmp4 = shl i32 1, %c2 + %tmp1 = and i32 %tmp, %k + %tmp2 = icmp eq i32 %tmp1, 0 + %tmp5 = and i32 %tmp4, %k + %tmp6 = icmp eq i32 %tmp5, 0 + %or = or i1 %tmp2, %tmp6 + ret i1 %or +} + -- 2.34.1