#include "InstCombineInternal.h"
#include "llvm-c/Initialization.h"
#include "llvm-c/Transforms/InstCombine.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetFolder.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IRBuilder.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/LegacyPassManager.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Utils/Local.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#define DEBUG_TYPE "instcombine"
#include "llvm/Transforms/Utils/InstructionWorklist.h"
using namespace llvm;
using namespace llvm::PatternMatch;
STATISTIC(NumWorklistIterations,
"Number of instruction combining iterations performed");
STATISTIC(NumCombined , "Number of insts combined");
STATISTIC(NumConstProp, "Number of constant folds");
STATISTIC(NumDeadInst , "Number of dead inst eliminated");
STATISTIC(NumSunkInst , "Number of instructions sunk");
STATISTIC(NumExpand, "Number of expansions");
STATISTIC(NumFactor , "Number of factorizations");
STATISTIC(NumReassoc , "Number of reassociations");
DEBUG_COUNTER(VisitCounter, "instcombine-visit",
"Controls which instructions are visited");
static constexpr unsigned InstCombineDefaultMaxIterations = 1000;
#ifndef NDEBUG
static constexpr unsigned InstCombineDefaultInfiniteLoopThreshold = 100;
#else
static constexpr unsigned InstCombineDefaultInfiniteLoopThreshold = 1000;
#endif
static cl::opt<bool>
EnableCodeSinking("instcombine-code-sinking", cl::desc("Enable code sinking"),
cl::init(true));
static cl::opt<unsigned> MaxSinkNumUsers(
"instcombine-max-sink-users", cl::init(32),
cl::desc("Maximum number of undroppable users for instruction sinking"));
static cl::opt<unsigned> LimitMaxIterations(
"instcombine-max-iterations",
cl::desc("Limit the maximum number of instruction combining iterations"),
cl::init(InstCombineDefaultMaxIterations));
static cl::opt<unsigned> InfiniteLoopDetectionThreshold(
"instcombine-infinite-loop-threshold",
cl::desc("Number of instruction combining iterations considered an "
"infinite loop"),
cl::init(InstCombineDefaultInfiniteLoopThreshold), cl::Hidden);
static cl::opt<unsigned>
MaxArraySize("instcombine-maxarray-size", cl::init(1024),
cl::desc("Maximum array size considered when doing a combine"));
static cl::opt<unsigned> ShouldLowerDbgDeclare("instcombine-lower-dbg-declare",
cl::Hidden, cl::init(true));
Optional<Instruction *>
InstCombiner::targetInstCombineIntrinsic(IntrinsicInst &II) {
if (II.getCalledFunction()->isTargetIntrinsic()) {
return TTI.instCombineIntrinsic(*this, II);
}
return None;
}
Optional<Value *> InstCombiner::targetSimplifyDemandedUseBitsIntrinsic(
IntrinsicInst &II, APInt DemandedMask, KnownBits &Known,
bool &KnownBitsComputed) {
if (II.getCalledFunction()->isTargetIntrinsic()) {
return TTI.simplifyDemandedUseBitsIntrinsic(*this, II, DemandedMask, Known,
KnownBitsComputed);
}
return None;
}
Optional<Value *> InstCombiner::targetSimplifyDemandedVectorEltsIntrinsic(
IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts, APInt &UndefElts2,
APInt &UndefElts3,
std::function<void(Instruction *, unsigned, APInt, APInt &)>
SimplifyAndSetOp) {
if (II.getCalledFunction()->isTargetIntrinsic()) {
return TTI.simplifyDemandedVectorEltsIntrinsic(
*this, II, DemandedElts, UndefElts, UndefElts2, UndefElts3,
SimplifyAndSetOp);
}
return None;
}
Value *InstCombinerImpl::EmitGEPOffset(User *GEP) {
return llvm::EmitGEPOffset(&Builder, DL, GEP);
}
bool InstCombinerImpl::isDesirableIntType(unsigned BitWidth) const {
switch (BitWidth) {
case 8:
case 16:
case 32:
return true;
default:
return DL.isLegalInteger(BitWidth);
}
}
bool InstCombinerImpl::shouldChangeType(unsigned FromWidth,
unsigned ToWidth) const {
bool FromLegal = FromWidth == 1 || DL.isLegalInteger(FromWidth);
bool ToLegal = ToWidth == 1 || DL.isLegalInteger(ToWidth);
if (ToWidth < FromWidth && isDesirableIntType(ToWidth))
return true;
if (FromLegal && !ToLegal)
return false;
if (!FromLegal && !ToLegal && ToWidth > FromWidth)
return false;
return true;
}
bool InstCombinerImpl::shouldChangeType(Type *From, Type *To) const {
if (!From->isIntegerTy() || !To->isIntegerTy())
return false;
unsigned FromWidth = From->getPrimitiveSizeInBits();
unsigned ToWidth = To->getPrimitiveSizeInBits();
return shouldChangeType(FromWidth, ToWidth);
}
static bool maintainNoSignedWrap(BinaryOperator &I, Value *B, Value *C) {
auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I);
if (!OBO || !OBO->hasNoSignedWrap())
return false;
Instruction::BinaryOps Opcode = I.getOpcode();
if (Opcode != Instruction::Add && Opcode != Instruction::Sub)
return false;
const APInt *BVal, *CVal;
if (!match(B, m_APInt(BVal)) || !match(C, m_APInt(CVal)))
return false;
bool Overflow = false;
if (Opcode == Instruction::Add)
(void)BVal->sadd_ov(*CVal, Overflow);
else
(void)BVal->ssub_ov(*CVal, Overflow);
return !Overflow;
}
static bool hasNoUnsignedWrap(BinaryOperator &I) {
auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I);
return OBO && OBO->hasNoUnsignedWrap();
}
static bool hasNoSignedWrap(BinaryOperator &I) {
auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I);
return OBO && OBO->hasNoSignedWrap();
}
static void ClearSubclassDataAfterReassociation(BinaryOperator &I) {
FPMathOperator *FPMO = dyn_cast<FPMathOperator>(&I);
if (!FPMO) {
I.clearSubclassOptionalData();
return;
}
FastMathFlags FMF = I.getFastMathFlags();
I.clearSubclassOptionalData();
I.setFastMathFlags(FMF);
}
static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1,
InstCombinerImpl &IC) {
auto *Cast = dyn_cast<CastInst>(BinOp1->getOperand(0));
if (!Cast || !Cast->hasOneUse())
return false;
auto CastOpcode = Cast->getOpcode();
if (CastOpcode != Instruction::ZExt)
return false;
if (!BinOp1->isBitwiseLogicOp())
return false;
auto AssocOpcode = BinOp1->getOpcode();
auto *BinOp2 = dyn_cast<BinaryOperator>(Cast->getOperand(0));
if (!BinOp2 || !BinOp2->hasOneUse() || BinOp2->getOpcode() != AssocOpcode)
return false;
Constant *C1, *C2;
if (!match(BinOp1->getOperand(1), m_Constant(C1)) ||
!match(BinOp2->getOperand(1), m_Constant(C2)))
return false;
Type *DestTy = C1->getType();
Constant *CastC2 = ConstantExpr::getCast(CastOpcode, C2, DestTy);
Constant *FoldedC = ConstantExpr::get(AssocOpcode, C1, CastC2);
IC.replaceOperand(*Cast, 0, BinOp2->getOperand(0));
IC.replaceOperand(*BinOp1, 1, FoldedC);
return true;
}
Value *InstCombinerImpl::simplifyIntToPtrRoundTripCast(Value *Val) {
auto *IntToPtr = dyn_cast<IntToPtrInst>(Val);
if (IntToPtr && DL.getPointerTypeSizeInBits(IntToPtr->getDestTy()) ==
DL.getTypeSizeInBits(IntToPtr->getSrcTy())) {
auto *PtrToInt = dyn_cast<PtrToIntInst>(IntToPtr->getOperand(0));
Type *CastTy = IntToPtr->getDestTy();
if (PtrToInt &&
CastTy->getPointerAddressSpace() ==
PtrToInt->getSrcTy()->getPointerAddressSpace() &&
DL.getPointerTypeSizeInBits(PtrToInt->getSrcTy()) ==
DL.getTypeSizeInBits(PtrToInt->getDestTy())) {
return CastInst::CreateBitOrPointerCast(PtrToInt->getOperand(0), CastTy,
"", PtrToInt);
}
}
return nullptr;
}
bool InstCombinerImpl::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
Instruction::BinaryOps Opcode = I.getOpcode();
bool Changed = false;
do {
if (I.isCommutative() && getComplexity(I.getOperand(0)) <
getComplexity(I.getOperand(1)))
Changed = !I.swapOperands();
BinaryOperator *Op0 = dyn_cast<BinaryOperator>(I.getOperand(0));
BinaryOperator *Op1 = dyn_cast<BinaryOperator>(I.getOperand(1));
if (I.isAssociative()) {
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);
Value *B = Op0->getOperand(1);
Value *C = I.getOperand(1);
if (Value *V = simplifyBinOp(Opcode, B, C, SQ.getWithInstruction(&I))) {
replaceOperand(I, 0, A);
replaceOperand(I, 1, V);
bool IsNUW = hasNoUnsignedWrap(I) && hasNoUnsignedWrap(*Op0);
bool IsNSW = maintainNoSignedWrap(I, B, C) && hasNoSignedWrap(*Op0);
ClearSubclassDataAfterReassociation(I);
if (IsNUW)
I.setHasNoUnsignedWrap(true);
if (IsNSW)
I.setHasNoSignedWrap(true);
Changed = true;
++NumReassoc;
continue;
}
}
if (Op1 && Op1->getOpcode() == Opcode) {
Value *A = I.getOperand(0);
Value *B = Op1->getOperand(0);
Value *C = Op1->getOperand(1);
if (Value *V = simplifyBinOp(Opcode, A, B, SQ.getWithInstruction(&I))) {
replaceOperand(I, 0, V);
replaceOperand(I, 1, C);
ClearSubclassDataAfterReassociation(I);
Changed = true;
++NumReassoc;
continue;
}
}
}
if (I.isAssociative() && I.isCommutative()) {
if (simplifyAssocCastAssoc(&I, *this)) {
Changed = true;
++NumReassoc;
continue;
}
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);
Value *B = Op0->getOperand(1);
Value *C = I.getOperand(1);
if (Value *V = simplifyBinOp(Opcode, C, A, SQ.getWithInstruction(&I))) {
replaceOperand(I, 0, V);
replaceOperand(I, 1, B);
ClearSubclassDataAfterReassociation(I);
Changed = true;
++NumReassoc;
continue;
}
}
if (Op1 && Op1->getOpcode() == Opcode) {
Value *A = I.getOperand(0);
Value *B = Op1->getOperand(0);
Value *C = Op1->getOperand(1);
if (Value *V = simplifyBinOp(Opcode, C, A, SQ.getWithInstruction(&I))) {
replaceOperand(I, 0, B);
replaceOperand(I, 1, V);
ClearSubclassDataAfterReassociation(I);
Changed = true;
++NumReassoc;
continue;
}
}
Value *A, *B;
Constant *C1, *C2, *CRes;
if (Op0 && Op1 &&
Op0->getOpcode() == Opcode && Op1->getOpcode() == Opcode &&
match(Op0, m_OneUse(m_BinOp(m_Value(A), m_Constant(C1)))) &&
match(Op1, m_OneUse(m_BinOp(m_Value(B), m_Constant(C2)))) &&
(CRes = ConstantFoldBinaryOpOperands(Opcode, C1, C2, DL))) {
bool IsNUW = hasNoUnsignedWrap(I) &&
hasNoUnsignedWrap(*Op0) &&
hasNoUnsignedWrap(*Op1);
BinaryOperator *NewBO = (IsNUW && Opcode == Instruction::Add) ?
BinaryOperator::CreateNUW(Opcode, A, B) :
BinaryOperator::Create(Opcode, A, B);
if (isa<FPMathOperator>(NewBO)) {
FastMathFlags Flags = I.getFastMathFlags();
Flags &= Op0->getFastMathFlags();
Flags &= Op1->getFastMathFlags();
NewBO->setFastMathFlags(Flags);
}
InsertNewInstWith(NewBO, I);
NewBO->takeName(Op1);
replaceOperand(I, 0, NewBO);
replaceOperand(I, 1, CRes);
ClearSubclassDataAfterReassociation(I);
if (IsNUW)
I.setHasNoUnsignedWrap(true);
Changed = true;
continue;
}
}
return Changed;
} while (true);
}
static bool leftDistributesOverRight(Instruction::BinaryOps LOp,
Instruction::BinaryOps ROp) {
if (LOp == Instruction::And)
return ROp == Instruction::Or || ROp == Instruction::Xor;
if (LOp == Instruction::Or)
return ROp == Instruction::And;
if (LOp == Instruction::Mul)
return ROp == Instruction::Add || ROp == Instruction::Sub;
return false;
}
static bool rightDistributesOverLeft(Instruction::BinaryOps LOp,
Instruction::BinaryOps ROp) {
if (Instruction::isCommutative(ROp))
return leftDistributesOverRight(ROp, LOp);
return Instruction::isBitwiseLogicOp(LOp) && Instruction::isShift(ROp);
}
static Value *getIdentityValue(Instruction::BinaryOps Opcode, Value *V) {
if (isa<Constant>(V))
return nullptr;
return ConstantExpr::getBinOpIdentity(Opcode, V->getType());
}
static Instruction::BinaryOps
getBinOpsForFactorization(Instruction::BinaryOps TopOpcode, BinaryOperator *Op,
Value *&LHS, Value *&RHS) {
assert(Op && "Expected a binary operator");
LHS = Op->getOperand(0);
RHS = Op->getOperand(1);
if (TopOpcode == Instruction::Add || TopOpcode == Instruction::Sub) {
Constant *C;
if (match(Op, m_Shl(m_Value(), m_Constant(C)))) {
RHS = ConstantExpr::getShl(ConstantInt::get(Op->getType(), 1), C);
return Instruction::Mul;
}
}
return Op->getOpcode();
}
Value *InstCombinerImpl::tryFactorization(BinaryOperator &I,
Instruction::BinaryOps InnerOpcode,
Value *A, Value *B, Value *C,
Value *D) {
assert(A && B && C && D && "All values must be provided");
Value *V = nullptr;
Value *SimplifiedInst = nullptr;
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
Instruction::BinaryOps TopLevelOpcode = I.getOpcode();
bool InnerCommutative = Instruction::isCommutative(InnerOpcode);
if (leftDistributesOverRight(InnerOpcode, TopLevelOpcode))
if (A == C || (InnerCommutative && A == D)) {
if (A != C)
std::swap(C, D);
V = simplifyBinOp(TopLevelOpcode, B, D, SQ.getWithInstruction(&I));
if (!V && LHS->hasOneUse() && RHS->hasOneUse())
V = Builder.CreateBinOp(TopLevelOpcode, B, D, RHS->getName());
if (V) {
SimplifiedInst = Builder.CreateBinOp(InnerOpcode, A, V);
}
}
if (!SimplifiedInst && rightDistributesOverLeft(TopLevelOpcode, InnerOpcode))
if (B == D || (InnerCommutative && B == C)) {
if (B != D)
std::swap(C, D);
V = simplifyBinOp(TopLevelOpcode, A, C, SQ.getWithInstruction(&I));
if (!V && LHS->hasOneUse() && RHS->hasOneUse())
V = Builder.CreateBinOp(TopLevelOpcode, A, C, LHS->getName());
if (V) {
SimplifiedInst = Builder.CreateBinOp(InnerOpcode, V, B);
}
}
if (SimplifiedInst) {
++NumFactor;
SimplifiedInst->takeName(&I);
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SimplifiedInst)) {
if (isa<OverflowingBinaryOperator>(SimplifiedInst)) {
bool HasNSW = false;
bool HasNUW = false;
if (isa<OverflowingBinaryOperator>(&I)) {
HasNSW = I.hasNoSignedWrap();
HasNUW = I.hasNoUnsignedWrap();
}
if (auto *LOBO = dyn_cast<OverflowingBinaryOperator>(LHS)) {
HasNSW &= LOBO->hasNoSignedWrap();
HasNUW &= LOBO->hasNoUnsignedWrap();
}
if (auto *ROBO = dyn_cast<OverflowingBinaryOperator>(RHS)) {
HasNSW &= ROBO->hasNoSignedWrap();
HasNUW &= ROBO->hasNoUnsignedWrap();
}
if (TopLevelOpcode == Instruction::Add &&
InnerOpcode == Instruction::Mul) {
const APInt *CInt;
if (match(V, m_APInt(CInt))) {
if (!CInt->isMinSignedValue())
BO->setHasNoSignedWrap(HasNSW);
}
BO->setHasNoUnsignedWrap(HasNUW);
}
}
}
}
return SimplifiedInst;
}
Value *InstCombinerImpl::SimplifyUsingDistributiveLaws(BinaryOperator &I) {
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
BinaryOperator *Op0 = dyn_cast<BinaryOperator>(LHS);
BinaryOperator *Op1 = dyn_cast<BinaryOperator>(RHS);
Instruction::BinaryOps TopLevelOpcode = I.getOpcode();
{
Value *A, *B, *C, *D;
Instruction::BinaryOps LHSOpcode, RHSOpcode;
if (Op0)
LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B);
if (Op1)
RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D);
if (Op0 && Op1 && LHSOpcode == RHSOpcode)
if (Value *V = tryFactorization(I, LHSOpcode, A, B, C, D))
return V;
if (Op0)
if (Value *Ident = getIdentityValue(LHSOpcode, RHS))
if (Value *V = tryFactorization(I, LHSOpcode, A, B, RHS, Ident))
return V;
if (Op1)
if (Value *Ident = getIdentityValue(RHSOpcode, LHS))
if (Value *V = tryFactorization(I, RHSOpcode, LHS, Ident, C, D))
return V;
}
if (Op0 && rightDistributesOverLeft(Op0->getOpcode(), TopLevelOpcode)) {
Value *A = Op0->getOperand(0), *B = Op0->getOperand(1), *C = RHS;
Instruction::BinaryOps InnerOpcode = Op0->getOpcode();
auto SQDistributive = SQ.getWithInstruction(&I).getWithoutUndef();
Value *L = simplifyBinOp(TopLevelOpcode, A, C, SQDistributive);
Value *R = simplifyBinOp(TopLevelOpcode, B, C, SQDistributive);
if (L && R) {
++NumExpand;
C = Builder.CreateBinOp(InnerOpcode, L, R);
C->takeName(&I);
return C;
}
if (L && L == ConstantExpr::getBinOpIdentity(InnerOpcode, L->getType())) {
++NumExpand;
C = Builder.CreateBinOp(TopLevelOpcode, B, C);
C->takeName(&I);
return C;
}
if (R && R == ConstantExpr::getBinOpIdentity(InnerOpcode, R->getType())) {
++NumExpand;
C = Builder.CreateBinOp(TopLevelOpcode, A, C);
C->takeName(&I);
return C;
}
}
if (Op1 && leftDistributesOverRight(TopLevelOpcode, Op1->getOpcode())) {
Value *A = LHS, *B = Op1->getOperand(0), *C = Op1->getOperand(1);
Instruction::BinaryOps InnerOpcode = Op1->getOpcode();
auto SQDistributive = SQ.getWithInstruction(&I).getWithoutUndef();
Value *L = simplifyBinOp(TopLevelOpcode, A, B, SQDistributive);
Value *R = simplifyBinOp(TopLevelOpcode, A, C, SQDistributive);
if (L && R) {
++NumExpand;
A = Builder.CreateBinOp(InnerOpcode, L, R);
A->takeName(&I);
return A;
}
if (L && L == ConstantExpr::getBinOpIdentity(InnerOpcode, L->getType())) {
++NumExpand;
A = Builder.CreateBinOp(TopLevelOpcode, A, C);
A->takeName(&I);
return A;
}
if (R && R == ConstantExpr::getBinOpIdentity(InnerOpcode, R->getType())) {
++NumExpand;
A = Builder.CreateBinOp(TopLevelOpcode, A, B);
A->takeName(&I);
return A;
}
}
return SimplifySelectsFeedingBinaryOp(I, LHS, RHS);
}
Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
Value *LHS,
Value *RHS) {
Value *A, *B, *C, *D, *E, *F;
bool LHSIsSelect = match(LHS, m_Select(m_Value(A), m_Value(B), m_Value(C)));
bool RHSIsSelect = match(RHS, m_Select(m_Value(D), m_Value(E), m_Value(F)));
if (!LHSIsSelect && !RHSIsSelect)
return nullptr;
FastMathFlags FMF;
BuilderTy::FastMathFlagGuard Guard(Builder);
if (isa<FPMathOperator>(&I)) {
FMF = I.getFastMathFlags();
Builder.setFastMathFlags(FMF);
}
Instruction::BinaryOps Opcode = I.getOpcode();
SimplifyQuery Q = SQ.getWithInstruction(&I);
Value *Cond, *True = nullptr, *False = nullptr;
if (LHSIsSelect && RHSIsSelect && A == D) {
Cond = A;
True = simplifyBinOp(Opcode, B, E, FMF, Q);
False = simplifyBinOp(Opcode, C, F, FMF, Q);
if (LHS->hasOneUse() && RHS->hasOneUse()) {
if (False && !True)
True = Builder.CreateBinOp(Opcode, B, E);
else if (True && !False)
False = Builder.CreateBinOp(Opcode, C, F);
}
} else if (LHSIsSelect && LHS->hasOneUse()) {
Cond = A;
True = simplifyBinOp(Opcode, B, RHS, FMF, Q);
False = simplifyBinOp(Opcode, C, RHS, FMF, Q);
} else if (RHSIsSelect && RHS->hasOneUse()) {
Cond = D;
True = simplifyBinOp(Opcode, LHS, E, FMF, Q);
False = simplifyBinOp(Opcode, LHS, F, FMF, Q);
}
if (!True || !False)
return nullptr;
Value *SI = Builder.CreateSelect(Cond, True, False);
SI->takeName(&I);
return SI;
}
void InstCombinerImpl::freelyInvertAllUsersOf(Value *I) {
for (User *U : I->users()) {
switch (cast<Instruction>(U)->getOpcode()) {
case Instruction::Select: {
auto *SI = cast<SelectInst>(U);
SI->swapValues();
SI->swapProfMetadata();
break;
}
case Instruction::Br:
cast<BranchInst>(U)->swapSuccessors(); break;
case Instruction::Xor:
replaceInstUsesWith(cast<Instruction>(*U), I);
break;
default:
llvm_unreachable("Got unexpected user - out of sync with "
"canFreelyInvertAllUsersOf() ?");
}
}
}
Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
Value *NegV;
if (match(V, m_Neg(m_Value(NegV))))
return NegV;
if (ConstantInt *C = dyn_cast<ConstantInt>(V))
return ConstantExpr::getNeg(C);
if (ConstantDataVector *C = dyn_cast<ConstantDataVector>(V))
if (C->getType()->getElementType()->isIntegerTy())
return ConstantExpr::getNeg(C);
if (ConstantVector *CV = dyn_cast<ConstantVector>(V)) {
for (unsigned i = 0, e = CV->getNumOperands(); i != e; ++i) {
Constant *Elt = CV->getAggregateElement(i);
if (!Elt)
return nullptr;
if (isa<UndefValue>(Elt))
continue;
if (!isa<ConstantInt>(Elt))
return nullptr;
}
return ConstantExpr::getNeg(CV);
}
if (auto *CV = dyn_cast<Constant>(V))
if (CV->getType()->isVectorTy() &&
CV->getType()->getScalarType()->isIntegerTy() && CV->getSplatValue())
return ConstantExpr::getNeg(CV);
return nullptr;
}
Instruction *InstCombinerImpl::foldBinopOfSextBoolToSelect(BinaryOperator &BO) {
Value *BO0 = BO.getOperand(0);
Value *BO1 = BO.getOperand(1);
Value *X;
Constant *C;
if (!match(BO0, m_SExt(m_Value(X))) || !match(BO1, m_ImmConstant(C)) ||
!X->getType()->isIntOrIntVectorTy(1))
return nullptr;
Constant *Ones = ConstantInt::getAllOnesValue(BO.getType());
Constant *Zero = ConstantInt::getNullValue(BO.getType());
Value *TVal = Builder.CreateBinOp(BO.getOpcode(), Ones, C);
Value *FVal = Builder.CreateBinOp(BO.getOpcode(), Zero, C);
return SelectInst::Create(X, TVal, FVal);
}
static Constant *constantFoldOperationIntoSelectOperand(
Instruction &I, SelectInst *SI, Value *SO) {
auto *ConstSO = dyn_cast<Constant>(SO);
if (!ConstSO)
return nullptr;
SmallVector<Constant *> ConstOps;
for (Value *Op : I.operands()) {
if (Op == SI)
ConstOps.push_back(ConstSO);
else if (auto *C = dyn_cast<Constant>(Op))
ConstOps.push_back(C);
else
llvm_unreachable("Operands should be select or constant");
}
return ConstantFoldInstOperands(&I, ConstOps, I.getModule()->getDataLayout());
}
static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO,
InstCombiner::BuilderTy &Builder) {
if (auto *Cast = dyn_cast<CastInst>(&I))
return Builder.CreateCast(Cast->getOpcode(), SO, I.getType());
if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
assert(canConstantFoldCallTo(II, cast<Function>(II->getCalledOperand())) &&
"Expected constant-foldable intrinsic");
Intrinsic::ID IID = II->getIntrinsicID();
if (II->arg_size() == 1)
return Builder.CreateUnaryIntrinsic(IID, SO);
assert(II->arg_size() == 2 && "Expected binary intrinsic");
assert(isa<Constant>(II->getArgOperand(1)) && "Expected constant operand");
return Builder.CreateBinaryIntrinsic(IID, SO, II->getArgOperand(1));
}
assert(I.isBinaryOp() && "Unexpected opcode for select folding");
bool ConstIsRHS = isa<Constant>(I.getOperand(1));
Constant *ConstOperand = cast<Constant>(I.getOperand(ConstIsRHS));
Value *Op0 = SO, *Op1 = ConstOperand;
if (!ConstIsRHS)
std::swap(Op0, Op1);
Value *NewBO = Builder.CreateBinOp(cast<BinaryOperator>(&I)->getOpcode(), Op0,
Op1, SO->getName() + ".op");
if (auto *NewBOI = dyn_cast<Instruction>(NewBO))
NewBOI->copyIRFlags(&I);
return NewBO;
}
Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
bool FoldWithMultiUse) {
if (!SI->hasOneUse() && !FoldWithMultiUse)
return nullptr;
Value *TV = SI->getTrueValue();
Value *FV = SI->getFalseValue();
if (!(isa<Constant>(TV) || isa<Constant>(FV)))
return nullptr;
if (SI->getType()->isIntOrIntVectorTy(1))
return nullptr;
if (auto *BC = dyn_cast<BitCastInst>(&Op)) {
VectorType *DestTy = dyn_cast<VectorType>(BC->getDestTy());
VectorType *SrcTy = dyn_cast<VectorType>(BC->getSrcTy());
if ((SrcTy == nullptr) != (DestTy == nullptr))
return nullptr;
if (SrcTy && SrcTy->getElementCount() != DestTy->getElementCount())
return nullptr;
}
if (auto *CI = dyn_cast<CmpInst>(SI->getCondition())) {
if (CI->hasOneUse()) {
Value *Op0 = CI->getOperand(0), *Op1 = CI->getOperand(1);
auto areLooselyEqual = [](Value *A, Value *B) {
if (A == B)
return true;
Constant *ConstA, *ConstB;
if (!match(A, m_Constant(ConstA)) || !match(B, m_Constant(ConstB)))
return false;
if (!A->getType()->isIntOrIntVectorTy() || A->getType() != B->getType())
return false;
auto *Cmp = ConstantExpr::getCompare(ICmpInst::ICMP_EQ, ConstA, ConstB);
const APInt *C;
return match(Cmp, m_APIntAllowUndef(C)) && C->isOne();
};
if ((areLooselyEqual(TV, Op0) && areLooselyEqual(FV, Op1)) ||
(areLooselyEqual(FV, Op0) && areLooselyEqual(TV, Op1)))
return nullptr;
}
}
Value *NewTV = constantFoldOperationIntoSelectOperand(Op, SI, TV);
Value *NewFV = constantFoldOperationIntoSelectOperand(Op, SI, FV);
if (!NewTV && !NewFV)
return nullptr;
if (!NewTV)
NewTV = foldOperationIntoSelectOperand(Op, TV, Builder);
if (!NewFV)
NewFV = foldOperationIntoSelectOperand(Op, FV, Builder);
return SelectInst::Create(SI->getCondition(), NewTV, NewFV, "", nullptr, SI);
}
static Value *foldOperationIntoPhiValue(BinaryOperator *I, Value *InV,
InstCombiner::BuilderTy &Builder) {
bool ConstIsRHS = isa<Constant>(I->getOperand(1));
Constant *C = cast<Constant>(I->getOperand(ConstIsRHS));
Value *Op0 = InV, *Op1 = C;
if (!ConstIsRHS)
std::swap(Op0, Op1);
Value *RI = Builder.CreateBinOp(I->getOpcode(), Op0, Op1, "phi.bo");
auto *FPInst = dyn_cast<Instruction>(RI);
if (FPInst && isa<FPMathOperator>(FPInst))
FPInst->copyFastMathFlags(I);
return RI;
}
Instruction *InstCombinerImpl::foldOpIntoPhi(Instruction &I, PHINode *PN) {
unsigned NumPHIValues = PN->getNumIncomingValues();
if (NumPHIValues == 0)
return nullptr;
if (!PN->hasOneUse()) {
for (User *U : PN->users()) {
Instruction *UI = cast<Instruction>(U);
if (UI != &I && !I.isIdenticalTo(UI))
return nullptr;
}
}
BasicBlock *NonConstBB = nullptr;
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InVal = PN->getIncomingValue(i);
if (!isa<FreezeInst>(I) && match(InVal, m_ImmConstant()))
continue;
if (isa<FreezeInst>(I) && isGuaranteedNotToBeUndefOrPoison(InVal))
continue;
if (isa<PHINode>(InVal)) return nullptr; if (NonConstBB) return nullptr;
NonConstBB = PN->getIncomingBlock(i);
if (isa<InvokeInst>(InVal))
if (cast<Instruction>(InVal)->getParent() == NonConstBB)
return nullptr;
if (isPotentiallyReachable(PN->getParent(), NonConstBB, nullptr, &DT, LI))
return nullptr;
}
if (NonConstBB != nullptr) {
BranchInst *BI = dyn_cast<BranchInst>(NonConstBB->getTerminator());
if (!BI || !BI->isUnconditional() || !DT.isReachableFromEntry(NonConstBB))
return nullptr;
}
PHINode *NewPN = PHINode::Create(I.getType(), PN->getNumIncomingValues());
InsertNewInstBefore(NewPN, *PN);
NewPN->takeName(PN);
if (NonConstBB)
Builder.SetInsertPoint(NonConstBB->getTerminator());
if (SelectInst *SI = dyn_cast<SelectInst>(&I)) {
Value *TrueV = SI->getTrueValue();
Value *FalseV = SI->getFalseValue();
BasicBlock *PhiTransBB = PN->getParent();
for (unsigned i = 0; i != NumPHIValues; ++i) {
BasicBlock *ThisBB = PN->getIncomingBlock(i);
Value *TrueVInPred = TrueV->DoPHITranslation(PhiTransBB, ThisBB);
Value *FalseVInPred = FalseV->DoPHITranslation(PhiTransBB, ThisBB);
Value *InV = nullptr;
Constant *InC = dyn_cast<Constant>(PN->getIncomingValue(i));
if (InC && isa<ConstantInt>(InC))
InV = InC->isNullValue() ? FalseVInPred : TrueVInPred;
else {
Builder.SetInsertPoint(ThisBB->getTerminator());
InV = Builder.CreateSelect(PN->getIncomingValue(i), TrueVInPred,
FalseVInPred, "phi.sel");
}
NewPN->addIncoming(InV, ThisBB);
}
} else if (CmpInst *CI = dyn_cast<CmpInst>(&I)) {
Constant *C = cast<Constant>(I.getOperand(1));
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InV = nullptr;
if (auto *InC = dyn_cast<Constant>(PN->getIncomingValue(i)))
InV = ConstantExpr::getCompare(CI->getPredicate(), InC, C);
else
InV = Builder.CreateCmp(CI->getPredicate(), PN->getIncomingValue(i),
C, "phi.cmp");
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
} else if (auto *BO = dyn_cast<BinaryOperator>(&I)) {
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InV = foldOperationIntoPhiValue(BO, PN->getIncomingValue(i),
Builder);
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
} else if (isa<FreezeInst>(&I)) {
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InV;
if (NonConstBB == PN->getIncomingBlock(i))
InV = Builder.CreateFreeze(PN->getIncomingValue(i), "phi.fr");
else
InV = PN->getIncomingValue(i);
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
} else {
CastInst *CI = cast<CastInst>(&I);
Type *RetTy = CI->getType();
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InV;
if (Constant *InC = dyn_cast<Constant>(PN->getIncomingValue(i)))
InV = ConstantExpr::getCast(CI->getOpcode(), InC, RetTy);
else
InV = Builder.CreateCast(CI->getOpcode(), PN->getIncomingValue(i),
I.getType(), "phi.cast");
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
}
for (User *U : make_early_inc_range(PN->users())) {
Instruction *User = cast<Instruction>(U);
if (User == &I) continue;
replaceInstUsesWith(*User, NewPN);
eraseInstFromFunction(*User);
}
return replaceInstUsesWith(I, NewPN);
}
Instruction *InstCombinerImpl::foldBinopWithPhiOperands(BinaryOperator &BO) {
auto *Phi0 = dyn_cast<PHINode>(BO.getOperand(0));
auto *Phi1 = dyn_cast<PHINode>(BO.getOperand(1));
if (!Phi0 || !Phi1 || !Phi0->hasOneUse() || !Phi1->hasOneUse() ||
Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2)
return nullptr;
if (BO.getParent() != Phi0->getParent() ||
BO.getParent() != Phi1->getParent())
return nullptr;
BasicBlock *ConstBB, *OtherBB;
Constant *C0, *C1;
if (match(Phi0->getIncomingValue(0), m_ImmConstant(C0))) {
ConstBB = Phi0->getIncomingBlock(0);
OtherBB = Phi0->getIncomingBlock(1);
} else if (match(Phi0->getIncomingValue(1), m_ImmConstant(C0))) {
ConstBB = Phi0->getIncomingBlock(1);
OtherBB = Phi0->getIncomingBlock(0);
} else {
return nullptr;
}
if (!match(Phi1->getIncomingValueForBlock(ConstBB), m_ImmConstant(C1)))
return nullptr;
auto *PredBlockBranch = dyn_cast<BranchInst>(OtherBB->getTerminator());
if (!PredBlockBranch || PredBlockBranch->isConditional() ||
!DT.isReachableFromEntry(OtherBB))
return nullptr;
for (auto BBIter = BO.getParent()->begin(); &*BBIter != &BO; ++BBIter)
if (!isGuaranteedToTransferExecutionToSuccessor(&*BBIter))
return nullptr;
Constant *NewC = ConstantFoldBinaryOpOperands(BO.getOpcode(), C0, C1, DL);
if (!NewC)
return nullptr;
Builder.SetInsertPoint(PredBlockBranch);
Value *NewBO = Builder.CreateBinOp(BO.getOpcode(),
Phi0->getIncomingValueForBlock(OtherBB),
Phi1->getIncomingValueForBlock(OtherBB));
if (auto *NotFoldedNewBO = dyn_cast<BinaryOperator>(NewBO))
NotFoldedNewBO->copyIRFlags(&BO);
PHINode *NewPhi = PHINode::Create(BO.getType(), 2);
NewPhi->addIncoming(NewBO, OtherBB);
NewPhi->addIncoming(NewC, ConstBB);
return NewPhi;
}
Instruction *InstCombinerImpl::foldBinOpIntoSelectOrPhi(BinaryOperator &I) {
if (!isa<Constant>(I.getOperand(1)))
return nullptr;
if (auto *Sel = dyn_cast<SelectInst>(I.getOperand(0))) {
if (Instruction *NewSel = FoldOpIntoSelect(I, Sel))
return NewSel;
} else if (auto *PN = dyn_cast<PHINode>(I.getOperand(0))) {
if (Instruction *NewPhi = foldOpIntoPhi(I, PN))
return NewPhi;
}
return nullptr;
}
static Type *findElementAtOffset(PointerType *PtrTy, int64_t IntOffset,
SmallVectorImpl<Value *> &NewIndices,
const DataLayout &DL) {
Type *Ty = PtrTy->getNonOpaquePointerElementType();
if (!Ty->isSized())
return nullptr;
APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), IntOffset);
SmallVector<APInt> Indices = DL.getGEPIndicesForOffset(Ty, Offset);
if (!Offset.isZero())
return nullptr;
for (const APInt &Index : Indices)
NewIndices.push_back(ConstantInt::get(PtrTy->getContext(), Index));
return Ty;
}
static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) {
if (GEP.hasAllZeroIndices() && !Src.hasAllZeroIndices() &&
!Src.hasOneUse())
return false;
return true;
}
Value *InstCombinerImpl::Descale(Value *Val, APInt Scale, bool &NoSignedWrap) {
assert(isa<IntegerType>(Val->getType()) && "Can only descale integers!");
assert(cast<IntegerType>(Val->getType())->getBitWidth() ==
Scale.getBitWidth() && "Scale not compatible with value!");
if (match(Val, m_Zero()) || Scale == 1) {
NoSignedWrap = true;
return Val;
}
if (Scale.isMinValue())
return nullptr;
Value *Op = Val;
std::pair<Instruction *, unsigned> Parent;
bool RequireNoSignedWrap = false;
int32_t logScale = Scale.exactLogBase2();
for (;; Op = Parent.first->getOperand(Parent.second)) { if (ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
APInt Quotient(Scale), Remainder(Scale); APInt::sdivrem(CI->getValue(), Scale, Quotient, Remainder);
if (!Remainder.isMinValue())
return nullptr;
Op = ConstantInt::get(CI->getType(), Quotient);
NoSignedWrap = true;
break;
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Op)) {
if (BO->getOpcode() == Instruction::Mul) {
NoSignedWrap = BO->hasNoSignedWrap();
if (RequireNoSignedWrap && !NoSignedWrap)
return nullptr;
Value *LHS = BO->getOperand(0);
Value *RHS = BO->getOperand(1);
if (ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
if (CI->getValue() == Scale) {
Op = LHS;
break;
}
if (!Op->hasOneUse())
return nullptr;
Parent = std::make_pair(BO, 1);
continue;
}
if (!Op->hasOneUse())
return nullptr;
Parent = std::make_pair(BO, 0);
continue;
}
if (logScale > 0 && BO->getOpcode() == Instruction::Shl &&
isa<ConstantInt>(BO->getOperand(1))) {
NoSignedWrap = BO->hasNoSignedWrap();
if (RequireNoSignedWrap && !NoSignedWrap)
return nullptr;
Value *LHS = BO->getOperand(0);
int32_t Amt = cast<ConstantInt>(BO->getOperand(1))->
getLimitedValue(Scale.getBitWidth());
if (Amt == logScale) {
Op = LHS;
break;
}
if (Amt < logScale || !Op->hasOneUse())
return nullptr;
Parent = std::make_pair(BO, 1);
Op = ConstantInt::get(BO->getType(), Amt - logScale);
break;
}
}
if (!Op->hasOneUse())
return nullptr;
if (CastInst *Cast = dyn_cast<CastInst>(Op)) {
if (Cast->getOpcode() == Instruction::SExt) {
unsigned SmallSize = Cast->getSrcTy()->getPrimitiveSizeInBits();
APInt SmallScale = Scale.trunc(SmallSize);
if (SmallScale.sext(Scale.getBitWidth()) != Scale)
return nullptr;
assert(SmallScale.exactLogBase2() == logScale);
RequireNoSignedWrap = true;
Parent = std::make_pair(Cast, 0);
Scale = SmallScale;
continue;
}
if (Cast->getOpcode() == Instruction::Trunc) {
if (RequireNoSignedWrap)
return nullptr;
unsigned LargeSize = Cast->getSrcTy()->getPrimitiveSizeInBits();
Parent = std::make_pair(Cast, 0);
Scale = Scale.sext(LargeSize);
if (logScale + 1 == (int32_t)Cast->getType()->getPrimitiveSizeInBits())
logScale = -1;
assert(Scale.exactLogBase2() == logScale);
continue;
}
}
return nullptr;
}
if (match(Op, m_Zero())) {
NoSignedWrap = true;
return Op;
}
if (!Parent.first)
return Op;
assert(Parent.first->hasOneUse() && "Drilled down when more than one use!");
assert(Op != Parent.first->getOperand(Parent.second) &&
"Descaling was a no-op?");
replaceOperand(*Parent.first, Parent.second, Op);
Worklist.push(Parent.first);
Instruction *Ancestor = Parent.first;
do {
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Ancestor)) {
bool OpNoSignedWrap = BO->hasNoSignedWrap();
NoSignedWrap &= OpNoSignedWrap;
if (NoSignedWrap != OpNoSignedWrap) {
BO->setHasNoSignedWrap(NoSignedWrap);
Worklist.push(Ancestor);
}
} else if (Ancestor->getOpcode() == Instruction::Trunc) {
NoSignedWrap = false;
}
assert((Ancestor->getOpcode() != Instruction::SExt || NoSignedWrap) &&
"Failed to keep proper track of nsw flags while drilling down?");
if (Ancestor == Val)
return Val;
assert(Ancestor->hasOneUse() && "Drilled down when more than one use!");
Ancestor = Ancestor->user_back();
} while (true);
}
Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
if (!isa<VectorType>(Inst.getType()))
return nullptr;
BinaryOperator::BinaryOps Opcode = Inst.getOpcode();
Value *LHS = Inst.getOperand(0), *RHS = Inst.getOperand(1);
assert(cast<VectorType>(LHS->getType())->getElementCount() ==
cast<VectorType>(Inst.getType())->getElementCount());
assert(cast<VectorType>(RHS->getType())->getElementCount() ==
cast<VectorType>(Inst.getType())->getElementCount());
Value *L0, *L1, *R0, *R1;
ArrayRef<int> Mask;
if (match(LHS, m_Shuffle(m_Value(L0), m_Value(L1), m_Mask(Mask))) &&
match(RHS, m_Shuffle(m_Value(R0), m_Value(R1), m_SpecificMask(Mask))) &&
LHS->hasOneUse() && RHS->hasOneUse() &&
cast<ShuffleVectorInst>(LHS)->isConcat() &&
cast<ShuffleVectorInst>(RHS)->isConcat()) {
Value *NewBO0 = Builder.CreateBinOp(Opcode, L0, R0);
if (auto *BO = dyn_cast<BinaryOperator>(NewBO0))
BO->copyIRFlags(&Inst);
Value *NewBO1 = Builder.CreateBinOp(Opcode, L1, R1);
if (auto *BO = dyn_cast<BinaryOperator>(NewBO1))
BO->copyIRFlags(&Inst);
return new ShuffleVectorInst(NewBO0, NewBO1, Mask);
}
if (!isSafeToSpeculativelyExecute(&Inst))
return nullptr;
auto createBinOpShuffle = [&](Value *X, Value *Y, ArrayRef<int> M) {
Value *XY = Builder.CreateBinOp(Opcode, X, Y);
if (auto *BO = dyn_cast<BinaryOperator>(XY))
BO->copyIRFlags(&Inst);
return new ShuffleVectorInst(XY, M);
};
Value *V1, *V2;
if (match(LHS, m_Shuffle(m_Value(V1), m_Undef(), m_Mask(Mask))) &&
match(RHS, m_Shuffle(m_Value(V2), m_Undef(), m_SpecificMask(Mask))) &&
V1->getType() == V2->getType() &&
(LHS->hasOneUse() || RHS->hasOneUse() || LHS == RHS)) {
return createBinOpShuffle(V1, V2, Mask);
}
if (Inst.isCommutative() &&
match(LHS, m_Shuffle(m_Value(V1), m_Value(V2), m_Mask(Mask))) &&
match(RHS,
m_Shuffle(m_Specific(V2), m_Specific(V1), m_SpecificMask(Mask)))) {
auto *LShuf = cast<ShuffleVectorInst>(LHS);
auto *RShuf = cast<ShuffleVectorInst>(RHS);
if (LShuf->isSelect() &&
!is_contained(LShuf->getShuffleMask(), UndefMaskElem) &&
RShuf->isSelect() &&
!is_contained(RShuf->getShuffleMask(), UndefMaskElem)) {
Instruction *NewBO = BinaryOperator::Create(Opcode, V1, V2);
NewBO->copyIRFlags(&Inst);
return NewBO;
}
}
Constant *C;
auto *InstVTy = dyn_cast<FixedVectorType>(Inst.getType());
if (InstVTy &&
match(&Inst,
m_c_BinOp(m_OneUse(m_Shuffle(m_Value(V1), m_Undef(), m_Mask(Mask))),
m_ImmConstant(C))) &&
cast<FixedVectorType>(V1->getType())->getNumElements() <=
InstVTy->getNumElements()) {
assert(InstVTy->getScalarType() == V1->getType()->getScalarType() &&
"Shuffle should not change scalar type");
bool ConstOp1 = isa<Constant>(RHS);
ArrayRef<int> ShMask = Mask;
unsigned SrcVecNumElts =
cast<FixedVectorType>(V1->getType())->getNumElements();
UndefValue *UndefScalar = UndefValue::get(C->getType()->getScalarType());
SmallVector<Constant *, 16> NewVecC(SrcVecNumElts, UndefScalar);
bool MayChange = true;
unsigned NumElts = InstVTy->getNumElements();
for (unsigned I = 0; I < NumElts; ++I) {
Constant *CElt = C->getAggregateElement(I);
if (ShMask[I] >= 0) {
assert(ShMask[I] < (int)NumElts && "Not expecting narrowing shuffle");
Constant *NewCElt = NewVecC[ShMask[I]];
if (!CElt || (!isa<UndefValue>(NewCElt) && NewCElt != CElt) ||
I >= SrcVecNumElts) {
MayChange = false;
break;
}
NewVecC[ShMask[I]] = CElt;
}
if (I >= SrcVecNumElts || ShMask[I] < 0) {
Constant *MaybeUndef =
ConstOp1
? ConstantFoldBinaryOpOperands(Opcode, UndefScalar, CElt, DL)
: ConstantFoldBinaryOpOperands(Opcode, CElt, UndefScalar, DL);
if (!MaybeUndef || !match(MaybeUndef, m_Undef())) {
MayChange = false;
break;
}
}
}
if (MayChange) {
Constant *NewC = ConstantVector::get(NewVecC);
if (Inst.isIntDivRem() || (Inst.isShift() && ConstOp1))
NewC = getSafeVectorConstantForBinop(Opcode, NewC, ConstOp1);
Value *NewLHS = ConstOp1 ? V1 : NewC;
Value *NewRHS = ConstOp1 ? NewC : V1;
return createBinOpShuffle(NewLHS, NewRHS, Mask);
}
}
if (Inst.isAssociative() && Inst.isCommutative()) {
if (isa<ShuffleVectorInst>(RHS))
std::swap(LHS, RHS);
Value *X;
ArrayRef<int> MaskC;
int SplatIndex;
Value *Y, *OtherOp;
if (!match(LHS,
m_OneUse(m_Shuffle(m_Value(X), m_Undef(), m_Mask(MaskC)))) ||
!match(MaskC, m_SplatOrUndefMask(SplatIndex)) ||
X->getType() != Inst.getType() ||
!match(RHS, m_OneUse(m_BinOp(Opcode, m_Value(Y), m_Value(OtherOp)))))
return nullptr;
if (isSplatValue(OtherOp, SplatIndex)) {
std::swap(Y, OtherOp);
} else if (!isSplatValue(Y, SplatIndex)) {
return nullptr;
}
Value *NewBO = Builder.CreateBinOp(Opcode, X, Y);
SmallVector<int, 8> NewMask(MaskC.size(), SplatIndex);
Value *NewSplat = Builder.CreateShuffleVector(NewBO, NewMask);
Instruction *R = BinaryOperator::Create(Opcode, NewSplat, OtherOp);
if (isa<FPMathOperator>(R)) {
R->copyFastMathFlags(&Inst);
R->andIRFlags(RHS);
}
if (auto *NewInstBO = dyn_cast<BinaryOperator>(NewBO))
NewInstBO->copyIRFlags(R);
return R;
}
return nullptr;
}
Instruction *InstCombinerImpl::narrowMathIfNoOverflow(BinaryOperator &BO) {
Value *Op0 = BO.getOperand(0), *Op1 = BO.getOperand(1);
if (BO.getOpcode() == Instruction::Sub)
std::swap(Op0, Op1);
Value *X;
bool IsSext = match(Op0, m_SExt(m_Value(X)));
if (!IsSext && !match(Op0, m_ZExt(m_Value(X))))
return nullptr;
CastInst::CastOps CastOpc = IsSext ? Instruction::SExt : Instruction::ZExt;
Value *Y;
if (!(match(Op1, m_ZExtOrSExt(m_Value(Y))) && X->getType() == Y->getType() &&
cast<Operator>(Op1)->getOpcode() == CastOpc &&
(Op0->hasOneUse() || Op1->hasOneUse()))) {
Constant *WideC;
if (!Op0->hasOneUse() || !match(Op1, m_Constant(WideC)))
return nullptr;
Constant *NarrowC = ConstantExpr::getTrunc(WideC, X->getType());
if (ConstantExpr::getCast(CastOpc, NarrowC, BO.getType()) != WideC)
return nullptr;
Y = NarrowC;
}
if (BO.getOpcode() == Instruction::Sub)
std::swap(X, Y);
if (!willNotOverflow(BO.getOpcode(), X, Y, BO, IsSext))
return nullptr;
Value *NarrowBO = Builder.CreateBinOp(BO.getOpcode(), X, Y, "narrow");
if (auto *NewBinOp = dyn_cast<BinaryOperator>(NarrowBO)) {
if (IsSext)
NewBinOp->setHasNoSignedWrap();
else
NewBinOp->setHasNoUnsignedWrap();
}
return CastInst::Create(CastOpc, NarrowBO, BO.getType());
}
static bool isMergedGEPInBounds(GEPOperator &GEP1, GEPOperator &GEP2) {
if (!GEP1.isInBounds() && !GEP2.isInBounds())
return false;
return (GEP1.isInBounds() || GEP1.hasAllZeroIndices()) &&
(GEP2.isInBounds() || GEP2.hasAllZeroIndices());
}
static Instruction *foldSelectGEP(GetElementPtrInst &GEP,
InstCombiner::BuilderTy &Builder) {
if (!GEP.hasAllConstantIndices())
return nullptr;
Instruction *Sel;
Value *Cond;
Constant *TrueC, *FalseC;
if (!match(GEP.getPointerOperand(), m_Instruction(Sel)) ||
!match(Sel,
m_Select(m_Value(Cond), m_Constant(TrueC), m_Constant(FalseC))))
return nullptr;
SmallVector<Value *, 4> IndexC(GEP.indices());
bool IsInBounds = GEP.isInBounds();
Type *Ty = GEP.getSourceElementType();
Value *NewTrueC = Builder.CreateGEP(Ty, TrueC, IndexC, "", IsInBounds);
Value *NewFalseC = Builder.CreateGEP(Ty, FalseC, IndexC, "", IsInBounds);
return SelectInst::Create(Cond, NewTrueC, NewFalseC, "", nullptr, Sel);
}
Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
GEPOperator *Src) {
if (!shouldMergeGEPs(*cast<GEPOperator>(&GEP), *Src))
return nullptr;
if (Src->getResultElementType() == GEP.getSourceElementType() &&
Src->getNumOperands() == 2 && GEP.getNumOperands() == 2 &&
Src->hasOneUse()) {
Value *GO1 = GEP.getOperand(1);
Value *SO1 = Src->getOperand(1);
if (LI) {
if (Loop *L = LI->getLoopFor(GEP.getParent())) {
if (L->isLoopInvariant(GO1) && !L->isLoopInvariant(SO1)) {
bool IsInBounds = Src->isInBounds() && GEP.isInBounds() &&
isKnownNonNegative(SO1, DL, 0, &AC, &GEP, &DT) &&
isKnownNonNegative(GO1, DL, 0, &AC, &GEP, &DT);
Builder.SetInsertPoint(cast<Instruction>(Src));
Value *NewSrc = Builder.CreateGEP(GEP.getSourceElementType(),
Src->getPointerOperand(), GO1,
Src->getName(), IsInBounds);
GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
GEP.getSourceElementType(), NewSrc, {SO1});
NewGEP->setIsInBounds(IsInBounds);
return NewGEP;
}
}
}
}
if (auto *SrcGEP = dyn_cast<GEPOperator>(Src->getOperand(0)))
if (SrcGEP->getNumOperands() == 2 && shouldMergeGEPs(*Src, *SrcGEP))
return nullptr;
Type *PtrTy = Src->getType()->getScalarType();
if (PtrTy->isOpaquePointerTy() && GEP.hasAllConstantIndices() &&
(Src->hasOneUse() || Src->hasAllConstantIndices())) {
gep_type_iterator GTI = gep_type_begin(*Src);
Type *BaseType = GTI.getIndexedType();
bool IsFirstType = true;
unsigned NumVarIndices = 0;
for (auto Pair : enumerate(Src->indices())) {
if (!isa<ConstantInt>(Pair.value())) {
BaseType = GTI.getIndexedType();
IsFirstType = false;
NumVarIndices = Pair.index() + 1;
}
++GTI;
}
APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
if (NumVarIndices != Src->getNumIndices()) {
if (isa<ScalableVectorType>(BaseType))
return nullptr;
SmallVector<Value *> ConstantIndices;
if (!IsFirstType)
ConstantIndices.push_back(
Constant::getNullValue(Type::getInt32Ty(GEP.getContext())));
append_range(ConstantIndices, drop_begin(Src->indices(), NumVarIndices));
Offset += DL.getIndexedOffsetInType(BaseType, ConstantIndices);
}
if (!GEP.accumulateConstantOffset(DL, Offset))
return nullptr;
APInt OffsetOld = Offset;
SmallVector<APInt> ConstIndices =
DL.getGEPIndicesForOffset(BaseType, Offset);
if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero())) {
if (Src->hasAllConstantIndices())
return isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP))
? GetElementPtrInst::CreateInBounds(
Builder.getInt8Ty(), Src->getOperand(0),
Builder.getInt(OffsetOld), GEP.getName())
: GetElementPtrInst::Create(
Builder.getInt8Ty(), Src->getOperand(0),
Builder.getInt(OffsetOld), GEP.getName());
return nullptr;
}
bool IsInBounds = isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP));
SmallVector<Value *> Indices;
append_range(Indices, drop_end(Src->indices(),
Src->getNumIndices() - NumVarIndices));
for (const APInt &Idx : drop_begin(ConstIndices, !IsFirstType)) {
Indices.push_back(ConstantInt::get(GEP.getContext(), Idx));
IsInBounds &= Idx.isNonNegative() == ConstIndices[0].isNonNegative();
}
return IsInBounds
? GetElementPtrInst::CreateInBounds(Src->getSourceElementType(),
Src->getOperand(0), Indices,
GEP.getName())
: GetElementPtrInst::Create(Src->getSourceElementType(),
Src->getOperand(0), Indices,
GEP.getName());
}
if (Src->getResultElementType() != GEP.getSourceElementType())
return nullptr;
SmallVector<Value*, 8> Indices;
bool EndsWithSequential = false;
for (gep_type_iterator I = gep_type_begin(*Src), E = gep_type_end(*Src);
I != E; ++I)
EndsWithSequential = I.isSequential();
if (EndsWithSequential) {
Value *SO1 = Src->getOperand(Src->getNumOperands()-1);
Value *GO1 = GEP.getOperand(1);
if (SO1->getType() != GO1->getType())
return nullptr;
Value *Sum =
simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
if (Sum == nullptr)
return nullptr;
if (Src->getNumOperands() == 2) {
GEP.setIsInBounds(isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP)));
replaceOperand(GEP, 0, Src->getOperand(0));
replaceOperand(GEP, 1, Sum);
return &GEP;
}
Indices.append(Src->op_begin()+1, Src->op_end()-1);
Indices.push_back(Sum);
Indices.append(GEP.op_begin()+2, GEP.op_end());
} else if (isa<Constant>(*GEP.idx_begin()) &&
cast<Constant>(*GEP.idx_begin())->isNullValue() &&
Src->getNumOperands() != 1) {
Indices.append(Src->op_begin()+1, Src->op_end());
Indices.append(GEP.idx_begin()+1, GEP.idx_end());
}
if (!Indices.empty())
return isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP))
? GetElementPtrInst::CreateInBounds(
Src->getSourceElementType(), Src->getOperand(0), Indices,
GEP.getName())
: GetElementPtrInst::Create(Src->getSourceElementType(),
Src->getOperand(0), Indices,
GEP.getName());
return nullptr;
}
Instruction *InstCombinerImpl::visitGEPOfBitcast(BitCastInst *BCI,
GetElementPtrInst &GEP) {
PointerType *SrcType = cast<PointerType>(BCI->getSrcTy());
if (SrcType->isOpaque())
return nullptr;
Type *GEPEltType = GEP.getSourceElementType();
Type *SrcEltType = SrcType->getNonOpaquePointerElementType();
Value *SrcOp = BCI->getOperand(0);
auto areMatchingArrayAndVecTypes = [](Type *ArrTy, Type *VecTy,
const DataLayout &DL) {
auto *VecVTy = cast<FixedVectorType>(VecTy);
return ArrTy->getArrayElementType() == VecVTy->getElementType() &&
ArrTy->getArrayNumElements() == VecVTy->getNumElements() &&
DL.getTypeAllocSize(ArrTy) == DL.getTypeAllocSize(VecTy);
};
if (GEP.getNumOperands() == 3 &&
((GEPEltType->isArrayTy() && isa<FixedVectorType>(SrcEltType) &&
areMatchingArrayAndVecTypes(GEPEltType, SrcEltType, DL)) ||
(isa<FixedVectorType>(GEPEltType) && SrcEltType->isArrayTy() &&
areMatchingArrayAndVecTypes(SrcEltType, GEPEltType, DL)))) {
SmallVector<Value *, 8> Indices(GEP.indices());
Value *NGEP =
Builder.CreateGEP(SrcEltType, SrcOp, Indices, "", GEP.isInBounds());
NGEP->takeName(&GEP);
if (NGEP->getType()->getPointerAddressSpace() != GEP.getAddressSpace())
return new AddrSpaceCastInst(NGEP, GEP.getType());
return replaceInstUsesWith(GEP, NGEP);
}
unsigned OffsetBits = DL.getIndexTypeSizeInBits(GEP.getType());
APInt Offset(OffsetBits, 0);
if (!isa<BitCastInst>(SrcOp) && GEP.accumulateConstantOffset(DL, Offset) &&
!isAllocationFn(SrcOp, &TLI)) {
if (!Offset) {
if (isa<AllocaInst>(SrcOp)) {
if (Instruction *I = visitBitCast(*BCI)) {
if (I != BCI) {
I->takeName(BCI);
BCI->getParent()->getInstList().insert(BCI->getIterator(), I);
replaceInstUsesWith(*BCI, I);
}
return &GEP;
}
}
if (SrcType->getPointerAddressSpace() != GEP.getAddressSpace())
return new AddrSpaceCastInst(SrcOp, GEP.getType());
return new BitCastInst(SrcOp, GEP.getType());
}
SmallVector<Value *, 8> NewIndices;
if (findElementAtOffset(SrcType, Offset.getSExtValue(), NewIndices, DL)) {
Value *NGEP = Builder.CreateGEP(SrcEltType, SrcOp, NewIndices, "",
GEP.isInBounds());
if (NGEP->getType() == GEP.getType())
return replaceInstUsesWith(GEP, NGEP);
NGEP->takeName(&GEP);
if (NGEP->getType()->getPointerAddressSpace() != GEP.getAddressSpace())
return new AddrSpaceCastInst(NGEP, GEP.getType());
return new BitCastInst(NGEP, GEP.getType());
}
}
return nullptr;
}
Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
Value *PtrOp = GEP.getOperand(0);
SmallVector<Value *, 8> Indices(GEP.indices());
Type *GEPType = GEP.getType();
Type *GEPEltType = GEP.getSourceElementType();
bool IsGEPSrcEleScalable = isa<ScalableVectorType>(GEPEltType);
if (Value *V = simplifyGEPInst(GEPEltType, PtrOp, Indices, GEP.isInBounds(),
SQ.getWithInstruction(&GEP)))
return replaceInstUsesWith(GEP, V);
if (auto *GEPFVTy = dyn_cast<FixedVectorType>(GEPType)) {
auto VWidth = GEPFVTy->getNumElements();
APInt UndefElts(VWidth, 0);
APInt AllOnesEltMask(APInt::getAllOnes(VWidth));
if (Value *V = SimplifyDemandedVectorElts(&GEP, AllOnesEltMask,
UndefElts)) {
if (V != &GEP)
return replaceInstUsesWith(GEP, V);
return &GEP;
}
}
bool MadeChange = false;
Type *NewScalarIndexTy =
DL.getIndexType(GEP.getPointerOperandType()->getScalarType());
gep_type_iterator GTI = gep_type_begin(GEP);
for (User::op_iterator I = GEP.op_begin() + 1, E = GEP.op_end(); I != E;
++I, ++GTI) {
if (GTI.isStruct())
continue;
Type *IndexTy = (*I)->getType();
Type *NewIndexType =
IndexTy->isVectorTy()
? VectorType::get(NewScalarIndexTy,
cast<VectorType>(IndexTy)->getElementCount())
: NewScalarIndexTy;
Type *EltTy = GTI.getIndexedType();
if (EltTy->isSized() && DL.getTypeAllocSize(EltTy).isZero())
if (!isa<Constant>(*I) || !match(I->get(), m_Zero())) {
*I = Constant::getNullValue(NewIndexType);
MadeChange = true;
}
if (IndexTy != NewIndexType) {
*I = Builder.CreateIntCast(*I, NewIndexType, true);
MadeChange = true;
}
}
if (MadeChange)
return &GEP;
if (auto *PN = dyn_cast<PHINode>(PtrOp)) {
auto *Op1 = dyn_cast<GetElementPtrInst>(PN->getOperand(0));
if (!Op1)
return nullptr;
if (Op1 == &GEP)
return nullptr;
int DI = -1;
for (auto I = PN->op_begin()+1, E = PN->op_end(); I !=E; ++I) {
auto *Op2 = dyn_cast<GetElementPtrInst>(*I);
if (!Op2 || Op1->getNumOperands() != Op2->getNumOperands() ||
Op1->getSourceElementType() != Op2->getSourceElementType())
return nullptr;
if (Op2 == &GEP)
return nullptr;
Type *CurTy = nullptr;
for (unsigned J = 0, F = Op1->getNumOperands(); J != F; ++J) {
if (Op1->getOperand(J)->getType() != Op2->getOperand(J)->getType())
return nullptr;
if (Op1->getOperand(J) != Op2->getOperand(J)) {
if (DI == -1) {
if (J > 1) {
assert(CurTy && "No current type?");
if (CurTy->isStructTy())
return nullptr;
}
DI = J;
} else {
return nullptr;
}
}
if (J > 0) {
if (J == 1) {
CurTy = Op1->getSourceElementType();
} else {
CurTy =
GetElementPtrInst::getTypeAtIndex(CurTy, Op1->getOperand(J));
}
}
}
}
if (DI != -1 && !PN->hasOneUse())
return nullptr;
auto *NewGEP = cast<GetElementPtrInst>(Op1->clone());
if (DI == -1) {
} else {
PHINode *NewPN;
{
IRBuilderBase::InsertPointGuard Guard(Builder);
Builder.SetInsertPoint(PN);
NewPN = Builder.CreatePHI(Op1->getOperand(DI)->getType(),
PN->getNumOperands());
}
for (auto &I : PN->operands())
NewPN->addIncoming(cast<GEPOperator>(I)->getOperand(DI),
PN->getIncomingBlock(I));
NewGEP->setOperand(DI, NewPN);
}
GEP.getParent()->getInstList().insert(
GEP.getParent()->getFirstInsertionPt(), NewGEP);
replaceOperand(GEP, 0, NewGEP);
PtrOp = NewGEP;
}
if (auto *Src = dyn_cast<GEPOperator>(PtrOp))
if (Instruction *I = visitGEPOfGEP(GEP, Src))
return I;
if (GEP.getNumIndices() == 1 && !IsGEPSrcEleScalable) {
unsigned AS = GEP.getPointerAddressSpace();
if (GEP.getOperand(1)->getType()->getScalarSizeInBits() ==
DL.getIndexSizeInBits(AS)) {
uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedSize();
bool Matched = false;
uint64_t C;
Value *V = nullptr;
if (TyAllocSize == 1) {
V = GEP.getOperand(1);
Matched = true;
} else if (match(GEP.getOperand(1),
m_AShr(m_Value(V), m_ConstantInt(C)))) {
if (TyAllocSize == 1ULL << C)
Matched = true;
} else if (match(GEP.getOperand(1),
m_SDiv(m_Value(V), m_ConstantInt(C)))) {
if (TyAllocSize == C)
Matched = true;
}
Value *Y;
Value *X = GEP.getOperand(0);
if (Matched &&
match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
getUnderlyingObject(X) == getUnderlyingObject(Y))
return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
}
}
if (GEPType->isVectorTy())
return nullptr;
Value *StrippedPtr = PtrOp->stripPointerCasts();
PointerType *StrippedPtrTy = cast<PointerType>(StrippedPtr->getType());
if (StrippedPtr != PtrOp && !StrippedPtrTy->isOpaque()) {
bool HasZeroPointerIndex = false;
Type *StrippedPtrEltTy = StrippedPtrTy->getNonOpaquePointerElementType();
if (auto *C = dyn_cast<ConstantInt>(GEP.getOperand(1)))
HasZeroPointerIndex = C->isZero();
if (HasZeroPointerIndex) {
if (auto *CATy = dyn_cast<ArrayType>(GEPEltType)) {
if (CATy->getElementType() == StrippedPtrEltTy) {
SmallVector<Value *, 8> Idx(drop_begin(GEP.indices()));
GetElementPtrInst *Res = GetElementPtrInst::Create(
StrippedPtrEltTy, StrippedPtr, Idx, GEP.getName());
Res->setIsInBounds(GEP.isInBounds());
if (StrippedPtrTy->getAddressSpace() == GEP.getAddressSpace())
return Res;
return new AddrSpaceCastInst(Builder.Insert(Res), GEPType);
}
if (auto *XATy = dyn_cast<ArrayType>(StrippedPtrEltTy)) {
if (CATy->getElementType() == XATy->getElementType()) {
if (StrippedPtrTy->getAddressSpace() == GEP.getAddressSpace()) {
GEP.setSourceElementType(XATy);
return replaceOperand(GEP, 0, StrippedPtr);
}
SmallVector<Value *, 8> Idx(GEP.indices());
Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Idx,
GEP.getName(), GEP.isInBounds());
return new AddrSpaceCastInst(NewGEP, GEPType);
}
}
}
} else if (GEP.getNumOperands() == 2 && !IsGEPSrcEleScalable) {
if (StrippedPtrEltTy->isArrayTy() &&
DL.getTypeAllocSize(StrippedPtrEltTy->getArrayElementType()) ==
DL.getTypeAllocSize(GEPEltType)) {
Type *IdxType = DL.getIndexType(GEPType);
Value *Idx[2] = {Constant::getNullValue(IdxType), GEP.getOperand(1)};
Value *NewGEP = Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Idx,
GEP.getName(), GEP.isInBounds());
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP, GEPType);
}
if (GEPEltType->isSized() && StrippedPtrEltTy->isSized()) {
uint64_t ResSize = DL.getTypeAllocSize(GEPEltType).getFixedSize();
uint64_t SrcSize = DL.getTypeAllocSize(StrippedPtrEltTy).getFixedSize();
if (ResSize && SrcSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = SrcSize / ResSize;
assert(Idx->getType() == DL.getIndexType(GEPType) &&
"Index type does not match the Data Layout preferences");
bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, NewIdx,
GEP.getName(), GEP.isInBounds() && NSW);
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP,
GEPType);
}
}
}
if (GEPEltType->isSized() && StrippedPtrEltTy->isSized() &&
StrippedPtrEltTy->isArrayTy()) {
uint64_t ResSize = DL.getTypeAllocSize(GEPEltType).getFixedSize();
uint64_t ArrayEltSize =
DL.getTypeAllocSize(StrippedPtrEltTy->getArrayElementType())
.getFixedSize();
if (ResSize && ArrayEltSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = ArrayEltSize / ResSize;
assert(Idx->getType() == DL.getIndexType(GEPType) &&
"Index type does not match the Data Layout preferences");
bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
Type *IndTy = DL.getIndexType(GEPType);
Value *Off[2] = {Constant::getNullValue(IndTy), NewIdx};
Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Off,
GEP.getName(), GEP.isInBounds() && NSW);
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP,
GEPType);
}
}
}
}
}
Value *ASCStrippedPtrOp = PtrOp;
if (auto *ASC = dyn_cast<AddrSpaceCastInst>(PtrOp)) {
if (auto *BC = dyn_cast<BitCastInst>(ASC->getOperand(0)))
ASCStrippedPtrOp = BC;
}
if (auto *BCI = dyn_cast<BitCastInst>(ASCStrippedPtrOp))
if (Instruction *I = visitGEPOfBitcast(BCI, GEP))
return I;
if (!GEP.isInBounds()) {
unsigned IdxWidth =
DL.getIndexSizeInBits(PtrOp->getType()->getPointerAddressSpace());
APInt BasePtrOffset(IdxWidth, 0);
Value *UnderlyingPtrOp =
PtrOp->stripAndAccumulateInBoundsConstantOffsets(DL,
BasePtrOffset);
if (auto *AI = dyn_cast<AllocaInst>(UnderlyingPtrOp)) {
if (GEP.accumulateConstantOffset(DL, BasePtrOffset) &&
BasePtrOffset.isNonNegative()) {
APInt AllocSize(
IdxWidth,
DL.getTypeAllocSize(AI->getAllocatedType()).getKnownMinSize());
if (BasePtrOffset.ule(AllocSize)) {
return GetElementPtrInst::CreateInBounds(
GEP.getSourceElementType(), PtrOp, Indices, GEP.getName());
}
}
}
}
if (Instruction *R = foldSelectGEP(GEP, Builder))
return R;
return nullptr;
}
static bool isNeverEqualToUnescapedAlloc(Value *V, const TargetLibraryInfo &TLI,
Instruction *AI) {
if (isa<ConstantPointerNull>(V))
return true;
if (auto *LI = dyn_cast<LoadInst>(V))
return isa<GlobalVariable>(LI->getPointerOperand());
return isAllocLikeFn(V, &TLI) && V != AI;
}
static bool isRemovableWrite(CallBase &CB, Value *UsedV,
const TargetLibraryInfo &TLI) {
if (!CB.use_empty())
return false;
if (CB.isTerminator())
return false;
if (!CB.willReturn() || !CB.doesNotThrow())
return false;
Optional<MemoryLocation> Dest = MemoryLocation::getForDest(&CB, TLI);
return Dest && Dest->Ptr == UsedV;
}
static bool isAllocSiteRemovable(Instruction *AI,
SmallVectorImpl<WeakTrackingVH> &Users,
const TargetLibraryInfo &TLI) {
SmallVector<Instruction*, 4> Worklist;
const Optional<StringRef> Family = getAllocationFamily(AI, &TLI);
Worklist.push_back(AI);
do {
Instruction *PI = Worklist.pop_back_val();
for (User *U : PI->users()) {
Instruction *I = cast<Instruction>(U);
switch (I->getOpcode()) {
default:
return false;
case Instruction::AddrSpaceCast:
case Instruction::BitCast:
case Instruction::GetElementPtr:
Users.emplace_back(I);
Worklist.push_back(I);
continue;
case Instruction::ICmp: {
ICmpInst *ICI = cast<ICmpInst>(I);
if (!ICI->isEquality())
return false;
unsigned OtherIndex = (ICI->getOperand(0) == PI) ? 1 : 0;
if (!isNeverEqualToUnescapedAlloc(ICI->getOperand(OtherIndex), TLI, AI))
return false;
Users.emplace_back(I);
continue;
}
case Instruction::Call:
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) {
default:
return false;
case Intrinsic::memmove:
case Intrinsic::memcpy:
case Intrinsic::memset: {
MemIntrinsic *MI = cast<MemIntrinsic>(II);
if (MI->isVolatile() || MI->getRawDest() != PI)
return false;
LLVM_FALLTHROUGH;
}
case Intrinsic::assume:
case Intrinsic::invariant_start:
case Intrinsic::invariant_end:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::objectsize:
Users.emplace_back(I);
continue;
case Intrinsic::launder_invariant_group:
case Intrinsic::strip_invariant_group:
Users.emplace_back(I);
Worklist.push_back(I);
continue;
}
}
if (isRemovableWrite(*cast<CallBase>(I), PI, TLI)) {
Users.emplace_back(I);
continue;
}
if (getFreedOperand(cast<CallBase>(I), &TLI) == PI &&
getAllocationFamily(I, &TLI) == Family) {
assert(Family);
Users.emplace_back(I);
continue;
}
if (getReallocatedOperand(cast<CallBase>(I), &TLI) == PI &&
getAllocationFamily(I, &TLI) == Family) {
assert(Family);
Users.emplace_back(I);
Worklist.push_back(I);
continue;
}
return false;
case Instruction::Store: {
StoreInst *SI = cast<StoreInst>(I);
if (SI->isVolatile() || SI->getPointerOperand() != PI)
return false;
Users.emplace_back(I);
continue;
}
}
llvm_unreachable("missing a return?");
}
} while (!Worklist.empty());
return true;
}
Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
assert(isa<AllocaInst>(MI) || isRemovableAlloc(&cast<CallBase>(MI), &TLI));
SmallVector<WeakTrackingVH, 64> Users;
SmallVector<DbgVariableIntrinsic *, 8> DVIs;
std::unique_ptr<DIBuilder> DIB;
if (isa<AllocaInst>(MI)) {
findDbgUsers(DVIs, &MI);
DIB.reset(new DIBuilder(*MI.getModule(), false));
}
if (isAllocSiteRemovable(&MI, Users, TLI)) {
for (unsigned i = 0, e = Users.size(); i != e; ++i) {
if (!Users[i])
continue;
Instruction *I = cast<Instruction>(&*Users[i]);
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
if (II->getIntrinsicID() == Intrinsic::objectsize) {
Value *Result =
lowerObjectSizeCall(II, DL, &TLI, AA, true);
replaceInstUsesWith(*I, Result);
eraseInstFromFunction(*I);
Users[i] = nullptr; }
}
}
for (unsigned i = 0, e = Users.size(); i != e; ++i) {
if (!Users[i])
continue;
Instruction *I = cast<Instruction>(&*Users[i]);
if (ICmpInst *C = dyn_cast<ICmpInst>(I)) {
replaceInstUsesWith(*C,
ConstantInt::get(Type::getInt1Ty(C->getContext()),
C->isFalseWhenEqual()));
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
for (auto *DVI : DVIs)
if (DVI->isAddressOfVariable())
ConvertDebugDeclareToDebugValue(DVI, SI, *DIB);
} else {
replaceInstUsesWith(*I, PoisonValue::get(I->getType()));
}
eraseInstFromFunction(*I);
}
if (InvokeInst *II = dyn_cast<InvokeInst>(&MI)) {
Module *M = II->getModule();
Function *F = Intrinsic::getDeclaration(M, Intrinsic::donothing);
InvokeInst::Create(F, II->getNormalDest(), II->getUnwindDest(),
None, "", II->getParent());
}
for (auto *DVI : DVIs)
if (DVI->isAddressOfVariable() || DVI->getExpression()->startsWithDeref())
DVI->eraseFromParent();
return eraseInstFromFunction(MI);
}
return nullptr;
}
static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI,
const DataLayout &DL) {
Value *Op = FI.getArgOperand(0);
BasicBlock *FreeInstrBB = FI.getParent();
BasicBlock *PredBB = FreeInstrBB->getSinglePredecessor();
if (!PredBB)
return nullptr;
BasicBlock *SuccBB;
Instruction *FreeInstrBBTerminator = FreeInstrBB->getTerminator();
if (!match(FreeInstrBBTerminator, m_UnconditionalBr(SuccBB)))
return nullptr;
if (FreeInstrBB->size() != 2) {
for (const Instruction &Inst : FreeInstrBB->instructionsWithoutDebug()) {
if (&Inst == &FI || &Inst == FreeInstrBBTerminator)
continue;
auto *Cast = dyn_cast<CastInst>(&Inst);
if (!Cast || !Cast->isNoopCast(DL))
return nullptr;
}
}
Instruction *TI = PredBB->getTerminator();
BasicBlock *TrueBB, *FalseBB;
ICmpInst::Predicate Pred;
if (!match(TI, m_Br(m_ICmp(Pred,
m_CombineOr(m_Specific(Op),
m_Specific(Op->stripPointerCasts())),
m_Zero()),
TrueBB, FalseBB)))
return nullptr;
if (Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
return nullptr;
if (SuccBB != (Pred == ICmpInst::ICMP_EQ ? TrueBB : FalseBB))
return nullptr;
assert(FreeInstrBB == (Pred == ICmpInst::ICMP_EQ ? FalseBB : TrueBB) &&
"Broken CFG: missing edge from predecessor to successor");
for (Instruction &Instr : llvm::make_early_inc_range(*FreeInstrBB)) {
if (&Instr == FreeInstrBBTerminator)
break;
Instr.moveBefore(TI);
}
assert(FreeInstrBB->size() == 1 &&
"Only the branch instruction should remain");
AttributeList Attrs = FI.getAttributes();
Attrs = Attrs.removeParamAttribute(FI.getContext(), 0, Attribute::NonNull);
Attribute Dereferenceable = Attrs.getParamAttr(0, Attribute::Dereferenceable);
if (Dereferenceable.isValid()) {
uint64_t Bytes = Dereferenceable.getDereferenceableBytes();
Attrs = Attrs.removeParamAttribute(FI.getContext(), 0,
Attribute::Dereferenceable);
Attrs = Attrs.addDereferenceableOrNullParamAttr(FI.getContext(), 0, Bytes);
}
FI.setAttributes(Attrs);
return &FI;
}
Instruction *InstCombinerImpl::visitFree(CallInst &FI, Value *Op) {
if (isa<UndefValue>(Op)) {
CreateNonTerminatorUnreachable(&FI);
return eraseInstFromFunction(FI);
}
if (isa<ConstantPointerNull>(Op))
return eraseInstFromFunction(FI);
CallInst *CI = dyn_cast<CallInst>(Op);
if (CI && CI->hasOneUse())
if (Value *ReallocatedOp = getReallocatedOperand(CI, &TLI))
return eraseInstFromFunction(*replaceInstUsesWith(*CI, ReallocatedOp));
if (MinimizeSize) {
LibFunc Func;
if (TLI.getLibFunc(FI, Func) && TLI.has(Func) && Func == LibFunc_free)
if (Instruction *I = tryToMoveFreeBeforeNullTest(FI, DL))
return I;
}
return nullptr;
}
static bool isMustTailCall(Value *V) {
if (auto *CI = dyn_cast<CallInst>(V))
return CI->isMustTailCall();
return false;
}
Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
if (RI.getNumOperands() == 0) return nullptr;
Value *ResultOp = RI.getOperand(0);
Type *VTy = ResultOp->getType();
if (!VTy->isIntegerTy() || isa<Constant>(ResultOp))
return nullptr;
if (isMustTailCall(ResultOp))
return nullptr;
KnownBits Known = computeKnownBits(ResultOp, 0, &RI);
if (Known.isConstant())
return replaceOperand(RI, 0,
Constant::getIntegerValue(VTy, Known.getConstant()));
return nullptr;
}
Instruction *InstCombinerImpl::visitUnreachableInst(UnreachableInst &I) {
while (Instruction *Prev = I.getPrevNonDebugInstruction()) {
if (Prev->isEHPad())
return nullptr;
if (!isGuaranteedToTransferExecutionToSuccessor(Prev))
return nullptr;
replaceInstUsesWith(*Prev, PoisonValue::get(Prev->getType()));
eraseInstFromFunction(*Prev);
}
assert(I.getParent()->sizeWithoutDebug() == 1 && "The block is now empty.");
return nullptr;
}
Instruction *InstCombinerImpl::visitUnconditionalBranchInst(BranchInst &BI) {
assert(BI.isUnconditional() && "Only for unconditional branches.");
auto GetLastSinkableStore = [](BasicBlock::iterator BBI) {
auto IsNoopInstrForStoreMerging = [](BasicBlock::iterator BBI) {
return BBI->isDebugOrPseudoInst() ||
(isa<BitCastInst>(BBI) && BBI->getType()->isPointerTy());
};
BasicBlock::iterator FirstInstr = BBI->getParent()->begin();
do {
if (BBI != FirstInstr)
--BBI;
} while (BBI != FirstInstr && IsNoopInstrForStoreMerging(BBI));
return dyn_cast<StoreInst>(BBI);
};
if (StoreInst *SI = GetLastSinkableStore(BasicBlock::iterator(BI)))
if (mergeStoreIntoSuccessor(*SI))
return &BI;
return nullptr;
}
Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) {
if (BI.isUnconditional())
return visitUnconditionalBranchInst(BI);
Value *X = nullptr;
if (match(&BI, m_Br(m_Not(m_Value(X)), m_BasicBlock(), m_BasicBlock())) &&
!isa<Constant>(X)) {
BI.swapSuccessors();
return replaceOperand(BI, 0, X);
}
if (!isa<ConstantInt>(BI.getCondition()) &&
BI.getSuccessor(0) == BI.getSuccessor(1))
return replaceOperand(
BI, 0, ConstantInt::getFalse(BI.getCondition()->getType()));
CmpInst::Predicate Pred;
if (match(&BI, m_Br(m_OneUse(m_FCmp(Pred, m_Value(), m_Value())),
m_BasicBlock(), m_BasicBlock())) &&
!isCanonicalPredicate(Pred)) {
CmpInst *Cond = cast<CmpInst>(BI.getCondition());
Cond->setPredicate(CmpInst::getInversePredicate(Pred));
BI.swapSuccessors();
Worklist.push(Cond);
return &BI;
}
return nullptr;
}
Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
Value *Cond = SI.getCondition();
Value *Op0;
ConstantInt *AddRHS;
if (match(Cond, m_Add(m_Value(Op0), m_ConstantInt(AddRHS)))) {
for (auto Case : SI.cases()) {
Constant *NewCase = ConstantExpr::getSub(Case.getCaseValue(), AddRHS);
assert(isa<ConstantInt>(NewCase) &&
"Result of expression should be constant");
Case.setValue(cast<ConstantInt>(NewCase));
}
return replaceOperand(SI, 0, Op0);
}
KnownBits Known = computeKnownBits(Cond, 0, &SI);
unsigned LeadingKnownZeros = Known.countMinLeadingZeros();
unsigned LeadingKnownOnes = Known.countMinLeadingOnes();
for (auto &C : SI.cases()) {
LeadingKnownZeros = std::min(
LeadingKnownZeros, C.getCaseValue()->getValue().countLeadingZeros());
LeadingKnownOnes = std::min(
LeadingKnownOnes, C.getCaseValue()->getValue().countLeadingOnes());
}
unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);
if (NewWidth > 0 && NewWidth < Known.getBitWidth() &&
shouldChangeType(Known.getBitWidth(), NewWidth)) {
IntegerType *Ty = IntegerType::get(SI.getContext(), NewWidth);
Builder.SetInsertPoint(&SI);
Value *NewCond = Builder.CreateTrunc(Cond, Ty, "trunc");
for (auto Case : SI.cases()) {
APInt TruncatedCase = Case.getCaseValue()->getValue().trunc(NewWidth);
Case.setValue(ConstantInt::get(SI.getContext(), TruncatedCase));
}
return replaceOperand(SI, 0, NewCond);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitExtractValueInst(ExtractValueInst &EV) {
Value *Agg = EV.getAggregateOperand();
if (!EV.hasIndices())
return replaceInstUsesWith(EV, Agg);
if (Value *V = simplifyExtractValueInst(Agg, EV.getIndices(),
SQ.getWithInstruction(&EV)))
return replaceInstUsesWith(EV, V);
if (InsertValueInst *IV = dyn_cast<InsertValueInst>(Agg)) {
const unsigned *exti, *exte, *insi, *inse;
for (exti = EV.idx_begin(), insi = IV->idx_begin(),
exte = EV.idx_end(), inse = IV->idx_end();
exti != exte && insi != inse;
++exti, ++insi) {
if (*insi != *exti)
return ExtractValueInst::Create(IV->getAggregateOperand(),
EV.getIndices());
}
if (exti == exte && insi == inse)
return replaceInstUsesWith(EV, IV->getInsertedValueOperand());
if (exti == exte) {
Value *NewEV = Builder.CreateExtractValue(IV->getAggregateOperand(),
EV.getIndices());
return InsertValueInst::Create(NewEV, IV->getInsertedValueOperand(),
makeArrayRef(insi, inse));
}
if (insi == inse)
return ExtractValueInst::Create(IV->getInsertedValueOperand(),
makeArrayRef(exti, exte));
}
if (WithOverflowInst *WO = dyn_cast<WithOverflowInst>(Agg)) {
Intrinsic::ID OvID = WO->getIntrinsicID();
if (*EV.idx_begin() == 0 &&
(OvID == Intrinsic::smul_with_overflow ||
OvID == Intrinsic::umul_with_overflow) &&
match(WO->getArgOperand(1), m_AllOnes())) {
return BinaryOperator::CreateNeg(WO->getArgOperand(0));
}
if (WO->hasOneUse()) {
if (*EV.idx_begin() == 0) {
Instruction::BinaryOps BinOp = WO->getBinaryOp();
Value *LHS = WO->getLHS(), *RHS = WO->getRHS();
replaceInstUsesWith(*WO, PoisonValue::get(WO->getType()));
eraseInstFromFunction(*WO);
return BinaryOperator::Create(BinOp, LHS, RHS);
}
assert(*EV.idx_begin() == 1 &&
"unexpected extract index for overflow inst");
const APInt *C;
if (match(WO->getRHS(), m_APInt(C))) {
ConstantRange NWR =
ConstantRange::makeExactNoWrapRegion(WO->getBinaryOp(), *C,
WO->getNoWrapKind());
CmpInst::Predicate Pred;
APInt NewRHSC, Offset;
NWR.getEquivalentICmp(Pred, NewRHSC, Offset);
auto *OpTy = WO->getRHS()->getType();
auto *NewLHS = WO->getLHS();
if (Offset != 0)
NewLHS = Builder.CreateAdd(NewLHS, ConstantInt::get(OpTy, Offset));
return new ICmpInst(ICmpInst::getInversePredicate(Pred), NewLHS,
ConstantInt::get(OpTy, NewRHSC));
}
}
}
if (LoadInst *L = dyn_cast<LoadInst>(Agg))
if (L->isSimple() && L->hasOneUse()) {
SmallVector<Value*, 4> Indices;
Indices.push_back(Builder.getInt32(0));
for (unsigned Idx : EV.indices())
Indices.push_back(Builder.getInt32(Idx));
Builder.SetInsertPoint(L);
Value *GEP = Builder.CreateInBoundsGEP(L->getType(),
L->getPointerOperand(), Indices);
Instruction *NL = Builder.CreateLoad(EV.getType(), GEP);
NL->setAAMetadata(L->getAAMetadata());
return replaceInstUsesWith(EV, NL);
}
return nullptr;
}
static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) {
switch (Personality) {
case EHPersonality::GNU_C:
case EHPersonality::GNU_C_SjLj:
case EHPersonality::Rust:
return false;
case EHPersonality::Unknown:
return false;
case EHPersonality::GNU_Ada:
return false;
case EHPersonality::GNU_CXX:
case EHPersonality::GNU_CXX_SjLj:
case EHPersonality::GNU_ObjC:
case EHPersonality::MSVC_X86SEH:
case EHPersonality::MSVC_TableSEH:
case EHPersonality::MSVC_CXX:
case EHPersonality::CoreCLR:
case EHPersonality::Wasm_CXX:
case EHPersonality::XL_CXX:
return TypeInfo->isNullValue();
}
llvm_unreachable("invalid enum");
}
static bool shorter_filter(const Value *LHS, const Value *RHS) {
return
cast<ArrayType>(LHS->getType())->getNumElements()
<
cast<ArrayType>(RHS->getType())->getNumElements();
}
Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
EHPersonality Personality =
classifyEHPersonality(LI.getParent()->getParent()->getPersonalityFn());
bool MakeNewInstruction = false; SmallVector<Constant *, 16> NewClauses; bool CleanupFlag = LI.isCleanup();
SmallPtrSet<Value *, 16> AlreadyCaught; for (unsigned i = 0, e = LI.getNumClauses(); i != e; ++i) {
bool isLastClause = i + 1 == e;
if (LI.isCatch(i)) {
Constant *CatchClause = LI.getClause(i);
Constant *TypeInfo = CatchClause->stripPointerCasts();
if (AlreadyCaught.insert(TypeInfo).second) {
NewClauses.push_back(CatchClause);
} else {
MakeNewInstruction = true;
}
if (isCatchAll(Personality, TypeInfo)) {
if (!isLastClause)
MakeNewInstruction = true;
CleanupFlag = false;
break;
}
} else {
assert(LI.isFilter(i) && "Unsupported landingpad clause!");
Constant *FilterClause = LI.getClause(i);
ArrayType *FilterType = cast<ArrayType>(FilterClause->getType());
unsigned NumTypeInfos = FilterType->getNumElements();
if (!NumTypeInfos) {
NewClauses.push_back(FilterClause);
if (!isLastClause)
MakeNewInstruction = true;
CleanupFlag = false;
break;
}
bool MakeNewFilter = false; SmallVector<Constant *, 16> NewFilterElts; if (isa<ConstantAggregateZero>(FilterClause)) {
assert(NumTypeInfos > 0 && "Should have handled empty filter already!");
Constant *TypeInfo =
Constant::getNullValue(FilterType->getElementType());
if (isCatchAll(Personality, TypeInfo)) {
MakeNewInstruction = true;
continue;
}
NewFilterElts.push_back(TypeInfo);
if (NumTypeInfos > 1)
MakeNewFilter = true;
} else {
ConstantArray *Filter = cast<ConstantArray>(FilterClause);
SmallPtrSet<Value *, 16> SeenInFilter; NewFilterElts.reserve(NumTypeInfos);
bool SawCatchAll = false;
for (unsigned j = 0; j != NumTypeInfos; ++j) {
Constant *Elt = Filter->getOperand(j);
Constant *TypeInfo = Elt->stripPointerCasts();
if (isCatchAll(Personality, TypeInfo)) {
SawCatchAll = true;
break;
}
if (SeenInFilter.insert(TypeInfo).second)
NewFilterElts.push_back(cast<Constant>(Elt));
}
if (SawCatchAll) {
MakeNewInstruction = true;
continue;
}
if (NewFilterElts.size() < NumTypeInfos)
MakeNewFilter = true;
}
if (MakeNewFilter) {
FilterType = ArrayType::get(FilterType->getElementType(),
NewFilterElts.size());
FilterClause = ConstantArray::get(FilterType, NewFilterElts);
MakeNewInstruction = true;
}
NewClauses.push_back(FilterClause);
if (MakeNewFilter && !NewFilterElts.size()) {
assert(MakeNewInstruction && "New filter but not a new instruction!");
CleanupFlag = false;
break;
}
}
}
for (unsigned i = 0, e = NewClauses.size(); i + 1 < e; ) {
unsigned j;
for (j = i; j != e; ++j)
if (!isa<ArrayType>(NewClauses[j]->getType()))
break;
for (unsigned k = i; k + 1 < j; ++k)
if (shorter_filter(NewClauses[k+1], NewClauses[k])) {
std::stable_sort(NewClauses.begin() + i, NewClauses.begin() + j,
shorter_filter);
MakeNewInstruction = true;
break;
}
i = j + 1;
}
for (unsigned i = 0; i + 1 < NewClauses.size(); ++i) {
Value *Filter = NewClauses[i];
ArrayType *FTy = dyn_cast<ArrayType>(Filter->getType());
if (!FTy)
continue;
unsigned FElts = FTy->getNumElements();
for (unsigned j = NewClauses.size() - 1; j != i; --j) {
Value *LFilter = NewClauses[j];
ArrayType *LTy = dyn_cast<ArrayType>(LFilter->getType());
if (!LTy)
continue;
SmallVectorImpl<Constant *>::iterator J = NewClauses.begin() + j;
if (!FElts) {
NewClauses.erase(J);
MakeNewInstruction = true;
continue;
}
unsigned LElts = LTy->getNumElements();
if (FElts > LElts)
continue;
if (isa<ConstantAggregateZero>(LFilter)) { if (isa<ConstantAggregateZero>(Filter)) {
assert(FElts <= LElts && "Should have handled this case earlier!");
NewClauses.erase(J);
MakeNewInstruction = true;
}
continue;
}
ConstantArray *LArray = cast<ConstantArray>(LFilter);
if (isa<ConstantAggregateZero>(Filter)) { assert(FElts > 0 && "Should have eliminated the empty filter earlier!");
for (unsigned l = 0; l != LElts; ++l)
if (LArray->getOperand(l)->isNullValue()) {
NewClauses.erase(J);
MakeNewInstruction = true;
break;
}
continue;
}
ConstantArray *FArray = cast<ConstantArray>(Filter);
bool AllFound = true;
for (unsigned f = 0; f != FElts; ++f) {
Value *FTypeInfo = FArray->getOperand(f)->stripPointerCasts();
AllFound = false;
for (unsigned l = 0; l != LElts; ++l) {
Value *LTypeInfo = LArray->getOperand(l)->stripPointerCasts();
if (LTypeInfo == FTypeInfo) {
AllFound = true;
break;
}
}
if (!AllFound)
break;
}
if (AllFound) {
NewClauses.erase(J);
MakeNewInstruction = true;
}
}
}
if (MakeNewInstruction) {
LandingPadInst *NLI = LandingPadInst::Create(LI.getType(),
NewClauses.size());
for (unsigned i = 0, e = NewClauses.size(); i != e; ++i)
NLI->addClause(NewClauses[i]);
if (NewClauses.empty())
CleanupFlag = true;
NLI->setCleanup(CleanupFlag);
return NLI;
}
if (LI.isCleanup() != CleanupFlag) {
assert(!CleanupFlag && "Adding a cleanup, not removing one?!");
LI.setCleanup(CleanupFlag);
return &LI;
}
return nullptr;
}
Value *
InstCombinerImpl::pushFreezeToPreventPoisonFromPropagating(FreezeInst &OrigFI) {
auto *OrigOp = OrigFI.getOperand(0);
auto *OrigOpInst = dyn_cast<Instruction>(OrigOp);
if (!OrigOpInst || !OrigOpInst->hasOneUse() || isa<PHINode>(OrigOp))
return nullptr;
if (canCreateUndefOrPoison(cast<Operator>(OrigOp), false))
return nullptr;
Use *MaybePoisonOperand = nullptr;
for (Use &U : OrigOpInst->operands()) {
if (isGuaranteedNotToBeUndefOrPoison(U.get()))
continue;
if (!MaybePoisonOperand)
MaybePoisonOperand = &U;
else
return nullptr;
}
OrigOpInst->dropPoisonGeneratingFlags();
if (!MaybePoisonOperand)
return OrigOp;
Builder.SetInsertPoint(OrigOpInst);
auto *FrozenMaybePoisonOperand = Builder.CreateFreeze(
MaybePoisonOperand->get(), MaybePoisonOperand->get()->getName() + ".fr");
replaceUse(*MaybePoisonOperand, FrozenMaybePoisonOperand);
return OrigOp;
}
Instruction *InstCombinerImpl::foldFreezeIntoRecurrence(FreezeInst &FI,
PHINode *PN) {
Use *StartU = nullptr;
SmallVector<Value *> Worklist;
for (Use &U : PN->incoming_values()) {
if (DT.dominates(PN->getParent(), PN->getIncomingBlock(U))) {
Worklist.push_back(U.get());
continue;
}
if (StartU)
return nullptr;
StartU = &U;
}
if (!StartU || Worklist.empty())
return nullptr;
Value *StartV = StartU->get();
BasicBlock *StartBB = PN->getIncomingBlock(*StartU);
bool StartNeedsFreeze = !isGuaranteedNotToBeUndefOrPoison(StartV);
if (StartNeedsFreeze && StartBB->getTerminator() == StartV)
return nullptr;
SmallPtrSet<Value *, 32> Visited;
SmallVector<Instruction *> DropFlags;
while (!Worklist.empty()) {
Value *V = Worklist.pop_back_val();
if (!Visited.insert(V).second)
continue;
if (Visited.size() > 32)
return nullptr;
if (V == PN || isGuaranteedNotToBeUndefOrPoison(V))
continue;
Instruction *I = dyn_cast<Instruction>(V);
if (!I || canCreateUndefOrPoison(cast<Operator>(I),
false))
return nullptr;
DropFlags.push_back(I);
append_range(Worklist, I->operands());
}
for (Instruction *I : DropFlags)
I->dropPoisonGeneratingFlags();
if (StartNeedsFreeze) {
Builder.SetInsertPoint(StartBB->getTerminator());
Value *FrozenStartV = Builder.CreateFreeze(StartV,
StartV->getName() + ".fr");
replaceUse(*StartU, FrozenStartV);
}
return replaceInstUsesWith(FI, PN);
}
bool InstCombinerImpl::freezeOtherUses(FreezeInst &FI) {
Value *Op = FI.getOperand(0);
if (isa<Constant>(Op) || Op->hasOneUse())
return false;
Instruction *MoveBefore = nullptr;
if (isa<Argument>(Op)) {
MoveBefore = &FI.getFunction()->getEntryBlock().front();
while (isa<AllocaInst>(MoveBefore))
MoveBefore = MoveBefore->getNextNode();
} else if (auto *PN = dyn_cast<PHINode>(Op)) {
MoveBefore = PN->getParent()->getFirstNonPHI();
} else if (auto *II = dyn_cast<InvokeInst>(Op)) {
MoveBefore = II->getNormalDest()->getFirstNonPHI();
} else if (auto *CB = dyn_cast<CallBrInst>(Op)) {
MoveBefore = CB->getDefaultDest()->getFirstNonPHI();
} else {
auto *I = cast<Instruction>(Op);
assert(!I->isTerminator() && "Cannot be a terminator");
MoveBefore = I->getNextNode();
}
bool Changed = false;
if (&FI != MoveBefore) {
FI.moveBefore(MoveBefore);
Changed = true;
}
Op->replaceUsesWithIf(&FI, [&](Use &U) -> bool {
bool Dominates = DT.dominates(&FI, U);
Changed |= Dominates;
return Dominates;
});
return Changed;
}
Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) {
Value *Op0 = I.getOperand(0);
if (Value *V = simplifyFreezeInst(Op0, SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);
if (auto *PN = dyn_cast<PHINode>(Op0)) {
if (Instruction *NV = foldOpIntoPhi(I, PN))
return NV;
if (Instruction *NV = foldFreezeIntoRecurrence(I, PN))
return NV;
}
if (Value *NI = pushFreezeToPreventPoisonFromPropagating(I))
return replaceInstUsesWith(I, NI);
auto getUndefReplacement = [&I](Type *Ty) {
Constant *BestValue = nullptr;
Constant *NullValue = Constant::getNullValue(Ty);
for (const auto *U : I.users()) {
Constant *C = NullValue;
if (match(U, m_Or(m_Value(), m_Value())))
C = ConstantInt::getAllOnesValue(Ty);
else if (match(U, m_Select(m_Specific(&I), m_Constant(), m_Value())))
C = ConstantInt::getTrue(Ty);
if (!BestValue)
BestValue = C;
else if (BestValue != C)
BestValue = NullValue;
}
assert(BestValue && "Must have at least one use");
return BestValue;
};
if (match(Op0, m_Undef()))
return replaceInstUsesWith(I, getUndefReplacement(I.getType()));
Constant *C;
if (match(Op0, m_Constant(C)) && C->containsUndefOrPoisonElement()) {
Constant *ReplaceC = getUndefReplacement(I.getType()->getScalarType());
return replaceInstUsesWith(I, Constant::replaceUndefsWith(C, ReplaceC));
}
if (freezeOtherUses(I))
return &I;
return nullptr;
}
static bool SoleWriteToDeadLocal(Instruction *I, TargetLibraryInfo &TLI) {
auto *CB = dyn_cast<CallBase>(I);
if (!CB)
return false;
Optional<MemoryLocation> Dest = MemoryLocation::getForDest(CB, TLI);
if (!Dest)
return false;
auto *AI = dyn_cast<AllocaInst>(getUnderlyingObject(Dest->Ptr));
if (!AI)
return false;
SmallVector<const User *> AllocaUsers;
SmallPtrSet<const User *, 4> Visited;
auto pushUsers = [&](const Instruction &I) {
for (const User *U : I.users()) {
if (Visited.insert(U).second)
AllocaUsers.push_back(U);
}
};
pushUsers(*AI);
while (!AllocaUsers.empty()) {
auto *UserI = cast<Instruction>(AllocaUsers.pop_back_val());
if (isa<BitCastInst>(UserI) || isa<GetElementPtrInst>(UserI) ||
isa<AddrSpaceCastInst>(UserI)) {
pushUsers(*UserI);
continue;
}
if (UserI == CB)
continue;
return false;
}
return true;
}
static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock,
TargetLibraryInfo &TLI) {
BasicBlock *SrcBlock = I->getParent();
if (isa<PHINode>(I) || I->isEHPad() || I->mayThrow() || !I->willReturn() ||
I->isTerminator())
return false;
if (isa<AllocaInst>(I))
return false;
if (isa<CatchSwitchInst>(DestBlock->getTerminator()))
return false;
if (auto *CI = dyn_cast<CallInst>(I)) {
if (CI->isConvergent())
return false;
}
if (I->mayWriteToMemory()) {
if (!SoleWriteToDeadLocal(I, TLI))
return false;
}
if (I->mayReadFromMemory()) {
if (DestBlock->getUniquePredecessor() != I->getParent())
return false;
for (BasicBlock::iterator Scan = std::next(I->getIterator()),
E = I->getParent()->end();
Scan != E; ++Scan)
if (Scan->mayWriteToMemory())
return false;
}
I->dropDroppableUses([DestBlock](const Use *U) {
if (auto *I = dyn_cast<Instruction>(U->getUser()))
return I->getParent() != DestBlock;
return true;
});
BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt();
I->moveBefore(&*InsertPos);
++NumSunkInst;
SmallVector<DbgVariableIntrinsic *, 2> DbgUsers;
findDbgUsers(DbgUsers, I);
SmallVector<DbgVariableIntrinsic *, 2> DbgUsersToSink;
for (DbgVariableIntrinsic *DVI : DbgUsers)
if (DVI->getParent() == SrcBlock)
DbgUsersToSink.push_back(DVI);
llvm::sort(DbgUsersToSink,
[](auto *A, auto *B) { return B->comesBefore(A); });
SmallVector<DbgVariableIntrinsic *, 2> DIIClones;
SmallSet<DebugVariable, 4> SunkVariables;
for (auto User : DbgUsersToSink) {
if (isa<DbgDeclareInst>(User))
continue;
DebugVariable DbgUserVariable =
DebugVariable(User->getVariable(), User->getExpression(),
User->getDebugLoc()->getInlinedAt());
if (!SunkVariables.insert(DbgUserVariable).second)
continue;
DIIClones.emplace_back(cast<DbgVariableIntrinsic>(User->clone()));
if (isa<DbgDeclareInst>(User) && isa<CastInst>(I))
DIIClones.back()->replaceVariableLocationOp(I, I->getOperand(0));
LLVM_DEBUG(dbgs() << "CLONE: " << *DIIClones.back() << '\n');
}
if (!DIIClones.empty()) {
salvageDebugInfoForDbgValues(*I, DbgUsers);
for (auto &DIIClone : llvm::reverse(DIIClones)) {
DIIClone->insertBefore(&*InsertPos);
LLVM_DEBUG(dbgs() << "SINK: " << *DIIClone << '\n');
}
}
return true;
}
bool InstCombinerImpl::run() {
while (!Worklist.isEmpty()) {
while (Instruction *I = Worklist.popDeferred()) {
if (isInstructionTriviallyDead(I, &TLI)) {
eraseInstFromFunction(*I);
++NumDeadInst;
continue;
}
Worklist.push(I);
}
Instruction *I = Worklist.removeOne();
if (I == nullptr) continue;
if (isInstructionTriviallyDead(I, &TLI)) {
eraseInstFromFunction(*I);
++NumDeadInst;
continue;
}
if (!DebugCounter::shouldExecute(VisitCounter))
continue;
if (!I->use_empty() &&
(I->getNumOperands() == 0 || isa<Constant>(I->getOperand(0)))) {
if (Constant *C = ConstantFoldInstruction(I, DL, &TLI)) {
LLVM_DEBUG(dbgs() << "IC: ConstFold to: " << *C << " from: " << *I
<< '\n');
replaceInstUsesWith(*I, C);
++NumConstProp;
if (isInstructionTriviallyDead(I, &TLI))
eraseInstFromFunction(*I);
MadeIRChange = true;
continue;
}
}
auto getOptionalSinkBlockForInst =
[this](Instruction *I) -> Optional<BasicBlock *> {
if (!EnableCodeSinking)
return None;
BasicBlock *BB = I->getParent();
BasicBlock *UserParent = nullptr;
unsigned NumUsers = 0;
for (auto *U : I->users()) {
if (U->isDroppable())
continue;
if (NumUsers > MaxSinkNumUsers)
return None;
Instruction *UserInst = cast<Instruction>(U);
if (PHINode *PN = dyn_cast<PHINode>(UserInst)) {
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
if (PN->getIncomingValue(i) == I) {
if (UserParent && UserParent != PN->getIncomingBlock(i))
return None;
UserParent = PN->getIncomingBlock(i);
}
}
assert(UserParent && "expected to find user block!");
} else {
if (UserParent && UserParent != UserInst->getParent())
return None;
UserParent = UserInst->getParent();
}
if (NumUsers == 0) {
if (UserParent == BB || !DT.isReachableFromEntry(UserParent))
return None;
auto *Term = UserParent->getTerminator();
if (UserParent->getUniquePredecessor() != BB && !succ_empty(Term))
return None;
assert(DT.dominates(BB, UserParent) && "Dominance relation broken?");
}
NumUsers++;
}
if (!UserParent)
return None;
return UserParent;
};
auto OptBB = getOptionalSinkBlockForInst(I);
if (OptBB) {
auto *UserParent = *OptBB;
if (TryToSinkInstruction(I, UserParent, TLI)) {
LLVM_DEBUG(dbgs() << "IC: Sink: " << *I << '\n');
MadeIRChange = true;
for (Use &U : I->operands())
if (Instruction *OpI = dyn_cast<Instruction>(U.get()))
Worklist.push(OpI);
}
}
Builder.SetInsertPoint(I);
Builder.CollectMetadataToCopy(
I, {LLVMContext::MD_dbg, LLVMContext::MD_annotation});
#ifndef NDEBUG
std::string OrigI;
#endif
LLVM_DEBUG(raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str(););
LLVM_DEBUG(dbgs() << "IC: Visiting: " << OrigI << '\n');
if (Instruction *Result = visit(*I)) {
++NumCombined;
if (Result != I) {
LLVM_DEBUG(dbgs() << "IC: Old = " << *I << '\n'
<< " New = " << *Result << '\n');
Result->copyMetadata(*I,
{LLVMContext::MD_dbg, LLVMContext::MD_annotation});
I->replaceAllUsesWith(Result);
Result->takeName(I);
BasicBlock *InstParent = I->getParent();
BasicBlock::iterator InsertPos = I->getIterator();
if (isa<PHINode>(Result) != isa<PHINode>(I)) {
if (isa<PHINode>(I)) InsertPos = InstParent->getFirstInsertionPt();
else InsertPos = InstParent->getFirstNonPHI()->getIterator();
}
InstParent->getInstList().insert(InsertPos, Result);
Worklist.pushUsersToWorkList(*Result);
Worklist.push(Result);
eraseInstFromFunction(*I);
} else {
LLVM_DEBUG(dbgs() << "IC: Mod = " << OrigI << '\n'
<< " New = " << *I << '\n');
if (isInstructionTriviallyDead(I, &TLI)) {
eraseInstFromFunction(*I);
} else {
Worklist.pushUsersToWorkList(*I);
Worklist.push(I);
}
}
MadeIRChange = true;
}
}
Worklist.zap();
return MadeIRChange;
}
class AliasScopeTracker {
SmallPtrSet<const MDNode *, 8> UsedAliasScopesAndLists;
SmallPtrSet<const MDNode *, 8> UsedNoAliasScopesAndLists;
public:
void analyse(Instruction *I) {
if (!I->hasMetadataOtherThanDebugLoc())
return;
auto Track = [](Metadata *ScopeList, auto &Container) {
const auto *MDScopeList = dyn_cast_or_null<MDNode>(ScopeList);
if (!MDScopeList || !Container.insert(MDScopeList).second)
return;
for (auto &MDOperand : MDScopeList->operands())
if (auto *MDScope = dyn_cast<MDNode>(MDOperand))
Container.insert(MDScope);
};
Track(I->getMetadata(LLVMContext::MD_alias_scope), UsedAliasScopesAndLists);
Track(I->getMetadata(LLVMContext::MD_noalias), UsedNoAliasScopesAndLists);
}
bool isNoAliasScopeDeclDead(Instruction *Inst) {
NoAliasScopeDeclInst *Decl = dyn_cast<NoAliasScopeDeclInst>(Inst);
if (!Decl)
return false;
assert(Decl->use_empty() &&
"llvm.experimental.noalias.scope.decl in use ?");
const MDNode *MDSL = Decl->getScopeList();
assert(MDSL->getNumOperands() == 1 &&
"llvm.experimental.noalias.scope should refer to a single scope");
auto &MDOperand = MDSL->getOperand(0);
if (auto *MD = dyn_cast<MDNode>(MDOperand))
return !UsedAliasScopesAndLists.contains(MD) ||
!UsedNoAliasScopesAndLists.contains(MD);
return true;
}
};
static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL,
const TargetLibraryInfo *TLI,
InstructionWorklist &ICWorklist) {
bool MadeIRChange = false;
SmallPtrSet<BasicBlock *, 32> Visited;
SmallVector<BasicBlock*, 256> Worklist;
Worklist.push_back(&F.front());
SmallVector<Instruction *, 128> InstrsForInstructionWorklist;
DenseMap<Constant *, Constant *> FoldedConstants;
AliasScopeTracker SeenAliasScopes;
do {
BasicBlock *BB = Worklist.pop_back_val();
if (!Visited.insert(BB).second)
continue;
for (Instruction &Inst : llvm::make_early_inc_range(*BB)) {
if (!Inst.use_empty() &&
(Inst.getNumOperands() == 0 || isa<Constant>(Inst.getOperand(0))))
if (Constant *C = ConstantFoldInstruction(&Inst, DL, TLI)) {
LLVM_DEBUG(dbgs() << "IC: ConstFold to: " << *C << " from: " << Inst
<< '\n');
Inst.replaceAllUsesWith(C);
++NumConstProp;
if (isInstructionTriviallyDead(&Inst, TLI))
Inst.eraseFromParent();
MadeIRChange = true;
continue;
}
for (Use &U : Inst.operands()) {
if (!isa<ConstantVector>(U) && !isa<ConstantExpr>(U))
continue;
auto *C = cast<Constant>(U);
Constant *&FoldRes = FoldedConstants[C];
if (!FoldRes)
FoldRes = ConstantFoldConstant(C, DL, TLI);
if (FoldRes != C) {
LLVM_DEBUG(dbgs() << "IC: ConstFold operand of: " << Inst
<< "\n Old = " << *C
<< "\n New = " << *FoldRes << '\n');
U = FoldRes;
MadeIRChange = true;
}
}
if (!Inst.isDebugOrPseudoInst()) {
InstrsForInstructionWorklist.push_back(&Inst);
SeenAliasScopes.analyse(&Inst);
}
}
Instruction *TI = BB->getTerminator();
if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
if (BI->isConditional() && isa<ConstantInt>(BI->getCondition())) {
bool CondVal = cast<ConstantInt>(BI->getCondition())->getZExtValue();
BasicBlock *ReachableBB = BI->getSuccessor(!CondVal);
Worklist.push_back(ReachableBB);
continue;
}
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
if (ConstantInt *Cond = dyn_cast<ConstantInt>(SI->getCondition())) {
Worklist.push_back(SI->findCaseValue(Cond)->getCaseSuccessor());
continue;
}
}
append_range(Worklist, successors(TI));
} while (!Worklist.empty());
for (BasicBlock &BB : F) {
if (Visited.count(&BB))
continue;
unsigned NumDeadInstInBB;
unsigned NumDeadDbgInstInBB;
std::tie(NumDeadInstInBB, NumDeadDbgInstInBB) =
removeAllNonTerminatorAndEHPadInstructions(&BB);
MadeIRChange |= NumDeadInstInBB + NumDeadDbgInstInBB > 0;
NumDeadInst += NumDeadInstInBB;
}
ICWorklist.reserve(InstrsForInstructionWorklist.size());
for (Instruction *Inst : reverse(InstrsForInstructionWorklist)) {
if (isInstructionTriviallyDead(Inst, TLI) ||
SeenAliasScopes.isNoAliasScopeDeclDead(Inst)) {
++NumDeadInst;
LLVM_DEBUG(dbgs() << "IC: DCE: " << *Inst << '\n');
salvageDebugInfo(*Inst);
Inst->eraseFromParent();
MadeIRChange = true;
continue;
}
ICWorklist.push(Inst);
}
return MadeIRChange;
}
static bool combineInstructionsOverFunction(
Function &F, InstructionWorklist &Worklist, AliasAnalysis *AA,
AssumptionCache &AC, TargetLibraryInfo &TLI, TargetTransformInfo &TTI,
DominatorTree &DT, OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI,
ProfileSummaryInfo *PSI, unsigned MaxIterations, LoopInfo *LI) {
auto &DL = F.getParent()->getDataLayout();
MaxIterations = std::min(MaxIterations, LimitMaxIterations.getValue());
IRBuilder<TargetFolder, IRBuilderCallbackInserter> Builder(
F.getContext(), TargetFolder(DL),
IRBuilderCallbackInserter([&Worklist, &AC](Instruction *I) {
Worklist.add(I);
if (auto *Assume = dyn_cast<AssumeInst>(I))
AC.registerAssumption(Assume);
}));
bool MadeIRChange = false;
if (ShouldLowerDbgDeclare)
MadeIRChange = LowerDbgDeclare(F);
unsigned Iteration = 0;
while (true) {
++NumWorklistIterations;
++Iteration;
if (Iteration > InfiniteLoopDetectionThreshold) {
report_fatal_error(
"Instruction Combining seems stuck in an infinite loop after " +
Twine(InfiniteLoopDetectionThreshold) + " iterations.");
}
if (Iteration > MaxIterations) {
LLVM_DEBUG(dbgs() << "\n\n[IC] Iteration limit #" << MaxIterations
<< " on " << F.getName()
<< " reached; stopping before reaching a fixpoint\n");
break;
}
LLVM_DEBUG(dbgs() << "\n\nINSTCOMBINE ITERATION #" << Iteration << " on "
<< F.getName() << "\n");
MadeIRChange |= prepareICWorklistFromFunction(F, DL, &TLI, Worklist);
InstCombinerImpl IC(Worklist, Builder, F.hasMinSize(), AA, AC, TLI, TTI, DT,
ORE, BFI, PSI, DL, LI);
IC.MaxArraySizeForCombine = MaxArraySize;
if (!IC.run())
break;
MadeIRChange = true;
}
return MadeIRChange;
}
InstCombinePass::InstCombinePass() : MaxIterations(LimitMaxIterations) {}
InstCombinePass::InstCombinePass(unsigned MaxIterations)
: MaxIterations(MaxIterations) {}
PreservedAnalyses InstCombinePass::run(Function &F,
FunctionAnalysisManager &AM) {
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
auto *LI = AM.getCachedResult<LoopAnalysis>(F);
auto *AA = &AM.getResult<AAManager>(F);
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
auto *BFI = (PSI && PSI->hasProfileSummary()) ?
&AM.getResult<BlockFrequencyAnalysis>(F) : nullptr;
if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE,
BFI, PSI, MaxIterations, LI))
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
return PA;
}
void InstructionCombiningPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
AU.addPreserved<AAResultsWrapperPass>();
AU.addPreserved<BasicAAWrapperPass>();
AU.addPreserved<GlobalsAAWrapperPass>();
AU.addRequired<ProfileSummaryInfoWrapperPass>();
LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
}
bool InstructionCombiningPass::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
auto AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>();
auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
ProfileSummaryInfo *PSI =
&getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
BlockFrequencyInfo *BFI =
(PSI && PSI->hasProfileSummary()) ?
&getAnalysis<LazyBlockFrequencyInfoPass>().getBFI() :
nullptr;
return combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE,
BFI, PSI, MaxIterations, LI);
}
char InstructionCombiningPass::ID = 0;
InstructionCombiningPass::InstructionCombiningPass()
: FunctionPass(ID), MaxIterations(InstCombineDefaultMaxIterations) {
initializeInstructionCombiningPassPass(*PassRegistry::getPassRegistry());
}
InstructionCombiningPass::InstructionCombiningPass(unsigned MaxIterations)
: FunctionPass(ID), MaxIterations(MaxIterations) {
initializeInstructionCombiningPassPass(*PassRegistry::getPassRegistry());
}
INITIALIZE_PASS_BEGIN(InstructionCombiningPass, "instcombine",
"Combine redundant instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LazyBlockFrequencyInfoPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_END(InstructionCombiningPass, "instcombine",
"Combine redundant instructions", false, false)
void llvm::initializeInstCombine(PassRegistry &Registry) {
initializeInstructionCombiningPassPass(Registry);
}
void LLVMInitializeInstCombine(LLVMPassRegistryRef R) {
initializeInstructionCombiningPassPass(*unwrap(R));
}
FunctionPass *llvm::createInstructionCombiningPass() {
return new InstructionCombiningPass();
}
FunctionPass *llvm::createInstructionCombiningPass(unsigned MaxIterations) {
return new InstructionCombiningPass(MaxIterations);
}
void LLVMAddInstructionCombiningPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createInstructionCombiningPass());
}