#include "InstCombineInternal.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Transforms/InstCombine/InstCombiner.h"
#include "llvm/Transforms/Utils/BuildLibCalls.h"
#include <cassert>
#define DEBUG_TYPE "instcombine"
#include "llvm/Transforms/Utils/InstructionWorklist.h"
using namespace llvm;
using namespace PatternMatch;
static Value *simplifyValueKnownNonZero(Value *V, InstCombinerImpl &IC,
Instruction &CxtI) {
if (!V->hasOneUse()) return nullptr;
bool MadeChange = false;
Value *A = nullptr, *B = nullptr, *One = nullptr;
if (match(V, m_LShr(m_OneUse(m_Shl(m_Value(One), m_Value(A))), m_Value(B))) &&
match(One, m_One())) {
A = IC.Builder.CreateSub(A, B);
return IC.Builder.CreateShl(One, A);
}
BinaryOperator *I = dyn_cast<BinaryOperator>(V);
if (I && I->isLogicalShift() &&
IC.isKnownToBeAPowerOfTwo(I->getOperand(0), false, 0, &CxtI)) {
if (Value *V2 = simplifyValueKnownNonZero(I->getOperand(0), IC, CxtI)) {
IC.replaceOperand(*I, 0, V2);
MadeChange = true;
}
if (I->getOpcode() == Instruction::LShr && !I->isExact()) {
I->setIsExact();
MadeChange = true;
}
if (I->getOpcode() == Instruction::Shl && !I->hasNoUnsignedWrap()) {
I->setHasNoUnsignedWrap();
MadeChange = true;
}
}
return MadeChange ? V : nullptr;
}
static Value *foldMulSelectToNegate(BinaryOperator &I,
InstCombiner::BuilderTy &Builder) {
Value *Cond, *OtherOp;
if (match(&I, m_c_Mul(m_OneUse(m_Select(m_Value(Cond), m_One(), m_AllOnes())),
m_Value(OtherOp)))) {
bool HasAnyNoWrap = I.hasNoSignedWrap() || I.hasNoUnsignedWrap();
Value *Neg = Builder.CreateNeg(OtherOp, "", false, HasAnyNoWrap);
return Builder.CreateSelect(Cond, OtherOp, Neg);
}
if (match(&I, m_c_Mul(m_OneUse(m_Select(m_Value(Cond), m_AllOnes(), m_One())),
m_Value(OtherOp)))) {
bool HasAnyNoWrap = I.hasNoSignedWrap() || I.hasNoUnsignedWrap();
Value *Neg = Builder.CreateNeg(OtherOp, "", false, HasAnyNoWrap);
return Builder.CreateSelect(Cond, Neg, OtherOp);
}
if (match(&I, m_c_FMul(m_OneUse(m_Select(m_Value(Cond), m_SpecificFP(1.0),
m_SpecificFP(-1.0))),
m_Value(OtherOp)))) {
IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.setFastMathFlags(I.getFastMathFlags());
return Builder.CreateSelect(Cond, OtherOp, Builder.CreateFNeg(OtherOp));
}
if (match(&I, m_c_FMul(m_OneUse(m_Select(m_Value(Cond), m_SpecificFP(-1.0),
m_SpecificFP(1.0))),
m_Value(OtherOp)))) {
IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.setFastMathFlags(I.getFastMathFlags());
return Builder.CreateSelect(Cond, Builder.CreateFNeg(OtherOp), OtherOp);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
if (Value *V = simplifyMulInst(I.getOperand(0), I.getOperand(1),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (SimplifyAssociativeOrCommutative(I))
return &I;
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
if (Value *V = SimplifyUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
unsigned BitWidth = I.getType()->getScalarSizeInBits();
if (match(Op1, m_AllOnes())) {
BinaryOperator *BO = BinaryOperator::CreateNeg(Op0, I.getName());
if (I.hasNoSignedWrap())
BO->setHasNoSignedWrap();
return BO;
}
{
Value *NewOp;
Constant *C1, *C2;
const APInt *IVal;
if (match(&I, m_Mul(m_Shl(m_Value(NewOp), m_Constant(C2)),
m_Constant(C1))) &&
match(C1, m_APInt(IVal))) {
Constant *Shl = ConstantExpr::getShl(C1, C2);
BinaryOperator *Mul = cast<BinaryOperator>(I.getOperand(0));
BinaryOperator *BO = BinaryOperator::CreateMul(NewOp, Shl);
if (I.hasNoUnsignedWrap() && Mul->hasNoUnsignedWrap())
BO->setHasNoUnsignedWrap();
if (I.hasNoSignedWrap() && Mul->hasNoSignedWrap() &&
Shl->isNotMinSignedValue())
BO->setHasNoSignedWrap();
return BO;
}
if (match(&I, m_Mul(m_Value(NewOp), m_Constant(C1)))) {
if (Constant *NewCst = ConstantExpr::getExactLogBase2(C1)) {
BinaryOperator *Shl = BinaryOperator::CreateShl(NewOp, NewCst);
if (I.hasNoUnsignedWrap())
Shl->setHasNoUnsignedWrap();
if (I.hasNoSignedWrap()) {
const APInt *V;
if (match(NewCst, m_APInt(V)) && *V != V->getBitWidth() - 1)
Shl->setHasNoSignedWrap();
}
return Shl;
}
}
}
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
if (Value *NegOp0 = Negator::Negate( true, Op0, *this))
return BinaryOperator::CreateMul(
NegOp0, ConstantExpr::getNeg(cast<Constant>(Op1)), I.getName());
}
if (Instruction *FoldedMul = foldBinOpIntoSelectOrPhi(I))
return FoldedMul;
if (Value *FoldedMul = foldMulSelectToNegate(I, Builder))
return replaceInstUsesWith(I, FoldedMul);
if (isa<Constant>(Op1)) {
Value *X;
Constant *C1;
if (match(Op0, m_OneUse(m_Add(m_Value(X), m_Constant(C1))))) {
Value *Mul = Builder.CreateMul(C1, Op1);
if (!match(Mul, m_Mul(m_Value(), m_Value())))
return BinaryOperator::CreateAdd(Builder.CreateMul(X, Op1), Mul);
}
}
if (Op0 == Op1) {
Value *X, *Y;
SelectPatternFlavor SPF = matchSelectPattern(Op0, X, Y).Flavor;
if (SPF == SPF_ABS || SPF == SPF_NABS)
return BinaryOperator::CreateMul(X, X);
if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))))
return BinaryOperator::CreateMul(X, X);
}
Value *X, *Y;
Constant *Op1C;
if (match(Op0, m_Neg(m_Value(X))) && match(Op1, m_Constant(Op1C)))
return BinaryOperator::CreateMul(X, ConstantExpr::getNeg(Op1C));
if (match(Op0, m_Neg(m_Value(X))) && match(Op1, m_Neg(m_Value(Y)))) {
auto *NewMul = BinaryOperator::CreateMul(X, Y);
if (I.hasNoSignedWrap() &&
cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap() &&
cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap())
NewMul->setHasNoSignedWrap();
return NewMul;
}
if (match(&I, m_c_Mul(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))
return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
{
Value *Y = Op1;
BinaryOperator *Div = dyn_cast<BinaryOperator>(Op0);
if (!Div || (Div->getOpcode() != Instruction::UDiv &&
Div->getOpcode() != Instruction::SDiv)) {
Y = Op0;
Div = dyn_cast<BinaryOperator>(Op1);
}
Value *Neg = dyn_castNegVal(Y);
if (Div && Div->hasOneUse() &&
(Div->getOperand(1) == Y || Div->getOperand(1) == Neg) &&
(Div->getOpcode() == Instruction::UDiv ||
Div->getOpcode() == Instruction::SDiv)) {
Value *X = Div->getOperand(0), *DivOp1 = Div->getOperand(1);
if (Div->isExact()) {
if (DivOp1 == Y)
return replaceInstUsesWith(I, X);
return BinaryOperator::CreateNeg(X);
}
auto RemOpc = Div->getOpcode() == Instruction::UDiv ? Instruction::URem
: Instruction::SRem;
Value *XFreeze = Builder.CreateFreeze(X, X->getName() + ".fr");
Value *Rem = Builder.CreateBinOp(RemOpc, XFreeze, DivOp1);
if (DivOp1 == Y)
return BinaryOperator::CreateSub(XFreeze, Rem);
return BinaryOperator::CreateSub(Rem, XFreeze);
}
}
Type *Ty = I.getType();
if (Ty->isIntOrIntVectorTy(1) ||
(match(Op0, m_And(m_Value(), m_One())) &&
match(Op1, m_And(m_Value(), m_One()))))
return BinaryOperator::CreateAnd(Op0, Op1);
{
Value *Y;
BinaryOperator *BO = nullptr;
bool ShlNSW = false;
if (match(Op0, m_Shl(m_One(), m_Value(Y)))) {
BO = BinaryOperator::CreateShl(Op1, Y);
ShlNSW = cast<ShlOperator>(Op0)->hasNoSignedWrap();
} else if (match(Op1, m_Shl(m_One(), m_Value(Y)))) {
BO = BinaryOperator::CreateShl(Op0, Y);
ShlNSW = cast<ShlOperator>(Op1)->hasNoSignedWrap();
}
if (BO) {
if (I.hasNoUnsignedWrap())
BO->setHasNoUnsignedWrap();
if (I.hasNoSignedWrap() && ShlNSW)
BO->setHasNoSignedWrap();
return BO;
}
}
if (((match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_ZExt(m_Value(Y)))) ||
(match(Op0, m_SExt(m_Value(X))) && match(Op1, m_SExt(m_Value(Y))))) &&
X->getType()->isIntOrIntVectorTy(1) && X->getType() == Y->getType() &&
(Op0->hasOneUse() || Op1->hasOneUse() || X == Y)) {
Value *And = Builder.CreateAnd(X, Y, "mulbool");
return CastInst::Create(Instruction::ZExt, And, Ty);
}
if (((match(Op0, m_SExt(m_Value(X))) && match(Op1, m_ZExt(m_Value(Y)))) ||
(match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_SExt(m_Value(Y))))) &&
X->getType()->isIntOrIntVectorTy(1) && X->getType() == Y->getType() &&
(Op0->hasOneUse() || Op1->hasOneUse())) {
Value *And = Builder.CreateAnd(X, Y, "mulbool");
return CastInst::Create(Instruction::SExt, And, Ty);
}
if (match(Op0, m_ZExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1))
return SelectInst::Create(X, Op1, ConstantInt::getNullValue(Ty));
if (match(Op1, m_ZExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1))
return SelectInst::Create(X, Op0, ConstantInt::getNullValue(Ty));
Constant *ImmC;
if (match(Op1, m_ImmConstant(ImmC))) {
if (match(Op0, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)) {
Constant *NegC = ConstantExpr::getNeg(ImmC);
return SelectInst::Create(X, NegC, ConstantInt::getNullValue(Ty));
}
const APInt *C;
if (match(Op0, m_OneUse(m_AShr(m_Value(X), m_APInt(C)))) &&
*C == C->getBitWidth() - 1) {
Constant *NegC = ConstantExpr::getNeg(ImmC);
Value *IsNeg = Builder.CreateIsNeg(X, "isneg");
return SelectInst::Create(IsNeg, NegC, ConstantInt::getNullValue(Ty));
}
}
const APInt *C;
if (match(&I, m_c_BinOp(m_LShr(m_Value(X), m_APInt(C)), m_Value(Y))) &&
*C == C->getBitWidth() - 1) {
Value *IsNeg = Builder.CreateIsNeg(X, "isneg");
return SelectInst::Create(IsNeg, Y, ConstantInt::getNullValue(Ty));
}
if (match(&I, m_c_BinOp(m_OneUse(m_And(m_Value(X), m_One())), m_Value(Y)))) {
Value *Tr = Builder.CreateTrunc(X, CmpInst::makeCmpResultType(Ty));
return SelectInst::Create(Tr, Y, ConstantInt::getNullValue(Ty));
}
if (match(&I, m_c_BinOp(m_Or(m_AShr(m_Value(X),
m_SpecificIntAllowUndef(BitWidth - 1)),
m_One()),
m_Deferred(X)))) {
Value *Abs = Builder.CreateBinaryIntrinsic(
Intrinsic::abs, X,
ConstantInt::getBool(I.getContext(), I.hasNoSignedWrap()));
Abs->takeName(&I);
return replaceInstUsesWith(I, Abs);
}
if (Instruction *Ext = narrowMathIfNoOverflow(I))
return Ext;
bool Changed = false;
if (!I.hasNoSignedWrap() && willNotOverflowSignedMul(Op0, Op1, I)) {
Changed = true;
I.setHasNoSignedWrap(true);
}
if (!I.hasNoUnsignedWrap() && willNotOverflowUnsignedMul(Op0, Op1, I)) {
Changed = true;
I.setHasNoUnsignedWrap(true);
}
return Changed ? &I : nullptr;
}
Instruction *InstCombinerImpl::foldFPSignBitOps(BinaryOperator &I) {
BinaryOperator::BinaryOps Opcode = I.getOpcode();
assert((Opcode == Instruction::FMul || Opcode == Instruction::FDiv) &&
"Expected fmul or fdiv");
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Value *X, *Y;
if (match(Op0, m_FNeg(m_Value(X))) && match(Op1, m_FNeg(m_Value(Y))))
return BinaryOperator::CreateWithCopiedFlags(Opcode, X, Y, &I);
if (Op0 == Op1 && match(Op0, m_FAbs(m_Value(X))))
return BinaryOperator::CreateWithCopiedFlags(Opcode, X, X, &I);
if (match(Op0, m_FAbs(m_Value(X))) && match(Op1, m_FAbs(m_Value(Y))) &&
(Op0->hasOneUse() || Op1->hasOneUse())) {
IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.setFastMathFlags(I.getFastMathFlags());
Value *XY = Builder.CreateBinOp(Opcode, X, Y);
Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, XY);
Fabs->takeName(&I);
return replaceInstUsesWith(I, Fabs);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
if (Value *V = simplifyFMulInst(I.getOperand(0), I.getOperand(1),
I.getFastMathFlags(),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (SimplifyAssociativeOrCommutative(I))
return &I;
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
if (Instruction *FoldedMul = foldBinOpIntoSelectOrPhi(I))
return FoldedMul;
if (Value *FoldedMul = foldMulSelectToNegate(I, Builder))
return replaceInstUsesWith(I, FoldedMul);
if (Instruction *R = foldFPSignBitOps(I))
return R;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (match(Op1, m_SpecificFP(-1.0)))
return UnaryOperator::CreateFNegFMF(Op0, &I);
Value *X, *Y;
Constant *C;
if (match(Op0, m_FNeg(m_Value(X))) && match(Op1, m_Constant(C)))
return BinaryOperator::CreateFMulFMF(X, ConstantExpr::getFNeg(C), &I);
if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1))
return replaceInstUsesWith(I, V);
if (I.hasAllowReassoc()) {
if (match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) {
Constant *C1;
if (match(Op0, m_OneUse(m_FDiv(m_Constant(C1), m_Value(X))))) {
Constant *CC1 =
ConstantFoldBinaryOpOperands(Instruction::FMul, C, C1, DL);
if (CC1 && CC1->isNormalFP())
return BinaryOperator::CreateFDivFMF(CC1, X, &I);
}
if (match(Op0, m_FDiv(m_Value(X), m_Constant(C1)))) {
Constant *CDivC1 =
ConstantFoldBinaryOpOperands(Instruction::FDiv, C, C1, DL);
if (CDivC1 && CDivC1->isNormalFP())
return BinaryOperator::CreateFMulFMF(X, CDivC1, &I);
Constant *C1DivC =
ConstantFoldBinaryOpOperands(Instruction::FDiv, C1, C, DL);
if (C1DivC && Op0->hasOneUse() && C1DivC->isNormalFP())
return BinaryOperator::CreateFDivFMF(X, C1DivC, &I);
}
if (match(Op0, m_OneUse(m_FAdd(m_Value(X), m_Constant(C1))))) {
if (Constant *CC1 = ConstantFoldBinaryOpOperands(
Instruction::FMul, C, C1, DL)) {
Value *XC = Builder.CreateFMulFMF(X, C, &I);
return BinaryOperator::CreateFAddFMF(XC, CC1, &I);
}
}
if (match(Op0, m_OneUse(m_FSub(m_Constant(C1), m_Value(X))))) {
if (Constant *CC1 = ConstantFoldBinaryOpOperands(
Instruction::FMul, C, C1, DL)) {
Value *XC = Builder.CreateFMulFMF(X, C, &I);
return BinaryOperator::CreateFSubFMF(CC1, XC, &I);
}
}
}
Value *Z;
if (match(&I, m_c_FMul(m_OneUse(m_FDiv(m_Value(X), m_Value(Y))),
m_Value(Z)))) {
Value *NewFMul = Builder.CreateFMulFMF(X, Z, &I);
return BinaryOperator::CreateFDivFMF(NewFMul, Y, &I);
}
if (I.hasNoNaNs() && match(Op0, m_OneUse(m_Sqrt(m_Value(X)))) &&
match(Op1, m_OneUse(m_Sqrt(m_Value(Y))))) {
Value *XY = Builder.CreateFMulFMF(X, Y, &I);
Value *Sqrt = Builder.CreateUnaryIntrinsic(Intrinsic::sqrt, XY, &I);
return replaceInstUsesWith(I, Sqrt);
}
if (I.hasNoSignedZeros() &&
match(Op0, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) &&
match(Y, m_Sqrt(m_Value(X))) && Op1 == X)
return BinaryOperator::CreateFDivFMF(X, Y, &I);
if (I.hasNoSignedZeros() &&
match(Op1, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) &&
match(Y, m_Sqrt(m_Value(X))) && Op0 == X)
return BinaryOperator::CreateFDivFMF(X, Y, &I);
if (I.hasNoNaNs() && I.hasNoSignedZeros() && Op0 == Op1 &&
Op0->hasNUses(2)) {
if (match(Op0, m_FDiv(m_Value(X), m_Sqrt(m_Value(Y))))) {
Value *XX = Builder.CreateFMulFMF(X, X, &I);
return BinaryOperator::CreateFDivFMF(XX, Y, &I);
}
if (match(Op0, m_FDiv(m_Sqrt(m_Value(Y)), m_Value(X)))) {
Value *XX = Builder.CreateFMulFMF(X, X, &I);
return BinaryOperator::CreateFDivFMF(Y, XX, &I);
}
}
if (I.isOnlyUserOfAnyOperand()) {
if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))) &&
match(Op1, m_Intrinsic<Intrinsic::pow>(m_Specific(X), m_Value(Z)))) {
auto *YZ = Builder.CreateFAddFMF(Y, Z, &I);
auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YZ, &I);
return replaceInstUsesWith(I, NewPow);
}
if (match(Op0, m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y))) &&
match(Op1, m_Intrinsic<Intrinsic::powi>(m_Specific(X), m_Value(Z))) &&
Y->getType() == Z->getType()) {
auto *YZ = Builder.CreateAdd(Y, Z);
auto *NewPow = Builder.CreateIntrinsic(
Intrinsic::powi, {X->getType(), YZ->getType()}, {X, YZ}, &I);
return replaceInstUsesWith(I, NewPow);
}
if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X))) &&
match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(Y)))) {
Value *XY = Builder.CreateFAddFMF(X, Y, &I);
Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I);
return replaceInstUsesWith(I, Exp);
}
if (match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X))) &&
match(Op1, m_Intrinsic<Intrinsic::exp2>(m_Value(Y)))) {
Value *XY = Builder.CreateFAddFMF(X, Y, &I);
Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I);
return replaceInstUsesWith(I, Exp2);
}
}
if (match(Op0, m_OneUse(m_c_FMul(m_Specific(Op1), m_Value(Y)))) &&
Op1 != Y) {
Value *XX = Builder.CreateFMulFMF(Op1, Op1, &I);
return BinaryOperator::CreateFMulFMF(XX, Y, &I);
}
if (match(Op1, m_OneUse(m_c_FMul(m_Specific(Op0), m_Value(Y)))) &&
Op0 != Y) {
Value *XX = Builder.CreateFMulFMF(Op0, Op0, &I);
return BinaryOperator::CreateFMulFMF(XX, Y, &I);
}
}
if (I.isFast()) {
IntrinsicInst *Log2 = nullptr;
if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::log2>(
m_OneUse(m_FMul(m_Value(X), m_SpecificFP(0.5))))))) {
Log2 = cast<IntrinsicInst>(Op0);
Y = Op1;
}
if (match(Op1, m_OneUse(m_Intrinsic<Intrinsic::log2>(
m_OneUse(m_FMul(m_Value(X), m_SpecificFP(0.5))))))) {
Log2 = cast<IntrinsicInst>(Op1);
Y = Op0;
}
if (Log2) {
Value *Log2 = Builder.CreateUnaryIntrinsic(Intrinsic::log2, X, &I);
Value *LogXTimesY = Builder.CreateFMulFMF(Log2, Y, &I);
return BinaryOperator::CreateFSubFMF(LogXTimesY, Y, &I);
}
}
return nullptr;
}
bool InstCombinerImpl::simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I) {
SelectInst *SI = dyn_cast<SelectInst>(I.getOperand(1));
if (!SI)
return false;
int NonNullOperand;
if (match(SI->getTrueValue(), m_Zero()))
NonNullOperand = 2;
else if (match(SI->getFalseValue(), m_Zero()))
NonNullOperand = 1;
else
return false;
replaceOperand(I, 1, SI->getOperand(NonNullOperand));
Value *SelectCond = SI->getCondition();
if (SI->use_empty() && SelectCond->hasOneUse())
return true;
BasicBlock::iterator BBI = I.getIterator(), BBFront = I.getParent()->begin();
Type *CondTy = SelectCond->getType();
while (BBI != BBFront) {
--BBI;
if (!isGuaranteedToTransferExecutionToSuccessor(&*BBI))
break;
for (Use &Op : BBI->operands()) {
if (Op == SI) {
replaceUse(Op, SI->getOperand(NonNullOperand));
Worklist.push(&*BBI);
} else if (Op == SelectCond) {
replaceUse(Op, NonNullOperand == 1 ? ConstantInt::getTrue(CondTy)
: ConstantInt::getFalse(CondTy));
Worklist.push(&*BBI);
}
}
if (&*BBI == SI)
SI = nullptr;
if (&*BBI == SelectCond)
SelectCond = nullptr;
if (!SelectCond && !SI)
break;
}
return true;
}
static bool multiplyOverflows(const APInt &C1, const APInt &C2, APInt &Product,
bool IsSigned) {
bool Overflow;
Product = IsSigned ? C1.smul_ov(C2, Overflow) : C1.umul_ov(C2, Overflow);
return Overflow;
}
static bool isMultiple(const APInt &C1, const APInt &C2, APInt &Quotient,
bool IsSigned) {
assert(C1.getBitWidth() == C2.getBitWidth() && "Constant widths not equal");
if (C2.isZero())
return false;
if (IsSigned && C1.isMinSignedValue() && C2.isAllOnes())
return false;
APInt Remainder(C1.getBitWidth(), 0ULL, IsSigned);
if (IsSigned)
APInt::sdivrem(C1, C2, Quotient, Remainder);
else
APInt::udivrem(C1, C2, Quotient, Remainder);
return Remainder.isMinValue();
}
Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
bool IsSigned = I.getOpcode() == Instruction::SDiv;
Type *Ty = I.getType();
if (Value *V = simplifyValueKnownNonZero(I.getOperand(1), *this, I))
return replaceOperand(I, 1, V);
if (simplifyDivRemOfSelectWithZeroOp(I))
return &I;
if (match(Op0, m_ImmConstant()) &&
match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) {
if (Instruction *R = FoldOpIntoSelect(I, cast<SelectInst>(Op1),
true))
return R;
}
const APInt *C2;
if (match(Op1, m_APInt(C2))) {
Value *X;
const APInt *C1;
if ((IsSigned && match(Op0, m_SDiv(m_Value(X), m_APInt(C1)))) ||
(!IsSigned && match(Op0, m_UDiv(m_Value(X), m_APInt(C1))))) {
APInt Product(C1->getBitWidth(), 0ULL, IsSigned);
if (!multiplyOverflows(*C1, *C2, Product, IsSigned))
return BinaryOperator::Create(I.getOpcode(), X,
ConstantInt::get(Ty, Product));
}
if ((IsSigned && match(Op0, m_NSWMul(m_Value(X), m_APInt(C1)))) ||
(!IsSigned && match(Op0, m_NUWMul(m_Value(X), m_APInt(C1))))) {
APInt Quotient(C1->getBitWidth(), 0ULL, IsSigned);
if (isMultiple(*C2, *C1, Quotient, IsSigned)) {
auto *NewDiv = BinaryOperator::Create(I.getOpcode(), X,
ConstantInt::get(Ty, Quotient));
NewDiv->setIsExact(I.isExact());
return NewDiv;
}
if (isMultiple(*C1, *C2, Quotient, IsSigned)) {
auto *Mul = BinaryOperator::Create(Instruction::Mul, X,
ConstantInt::get(Ty, Quotient));
auto *OBO = cast<OverflowingBinaryOperator>(Op0);
Mul->setHasNoUnsignedWrap(!IsSigned && OBO->hasNoUnsignedWrap());
Mul->setHasNoSignedWrap(OBO->hasNoSignedWrap());
return Mul;
}
}
if ((IsSigned && match(Op0, m_NSWShl(m_Value(X), m_APInt(C1))) &&
C1->ult(C1->getBitWidth() - 1)) ||
(!IsSigned && match(Op0, m_NUWShl(m_Value(X), m_APInt(C1))) &&
C1->ult(C1->getBitWidth()))) {
APInt Quotient(C1->getBitWidth(), 0ULL, IsSigned);
APInt C1Shifted = APInt::getOneBitSet(
C1->getBitWidth(), static_cast<unsigned>(C1->getZExtValue()));
if (isMultiple(*C2, C1Shifted, Quotient, IsSigned)) {
auto *BO = BinaryOperator::Create(I.getOpcode(), X,
ConstantInt::get(Ty, Quotient));
BO->setIsExact(I.isExact());
return BO;
}
if (isMultiple(C1Shifted, *C2, Quotient, IsSigned)) {
auto *Mul = BinaryOperator::Create(Instruction::Mul, X,
ConstantInt::get(Ty, Quotient));
auto *OBO = cast<OverflowingBinaryOperator>(Op0);
Mul->setHasNoUnsignedWrap(!IsSigned && OBO->hasNoUnsignedWrap());
Mul->setHasNoSignedWrap(OBO->hasNoSignedWrap());
return Mul;
}
}
if (!C2->isZero()) if (Instruction *FoldedDiv = foldBinOpIntoSelectOrPhi(I))
return FoldedDiv;
}
if (match(Op0, m_One())) {
assert(!Ty->isIntOrIntVectorTy(1) && "i1 divide not removed?");
if (IsSigned) {
Value *F1 = Builder.CreateFreeze(Op1, Op1->getName() + ".fr");
Value *Inc = Builder.CreateAdd(F1, Op0);
Value *Cmp = Builder.CreateICmpULT(Inc, ConstantInt::get(Ty, 3));
return SelectInst::Create(Cmp, F1, ConstantInt::get(Ty, 0));
} else {
return new ZExtInst(Builder.CreateICmpEQ(Op1, Op0), Ty);
}
}
if (SimplifyDemandedInstructionBits(I))
return &I;
Value *X, *Z;
if (match(Op0, m_Sub(m_Value(X), m_Value(Z)))) if ((IsSigned && match(Z, m_SRem(m_Specific(X), m_Specific(Op1)))) ||
(!IsSigned && match(Z, m_URem(m_Specific(X), m_Specific(Op1)))))
return BinaryOperator::Create(I.getOpcode(), X, Op1);
Value *Y;
if (IsSigned && match(Op0, m_NSWShl(m_Specific(Op1), m_Value(Y))))
return BinaryOperator::CreateNSWShl(ConstantInt::get(Ty, 1), Y);
if (!IsSigned && match(Op0, m_NUWShl(m_Specific(Op1), m_Value(Y))))
return BinaryOperator::CreateNUWShl(ConstantInt::get(Ty, 1), Y);
if (match(Op1, m_c_Mul(m_Specific(Op0), m_Value(Y)))) {
bool HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
bool HasNUW = cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
if ((IsSigned && HasNSW) || (!IsSigned && HasNUW)) {
replaceOperand(I, 0, ConstantInt::get(Ty, 1));
replaceOperand(I, 1, Y);
return &I;
}
}
return nullptr;
}
static const unsigned MaxDepth = 6;
static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
bool DoFold) {
auto IfFold = [DoFold](function_ref<Value *()> Fn) {
if (!DoFold)
return reinterpret_cast<Value *>(-1);
return Fn();
};
if (match(Op, m_Power2()))
return IfFold([&]() {
Constant *C = ConstantExpr::getExactLogBase2(cast<Constant>(Op));
if (!C)
llvm_unreachable("Failed to constant fold udiv -> logbase2");
return C;
});
if (Depth++ == MaxDepth)
return nullptr;
Value *X, *Y;
if (match(Op, m_ZExt(m_Value(X))))
if (Value *LogX = takeLog2(Builder, X, Depth, DoFold))
return IfFold([&]() { return Builder.CreateZExt(LogX, Op->getType()); });
if (match(Op, m_Shl(m_Value(X), m_Value(Y))))
if (Value *LogX = takeLog2(Builder, X, Depth, DoFold))
return IfFold([&]() { return Builder.CreateAdd(LogX, Y); });
if (SelectInst *SI = dyn_cast<SelectInst>(Op))
if (Value *LogX = takeLog2(Builder, SI->getOperand(1), Depth, DoFold))
if (Value *LogY = takeLog2(Builder, SI->getOperand(2), Depth, DoFold))
return IfFold([&]() {
return Builder.CreateSelect(SI->getOperand(0), LogX, LogY);
});
auto *MinMax = dyn_cast<MinMaxIntrinsic>(Op);
if (MinMax && MinMax->hasOneUse() && !MinMax->isSigned())
if (Value *LogX = takeLog2(Builder, MinMax->getLHS(), Depth, DoFold))
if (Value *LogY = takeLog2(Builder, MinMax->getRHS(), Depth, DoFold))
return IfFold([&]() {
return Builder.CreateBinaryIntrinsic(
MinMax->getIntrinsicID(), LogX, LogY);
});
return nullptr;
}
static Instruction *narrowUDivURem(BinaryOperator &I,
InstCombiner::BuilderTy &Builder) {
Instruction::BinaryOps Opcode = I.getOpcode();
Value *N = I.getOperand(0);
Value *D = I.getOperand(1);
Type *Ty = I.getType();
Value *X, *Y;
if (match(N, m_ZExt(m_Value(X))) && match(D, m_ZExt(m_Value(Y))) &&
X->getType() == Y->getType() && (N->hasOneUse() || D->hasOneUse())) {
Value *NarrowOp = Builder.CreateBinOp(Opcode, X, Y);
return new ZExtInst(NarrowOp, Ty);
}
Constant *C;
if ((match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) ||
(match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C)))) {
Constant *TruncC = ConstantExpr::getTrunc(C, X->getType());
if (ConstantExpr::getZExt(TruncC, Ty) != C)
return nullptr;
Value *NarrowOp = isa<Constant>(D) ? Builder.CreateBinOp(Opcode, X, TruncC)
: Builder.CreateBinOp(Opcode, TruncC, X);
return new ZExtInst(NarrowOp, Ty);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
if (Value *V = simplifyUDivInst(I.getOperand(0), I.getOperand(1),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Common = commonIDivTransforms(I))
return Common;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Value *X;
const APInt *C1, *C2;
if (match(Op0, m_LShr(m_Value(X), m_APInt(C1))) && match(Op1, m_APInt(C2))) {
bool Overflow;
APInt C2ShlC1 = C2->ushl_ov(*C1, Overflow);
if (!Overflow) {
bool IsExact = I.isExact() && match(Op0, m_Exact(m_Value()));
BinaryOperator *BO = BinaryOperator::CreateUDiv(
X, ConstantInt::get(X->getType(), C2ShlC1));
if (IsExact)
BO->setIsExact();
return BO;
}
}
Type *Ty = I.getType();
if (match(Op1, m_Negative())) {
Value *Cmp = Builder.CreateICmpUGE(Op0, Op1);
return CastInst::CreateZExtOrBitCast(Cmp, Ty);
}
if (match(Op1, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)) {
Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::getAllOnesValue(Ty));
return CastInst::CreateZExtOrBitCast(Cmp, Ty);
}
if (Instruction *NarrowDiv = narrowUDivURem(I, Builder))
return NarrowDiv;
Value *A, *B;
if (match(Op0, m_NUWMul(m_Value(A), m_Value(B)))) {
if (match(Op1, m_NUWMul(m_Specific(A), m_Value(X))) ||
match(Op1, m_NUWMul(m_Value(X), m_Specific(A))))
return BinaryOperator::CreateUDiv(B, X);
if (match(Op1, m_NUWMul(m_Specific(B), m_Value(X))) ||
match(Op1, m_NUWMul(m_Value(X), m_Specific(B))))
return BinaryOperator::CreateUDiv(A, X);
}
if (takeLog2(Builder, Op1, 0, false)) {
Value *Res = takeLog2(Builder, Op1, 0, true);
return replaceInstUsesWith(
I, Builder.CreateLShr(Op0, Res, I.getName(), I.isExact()));
}
return nullptr;
}
Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
if (Value *V = simplifySDivInst(I.getOperand(0), I.getOperand(1),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Common = commonIDivTransforms(I))
return Common;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Type *Ty = I.getType();
Value *X;
if (match(Op1, m_AllOnes()) ||
(match(Op1, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)))
return BinaryOperator::CreateNeg(Op0);
if (match(Op1, m_SignMask()))
return new ZExtInst(Builder.CreateICmpEQ(Op0, Op1), Ty);
if (I.isExact() && ((match(Op1, m_Power2()) && match(Op1, m_NonNegative())) ||
match(Op1, m_NegatedPower2()))) {
bool DivisorWasNegative = match(Op1, m_NegatedPower2());
if (DivisorWasNegative)
Op1 = ConstantExpr::getNeg(cast<Constant>(Op1));
auto *AShr = BinaryOperator::CreateExactAShr(
Op0, ConstantExpr::getExactLogBase2(cast<Constant>(Op1)), I.getName());
if (!DivisorWasNegative)
return AShr;
Builder.Insert(AShr);
AShr->setName(I.getName() + ".neg");
return BinaryOperator::CreateNeg(AShr, I.getName());
}
const APInt *Op1C;
if (match(Op1, m_APInt(Op1C))) {
Value *Op0Src;
if (match(Op0, m_OneUse(m_SExt(m_Value(Op0Src)))) &&
Op0Src->getType()->getScalarSizeInBits() >= Op1C->getMinSignedBits()) {
Constant *NarrowDivisor =
ConstantExpr::getTrunc(cast<Constant>(Op1), Op0Src->getType());
Value *NarrowOp = Builder.CreateSDiv(Op0Src, NarrowDivisor);
return new SExtInst(NarrowOp, Ty);
}
if (!Op1C->isMinSignedValue() &&
match(Op0, m_NSWSub(m_Zero(), m_Value(X)))) {
Constant *NegC = ConstantInt::get(Ty, -(*Op1C));
Instruction *BO = BinaryOperator::CreateSDiv(X, NegC);
BO->setIsExact(I.isExact());
return BO;
}
}
Value *Y;
if (match(&I, m_SDiv(m_OneUse(m_NSWSub(m_Zero(), m_Value(X))), m_Value(Y))))
return BinaryOperator::CreateNSWNeg(
Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
if (match(&I, m_c_BinOp(
m_OneUse(m_Intrinsic<Intrinsic::abs>(m_Value(X), m_One())),
m_Deferred(X)))) {
Value *Cond = Builder.CreateIsNotNeg(X);
return SelectInst::Create(Cond, ConstantInt::get(Ty, 1),
ConstantInt::getAllOnesValue(Ty));
}
APInt Mask(APInt::getSignMask(Ty->getScalarSizeInBits()));
if (MaskedValueIsZero(Op0, Mask, 0, &I)) {
if (MaskedValueIsZero(Op1, Mask, 0, &I)) {
auto *BO = BinaryOperator::CreateUDiv(Op0, Op1, I.getName());
BO->setIsExact(I.isExact());
return BO;
}
if (match(Op1, m_NegatedPower2())) {
Constant *CNegLog2 = ConstantExpr::getExactLogBase2(
ConstantExpr::getNeg(cast<Constant>(Op1)));
Value *Shr = Builder.CreateLShr(Op0, CNegLog2, I.getName(), I.isExact());
return BinaryOperator::CreateNeg(Shr);
}
if (isKnownToBeAPowerOfTwo(Op1, true, 0, &I)) {
auto *BO = BinaryOperator::CreateUDiv(Op0, Op1, I.getName());
BO->setIsExact(I.isExact());
return BO;
}
}
return nullptr;
}
static Instruction *foldFDivConstantDivisor(BinaryOperator &I) {
Constant *C;
if (!match(I.getOperand(1), m_Constant(C)))
return nullptr;
Value *X;
if (match(I.getOperand(0), m_FNeg(m_Value(X))))
return BinaryOperator::CreateFDivFMF(X, ConstantExpr::getFNeg(C), &I);
if (!(C->hasExactInverseFP() || (I.hasAllowReciprocal() && C->isNormalFP())))
return nullptr;
const DataLayout &DL = I.getModule()->getDataLayout();
auto *RecipC = ConstantFoldBinaryOpOperands(
Instruction::FDiv, ConstantFP::get(I.getType(), 1.0), C, DL);
if (!RecipC || !RecipC->isNormalFP())
return nullptr;
return BinaryOperator::CreateFMulFMF(I.getOperand(0), RecipC, &I);
}
static Instruction *foldFDivConstantDividend(BinaryOperator &I) {
Constant *C;
if (!match(I.getOperand(0), m_Constant(C)))
return nullptr;
Value *X;
if (match(I.getOperand(1), m_FNeg(m_Value(X))))
return BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I);
if (!I.hasAllowReassoc() || !I.hasAllowReciprocal())
return nullptr;
Constant *C2, *NewC = nullptr;
const DataLayout &DL = I.getModule()->getDataLayout();
if (match(I.getOperand(1), m_FMul(m_Value(X), m_Constant(C2)))) {
NewC = ConstantFoldBinaryOpOperands(Instruction::FDiv, C, C2, DL);
} else if (match(I.getOperand(1), m_FDiv(m_Value(X), m_Constant(C2)))) {
NewC = ConstantFoldBinaryOpOperands(Instruction::FMul, C, C2, DL);
}
if (!NewC || !NewC->isNormalFP())
return nullptr;
return BinaryOperator::CreateFDivFMF(NewC, X, &I);
}
static Instruction *foldFDivPowDivisor(BinaryOperator &I,
InstCombiner::BuilderTy &Builder) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
auto *II = dyn_cast<IntrinsicInst>(Op1);
if (!II || !II->hasOneUse() || !I.hasAllowReassoc() ||
!I.hasAllowReciprocal())
return nullptr;
Intrinsic::ID IID = II->getIntrinsicID();
SmallVector<Value *> Args;
switch (IID) {
case Intrinsic::pow:
Args.push_back(II->getArgOperand(0));
Args.push_back(Builder.CreateFNegFMF(II->getArgOperand(1), &I));
break;
case Intrinsic::powi: {
if (!I.hasNoInfs())
return nullptr;
Args.push_back(II->getArgOperand(0));
Args.push_back(Builder.CreateNeg(II->getArgOperand(1)));
Type *Tys[] = {I.getType(), II->getArgOperand(1)->getType()};
Value *Pow = Builder.CreateIntrinsic(IID, Tys, Args, &I);
return BinaryOperator::CreateFMulFMF(Op0, Pow, &I);
}
case Intrinsic::exp:
case Intrinsic::exp2:
Args.push_back(Builder.CreateFNegFMF(II->getArgOperand(0), &I));
break;
default:
return nullptr;
}
Value *Pow = Builder.CreateIntrinsic(IID, I.getType(), Args, &I);
return BinaryOperator::CreateFMulFMF(Op0, Pow, &I);
}
Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
Module *M = I.getModule();
if (Value *V = simplifyFDivInst(I.getOperand(0), I.getOperand(1),
I.getFastMathFlags(),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
if (Instruction *R = foldFDivConstantDivisor(I))
return R;
if (Instruction *R = foldFDivConstantDividend(I))
return R;
if (Instruction *R = foldFPSignBitOps(I))
return R;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (isa<Constant>(Op0))
if (SelectInst *SI = dyn_cast<SelectInst>(Op1))
if (Instruction *R = FoldOpIntoSelect(I, SI))
return R;
if (isa<Constant>(Op1))
if (SelectInst *SI = dyn_cast<SelectInst>(Op0))
if (Instruction *R = FoldOpIntoSelect(I, SI))
return R;
if (I.hasAllowReassoc() && I.hasAllowReciprocal()) {
Value *X, *Y;
if (match(Op0, m_OneUse(m_FDiv(m_Value(X), m_Value(Y)))) &&
(!isa<Constant>(Y) || !isa<Constant>(Op1))) {
Value *YZ = Builder.CreateFMulFMF(Y, Op1, &I);
return BinaryOperator::CreateFDivFMF(X, YZ, &I);
}
if (match(Op1, m_OneUse(m_FDiv(m_Value(X), m_Value(Y)))) &&
(!isa<Constant>(Y) || !isa<Constant>(Op0))) {
Value *YZ = Builder.CreateFMulFMF(Y, Op0, &I);
return BinaryOperator::CreateFDivFMF(YZ, X, &I);
}
if (match(Op1, m_FDiv(m_SpecificFP(1.0), m_Value(Y))))
return BinaryOperator::CreateFMulFMF(Y, Op0, &I);
}
if (I.hasAllowReassoc() && Op0->hasOneUse() && Op1->hasOneUse()) {
Value *X;
bool IsTan = match(Op0, m_Intrinsic<Intrinsic::sin>(m_Value(X))) &&
match(Op1, m_Intrinsic<Intrinsic::cos>(m_Specific(X)));
bool IsCot =
!IsTan && match(Op0, m_Intrinsic<Intrinsic::cos>(m_Value(X))) &&
match(Op1, m_Intrinsic<Intrinsic::sin>(m_Specific(X)));
if ((IsTan || IsCot) && hasFloatFn(M, &TLI, I.getType(), LibFunc_tan,
LibFunc_tanf, LibFunc_tanl)) {
IRBuilder<> B(&I);
IRBuilder<>::FastMathFlagGuard FMFGuard(B);
B.setFastMathFlags(I.getFastMathFlags());
AttributeList Attrs =
cast<CallBase>(Op0)->getCalledFunction()->getAttributes();
Value *Res = emitUnaryFloatFnCall(X, &TLI, LibFunc_tan, LibFunc_tanf,
LibFunc_tanl, B, Attrs);
if (IsCot)
Res = B.CreateFDiv(ConstantFP::get(I.getType(), 1.0), Res);
return replaceInstUsesWith(I, Res);
}
}
Value *X, *Y;
if (I.hasNoNaNs() && I.hasAllowReassoc() &&
match(Op1, m_c_FMul(m_Specific(Op0), m_Value(Y)))) {
replaceOperand(I, 0, ConstantFP::get(I.getType(), 1.0));
replaceOperand(I, 1, Y);
return &I;
}
if (I.hasNoNaNs() && I.hasNoInfs() &&
(match(&I, m_FDiv(m_Value(X), m_FAbs(m_Deferred(X)))) ||
match(&I, m_FDiv(m_FAbs(m_Value(X)), m_Deferred(X))))) {
Value *V = Builder.CreateBinaryIntrinsic(
Intrinsic::copysign, ConstantFP::get(I.getType(), 1.0), X, &I);
return replaceInstUsesWith(I, V);
}
if (Instruction *Mul = foldFDivPowDivisor(I, Builder))
return Mul;
return nullptr;
}
Instruction *InstCombinerImpl::commonIRemTransforms(BinaryOperator &I) {
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Value *V = simplifyValueKnownNonZero(I.getOperand(1), *this, I))
return replaceOperand(I, 1, V);
if (simplifyDivRemOfSelectWithZeroOp(I))
return &I;
if (match(Op0, m_ImmConstant()) &&
match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) {
if (Instruction *R = FoldOpIntoSelect(I, cast<SelectInst>(Op1),
true))
return R;
}
if (isa<Constant>(Op1)) {
if (Instruction *Op0I = dyn_cast<Instruction>(Op0)) {
if (SelectInst *SI = dyn_cast<SelectInst>(Op0I)) {
if (Instruction *R = FoldOpIntoSelect(I, SI))
return R;
} else if (auto *PN = dyn_cast<PHINode>(Op0I)) {
const APInt *Op1Int;
if (match(Op1, m_APInt(Op1Int)) && !Op1Int->isMinValue() &&
(I.getOpcode() == Instruction::URem ||
!Op1Int->isMinSignedValue())) {
if (Instruction *NV = foldOpIntoPhi(I, PN))
return NV;
}
}
if (SimplifyDemandedInstructionBits(I))
return &I;
}
}
return nullptr;
}
Instruction *InstCombinerImpl::visitURem(BinaryOperator &I) {
if (Value *V = simplifyURemInst(I.getOperand(0), I.getOperand(1),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *common = commonIRemTransforms(I))
return common;
if (Instruction *NarrowRem = narrowUDivURem(I, Builder))
return NarrowRem;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Type *Ty = I.getType();
if (isKnownToBeAPowerOfTwo(Op1, true, 0, &I)) {
Constant *N1 = Constant::getAllOnesValue(Ty);
Value *Add = Builder.CreateAdd(Op1, N1);
return BinaryOperator::CreateAnd(Op0, Add);
}
if (match(Op0, m_One())) {
Value *Cmp = Builder.CreateICmpNE(Op1, ConstantInt::get(Ty, 1));
return CastInst::CreateZExtOrBitCast(Cmp, Ty);
}
if (match(Op1, m_Negative())) {
Value *F0 = Builder.CreateFreeze(Op0, Op0->getName() + ".fr");
Value *Cmp = Builder.CreateICmpULT(F0, Op1);
Value *Sub = Builder.CreateSub(F0, Op1);
return SelectInst::Create(Cmp, F0, Sub);
}
Value *X;
if (match(Op1, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)) {
Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::getAllOnesValue(Ty));
return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), Op0);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitSRem(BinaryOperator &I) {
if (Value *V = simplifySRemInst(I.getOperand(0), I.getOperand(1),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Common = commonIRemTransforms(I))
return Common;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
{
const APInt *Y;
if (match(Op1, m_Negative(Y)) && !Y->isMinSignedValue())
return replaceOperand(I, 1, ConstantInt::get(I.getType(), -*Y));
}
Value *X, *Y;
if (match(&I, m_SRem(m_OneUse(m_NSWSub(m_Zero(), m_Value(X))), m_Value(Y))))
return BinaryOperator::CreateNSWNeg(Builder.CreateSRem(X, Y));
APInt Mask(APInt::getSignMask(I.getType()->getScalarSizeInBits()));
if (MaskedValueIsZero(Op1, Mask, 0, &I) &&
MaskedValueIsZero(Op0, Mask, 0, &I)) {
return BinaryOperator::CreateURem(Op0, Op1, I.getName());
}
if (isa<ConstantVector>(Op1) || isa<ConstantDataVector>(Op1)) {
Constant *C = cast<Constant>(Op1);
unsigned VWidth = cast<FixedVectorType>(C->getType())->getNumElements();
bool hasNegative = false;
bool hasMissing = false;
for (unsigned i = 0; i != VWidth; ++i) {
Constant *Elt = C->getAggregateElement(i);
if (!Elt) {
hasMissing = true;
break;
}
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Elt))
if (RHS->isNegative())
hasNegative = true;
}
if (hasNegative && !hasMissing) {
SmallVector<Constant *, 16> Elts(VWidth);
for (unsigned i = 0; i != VWidth; ++i) {
Elts[i] = C->getAggregateElement(i); if (ConstantInt *RHS = dyn_cast<ConstantInt>(Elts[i])) {
if (RHS->isNegative())
Elts[i] = cast<ConstantInt>(ConstantExpr::getNeg(RHS));
}
}
Constant *NewRHSV = ConstantVector::get(Elts);
if (NewRHSV != C) return replaceOperand(I, 1, NewRHSV);
}
}
return nullptr;
}
Instruction *InstCombinerImpl::visitFRem(BinaryOperator &I) {
if (Value *V = simplifyFRemInst(I.getOperand(0), I.getOperand(1),
I.getFastMathFlags(),
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (Instruction *X = foldVectorBinop(I))
return X;
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
return nullptr;
}