176 using namespace llvm;
179 "disable-separate-const-offset-from-gep",
cl::init(
false),
180 cl::desc(
"Do not separate the constant offset from a GEP instruction"),
187 cl::desc(
"Verify this pass produces no dead code"),
205 class ConstantOffsetExtractor {
224 :
IP(InsertionPt),
DL(InsertionPt->getModule()->getDataLayout()), DT(DT) {
240 APInt find(
Value *V,
bool SignExtended,
bool ZeroExtended,
bool NonNegative);
259 Value *rebuildWithoutConstOffset();
275 Value *distributeExtsAndCloneChain(
unsigned ChainIndex);
277 Value *removeConstOffset(
unsigned ChainIndex);
290 bool CanTraceInto(
bool SignExtended,
bool ZeroExtended,
BinaryOperator *BO,
311 class SeparateConstOffsetFromGEP :
public FunctionPass {
315 bool LowerGEP =
false)
326 bool doInitialization(
Module &M)
override {
330 bool runOnFunction(
Function &
F)
override;
344 int64_t AccumulativeByteOffset);
353 int64_t AccumulativeByteOffset);
390 SeparateConstOffsetFromGEP,
"separate-const-offset-from-gep",
391 "Split GEPs to a variadic base and a constant offset for better CSE",
false,
396 SeparateConstOffsetFromGEP, "separate-
const-offset-from-
gep",
397 "
Split GEPs to a variadic base and a constant offset
for better
CSE",
false,
403 return new SeparateConstOffsetFromGEP(TM, LowerGEP);
406 bool ConstantOffsetExtractor::CanTraceInto(
bool SignExtended,
413 if (BO->
getOpcode() != Instruction::Add &&
437 if (BO->
getOpcode() == Instruction::Add && !ZeroExtended && NonNegative) {
446 if (
ConstantInt *ConstLHS = dyn_cast<ConstantInt>(LHS)) {
447 if (!ConstLHS->isNegative())
450 if (
ConstantInt *ConstRHS = dyn_cast<ConstantInt>(RHS)) {
451 if (!ConstRHS->isNegative())
458 if (BO->
getOpcode() == Instruction::Add ||
474 APInt ConstantOffset = find(BO->
getOperand(0), SignExtended, ZeroExtended,
481 if (ConstantOffset != 0)
return ConstantOffset;
482 ConstantOffset = find(BO->
getOperand(1), SignExtended, ZeroExtended,
487 ConstantOffset = -ConstantOffset;
488 return ConstantOffset;
491 APInt ConstantOffsetExtractor::find(
Value *V,
bool SignExtended,
492 bool ZeroExtended,
bool NonNegative) {
500 if (U ==
nullptr)
return APInt(BitWidth, 0);
502 APInt ConstantOffset(BitWidth, 0);
505 ConstantOffset = CI->getValue();
508 if (CanTraceInto(SignExtended, ZeroExtended, BO, NonNegative))
509 ConstantOffset = findInEitherOperand(BO, SignExtended, ZeroExtended);
510 }
else if (isa<SExtInst>(V)) {
512 ZeroExtended, NonNegative).sext(BitWidth);
513 }
else if (isa<ZExtInst>(V)) {
520 true,
false).zext(BitWidth);
526 if (ConstantOffset != 0)
527 UserChain.push_back(U);
528 return ConstantOffset;
531 Value *ConstantOffsetExtractor::applyExts(
Value *V) {
535 for (
auto I = ExtInsts.rbegin(), E = ExtInsts.rend();
I != E; ++
I) {
536 if (
Constant *C = dyn_cast<Constant>(Current)) {
550 Value *ConstantOffsetExtractor::rebuildWithoutConstOffset() {
551 distributeExtsAndCloneChain(UserChain.size() - 1);
553 unsigned NewSize = 0;
554 for (
auto I = UserChain.begin(), E = UserChain.end();
I != E; ++
I) {
556 UserChain[NewSize] = *
I;
560 UserChain.resize(NewSize);
561 return removeConstOffset(UserChain.size() - 1);
565 ConstantOffsetExtractor::distributeExtsAndCloneChain(
unsigned ChainIndex) {
566 User *U = UserChain[ChainIndex];
567 if (ChainIndex == 0) {
568 assert(isa<ConstantInt>(U));
570 return UserChain[ChainIndex] = cast<ConstantInt>(applyExts(U));
573 if (
CastInst *Cast = dyn_cast<CastInst>(U)) {
574 assert((isa<SExtInst>(Cast) || isa<ZExtInst>(Cast)) &&
575 "We only traced into two types of CastInst: sext and zext");
576 ExtInsts.push_back(Cast);
577 UserChain[ChainIndex] =
nullptr;
578 return distributeExtsAndCloneChain(ChainIndex - 1);
584 unsigned OpNo = (BO->
getOperand(0) == UserChain[ChainIndex - 1] ? 0 : 1);
586 Value *NextInChain = distributeExtsAndCloneChain(ChainIndex - 1);
596 return UserChain[ChainIndex] = NewBO;
599 Value *ConstantOffsetExtractor::removeConstOffset(
unsigned ChainIndex) {
600 if (ChainIndex == 0) {
601 assert(isa<ConstantInt>(UserChain[ChainIndex]));
607 "distributeExtsAndCloneChain clones each BinaryOperator in "
608 "UserChain, so no one should be used more than "
611 unsigned OpNo = (BO->
getOperand(0) == UserChain[ChainIndex - 1] ? 0 : 1);
612 assert(BO->
getOperand(OpNo) == UserChain[ChainIndex - 1]);
613 Value *NextInChain = removeConstOffset(ChainIndex - 1);
618 if (
ConstantInt *CI = dyn_cast<ConstantInt>(NextInChain)) {
619 if (CI->isZero() && !(BO->
getOpcode() == Instruction::Sub && OpNo == 0))
638 NewOp = Instruction::Add;
652 User *&UserChainTail,
654 ConstantOffsetExtractor Extractor(GEP, DT);
656 APInt ConstantOffset =
657 Extractor.find(Idx,
false,
false,
659 if (ConstantOffset == 0) {
660 UserChainTail =
nullptr;
664 Value *IdxWithoutConstOffset = Extractor.rebuildWithoutConstOffset();
665 UserChainTail = Extractor.UserChain.back();
666 return IdxWithoutConstOffset;
672 return ConstantOffsetExtractor(GEP, DT)
673 .find(Idx,
false,
false,
678 bool SeparateConstOffsetFromGEP::canonicalizeArrayIndicesToPointerSize(
680 bool Changed =
false;
684 I != E; ++
I, ++GTI) {
686 if (isa<SequentialType>(*GTI)) {
687 if ((*I)->getType() != IntPtrTy) {
698 bool &NeedsExtraction) {
699 NeedsExtraction =
false;
700 int64_t AccumulativeByteOffset = 0;
703 if (isa<SequentialType>(*GTI)) {
705 int64_t ConstantOffset =
707 if (ConstantOffset != 0) {
708 NeedsExtraction =
true;
712 AccumulativeByteOffset +=
715 }
else if (LowerGEP) {
720 NeedsExtraction =
true;
721 AccumulativeByteOffset +=
722 DL->getStructLayout(StTy)->getElementOffset(Field);
726 return AccumulativeByteOffset;
729 void SeparateConstOffsetFromGEP::lowerToSingleIndexGEPs(
737 if (ResultPtr->
getType() != I8PtrTy)
738 ResultPtr = Builder.CreateBitCast(ResultPtr, I8PtrTy);
744 if (isa<SequentialType>(*GTI)) {
754 if (ElementSize != 1) {
756 Idx = Builder.CreateShl(
764 Builder.CreateGEP(Builder.getInt8Ty(), ResultPtr, Idx,
"uglygep");
769 if (AccumulativeByteOffset != 0) {
772 Builder.CreateGEP(Builder.getInt8Ty(), ResultPtr, Offset,
"uglygep");
775 ResultPtr = Builder.CreateBitCast(ResultPtr, Variadic->
getType());
783 int64_t AccumulativeByteOffset) {
787 Value *ResultPtr = Builder.CreatePtrToInt(Variadic->
getOperand(0), IntPtrTy);
793 if (isa<SequentialType>(*GTI)) {
803 if (ElementSize != 1) {
805 Idx = Builder.CreateShl(
812 ResultPtr = Builder.CreateAdd(ResultPtr, Idx);
817 if (AccumulativeByteOffset != 0) {
818 ResultPtr = Builder.CreateAdd(
822 ResultPtr = Builder.CreateIntToPtr(ResultPtr, Variadic->
getType());
837 bool Changed = canonicalizeArrayIndicesToPointerSize(GEP);
839 bool NeedsExtraction;
840 int64_t AccumulativeByteOffset = accumulateByteOffset(GEP, NeedsExtraction);
842 if (!NeedsExtraction)
853 getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
857 nullptr, AccumulativeByteOffset,
873 if (isa<SequentialType>(*GTI)) {
879 ConstantOffsetExtractor::Extract(OldIdx, GEP, UserChainTail, DT);
880 if (NewIdx !=
nullptr) {
917 lowerToSingleIndexGEPs(GEP, AccumulativeByteOffset);
919 lowerToArithmetics(GEP, AccumulativeByteOffset);
924 if (AccumulativeByteOffset == 0)
961 int64_t ElementTypeSizeOfGEP =
static_cast<int64_t
>(
964 if (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0) {
967 int64_t Index = AccumulativeByteOffset / ElementTypeSizeOfGEP;
988 NewGEP =
new BitCastInst(NewGEP, I8PtrTy,
"", GEP);
1003 bool SeparateConstOffsetFromGEP::runOnFunction(
Function &
F) {
1004 if (skipOptnoneFunction(F))
1010 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1012 bool Changed =
false;
1016 Changed |= splitGEP(GEP);
1024 verifyNoDeadCode(F);
1029 void SeparateConstOffsetFromGEP::verifyNoDeadCode(
Function &F) {
1033 std::string ErrMessage;
1035 RSO <<
"Dead instruction detected!\n" <<
I <<
"\n";
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type (if unknown returns 0).
INITIALIZE_PASS_BEGIN(SeparateConstOffsetFromGEP,"separate-const-offset-from-gep","Split GEPs to a variadic base and a constant offset for better CSE", false, false) INITIALIZE_PASS_END(SeparateConstOffsetFromGEP
iplist< Instruction >::iterator eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing basic block and deletes it...
A parsed version of the target data layout string in and methods for querying it. ...
Type * getIndexedType() const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
A Module instance is used to store all the information related to an LLVM module. ...
unsigned getNumOperands() const
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
static cl::opt< bool > VerifyNoDeadCode("reassociate-geps-verify-no-dead-code", cl::init(false), cl::desc("Verify this pass produces no dead code"), cl::Hidden)
bool haveNoCommonBitsSet(Value *LHS, Value *RHS, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr)
Returns true if LHS and RHS have no common bits set.
const Function * getParent() const
Return the enclosing method, or null if none.
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys=None)
Return the function type for an intrinsic.
unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static Constant * getNullValue(Type *Ty)
StringRef getName() const
Return a constant reference to the value's name.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
This is the base class for all instructions that perform data casts.
StructType - Class to represent struct types.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
A Use represents the edge between a Value definition and its users.
void setIsInBounds(bool b=true)
setIsInBounds - Set or clear the inbounds flag on this GEP instruction.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
separate const offset from Split GEPs to a variadic base and a constant offset for better CSE
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Instruction * clone() const
clone() - Create a copy of 'this' instruction that is identical in all ways except the following: ...
This class represents a no-op cast from one type to another.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
Type * getElementType() const
void initializeSeparateConstOffsetFromGEPPass(PassRegistry &)
bool isInBounds() const
isInBounds - Determine whether the GEP has the inbounds flag.
GetElementPtrInst - an instruction for type-safe pointer arithmetic to access elements of arrays and ...
initializer< Ty > init(const Ty &Val)
FunctionPass * createSeparateConstOffsetFromGEPPass(const TargetMachine *TM=nullptr, bool LowerGEP=false)
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction...
The instances of the Type class are immutable: once they are created, they are never changed...
bool isVectorTy() const
isVectorTy - True if this is an instance of VectorType.
This is an important base class in LLVM.
static const SubtargetFeatureKV * Find(StringRef S, ArrayRef< SubtargetFeatureKV > A)
Find KV in array using binary search.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
APInt Or(const APInt &LHS, const APInt &RHS)
Bitwise OR function for APInt.
Represent the analysis usage information of a pass.
static cl::opt< bool > DisableSeparateConstOffsetFromGEP("disable-separate-const-offset-from-gep", cl::init(false), cl::desc("Do not separate the constant offset from a GEP instruction"), cl::Hidden)
for(unsigned i=0, e=MI->getNumOperands();i!=e;++i)
FunctionPass class - This class is used to implement most global optimizations.
Value * getOperand(unsigned i) const
bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr)
RecursivelyDeleteTriviallyDeadInstructions - If the specified value is a trivially dead instruction...
bool hasAllConstantIndices() const
hasAllConstantIndices - Return true if all of the indices of this GEP are constant integers...
LLVMContext & getContext() const
All values hold a context through their type.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
bool hasNoSignedWrap() const
Determine whether the no signed wrap flag is set.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
BinaryOps getOpcode() const
static CastInst * CreateIntegerCast(Value *S, Type *Ty, bool isSigned, const Twine &Name="", Instruction *InsertBefore=nullptr)
Create a ZExt, BitCast, or Trunc for int -> int casts.
unsigned getIntegerBitWidth() const
This is the shared class of boolean and integer constants.
unsigned logBase2() const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
SequentialType * getType() const
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
void setOperand(unsigned i, Value *Val)
Class for arbitrary precision integers.
static BinaryOperator * Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name=Twine(), Instruction *InsertBefore=nullptr)
Construct a binary instruction, given the opcode and the two operands.
static Constant * getCast(unsigned ops, Constant *C, Type *Ty, bool OnlyIfReduced=false)
Convenience function for getting a Cast operation.
LLVM_ATTRIBUTE_UNUSED_RESULT std::enable_if< !is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
separate const offset from gep
A raw_ostream that writes to an std::string.
bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
isInstructionTriviallyDead - Return true if the result produced by the instruction is not used...
LLVM Value Representation.
bool hasNoUnsignedWrap() const
Determine whether the no unsigned wrap flag is set.
Primary interface to the complete machine description for the target machine.
C - The default llvm calling convention, compatible with C.
Legacy analysis pass which computes a DominatorTree.
unsigned getNumUses() const
This method computes the number of uses of this Value.
static void Split(std::vector< std::string > &V, StringRef S)
Split - Splits a string of comma separated items in to a vector of strings.
separate const offset from Split GEPs to a variadic base and a constant offset for better false
static IntegerType * getInt8Ty(LLVMContext &C)
const BasicBlock * getParent() const
Type * getResultElementType() const
gep_type_iterator gep_type_begin(const User *GEP)