InstructionCombining.cpp [plain text]
#define DEBUG_TYPE "instcombine"
#include "llvm/Transforms/Scalar.h"
#include "InstCombine.h"
#include "llvm-c/Initialization.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/Support/PatternMatch.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include <algorithm>
#include <climits>
using namespace llvm;
using namespace llvm::PatternMatch;
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");
static cl::opt<bool> UnsafeFPShrink("enable-double-float-shrink", cl::Hidden,
cl::init(false),
cl::desc("Enable unsafe double to float "
"shrinking for math lib calls"));
void llvm::initializeInstCombine(PassRegistry &Registry) {
initializeInstCombinerPass(Registry);
}
void LLVMInitializeInstCombine(LLVMPassRegistryRef R) {
initializeInstCombine(*unwrap(R));
}
char InstCombiner::ID = 0;
INITIALIZE_PASS_BEGIN(InstCombiner, "instcombine",
"Combine redundant instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo)
INITIALIZE_PASS_END(InstCombiner, "instcombine",
"Combine redundant instructions", false, false)
void InstCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<TargetLibraryInfo>();
}
Value *InstCombiner::EmitGEPOffset(User *GEP) {
return llvm::EmitGEPOffset(Builder, *getDataLayout(), GEP);
}
bool InstCombiner::ShouldChangeType(Type *From, Type *To) const {
assert(From->isIntegerTy() && To->isIntegerTy());
if (!TD) return false;
unsigned FromWidth = From->getPrimitiveSizeInBits();
unsigned ToWidth = To->getPrimitiveSizeInBits();
bool FromLegal = TD->isLegalInteger(FromWidth);
bool ToLegal = TD->isLegalInteger(ToWidth);
if (FromLegal && !ToLegal)
return false;
if (!FromLegal && !ToLegal && ToWidth > FromWidth)
return false;
return true;
}
static bool MaintainNoSignedWrap(BinaryOperator &I, Value *B, Value *C) {
OverflowingBinaryOperator *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;
}
ConstantInt *CB = dyn_cast<ConstantInt>(B);
ConstantInt *CC = dyn_cast<ConstantInt>(C);
if (!CB || !CC) {
return false;
}
const APInt &BVal = CB->getValue();
const APInt &CVal = CC->getValue();
bool Overflow = false;
if (Opcode == Instruction::Add) {
BVal.sadd_ov(CVal, Overflow);
} else {
BVal.ssub_ov(CVal, Overflow);
}
return !Overflow;
}
bool InstCombiner::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, TD)) {
I.setOperand(0, A);
I.setOperand(1, V);
if (MaintainNoSignedWrap(I, B, C) &&
(!Op0 || (isa<BinaryOperator>(Op0) && Op0->hasNoSignedWrap()))) {
I.clearSubclassOptionalData();
I.setHasNoSignedWrap(true);
} else {
I.clearSubclassOptionalData();
}
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, TD)) {
I.setOperand(0, V);
I.setOperand(1, C);
I.clearSubclassOptionalData();
Changed = true;
++NumReassoc;
continue;
}
}
}
if (I.isAssociative() && I.isCommutative()) {
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, TD)) {
I.setOperand(0, V);
I.setOperand(1, B);
I.clearSubclassOptionalData();
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, TD)) {
I.setOperand(0, B);
I.setOperand(1, V);
I.clearSubclassOptionalData();
Changed = true;
++NumReassoc;
continue;
}
}
if (Op0 && Op1 &&
Op0->getOpcode() == Opcode && Op1->getOpcode() == Opcode &&
isa<Constant>(Op0->getOperand(1)) &&
isa<Constant>(Op1->getOperand(1)) &&
Op0->hasOneUse() && Op1->hasOneUse()) {
Value *A = Op0->getOperand(0);
Constant *C1 = cast<Constant>(Op0->getOperand(1));
Value *B = Op1->getOperand(0);
Constant *C2 = cast<Constant>(Op1->getOperand(1));
Constant *Folded = ConstantExpr::get(Opcode, C1, C2);
BinaryOperator *New = BinaryOperator::Create(Opcode, A, B);
InsertNewInstWith(New, I);
New->takeName(Op1);
I.setOperand(0, New);
I.setOperand(1, Folded);
I.clearSubclassOptionalData();
Changed = true;
continue;
}
}
return Changed;
} while (1);
}
static bool LeftDistributesOverRight(Instruction::BinaryOps LOp,
Instruction::BinaryOps ROp) {
switch (LOp) {
default:
return false;
case Instruction::And:
switch (ROp) {
default:
return false;
case Instruction::Or:
case Instruction::Xor:
return true;
}
case Instruction::Mul:
switch (ROp) {
default:
return false;
case Instruction::Add:
case Instruction::Sub:
return true;
}
case Instruction::Or:
switch (ROp) {
default:
return false;
case Instruction::And:
return true;
}
}
}
static bool RightDistributesOverLeft(Instruction::BinaryOps LOp,
Instruction::BinaryOps ROp) {
if (Instruction::isCommutative(ROp))
return LeftDistributesOverRight(ROp, LOp);
return false;
}
Value *InstCombiner::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();
if (Op0 && Op1 && Op0->getOpcode() == Op1->getOpcode()) {
Value *A = Op0->getOperand(0), *B = Op0->getOperand(1);
Value *C = Op1->getOperand(0), *D = Op1->getOperand(1);
Instruction::BinaryOps InnerOpcode = Op0->getOpcode();
bool InnerCommutative = Instruction::isCommutative(InnerOpcode);
if (LeftDistributesOverRight(InnerOpcode, TopLevelOpcode))
if (A == C || (InnerCommutative && A == D)) {
if (A != C)
std::swap(C, D);
Value *V = SimplifyBinOp(TopLevelOpcode, B, D, TD);
if (!V && Op0->hasOneUse() && Op1->hasOneUse())
V = Builder->CreateBinOp(TopLevelOpcode, B, D, Op1->getName());
if (V) {
++NumFactor;
V = Builder->CreateBinOp(InnerOpcode, A, V);
V->takeName(&I);
return V;
}
}
if (RightDistributesOverLeft(TopLevelOpcode, InnerOpcode))
if (B == D || (InnerCommutative && B == C)) {
if (B != D)
std::swap(C, D);
Value *V = SimplifyBinOp(TopLevelOpcode, A, C, TD);
if (!V && Op0->hasOneUse() && Op1->hasOneUse())
V = Builder->CreateBinOp(TopLevelOpcode, A, C, Op0->getName());
if (V) {
++NumFactor;
V = Builder->CreateBinOp(InnerOpcode, V, B);
V->takeName(&I);
return V;
}
}
}
if (Op0 && RightDistributesOverLeft(Op0->getOpcode(), TopLevelOpcode)) {
Value *A = Op0->getOperand(0), *B = Op0->getOperand(1), *C = RHS;
Instruction::BinaryOps InnerOpcode = Op0->getOpcode();
if (Value *L = SimplifyBinOp(TopLevelOpcode, A, C, TD))
if (Value *R = SimplifyBinOp(TopLevelOpcode, B, C, TD)) {
++NumExpand;
if ((L == A && R == B) ||
(Instruction::isCommutative(InnerOpcode) && L == B && R == A))
return Op0;
if (Value *V = SimplifyBinOp(InnerOpcode, L, R, TD))
return V;
C = Builder->CreateBinOp(InnerOpcode, L, R);
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();
if (Value *L = SimplifyBinOp(TopLevelOpcode, A, B, TD))
if (Value *R = SimplifyBinOp(TopLevelOpcode, A, C, TD)) {
++NumExpand;
if ((L == B && R == C) ||
(Instruction::isCommutative(InnerOpcode) && L == C && R == B))
return Op1;
if (Value *V = SimplifyBinOp(InnerOpcode, L, R, TD))
return V;
A = Builder->CreateBinOp(InnerOpcode, L, R);
A->takeName(&I);
return A;
}
}
return 0;
}
Value *InstCombiner::dyn_castNegVal(Value *V) const {
if (BinaryOperator::isNeg(V))
return BinaryOperator::getNegArgument(V);
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);
return 0;
}
Value *InstCombiner::dyn_castFNegVal(Value *V, bool IgnoreZeroSign) const {
if (BinaryOperator::isFNeg(V, IgnoreZeroSign))
return BinaryOperator::getFNegArgument(V);
if (ConstantFP *C = dyn_cast<ConstantFP>(V))
return ConstantExpr::getFNeg(C);
if (ConstantDataVector *C = dyn_cast<ConstantDataVector>(V))
if (C->getType()->getElementType()->isFloatingPointTy())
return ConstantExpr::getFNeg(C);
return 0;
}
static Value *FoldOperationIntoSelectOperand(Instruction &I, Value *SO,
InstCombiner *IC) {
if (CastInst *CI = dyn_cast<CastInst>(&I)) {
return IC->Builder->CreateCast(CI->getOpcode(), SO, I.getType());
}
bool ConstIsRHS = isa<Constant>(I.getOperand(1));
Constant *ConstOperand = cast<Constant>(I.getOperand(ConstIsRHS));
if (Constant *SOC = dyn_cast<Constant>(SO)) {
if (ConstIsRHS)
return ConstantExpr::get(I.getOpcode(), SOC, ConstOperand);
return ConstantExpr::get(I.getOpcode(), ConstOperand, SOC);
}
Value *Op0 = SO, *Op1 = ConstOperand;
if (!ConstIsRHS)
std::swap(Op0, Op1);
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(&I))
return IC->Builder->CreateBinOp(BO->getOpcode(), Op0, Op1,
SO->getName()+".op");
if (ICmpInst *CI = dyn_cast<ICmpInst>(&I))
return IC->Builder->CreateICmp(CI->getPredicate(), Op0, Op1,
SO->getName()+".cmp");
if (FCmpInst *CI = dyn_cast<FCmpInst>(&I))
return IC->Builder->CreateICmp(CI->getPredicate(), Op0, Op1,
SO->getName()+".cmp");
llvm_unreachable("Unknown binary instruction type!");
}
Instruction *InstCombiner::FoldOpIntoSelect(Instruction &Op, SelectInst *SI) {
if (!SI->hasOneUse()) return 0;
Value *TV = SI->getOperand(1);
Value *FV = SI->getOperand(2);
if (isa<Constant>(TV) || isa<Constant>(FV)) {
if (SI->getType()->isIntegerTy(1)) return 0;
if (BitCastInst *BC = dyn_cast<BitCastInst>(&Op)) {
VectorType *DestTy = dyn_cast<VectorType>(BC->getDestTy());
VectorType *SrcTy = dyn_cast<VectorType>(BC->getSrcTy());
if ((SrcTy == NULL) != (DestTy == NULL)) return 0;
if (SrcTy && SrcTy->getNumElements() != DestTy->getNumElements())
return 0;
}
Value *SelectTrueVal = FoldOperationIntoSelectOperand(Op, TV, this);
Value *SelectFalseVal = FoldOperationIntoSelectOperand(Op, FV, this);
return SelectInst::Create(SI->getCondition(),
SelectTrueVal, SelectFalseVal);
}
return 0;
}
Instruction *InstCombiner::FoldOpIntoPhi(Instruction &I) {
PHINode *PN = cast<PHINode>(I.getOperand(0));
unsigned NumPHIValues = PN->getNumIncomingValues();
if (NumPHIValues == 0)
return 0;
if (!PN->hasOneUse()) {
for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end();
UI != E; ++UI) {
Instruction *User = cast<Instruction>(*UI);
if (User != &I && !I.isIdenticalTo(User))
return 0;
}
}
BasicBlock *NonConstBB = 0;
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InVal = PN->getIncomingValue(i);
if (isa<Constant>(InVal) && !isa<ConstantExpr>(InVal))
continue;
if (isa<PHINode>(InVal)) return 0; if (NonConstBB) return 0;
NonConstBB = PN->getIncomingBlock(i);
if (InvokeInst *II = dyn_cast<InvokeInst>(InVal))
if (II->getParent() == NonConstBB)
return 0;
if (NonConstBB == I.getParent())
return 0;
}
if (NonConstBB != 0) {
BranchInst *BI = dyn_cast<BranchInst>(NonConstBB->getTerminator());
if (!BI || !BI->isUnconditional()) return 0;
}
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 = 0;
if (Constant *InC = dyn_cast<Constant>(PN->getIncomingValue(i)))
InV = InC->isNullValue() ? FalseVInPred : TrueVInPred;
else
InV = Builder->CreateSelect(PN->getIncomingValue(i),
TrueVInPred, FalseVInPred, "phitmp");
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 = 0;
if (Constant *InC = dyn_cast<Constant>(PN->getIncomingValue(i)))
InV = ConstantExpr::getCompare(CI->getPredicate(), InC, C);
else if (isa<ICmpInst>(CI))
InV = Builder->CreateICmp(CI->getPredicate(), PN->getIncomingValue(i),
C, "phitmp");
else
InV = Builder->CreateFCmp(CI->getPredicate(), PN->getIncomingValue(i),
C, "phitmp");
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
} else if (I.getNumOperands() == 2) {
Constant *C = cast<Constant>(I.getOperand(1));
for (unsigned i = 0; i != NumPHIValues; ++i) {
Value *InV = 0;
if (Constant *InC = dyn_cast<Constant>(PN->getIncomingValue(i)))
InV = ConstantExpr::get(I.getOpcode(), InC, C);
else
InV = Builder->CreateBinOp(cast<BinaryOperator>(I).getOpcode(),
PN->getIncomingValue(i), C, "phitmp");
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(), "phitmp");
NewPN->addIncoming(InV, PN->getIncomingBlock(i));
}
}
for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end();
UI != E; ) {
Instruction *User = cast<Instruction>(*UI++);
if (User == &I) continue;
ReplaceInstUsesWith(*User, NewPN);
EraseInstFromFunction(*User);
}
return ReplaceInstUsesWith(I, NewPN);
}
Type *InstCombiner::FindElementAtOffset(Type *Ty, int64_t Offset,
SmallVectorImpl<Value*> &NewIndices) {
if (!TD) return 0;
if (!Ty->isSized()) return 0;
Type *IntPtrTy = TD->getIntPtrType(Ty->getContext());
int64_t FirstIdx = 0;
if (int64_t TySize = TD->getTypeAllocSize(Ty)) {
FirstIdx = Offset/TySize;
Offset -= FirstIdx*TySize;
if (Offset < 0) {
--FirstIdx;
Offset += TySize;
assert(Offset >= 0);
}
assert((uint64_t)Offset < (uint64_t)TySize && "Out of range offset");
}
NewIndices.push_back(ConstantInt::get(IntPtrTy, FirstIdx));
while (Offset) {
if (uint64_t(Offset*8) >= TD->getTypeSizeInBits(Ty))
return 0;
if (StructType *STy = dyn_cast<StructType>(Ty)) {
const StructLayout *SL = TD->getStructLayout(STy);
assert(Offset < (int64_t)SL->getSizeInBytes() &&
"Offset must stay within the indexed type");
unsigned Elt = SL->getElementContainingOffset(Offset);
NewIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ty->getContext()),
Elt));
Offset -= SL->getElementOffset(Elt);
Ty = STy->getElementType(Elt);
} else if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
uint64_t EltSize = TD->getTypeAllocSize(AT->getElementType());
assert(EltSize && "Cannot index into a zero-sized array");
NewIndices.push_back(ConstantInt::get(IntPtrTy,Offset/EltSize));
Offset %= EltSize;
Ty = AT->getElementType();
} else {
return 0;
}
}
return Ty;
}
static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) {
if (GEP.hasAllZeroIndices() && !Src.hasAllZeroIndices() &&
!Src.hasOneUse())
return false;
return true;
}
Value *InstCombiner::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 0;
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 0;
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 0;
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 0;
Parent = std::make_pair(BO, 1);
continue;
}
if (!Op->hasOneUse())
return 0;
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 0;
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 0;
Parent = std::make_pair(BO, 1);
Op = ConstantInt::get(BO->getType(), Amt - logScale);
break;
}
}
if (!Op->hasOneUse())
return 0;
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 0;
assert(SmallScale.exactLogBase2() == logScale);
RequireNoSignedWrap = true;
Parent = std::make_pair(Cast, 0);
Scale = SmallScale;
continue;
}
if (Cast->getOpcode() == Instruction::Trunc) {
if (RequireNoSignedWrap)
return 0;
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 0;
}
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?");
Parent.first->setOperand(Parent.second, Op);
Worklist.Add(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.Add(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->use_back();
} while (1);
}
Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) {
SmallVector<Value*, 8> Ops(GEP.op_begin(), GEP.op_end());
if (Value *V = SimplifyGEPInst(Ops, TD))
return ReplaceInstUsesWith(GEP, V);
Value *PtrOp = GEP.getOperand(0);
if (TD) {
bool MadeChange = false;
Type *IntPtrTy = TD->getIntPtrType(GEP.getPointerOperandType());
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) {
SequentialType *SeqTy = dyn_cast<SequentialType>(*GTI);
if (!SeqTy) continue;
if (SeqTy->getElementType()->isSized() &&
TD->getTypeAllocSize(SeqTy->getElementType()) == 0)
if (!isa<Constant>(*I) || !cast<Constant>(*I)->isNullValue()) {
*I = Constant::getNullValue(IntPtrTy);
MadeChange = true;
}
Type *IndexTy = (*I)->getType();
if (IndexTy != IntPtrTy) {
*I = Builder->CreateIntCast(*I, IntPtrTy, true);
MadeChange = true;
}
}
if (MadeChange) return &GEP;
}
if (GEPOperator *Src = dyn_cast<GEPOperator>(PtrOp)) {
if (!shouldMergeGEPs(*cast<GEPOperator>(&GEP), *Src))
return 0;
if (GEPOperator *SrcGEP =
dyn_cast<GEPOperator>(Src->getOperand(0)))
if (SrcGEP->getNumOperands() == 2 && shouldMergeGEPs(*Src, *SrcGEP))
return 0;
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)->isStructTy();
if (EndsWithSequential) {
Value *Sum;
Value *SO1 = Src->getOperand(Src->getNumOperands()-1);
Value *GO1 = GEP.getOperand(1);
if (SO1 == Constant::getNullValue(SO1->getType())) {
Sum = GO1;
} else if (GO1 == Constant::getNullValue(GO1->getType())) {
Sum = SO1;
} else {
if (SO1->getType() != GO1->getType())
return 0;
Sum = Builder->CreateAdd(SO1, GO1, PtrOp->getName()+".sum");
}
if (Src->getNumOperands() == 2) {
GEP.setOperand(0, Src->getOperand(0));
GEP.setOperand(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 (GEP.isInBounds() && Src->isInBounds()) ?
GetElementPtrInst::CreateInBounds(Src->getOperand(0), Indices,
GEP.getName()) :
GetElementPtrInst::Create(Src->getOperand(0), Indices, GEP.getName());
}
Value *StrippedPtr = PtrOp->stripPointerCasts();
PointerType *StrippedPtrTy = dyn_cast<PointerType>(StrippedPtr->getType());
if (!StrippedPtrTy)
return 0;
if (StrippedPtr != PtrOp &&
StrippedPtrTy->getAddressSpace() == GEP.getPointerAddressSpace()) {
bool HasZeroPointerIndex = false;
if (ConstantInt *C = dyn_cast<ConstantInt>(GEP.getOperand(1)))
HasZeroPointerIndex = C->isZero();
if (HasZeroPointerIndex) {
PointerType *CPTy = cast<PointerType>(PtrOp->getType());
if (ArrayType *CATy =
dyn_cast<ArrayType>(CPTy->getElementType())) {
if (CATy->getElementType() == StrippedPtrTy->getElementType()) {
SmallVector<Value*, 8> Idx(GEP.idx_begin()+1, GEP.idx_end());
GetElementPtrInst *Res =
GetElementPtrInst::Create(StrippedPtr, Idx, GEP.getName());
Res->setIsInBounds(GEP.isInBounds());
return Res;
}
if (ArrayType *XATy =
dyn_cast<ArrayType>(StrippedPtrTy->getElementType())){
if (CATy->getElementType() == XATy->getElementType()) {
GEP.setOperand(0, StrippedPtr);
return &GEP;
}
}
}
} else if (GEP.getNumOperands() == 2) {
Type *SrcElTy = StrippedPtrTy->getElementType();
Type *ResElTy=cast<PointerType>(PtrOp->getType())->getElementType();
if (TD && SrcElTy->isArrayTy() &&
TD->getTypeAllocSize(cast<ArrayType>(SrcElTy)->getElementType()) ==
TD->getTypeAllocSize(ResElTy)) {
Value *Idx[2];
Idx[0] = Constant::getNullValue(Type::getInt32Ty(GEP.getContext()));
Idx[1] = GEP.getOperand(1);
Value *NewGEP = GEP.isInBounds() ?
Builder->CreateInBoundsGEP(StrippedPtr, Idx, GEP.getName()) :
Builder->CreateGEP(StrippedPtr, Idx, GEP.getName());
return new BitCastInst(NewGEP, GEP.getType());
}
if (TD && ResElTy->isSized() && SrcElTy->isSized()) {
uint64_t ResSize = TD->getTypeAllocSize(ResElTy);
uint64_t SrcSize = TD->getTypeAllocSize(SrcElTy);
if (ResSize && SrcSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = SrcSize / ResSize;
assert(Idx->getType() == TD->getIntPtrType(GEP.getContext()) &&
"Index not cast to pointer width?");
bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
Value *NewGEP = GEP.isInBounds() && NSW ?
Builder->CreateInBoundsGEP(StrippedPtr, NewIdx, GEP.getName()) :
Builder->CreateGEP(StrippedPtr, NewIdx, GEP.getName());
return new BitCastInst(NewGEP, GEP.getType());
}
}
}
if (TD && ResElTy->isSized() && SrcElTy->isSized() &&
SrcElTy->isArrayTy()) {
uint64_t ResSize = TD->getTypeAllocSize(ResElTy);
uint64_t ArrayEltSize =
TD->getTypeAllocSize(cast<ArrayType>(SrcElTy)->getElementType());
if (ResSize && ArrayEltSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = ArrayEltSize / ResSize;
assert(Idx->getType() == TD->getIntPtrType(GEP.getContext()) &&
"Index not cast to pointer width?");
bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
Value *Off[2];
Off[0] = Constant::getNullValue(Type::getInt32Ty(GEP.getContext()));
Off[1] = NewIdx;
Value *NewGEP = GEP.isInBounds() && NSW ?
Builder->CreateInBoundsGEP(StrippedPtr, Off, GEP.getName()) :
Builder->CreateGEP(StrippedPtr, Off, GEP.getName());
return new BitCastInst(NewGEP, GEP.getType());
}
}
}
}
}
if (BitCastInst *BCI = dyn_cast<BitCastInst>(PtrOp)) {
APInt Offset(TD ? TD->getPointerSizeInBits() : 1, 0);
if (TD &&
!isa<BitCastInst>(BCI->getOperand(0)) &&
GEP.accumulateConstantOffset(*TD, Offset) &&
StrippedPtrTy->getAddressSpace() == GEP.getPointerAddressSpace()) {
if (!Offset) {
if (isa<AllocaInst>(BCI->getOperand(0)) ||
isAllocationFn(BCI->getOperand(0), TLI)) {
if (Instruction *I = visitBitCast(*BCI)) {
if (I != BCI) {
I->takeName(BCI);
BCI->getParent()->getInstList().insert(BCI, I);
ReplaceInstUsesWith(*BCI, I);
}
return &GEP;
}
}
return new BitCastInst(BCI->getOperand(0), GEP.getType());
}
SmallVector<Value*, 8> NewIndices;
Type *InTy =
cast<PointerType>(BCI->getOperand(0)->getType())->getElementType();
if (FindElementAtOffset(InTy, Offset.getSExtValue(), NewIndices)) {
Value *NGEP = GEP.isInBounds() ?
Builder->CreateInBoundsGEP(BCI->getOperand(0), NewIndices) :
Builder->CreateGEP(BCI->getOperand(0), NewIndices);
if (NGEP->getType() == GEP.getType())
return ReplaceInstUsesWith(GEP, NGEP);
NGEP->takeName(&GEP);
return new BitCastInst(NGEP, GEP.getType());
}
}
}
return 0;
}
static bool
isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakVH> &Users,
const TargetLibraryInfo *TLI) {
SmallVector<Instruction*, 4> Worklist;
Worklist.push_back(AI);
do {
Instruction *PI = Worklist.pop_back_val();
for (Value::use_iterator UI = PI->use_begin(), UE = PI->use_end(); UI != UE;
++UI) {
Instruction *I = cast<Instruction>(*UI);
switch (I->getOpcode()) {
default:
return false;
case Instruction::BitCast:
case Instruction::GetElementPtr:
Users.push_back(I);
Worklist.push_back(I);
continue;
case Instruction::ICmp: {
ICmpInst *ICI = cast<ICmpInst>(I);
if (!ICI->isEquality() || !isa<ConstantPointerNull>(ICI->getOperand(1)))
return false;
Users.push_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;
}
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
case Intrinsic::invariant_start:
case Intrinsic::invariant_end:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::objectsize:
Users.push_back(I);
continue;
}
}
if (isFreeCall(I, TLI)) {
Users.push_back(I);
continue;
}
return false;
case Instruction::Store: {
StoreInst *SI = cast<StoreInst>(I);
if (SI->isVolatile() || SI->getPointerOperand() != PI)
return false;
Users.push_back(I);
continue;
}
}
llvm_unreachable("missing a return?");
}
} while (!Worklist.empty());
return true;
}
Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
SmallVector<WeakVH, 64> Users;
if (isAllocSiteRemovable(&MI, Users, TLI)) {
for (unsigned i = 0, e = Users.size(); i != e; ++i) {
Instruction *I = cast_or_null<Instruction>(&*Users[i]);
if (!I) continue;
if (ICmpInst *C = dyn_cast<ICmpInst>(I)) {
ReplaceInstUsesWith(*C,
ConstantInt::get(Type::getInt1Ty(C->getContext()),
C->isFalseWhenEqual()));
} else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I)) {
ReplaceInstUsesWith(*I, UndefValue::get(I->getType()));
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
if (II->getIntrinsicID() == Intrinsic::objectsize) {
ConstantInt *CI = cast<ConstantInt>(II->getArgOperand(1));
uint64_t DontKnow = CI->isZero() ? -1ULL : 0;
ReplaceInstUsesWith(*I, ConstantInt::get(I->getType(), DontKnow));
}
}
EraseInstFromFunction(*I);
}
if (InvokeInst *II = dyn_cast<InvokeInst>(&MI)) {
Module *M = II->getParent()->getParent()->getParent();
Function *F = Intrinsic::getDeclaration(M, Intrinsic::donothing);
InvokeInst::Create(F, II->getNormalDest(), II->getUnwindDest(),
ArrayRef<Value *>(), "", II->getParent());
}
return EraseInstFromFunction(MI);
}
return 0;
}
static Instruction *
tryToMoveFreeBeforeNullTest(CallInst &FI) {
Value *Op = FI.getArgOperand(0);
BasicBlock *FreeInstrBB = FI.getParent();
BasicBlock *PredBB = FreeInstrBB->getSinglePredecessor();
if (!PredBB)
return 0;
if (FreeInstrBB->size() != 2)
return 0;
BasicBlock *SuccBB;
if (!match(FreeInstrBB->getTerminator(), m_UnconditionalBr(SuccBB)))
return 0;
TerminatorInst *TI = PredBB->getTerminator();
BasicBlock *TrueBB, *FalseBB;
ICmpInst::Predicate Pred;
if (!match(TI, m_Br(m_ICmp(Pred, m_Specific(Op), m_Zero()), TrueBB, FalseBB)))
return 0;
if (Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
return 0;
if (SuccBB != (Pred == ICmpInst::ICMP_EQ ? TrueBB : FalseBB))
return 0;
assert(FreeInstrBB == (Pred == ICmpInst::ICMP_EQ ? FalseBB : TrueBB) &&
"Broken CFG: missing edge from predecessor to successor");
FI.moveBefore(TI);
return &FI;
}
Instruction *InstCombiner::visitFree(CallInst &FI) {
Value *Op = FI.getArgOperand(0);
if (isa<UndefValue>(Op)) {
Builder->CreateStore(ConstantInt::getTrue(FI.getContext()),
UndefValue::get(Type::getInt1PtrTy(FI.getContext())));
return EraseInstFromFunction(FI);
}
if (isa<ConstantPointerNull>(Op))
return EraseInstFromFunction(FI);
if (MinimizeSize)
if (Instruction *I = tryToMoveFreeBeforeNullTest(FI))
return I;
return 0;
}
Instruction *InstCombiner::visitBranchInst(BranchInst &BI) {
Value *X = 0;
BasicBlock *TrueDest;
BasicBlock *FalseDest;
if (match(&BI, m_Br(m_Not(m_Value(X)), TrueDest, FalseDest)) &&
!isa<Constant>(X)) {
BI.setCondition(X);
BI.swapSuccessors();
return &BI;
}
FCmpInst::Predicate FPred; Value *Y;
if (match(&BI, m_Br(m_FCmp(FPred, m_Value(X), m_Value(Y)),
TrueDest, FalseDest)) &&
BI.getCondition()->hasOneUse())
if (FPred == FCmpInst::FCMP_ONE || FPred == FCmpInst::FCMP_OLE ||
FPred == FCmpInst::FCMP_OGE) {
FCmpInst *Cond = cast<FCmpInst>(BI.getCondition());
Cond->setPredicate(FCmpInst::getInversePredicate(FPred));
BI.swapSuccessors();
Worklist.Add(Cond);
return &BI;
}
ICmpInst::Predicate IPred;
if (match(&BI, m_Br(m_ICmp(IPred, m_Value(X), m_Value(Y)),
TrueDest, FalseDest)) &&
BI.getCondition()->hasOneUse())
if (IPred == ICmpInst::ICMP_NE || IPred == ICmpInst::ICMP_ULE ||
IPred == ICmpInst::ICMP_SLE || IPred == ICmpInst::ICMP_UGE ||
IPred == ICmpInst::ICMP_SGE) {
ICmpInst *Cond = cast<ICmpInst>(BI.getCondition());
Cond->setPredicate(ICmpInst::getInversePredicate(IPred));
BI.swapSuccessors();
Worklist.Add(Cond);
return &BI;
}
return 0;
}
Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) {
Value *Cond = SI.getCondition();
if (Instruction *I = dyn_cast<Instruction>(Cond)) {
if (I->getOpcode() == Instruction::Add)
if (ConstantInt *AddRHS = dyn_cast<ConstantInt>(I->getOperand(1))) {
for (SwitchInst::CaseIt i = SI.case_begin(), e = SI.case_end();
i != e; ++i) {
ConstantInt* CaseVal = i.getCaseValue();
Constant* NewCaseVal = ConstantExpr::getSub(cast<Constant>(CaseVal),
AddRHS);
assert(isa<ConstantInt>(NewCaseVal) &&
"Result of expression should be constant");
i.setValue(cast<ConstantInt>(NewCaseVal));
}
SI.setCondition(I->getOperand(0));
Worklist.Add(I);
return &SI;
}
}
return 0;
}
Instruction *InstCombiner::visitExtractValueInst(ExtractValueInst &EV) {
Value *Agg = EV.getAggregateOperand();
if (!EV.hasIndices())
return ReplaceInstUsesWith(EV, Agg);
if (Constant *C = dyn_cast<Constant>(Agg)) {
if (Constant *C2 = C->getAggregateElement(*EV.idx_begin())) {
if (EV.getNumIndices() == 0)
return ReplaceInstUsesWith(EV, C2);
return ExtractValueInst::Create(C2, EV.getIndices().slice(1));
}
return 0; }
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 (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Agg)) {
if (II->hasOneUse()) {
switch (II->getIntrinsicID()) {
case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow:
if (*EV.idx_begin() == 0) { Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1);
ReplaceInstUsesWith(*II, UndefValue::get(II->getType()));
EraseInstFromFunction(*II);
return BinaryOperator::CreateAdd(LHS, RHS);
}
if (II->getIntrinsicID() == Intrinsic::uadd_with_overflow)
if (ConstantInt *CI = dyn_cast<ConstantInt>(II->getArgOperand(1)))
return new ICmpInst(ICmpInst::ICMP_UGT, II->getArgOperand(0),
ConstantExpr::getNot(CI));
break;
case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
if (*EV.idx_begin() == 0) { Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1);
ReplaceInstUsesWith(*II, UndefValue::get(II->getType()));
EraseInstFromFunction(*II);
return BinaryOperator::CreateSub(LHS, RHS);
}
break;
case Intrinsic::umul_with_overflow:
case Intrinsic::smul_with_overflow:
if (*EV.idx_begin() == 0) { Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1);
ReplaceInstUsesWith(*II, UndefValue::get(II->getType()));
EraseInstFromFunction(*II);
return BinaryOperator::CreateMul(LHS, RHS);
}
break;
default:
break;
}
}
}
if (LoadInst *L = dyn_cast<LoadInst>(Agg))
if (L->isSimple() && L->hasOneUse()) {
SmallVector<Value*, 4> Indices;
Indices.push_back(Builder->getInt32(0));
for (ExtractValueInst::idx_iterator I = EV.idx_begin(), E = EV.idx_end();
I != E; ++I)
Indices.push_back(Builder->getInt32(*I));
Builder->SetInsertPoint(L->getParent(), L);
Value *GEP = Builder->CreateInBoundsGEP(L->getPointerOperand(), Indices);
return ReplaceInstUsesWith(EV, Builder->CreateLoad(GEP));
}
return 0;
}
enum Personality_Type {
Unknown_Personality,
GNU_Ada_Personality,
GNU_CXX_Personality,
GNU_ObjC_Personality
};
static Personality_Type RecognizePersonality(Value *Pers) {
Function *F = dyn_cast<Function>(Pers->stripPointerCasts());
if (!F)
return Unknown_Personality;
return StringSwitch<Personality_Type>(F->getName())
.Case("__gnat_eh_personality", GNU_Ada_Personality)
.Case("__gxx_personality_v0", GNU_CXX_Personality)
.Case("__objc_personality_v0", GNU_ObjC_Personality)
.Default(Unknown_Personality);
}
static bool isCatchAll(Personality_Type Personality, Constant *TypeInfo) {
switch (Personality) {
case Unknown_Personality:
return false;
case GNU_Ada_Personality:
return false;
case GNU_CXX_Personality:
case GNU_ObjC_Personality:
return TypeInfo->isNullValue();
}
llvm_unreachable("Unknown personality!");
}
static bool shorter_filter(const Value *LHS, const Value *RHS) {
return
cast<ArrayType>(LHS->getType())->getNumElements()
<
cast<ArrayType>(RHS->getType())->getNumElements();
}
Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) {
Personality_Type Personality = RecognizePersonality(LI.getPersonalityFn());
bool MakeNewInstruction = false; SmallVector<Value *, 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)) {
Value *CatchClause = LI.getClause(i);
Constant *TypeInfo = cast<Constant>(CatchClause->stripPointerCasts());
if (AlreadyCaught.insert(TypeInfo)) {
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!");
Value *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) {
Value *Elt = Filter->getOperand(j);
Constant *TypeInfo = cast<Constant>(Elt->stripPointerCasts());
if (isCatchAll(Personality, TypeInfo)) {
SawCatchAll = true;
break;
}
if (AlreadyCaught.count(TypeInfo))
continue;
if (SeenInFilter.insert(TypeInfo))
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;
SmallVector<Value *, 16>::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(),
LI.getPersonalityFn(),
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 0;
}
static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) {
assert(I->hasOneUse() && "Invariants didn't hold!");
if (isa<PHINode>(I) || isa<LandingPadInst>(I) || I->mayHaveSideEffects() ||
isa<TerminatorInst>(I))
return false;
if (isa<AllocaInst>(I) && I->getParent() ==
&DestBlock->getParent()->getEntryBlock())
return false;
if (I->mayReadFromMemory()) {
for (BasicBlock::iterator Scan = I, E = I->getParent()->end();
Scan != E; ++Scan)
if (Scan->mayWriteToMemory())
return false;
}
BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt();
I->moveBefore(InsertPos);
++NumSunkInst;
return true;
}
static bool AddReachableCodeToWorklist(BasicBlock *BB,
SmallPtrSet<BasicBlock*, 64> &Visited,
InstCombiner &IC,
const DataLayout *TD,
const TargetLibraryInfo *TLI) {
bool MadeIRChange = false;
SmallVector<BasicBlock*, 256> Worklist;
Worklist.push_back(BB);
SmallVector<Instruction*, 128> InstrsForInstCombineWorklist;
DenseMap<ConstantExpr*, Constant*> FoldedConstants;
do {
BB = Worklist.pop_back_val();
if (!Visited.insert(BB)) continue;
for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ) {
Instruction *Inst = BBI++;
if (isInstructionTriviallyDead(Inst, TLI)) {
++NumDeadInst;
DEBUG(errs() << "IC: DCE: " << *Inst << '\n');
Inst->eraseFromParent();
continue;
}
if (!Inst->use_empty() && isa<Constant>(Inst->getOperand(0)))
if (Constant *C = ConstantFoldInstruction(Inst, TD, TLI)) {
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: "
<< *Inst << '\n');
Inst->replaceAllUsesWith(C);
++NumConstProp;
Inst->eraseFromParent();
continue;
}
if (TD) {
for (User::op_iterator i = Inst->op_begin(), e = Inst->op_end();
i != e; ++i) {
ConstantExpr *CE = dyn_cast<ConstantExpr>(i);
if (CE == 0) continue;
Constant*& FoldRes = FoldedConstants[CE];
if (!FoldRes)
FoldRes = ConstantFoldConstantExpression(CE, TD, TLI);
if (!FoldRes)
FoldRes = CE;
if (FoldRes != CE) {
*i = FoldRes;
MadeIRChange = true;
}
}
}
InstrsForInstCombineWorklist.push_back(Inst);
}
TerminatorInst *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())) {
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end();
i != e; ++i)
if (i.getCaseValue() == Cond) {
BasicBlock *ReachableBB = i.getCaseSuccessor();
Worklist.push_back(ReachableBB);
continue;
}
Worklist.push_back(SI->getDefaultDest());
continue;
}
}
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
Worklist.push_back(TI->getSuccessor(i));
} while (!Worklist.empty());
IC.Worklist.AddInitialGroup(&InstrsForInstCombineWorklist[0],
InstrsForInstCombineWorklist.size());
return MadeIRChange;
}
bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
MadeIRChange = false;
DEBUG(errs() << "\n\nINSTCOMBINE ITERATION #" << Iteration << " on "
<< F.getName() << "\n");
{
SmallPtrSet<BasicBlock*, 64> Visited;
MadeIRChange |= AddReachableCodeToWorklist(F.begin(), Visited, *this, TD,
TLI);
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
if (Visited.count(BB)) continue;
Instruction *EndInst = BB->getTerminator(); while (EndInst != BB->begin()) {
BasicBlock::iterator I = EndInst;
Instruction *Inst = --I;
if (!Inst->use_empty())
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
if (isa<LandingPadInst>(Inst)) {
EndInst = Inst;
continue;
}
if (!isa<DbgInfoIntrinsic>(Inst)) {
++NumDeadInst;
MadeIRChange = true;
}
Inst->eraseFromParent();
}
}
}
while (!Worklist.isEmpty()) {
Instruction *I = Worklist.RemoveOne();
if (I == 0) continue;
if (isInstructionTriviallyDead(I, TLI)) {
DEBUG(errs() << "IC: DCE: " << *I << '\n');
EraseInstFromFunction(*I);
++NumDeadInst;
MadeIRChange = true;
continue;
}
if (!I->use_empty() && isa<Constant>(I->getOperand(0)))
if (Constant *C = ConstantFoldInstruction(I, TD, TLI)) {
DEBUG(errs() << "IC: ConstFold to: " << *C << " from: " << *I << '\n');
ReplaceInstUsesWith(*I, C);
++NumConstProp;
EraseInstFromFunction(*I);
MadeIRChange = true;
continue;
}
if (I->hasOneUse()) {
BasicBlock *BB = I->getParent();
Instruction *UserInst = cast<Instruction>(I->use_back());
BasicBlock *UserParent;
if (PHINode *PN = dyn_cast<PHINode>(UserInst))
UserParent = PN->getIncomingBlock(I->use_begin().getUse());
else
UserParent = UserInst->getParent();
if (UserParent != BB) {
bool UserIsSuccessor = false;
for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI)
if (*SI == UserParent) {
UserIsSuccessor = true;
break;
}
if (UserIsSuccessor && UserParent->getSinglePredecessor())
MadeIRChange |= TryToSinkInstruction(I, UserParent);
}
}
Builder->SetInsertPoint(I->getParent(), I);
Builder->SetCurrentDebugLocation(I->getDebugLoc());
#ifndef NDEBUG
std::string OrigI;
#endif
DEBUG(raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str(););
DEBUG(errs() << "IC: Visiting: " << OrigI << '\n');
if (Instruction *Result = visit(*I)) {
++NumCombined;
if (Result != I) {
DEBUG(errs() << "IC: Old = " << *I << '\n'
<< " New = " << *Result << '\n');
if (!I->getDebugLoc().isUnknown())
Result->setDebugLoc(I->getDebugLoc());
I->replaceAllUsesWith(Result);
Result->takeName(I);
Worklist.Add(Result);
Worklist.AddUsersToWorkList(*Result);
BasicBlock *InstParent = I->getParent();
BasicBlock::iterator InsertPos = I;
if (!isa<PHINode>(Result) && isa<PHINode>(InsertPos))
InsertPos = InstParent->getFirstInsertionPt();
InstParent->getInstList().insert(InsertPos, Result);
EraseInstFromFunction(*I);
} else {
#ifndef NDEBUG
DEBUG(errs() << "IC: Mod = " << OrigI << '\n'
<< " New = " << *I << '\n');
#endif
if (isInstructionTriviallyDead(I, TLI)) {
EraseInstFromFunction(*I);
} else {
Worklist.Add(I);
Worklist.AddUsersToWorkList(*I);
}
}
MadeIRChange = true;
}
}
Worklist.Zap();
return MadeIRChange;
}
namespace {
class InstCombinerLibCallSimplifier : public LibCallSimplifier {
InstCombiner *IC;
public:
InstCombinerLibCallSimplifier(const DataLayout *TD,
const TargetLibraryInfo *TLI,
InstCombiner *IC)
: LibCallSimplifier(TD, TLI, UnsafeFPShrink) {
this->IC = IC;
}
virtual void replaceAllUsesWith(Instruction *I, Value *With) const {
IC->ReplaceInstUsesWith(*I, With);
}
};
}
bool InstCombiner::runOnFunction(Function &F) {
TD = getAnalysisIfAvailable<DataLayout>();
TLI = &getAnalysis<TargetLibraryInfo>();
MinimizeSize = F.getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::MinSize);
IRBuilder<true, TargetFolder, InstCombineIRInserter>
TheBuilder(F.getContext(), TargetFolder(TD),
InstCombineIRInserter(Worklist));
Builder = &TheBuilder;
InstCombinerLibCallSimplifier TheSimplifier(TD, TLI, this);
Simplifier = &TheSimplifier;
bool EverMadeChange = false;
EverMadeChange = LowerDbgDeclare(F);
unsigned Iteration = 0;
while (DoOneIteration(F, Iteration++))
EverMadeChange = true;
Builder = 0;
return EverMadeChange;
}
FunctionPass *llvm::createInstructionCombiningPass() {
return new InstCombiner();
}