From: Craig Topper Date: Mon, 14 Aug 2017 21:39:51 +0000 (+0000) Subject: Recommit r310869, "[InstSimplify][InstCombine] Modify the interface of decomposeBitTe... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fc52a9c1a3aa916dc307f3c875d6f0bf5140c983;p=llvm Recommit r310869, "[InstSimplify][InstCombine] Modify the interface of decomposeBitTestICmp and use it in the InstSimplify" This recommits r310869, with the moved files and no extra changes. Original commit message: This addresses a fixme in InstSimplify about using decomposeBitTest. This also fixes InstSimplify to handle ugt and ult compares too. I've modified the interface a little to return only the APInt version of the mask that InstSimplify needs. InstCombine now has a small wrapper routine to create a Constant out of it. I've also dropped the returning of 0 since InstSimplify doesn't need that. So InstCombine creates a zero constant itself. I also had to make decomposeBitTest support vectors since InstSimplify needs that. As InstSimplify can't use something from the Transforms library, I've moved the CmpInstAnalysis code to the Analysis library. Differential Revision: https://reviews.llvm.org/D36593 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310889 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Transforms/Utils/CmpInstAnalysis.h b/include/llvm/Analysis/CmpInstAnalysis.h similarity index 85% rename from include/llvm/Transforms/Utils/CmpInstAnalysis.h rename to include/llvm/Analysis/CmpInstAnalysis.h index 5ec3888d453..1079d5abc7f 100644 --- a/include/llvm/Transforms/Utils/CmpInstAnalysis.h +++ b/include/llvm/Analysis/CmpInstAnalysis.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TRANSFORMS_UTILS_CMPINSTANALYSIS_H -#define LLVM_TRANSFORMS_UTILS_CMPINSTANALYSIS_H +#ifndef LLVM_ANALYSIS_CMPINSTANALYSIS_H +#define LLVM_ANALYSIS_CMPINSTANALYSIS_H #include "llvm/IR/InstrTypes.h" @@ -60,10 +60,11 @@ namespace llvm { /// equality comparison (which is signless). bool PredicatesFoldable(CmpInst::Predicate p1, CmpInst::Predicate p2); - /// Decompose an icmp into the form ((X & Y) pred Z) if possible. The returned - /// predicate is either == or !=. Returns false if decomposition fails. - bool decomposeBitTestICmp(const ICmpInst *I, CmpInst::Predicate &Pred, - Value *&X, Value *&Y, Value *&Z); + /// Decompose an icmp into the form ((X & Mask) pred 0) if possible. The + /// returned predicate is either == or !=. Returns false if decomposition + /// fails. + bool decomposeBitTestICmp(Value *LHS, Value *RHS, CmpInst::Predicate &Pred, + Value *&X, APInt &Mask); } // end namespace llvm diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 161709a4846..45268dd5c76 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_library(LLVMAnalysis CallGraphSCCPass.cpp CallPrinter.cpp CaptureTracking.cpp + CmpInstAnalysis.cpp CostModel.cpp CodeMetrics.cpp ConstantFolding.cpp diff --git a/lib/Transforms/Utils/CmpInstAnalysis.cpp b/lib/Analysis/CmpInstAnalysis.cpp similarity index 80% rename from lib/Transforms/Utils/CmpInstAnalysis.cpp rename to lib/Analysis/CmpInstAnalysis.cpp index d9294c49930..079811fe9a2 100644 --- a/lib/Transforms/Utils/CmpInstAnalysis.cpp +++ b/lib/Analysis/CmpInstAnalysis.cpp @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Utils/CmpInstAnalysis.h" +#include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/PatternMatch.h" using namespace llvm; @@ -63,46 +64,46 @@ bool llvm::PredicatesFoldable(ICmpInst::Predicate p1, ICmpInst::Predicate p2) { (CmpInst::isSigned(p2) && ICmpInst::isEquality(p1)); } -bool llvm::decomposeBitTestICmp(const ICmpInst *I, CmpInst::Predicate &Pred, - Value *&X, Value *&Y, Value *&Z) { - ConstantInt *C = dyn_cast(I->getOperand(1)); - if (!C) +bool llvm::decomposeBitTestICmp(Value *LHS, Value *RHS, + CmpInst::Predicate &Pred, + Value *&X, APInt &Mask) { + const APInt *C; + if (!match(RHS, PatternMatch::m_APInt(C))) return false; - switch (I->getPredicate()) { + switch (Pred) { default: return false; case ICmpInst::ICMP_SLT: // X < 0 is equivalent to (X & SignMask) != 0. - if (!C->isZero()) + if (!C->isNullValue()) return false; - Y = ConstantInt::get(I->getContext(), APInt::getSignMask(C->getBitWidth())); + Mask = APInt::getSignMask(C->getBitWidth()); Pred = ICmpInst::ICMP_NE; break; case ICmpInst::ICMP_SGT: // X > -1 is equivalent to (X & SignMask) == 0. - if (!C->isMinusOne()) + if (!C->isAllOnesValue()) return false; - Y = ConstantInt::get(I->getContext(), APInt::getSignMask(C->getBitWidth())); + Mask = APInt::getSignMask(C->getBitWidth()); Pred = ICmpInst::ICMP_EQ; break; case ICmpInst::ICMP_ULT: // X getValue().isPowerOf2()) + if (!C->isPowerOf2()) return false; - Y = ConstantInt::get(I->getContext(), -C->getValue()); + Mask = -*C; Pred = ICmpInst::ICMP_EQ; break; case ICmpInst::ICMP_UGT: // X >u 2^n-1 is equivalent to (X & ~(2^n-1)) != 0. - if (!(C->getValue() + 1).isPowerOf2()) + if (!(*C + 1).isPowerOf2()) return false; - Y = ConstantInt::get(I->getContext(), ~C->getValue()); + Mask = ~*C; Pred = ICmpInst::ICMP_NE; break; } - X = I->getOperand(0); - Z = ConstantInt::getNullValue(C->getType()); + X = LHS; return true; } diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 9729629b167..d155f6b4803 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -23,6 +23,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/MemoryBuiltins.h" @@ -3620,32 +3621,29 @@ static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X, /// An alternative way to test if a bit is set or not uses sgt/slt instead of /// eq/ne. -static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *TrueVal, - Value *FalseVal, - bool TrueWhenUnset) { +static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *CmpRHS, + ICmpInst::Predicate Pred, + Value *TrueVal, Value *FalseVal) { + Value *X; + APInt Mask; + if (!decomposeBitTestICmp(CmpLHS, CmpRHS, Pred, X, Mask)) + return nullptr; + unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits(); if (!BitWidth) return nullptr; - APInt MinSignedValue; - Value *X; - if (match(CmpLHS, m_Trunc(m_Value(X))) && (X == TrueVal || X == FalseVal)) { + Value *ExtX; + if (match(X, m_Trunc(m_Value(ExtX))) && + (ExtX == TrueVal || ExtX == FalseVal)) { // icmp slt (trunc X), 0 <--> icmp ne (and X, C), 0 // icmp sgt (trunc X), -1 <--> icmp eq (and X, C), 0 - unsigned DestSize = CmpLHS->getType()->getScalarSizeInBits(); - MinSignedValue = APInt::getSignedMinValue(DestSize).zext(BitWidth); - } else { - // icmp slt X, 0 <--> icmp ne (and X, C), 0 - // icmp sgt X, -1 <--> icmp eq (and X, C), 0 - X = CmpLHS; - MinSignedValue = APInt::getSignedMinValue(BitWidth); + X = ExtX; + Mask = Mask.zext(BitWidth); } - if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, &MinSignedValue, - TrueWhenUnset)) - return V; - - return nullptr; + return simplifySelectBitTest(TrueVal, FalseVal, X, &Mask, + Pred == ICmpInst::ICMP_EQ); } /// Try to simplify a select instruction when its condition operand is an @@ -3658,9 +3656,6 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, if (!match(CondVal, m_ICmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS)))) return nullptr; - // FIXME: This code is nearly duplicated in InstCombine. Using/refactoring - // decomposeBitTestICmp() might help. - // FIXME this should support ICMP_SLE/SGE forms as well if (ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero())) { Value *X; const APInt *Y; @@ -3668,18 +3663,13 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, Y, Pred == ICmpInst::ICMP_EQ)) return V; - } else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) { - // Comparing signed-less-than 0 checks if the sign bit is set. - if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal, - false)) - return V; - } else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) { - // Comparing signed-greater-than -1 checks if the sign bit is not set. - if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal, - true)) - return V; } + // Check for other compares that behave like bit test. + if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, CmpRHS, Pred, + TrueVal, FalseVal)) + return V; + if (CondVal->hasOneUse()) { const APInt *C; if (match(CmpRHS, m_APInt(C))) { diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index dfc2ea3e4de..8f0254f2171 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -12,11 +12,11 @@ //===----------------------------------------------------------------------===// #include "InstCombineInternal.h" +#include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/PatternMatch.h" -#include "llvm/Transforms/Utils/CmpInstAnalysis.h" #include "llvm/Transforms/Utils/Local.h" using namespace llvm; using namespace PatternMatch; @@ -292,6 +292,18 @@ static unsigned conjugateICmpMask(unsigned Mask) { return NewMask; } +// Adapts the external decomposeBitTestICmp for local use. +static bool decomposeBitTestICmp(Value *LHS, Value *RHS, CmpInst::Predicate &Pred, + Value *&X, Value *&Y, Value *&Z) { + APInt Mask; + if (!llvm::decomposeBitTestICmp(LHS, RHS, Pred, X, Mask)) + return false; + + Y = ConstantInt::get(LHS->getType(), Mask); + Z = ConstantInt::get(RHS->getType(), 0); + return true; +} + /// Handle (icmp(A & B) ==/!= C) &/| (icmp(A & D) ==/!= E). /// Return the set of pattern classes (from MaskedICmpType) that both LHS and /// RHS satisfy. @@ -316,7 +328,7 @@ static unsigned getMaskedTypeForICmpPair(Value *&A, Value *&B, Value *&C, Value *L2 = LHS->getOperand(1); Value *L11, *L12, *L21, *L22; // Check whether the icmp can be decomposed into a bit test. - if (decomposeBitTestICmp(LHS, PredL, L11, L12, L2)) { + if (decomposeBitTestICmp(L1, L2, PredL, L11, L12, L2)) { L21 = L22 = L1 = nullptr; } else { // Look for ANDs in the LHS icmp. @@ -347,7 +359,7 @@ static unsigned getMaskedTypeForICmpPair(Value *&A, Value *&B, Value *&C, Value *R2 = RHS->getOperand(1); Value *R11, *R12; bool Ok = false; - if (decomposeBitTestICmp(RHS, PredR, R11, R12, R2)) { + if (decomposeBitTestICmp(R1, R2, PredR, R11, R12, R2)) { if (R11 == L11 || R11 == L12 || R11 == L21 || R11 == L22) { A = R11; D = R12; diff --git a/lib/Transforms/Utils/CMakeLists.txt b/lib/Transforms/Utils/CMakeLists.txt index 83bc05d0311..8561ec78b1c 100644 --- a/lib/Transforms/Utils/CMakeLists.txt +++ b/lib/Transforms/Utils/CMakeLists.txt @@ -7,7 +7,6 @@ add_llvm_library(LLVMTransformUtils BypassSlowDivision.cpp CloneFunction.cpp CloneModule.cpp - CmpInstAnalysis.cpp CodeExtractor.cpp CtorUtils.cpp DemoteRegToStack.cpp diff --git a/test/Transforms/InstSimplify/select.ll b/test/Transforms/InstSimplify/select.ll index e9c94170a94..4134191a3cf 100644 --- a/test/Transforms/InstSimplify/select.ll +++ b/test/Transforms/InstSimplify/select.ll @@ -160,13 +160,10 @@ define <2 x i8> @test11vec(<2 x i8> %X) { ret <2 x i8> %sel } -; TODO: we should be able to simplify this define i32 @test12(i32 %X) { ; CHECK-LABEL: @test12( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 4 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 3 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[AND]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] ; %cmp = icmp ult i32 %X, 4 %and = and i32 %X, 3 @@ -189,13 +186,10 @@ define i32 @test12noncanon(i32 %X) { ret i32 %cond } -; TODO: we should be able to simplify this define i32 @test13(i32 %X) { ; CHECK-LABEL: @test13( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], 3 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 3 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[X]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] ; %cmp = icmp ugt i32 %X, 3 %and = and i32 %X, 3