10b57cec5SDimitry Andric //===- CmpInstAnalysis.cpp - Utils to help fold compares ---------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file holds routines to help analyse compare instructions 100b57cec5SDimitry Andric // and fold them into constants or other compare instructions 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/Analysis/CmpInstAnalysis.h" 150b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 160b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 170b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace llvm; 200b57cec5SDimitry Andric 2181ad6265SDimitry Andric unsigned llvm::getICmpCode(CmpInst::Predicate Pred) { 220b57cec5SDimitry Andric switch (Pred) { 230b57cec5SDimitry Andric // False -> 0 240b57cec5SDimitry Andric case ICmpInst::ICMP_UGT: return 1; // 001 250b57cec5SDimitry Andric case ICmpInst::ICMP_SGT: return 1; // 001 260b57cec5SDimitry Andric case ICmpInst::ICMP_EQ: return 2; // 010 270b57cec5SDimitry Andric case ICmpInst::ICMP_UGE: return 3; // 011 280b57cec5SDimitry Andric case ICmpInst::ICMP_SGE: return 3; // 011 290b57cec5SDimitry Andric case ICmpInst::ICMP_ULT: return 4; // 100 300b57cec5SDimitry Andric case ICmpInst::ICMP_SLT: return 4; // 100 310b57cec5SDimitry Andric case ICmpInst::ICMP_NE: return 5; // 101 320b57cec5SDimitry Andric case ICmpInst::ICMP_ULE: return 6; // 110 330b57cec5SDimitry Andric case ICmpInst::ICMP_SLE: return 6; // 110 340b57cec5SDimitry Andric // True -> 7 350b57cec5SDimitry Andric default: 360b57cec5SDimitry Andric llvm_unreachable("Invalid ICmp predicate!"); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric Constant *llvm::getPredForICmpCode(unsigned Code, bool Sign, Type *OpTy, 410b57cec5SDimitry Andric CmpInst::Predicate &Pred) { 420b57cec5SDimitry Andric switch (Code) { 430b57cec5SDimitry Andric default: llvm_unreachable("Illegal ICmp code!"); 440b57cec5SDimitry Andric case 0: // False. 450b57cec5SDimitry Andric return ConstantInt::get(CmpInst::makeCmpResultType(OpTy), 0); 460b57cec5SDimitry Andric case 1: Pred = Sign ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT; break; 470b57cec5SDimitry Andric case 2: Pred = ICmpInst::ICMP_EQ; break; 480b57cec5SDimitry Andric case 3: Pred = Sign ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; break; 490b57cec5SDimitry Andric case 4: Pred = Sign ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT; break; 500b57cec5SDimitry Andric case 5: Pred = ICmpInst::ICMP_NE; break; 510b57cec5SDimitry Andric case 6: Pred = Sign ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; break; 520b57cec5SDimitry Andric case 7: // True. 530b57cec5SDimitry Andric return ConstantInt::get(CmpInst::makeCmpResultType(OpTy), 1); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric return nullptr; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool llvm::predicatesFoldable(ICmpInst::Predicate P1, ICmpInst::Predicate P2) { 590b57cec5SDimitry Andric return (CmpInst::isSigned(P1) == CmpInst::isSigned(P2)) || 600b57cec5SDimitry Andric (CmpInst::isSigned(P1) && ICmpInst::isEquality(P2)) || 610b57cec5SDimitry Andric (CmpInst::isSigned(P2) && ICmpInst::isEquality(P1)); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 6481ad6265SDimitry Andric Constant *llvm::getPredForFCmpCode(unsigned Code, Type *OpTy, 6581ad6265SDimitry Andric CmpInst::Predicate &Pred) { 6681ad6265SDimitry Andric Pred = static_cast<FCmpInst::Predicate>(Code); 6781ad6265SDimitry Andric assert(FCmpInst::FCMP_FALSE <= Pred && Pred <= FCmpInst::FCMP_TRUE && 6881ad6265SDimitry Andric "Unexpected FCmp predicate!"); 6981ad6265SDimitry Andric if (Pred == FCmpInst::FCMP_FALSE) 7081ad6265SDimitry Andric return ConstantInt::get(CmpInst::makeCmpResultType(OpTy), 0); 7181ad6265SDimitry Andric if (Pred == FCmpInst::FCMP_TRUE) 7281ad6265SDimitry Andric return ConstantInt::get(CmpInst::makeCmpResultType(OpTy), 1); 7381ad6265SDimitry Andric return nullptr; 7481ad6265SDimitry Andric } 7581ad6265SDimitry Andric 760b57cec5SDimitry Andric bool llvm::decomposeBitTestICmp(Value *LHS, Value *RHS, 770b57cec5SDimitry Andric CmpInst::Predicate &Pred, 780b57cec5SDimitry Andric Value *&X, APInt &Mask, bool LookThruTrunc) { 790b57cec5SDimitry Andric using namespace PatternMatch; 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric const APInt *C; 82*0fca6ea1SDimitry Andric if (!match(RHS, m_APIntAllowPoison(C))) 830b57cec5SDimitry Andric return false; 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric switch (Pred) { 860b57cec5SDimitry Andric default: 870b57cec5SDimitry Andric return false; 880b57cec5SDimitry Andric case ICmpInst::ICMP_SLT: 890b57cec5SDimitry Andric // X < 0 is equivalent to (X & SignMask) != 0. 90349cc55cSDimitry Andric if (!C->isZero()) 910b57cec5SDimitry Andric return false; 920b57cec5SDimitry Andric Mask = APInt::getSignMask(C->getBitWidth()); 930b57cec5SDimitry Andric Pred = ICmpInst::ICMP_NE; 940b57cec5SDimitry Andric break; 950b57cec5SDimitry Andric case ICmpInst::ICMP_SLE: 960b57cec5SDimitry Andric // X <= -1 is equivalent to (X & SignMask) != 0. 97349cc55cSDimitry Andric if (!C->isAllOnes()) 980b57cec5SDimitry Andric return false; 990b57cec5SDimitry Andric Mask = APInt::getSignMask(C->getBitWidth()); 1000b57cec5SDimitry Andric Pred = ICmpInst::ICMP_NE; 1010b57cec5SDimitry Andric break; 1020b57cec5SDimitry Andric case ICmpInst::ICMP_SGT: 1030b57cec5SDimitry Andric // X > -1 is equivalent to (X & SignMask) == 0. 104349cc55cSDimitry Andric if (!C->isAllOnes()) 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric Mask = APInt::getSignMask(C->getBitWidth()); 1070b57cec5SDimitry Andric Pred = ICmpInst::ICMP_EQ; 1080b57cec5SDimitry Andric break; 1090b57cec5SDimitry Andric case ICmpInst::ICMP_SGE: 1100b57cec5SDimitry Andric // X >= 0 is equivalent to (X & SignMask) == 0. 111349cc55cSDimitry Andric if (!C->isZero()) 1120b57cec5SDimitry Andric return false; 1130b57cec5SDimitry Andric Mask = APInt::getSignMask(C->getBitWidth()); 1140b57cec5SDimitry Andric Pred = ICmpInst::ICMP_EQ; 1150b57cec5SDimitry Andric break; 1160b57cec5SDimitry Andric case ICmpInst::ICMP_ULT: 1170b57cec5SDimitry Andric // X <u 2^n is equivalent to (X & ~(2^n-1)) == 0. 1180b57cec5SDimitry Andric if (!C->isPowerOf2()) 1190b57cec5SDimitry Andric return false; 1200b57cec5SDimitry Andric Mask = -*C; 1210b57cec5SDimitry Andric Pred = ICmpInst::ICMP_EQ; 1220b57cec5SDimitry Andric break; 1230b57cec5SDimitry Andric case ICmpInst::ICMP_ULE: 1240b57cec5SDimitry Andric // X <=u 2^n-1 is equivalent to (X & ~(2^n-1)) == 0. 1250b57cec5SDimitry Andric if (!(*C + 1).isPowerOf2()) 1260b57cec5SDimitry Andric return false; 1270b57cec5SDimitry Andric Mask = ~*C; 1280b57cec5SDimitry Andric Pred = ICmpInst::ICMP_EQ; 1290b57cec5SDimitry Andric break; 1300b57cec5SDimitry Andric case ICmpInst::ICMP_UGT: 1310b57cec5SDimitry Andric // X >u 2^n-1 is equivalent to (X & ~(2^n-1)) != 0. 1320b57cec5SDimitry Andric if (!(*C + 1).isPowerOf2()) 1330b57cec5SDimitry Andric return false; 1340b57cec5SDimitry Andric Mask = ~*C; 1350b57cec5SDimitry Andric Pred = ICmpInst::ICMP_NE; 1360b57cec5SDimitry Andric break; 1370b57cec5SDimitry Andric case ICmpInst::ICMP_UGE: 1380b57cec5SDimitry Andric // X >=u 2^n is equivalent to (X & ~(2^n-1)) != 0. 1390b57cec5SDimitry Andric if (!C->isPowerOf2()) 1400b57cec5SDimitry Andric return false; 1410b57cec5SDimitry Andric Mask = -*C; 1420b57cec5SDimitry Andric Pred = ICmpInst::ICMP_NE; 1430b57cec5SDimitry Andric break; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric if (LookThruTrunc && match(LHS, m_Trunc(m_Value(X)))) { 1470b57cec5SDimitry Andric Mask = Mask.zext(X->getType()->getScalarSizeInBits()); 1480b57cec5SDimitry Andric } else { 1490b57cec5SDimitry Andric X = LHS; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric return true; 1530b57cec5SDimitry Andric } 154