diff options
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp')
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index c70d7585cac..2f72e0ab6e9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -389,6 +389,79 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { } } + // Check for (mul (sext x), y), see if we can merge this into an + // integer mul followed by a sext. + if (SExtInst *Op0Conv = dyn_cast<SExtInst>(Op0)) { + // (mul (sext x), cst) --> (sext (mul x, cst')) + if (ConstantInt *Op1C = dyn_cast<ConstantInt>(Op1)) { + if (Op0Conv->hasOneUse()) { + Constant *CI = + ConstantExpr::getTrunc(Op1C, Op0Conv->getOperand(0)->getType()); + if (ConstantExpr::getSExt(CI, I.getType()) == Op1C && + WillNotOverflowSignedMul(Op0Conv->getOperand(0), CI, I)) { + // Insert the new, smaller mul. + Value *NewMul = + Builder->CreateNSWMul(Op0Conv->getOperand(0), CI, "mulconv"); + return new SExtInst(NewMul, I.getType()); + } + } + } + + // (mul (sext x), (sext y)) --> (sext (mul int x, y)) + if (SExtInst *Op1Conv = dyn_cast<SExtInst>(Op1)) { + // Only do this if x/y have the same type, if at last one of them has a + // single use (so we don't increase the number of sexts), and if the + // integer mul will not overflow. + if (Op0Conv->getOperand(0)->getType() == + Op1Conv->getOperand(0)->getType() && + (Op0Conv->hasOneUse() || Op1Conv->hasOneUse()) && + WillNotOverflowSignedMul(Op0Conv->getOperand(0), + Op1Conv->getOperand(0), I)) { + // Insert the new integer mul. + Value *NewMul = Builder->CreateNSWMul( + Op0Conv->getOperand(0), Op1Conv->getOperand(0), "mulconv"); + return new SExtInst(NewMul, I.getType()); + } + } + } + + // Check for (mul (zext x), y), see if we can merge this into an + // integer mul followed by a zext. + if (auto *Op0Conv = dyn_cast<ZExtInst>(Op0)) { + // (mul (zext x), cst) --> (zext (mul x, cst')) + if (ConstantInt *Op1C = dyn_cast<ConstantInt>(Op1)) { + if (Op0Conv->hasOneUse()) { + Constant *CI = + ConstantExpr::getTrunc(Op1C, Op0Conv->getOperand(0)->getType()); + if (ConstantExpr::getZExt(CI, I.getType()) == Op1C && + WillNotOverflowSignedMul(Op0Conv->getOperand(0), CI, I)) { + // Insert the new, smaller mul. + Value *NewMul = + Builder->CreateNUWMul(Op0Conv->getOperand(0), CI, "mulconv"); + return new ZExtInst(NewMul, I.getType()); + } + } + } + + // (mul (zext x), (zext y)) --> (zext (mul int x, y)) + if (auto *Op1Conv = dyn_cast<ZExtInst>(Op1)) { + // Only do this if x/y have the same type, if at last one of them has a + // single use (so we don't increase the number of zexts), and if the + // integer mul will not overflow. + if (Op0Conv->getOperand(0)->getType() == + Op1Conv->getOperand(0)->getType() && + (Op0Conv->hasOneUse() || Op1Conv->hasOneUse()) && + computeOverflowForUnsignedMul(Op0Conv->getOperand(0), + Op1Conv->getOperand(0), + &I) == OverflowResult::NeverOverflows) { + // Insert the new integer mul. + Value *NewMul = Builder->CreateNUWMul( + Op0Conv->getOperand(0), Op1Conv->getOperand(0), "mulconv"); + return new ZExtInst(NewMul, I.getType()); + } + } + } + if (!I.hasNoSignedWrap() && WillNotOverflowSignedMul(Op0, Op1, I)) { Changed = true; I.setHasNoSignedWrap(true); |