From 0f5efe56258f8cd6ceff4d7955a5d80144cd9cb0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 28 Jan 2010 02:15:55 +0000 Subject: [PATCH] Remove SCEVAllocSizeExpr and SCEVFieldOffsetExpr, and in their place use plain SCEVUnknowns with ConstantExpr::getSizeOf and ConstantExpr::getOffsetOf constants. This eliminates a bunch of special-case code. Also add code for pattern-matching these expressions, for clients that want to recognize them. Move ScalarEvolution's logic for expanding array and vector sizeof expressions into an element count times the element size, to expose the multiplication to subsequent folding, into the regular constant folder. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@94737 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/Analysis/ScalarEvolutionExpander.h | 4 - .../Analysis/ScalarEvolutionExpressions.h | 105 ++-------- lib/Analysis/ScalarEvolution.cpp | 179 +++++++++--------- lib/Analysis/ScalarEvolutionExpander.cpp | 26 +-- lib/VMCore/ConstantFold.cpp | 33 +++- lib/VMCore/Constants.cpp | 4 +- 6 files changed, 144 insertions(+), 207 deletions(-) diff --git a/include/llvm/Analysis/ScalarEvolutionExpander.h b/include/llvm/Analysis/ScalarEvolutionExpander.h index 01df503a5e1..796b1685a7f 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpander.h +++ b/include/llvm/Analysis/ScalarEvolutionExpander.h @@ -167,10 +167,6 @@ namespace llvm { Value *visitUMaxExpr(const SCEVUMaxExpr *S); - Value *visitFieldOffsetExpr(const SCEVFieldOffsetExpr *S); - - Value *visitAllocSizeExpr(const SCEVAllocSizeExpr *S); - Value *visitUnknown(const SCEVUnknown *S) { return S->getValue(); } diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h index 64b8b0bf786..5b93458f11d 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h @@ -27,7 +27,7 @@ namespace llvm { // folders simpler. scConstant, scTruncate, scZeroExtend, scSignExtend, scAddExpr, scMulExpr, scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr, - scFieldOffset, scAllocSize, scUnknown, scCouldNotCompute + scUnknown, scCouldNotCompute }; //===--------------------------------------------------------------------===// @@ -511,95 +511,6 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVTargetDataConstant - This node is the base class for representing - /// target-dependent values in a target-independent way. - /// - class SCEVTargetDataConstant : public SCEV { - protected: - const Type *Ty; - SCEVTargetDataConstant(const FoldingSetNodeID &ID, enum SCEVTypes T, - const Type *ty) : - SCEV(ID, T), Ty(ty) {} - - public: - virtual bool isLoopInvariant(const Loop *) const { return true; } - virtual bool hasComputableLoopEvolution(const Loop *) const { - return false; // not computable - } - - virtual bool hasOperand(const SCEV *) const { - return false; - } - - bool dominates(BasicBlock *, DominatorTree *) const { - return true; - } - - bool properlyDominates(BasicBlock *, DominatorTree *) const { - return true; - } - - virtual const Type *getType() const { return Ty; } - - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const SCEVTargetDataConstant *S) { return true; } - static inline bool classof(const SCEV *S) { - return S->getSCEVType() == scFieldOffset || - S->getSCEVType() == scAllocSize; - } - }; - - //===--------------------------------------------------------------------===// - /// SCEVFieldOffsetExpr - This node represents an offsetof expression. - /// - class SCEVFieldOffsetExpr : public SCEVTargetDataConstant { - friend class ScalarEvolution; - - const StructType *STy; - unsigned FieldNo; - SCEVFieldOffsetExpr(const FoldingSetNodeID &ID, const Type *ty, - const StructType *sty, unsigned fieldno) : - SCEVTargetDataConstant(ID, scFieldOffset, ty), - STy(sty), FieldNo(fieldno) {} - - public: - const StructType *getStructType() const { return STy; } - unsigned getFieldNo() const { return FieldNo; } - - virtual void print(raw_ostream &OS) const; - - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const SCEVFieldOffsetExpr *S) { return true; } - static inline bool classof(const SCEV *S) { - return S->getSCEVType() == scFieldOffset; - } - }; - - //===--------------------------------------------------------------------===// - /// SCEVAllocSize - This node represents a sizeof expression. - /// - class SCEVAllocSizeExpr : public SCEVTargetDataConstant { - friend class ScalarEvolution; - - const Type *AllocTy; - SCEVAllocSizeExpr(const FoldingSetNodeID &ID, - const Type *ty, const Type *allocty) : - SCEVTargetDataConstant(ID, scAllocSize, ty), - AllocTy(allocty) {} - - public: - const Type *getAllocType() const { return AllocTy; } - - virtual void print(raw_ostream &OS) const; - - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const SCEVAllocSizeExpr *S) { return true; } - static inline bool classof(const SCEV *S) { - return S->getSCEVType() == scAllocSize; - } - }; - //===--------------------------------------------------------------------===// /// SCEVUnknown - This means that we are dealing with an entirely unknown SCEV /// value, and only represent it as its LLVM Value. This is the "bottom" @@ -615,6 +526,16 @@ namespace llvm { public: Value *getValue() const { return V; } + /// isSizeOf, isAlignOf, isOffsetOf - Test whether this is a special + /// constant representing a type size, alignment, or field offset in + /// a target-independent manner, and hasn't happened to have been + /// folded with other operations into something unrecognizable. This + /// is mainly only useful for pretty-printing and other situations + /// where it isn't absolutely required for these to succeed. + bool isSizeOf(const Type *&AllocTy) const; + bool isAlignOf(const Type *&AllocTy) const; + bool isOffsetOf(const StructType *&STy, Constant *&FieldNo) const; + virtual bool isLoopInvariant(const Loop *L) const; virtual bool hasComputableLoopEvolution(const Loop *QL) const { return false; // not computable @@ -665,10 +586,6 @@ namespace llvm { return ((SC*)this)->visitSMaxExpr((const SCEVSMaxExpr*)S); case scUMaxExpr: return ((SC*)this)->visitUMaxExpr((const SCEVUMaxExpr*)S); - case scFieldOffset: - return ((SC*)this)->visitFieldOffsetExpr((const SCEVFieldOffsetExpr*)S); - case scAllocSize: - return ((SC*)this)->visitAllocSizeExpr((const SCEVAllocSizeExpr*)S); case scUnknown: return ((SC*)this)->visitUnknown((const SCEVUnknown*)S); case scCouldNotCompute: diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index b2395af9243..f19e153e0d4 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -321,15 +321,6 @@ void SCEVAddRecExpr::print(raw_ostream &OS) const { OS << ">"; } -void SCEVFieldOffsetExpr::print(raw_ostream &OS) const { - // LLVM struct fields don't have names, so just print the field number. - OS << "offsetof(" << *STy << ", " << FieldNo << ")"; -} - -void SCEVAllocSizeExpr::print(raw_ostream &OS) const { - OS << "sizeof(" << *AllocTy << ")"; -} - bool SCEVUnknown::isLoopInvariant(const Loop *L) const { // All non-instruction values are loop invariant. All instructions are loop // invariant if they are not contained in the specified loop. @@ -356,7 +347,90 @@ const Type *SCEVUnknown::getType() const { return V->getType(); } +bool SCEVUnknown::isOffsetOf(const StructType *&STy, Constant *&FieldNo) const { + if (ConstantExpr *VCE = dyn_cast(V)) + if (VCE->getOpcode() == Instruction::PtrToInt) + if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) + if (CE->getOpcode() == Instruction::GetElementPtr) + if (CE->getOperand(0)->isNullValue()) { + const Type *Ty = + cast(CE->getOperand(0)->getType())->getElementType(); + if (const StructType *StructTy = dyn_cast(Ty)) + if (CE->getNumOperands() == 3 && + CE->getOperand(1)->isNullValue()) { + STy = StructTy; + FieldNo = CE->getOperand(2); + return true; + } + } + + return false; +} + +bool SCEVUnknown::isSizeOf(const Type *&AllocTy) const { + if (ConstantExpr *VCE = dyn_cast(V)) + if (VCE->getOpcode() == Instruction::PtrToInt) + if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) + if (CE->getOpcode() == Instruction::GetElementPtr) + if (CE->getOperand(0)->isNullValue()) { + const Type *Ty = + cast(CE->getOperand(0)->getType())->getElementType(); + if (CE->getNumOperands() == 2) + if (ConstantInt *CI = dyn_cast(CE->getOperand(1))) + if (CI->isOne()) { + AllocTy = Ty; + return true; + } + } + + return false; +} + +bool SCEVUnknown::isAlignOf(const Type *&AllocTy) const { + if (ConstantExpr *VCE = dyn_cast(V)) + if (VCE->getOpcode() == Instruction::PtrToInt) + if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) + if (CE->getOpcode() == Instruction::GetElementPtr) + if (CE->getOperand(0)->isNullValue()) { + const Type *Ty = + cast(CE->getOperand(0)->getType())->getElementType(); + if (const StructType *STy = dyn_cast(Ty)) + if (CE->getNumOperands() == 3 && + CE->getOperand(1)->isNullValue()) { + if (ConstantInt *CI = dyn_cast(CE->getOperand(2))) + if (CI->isOne() && + STy->getNumElements() == 2 && + STy->getElementType(0)->isInteger(1)) { + AllocTy = STy->getElementType(1); + return true; + } + } + } + + return false; +} + void SCEVUnknown::print(raw_ostream &OS) const { + const Type *AllocTy; + if (isSizeOf(AllocTy)) { + OS << "sizeof(" << *AllocTy << ")"; + return; + } + if (isAlignOf(AllocTy)) { + OS << "alignof(" << *AllocTy << ")"; + return; + } + + const StructType *STy; + Constant *FieldNo; + if (isOffsetOf(STy, FieldNo)) { + OS << "offsetof(" << *STy << ", "; + WriteAsOperand(OS, FieldNo, false); + OS << ")"; + return; + } + + // Otherwise just print it normally. WriteAsOperand(OS, V, false); } @@ -515,21 +589,6 @@ namespace { return operator()(LC->getOperand(), RC->getOperand()); } - // Compare offsetof expressions. - if (const SCEVFieldOffsetExpr *LA = dyn_cast(LHS)) { - const SCEVFieldOffsetExpr *RA = cast(RHS); - if (CompareTypes(LA->getStructType(), RA->getStructType()) || - CompareTypes(RA->getStructType(), LA->getStructType())) - return CompareTypes(LA->getStructType(), RA->getStructType()); - return LA->getFieldNo() < RA->getFieldNo(); - } - - // Compare sizeof expressions by the allocation type. - if (const SCEVAllocSizeExpr *LA = dyn_cast(LHS)) { - const SCEVAllocSizeExpr *RA = cast(RHS); - return CompareTypes(LA->getAllocType(), RA->getAllocType()); - } - llvm_unreachable("Unknown SCEV kind!"); return false; } @@ -2174,72 +2233,19 @@ const SCEV *ScalarEvolution::getUMinExpr(const SCEV *LHS, const SCEV *ScalarEvolution::getFieldOffsetExpr(const StructType *STy, unsigned FieldNo) { - // If we have TargetData we can determine the constant offset. - if (TD) { - const Type *IntPtrTy = TD->getIntPtrType(getContext()); - const StructLayout &SL = *TD->getStructLayout(STy); - uint64_t Offset = SL.getElementOffset(FieldNo); - return getIntegerSCEV(Offset, IntPtrTy); - } - - // Field 0 is always at offset 0. - if (FieldNo == 0) { - const Type *Ty = getEffectiveSCEVType(PointerType::getUnqual(STy)); - return getIntegerSCEV(0, Ty); - } - - // Okay, it looks like we really DO need an offsetof expr. Check to see if we - // already have one, otherwise create a new one. - FoldingSetNodeID ID; - ID.AddInteger(scFieldOffset); - ID.AddPointer(STy); - ID.AddInteger(FieldNo); - void *IP = 0; - if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; - SCEV *S = SCEVAllocator.Allocate(); + Constant *C = ConstantExpr::getOffsetOf(STy, FieldNo); + if (ConstantExpr *CE = dyn_cast(C)) + C = ConstantFoldConstantExpression(CE, TD); const Type *Ty = getEffectiveSCEVType(PointerType::getUnqual(STy)); - new (S) SCEVFieldOffsetExpr(ID, Ty, STy, FieldNo); - UniqueSCEVs.InsertNode(S, IP); - return S; + return getTruncateOrZeroExtend(getSCEV(C), Ty); } const SCEV *ScalarEvolution::getAllocSizeExpr(const Type *AllocTy) { - // If we have TargetData we can determine the constant size. - if (TD && AllocTy->isSized()) { - const Type *IntPtrTy = TD->getIntPtrType(getContext()); - return getIntegerSCEV(TD->getTypeAllocSize(AllocTy), IntPtrTy); - } - - // Expand an array size into the element size times the number - // of elements. - if (const ArrayType *ATy = dyn_cast(AllocTy)) { - const SCEV *E = getAllocSizeExpr(ATy->getElementType()); - return getMulExpr( - E, getConstant(ConstantInt::get(cast(E->getType()), - ATy->getNumElements()))); - } - - // Expand a vector size into the element size times the number - // of elements. - if (const VectorType *VTy = dyn_cast(AllocTy)) { - const SCEV *E = getAllocSizeExpr(VTy->getElementType()); - return getMulExpr( - E, getConstant(ConstantInt::get(cast(E->getType()), - VTy->getNumElements()))); - } - - // Okay, it looks like we really DO need a sizeof expr. Check to see if we - // already have one, otherwise create a new one. - FoldingSetNodeID ID; - ID.AddInteger(scAllocSize); - ID.AddPointer(AllocTy); - void *IP = 0; - if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; - SCEV *S = SCEVAllocator.Allocate(); + Constant *C = ConstantExpr::getSizeOf(AllocTy); + if (ConstantExpr *CE = dyn_cast(C)) + C = ConstantFoldConstantExpression(CE, TD); const Type *Ty = getEffectiveSCEVType(PointerType::getUnqual(AllocTy)); - new (S) SCEVAllocSizeExpr(ID, Ty, AllocTy); - UniqueSCEVs.InsertNode(S, IP); - return S; + return getTruncateOrZeroExtend(getSCEV(C), Ty); } const SCEV *ScalarEvolution::getUnknown(Value *V) { @@ -4242,9 +4248,6 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) { return getTruncateExpr(Op, Cast->getType()); } - if (isa(V)) - return V; - llvm_unreachable("Unknown SCEV type!"); return 0; } diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp index a72f58f64fa..9e2e712cdd0 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp @@ -427,22 +427,22 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, } } } else { - // Without TargetData, just check for a SCEVFieldOffsetExpr of the + // Without TargetData, just check for an offsetof expression of the // appropriate struct type. for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (const SCEVFieldOffsetExpr *FO = - dyn_cast(Ops[i])) - if (FO->getStructType() == STy) { - unsigned FieldNo = FO->getFieldNo(); - GepIndices.push_back( - ConstantInt::get(Type::getInt32Ty(Ty->getContext()), - FieldNo)); - ElTy = STy->getTypeAtIndex(FieldNo); + if (const SCEVUnknown *U = dyn_cast(Ops[i])) { + const StructType *StructTy; + Constant *FieldNo; + if (U->isOffsetOf(StructTy, FieldNo) && StructTy == STy) { + GepIndices.push_back(FieldNo); + ElTy = + STy->getTypeAtIndex(cast(FieldNo)->getZExtValue()); Ops[i] = SE.getConstant(Ty, 0); AnyNonZeroIndices = true; FoundFieldNo = true; break; } + } } // If no struct field offsets were found, tentatively assume that // field zero was selected (since the zero offset would obviously @@ -1001,14 +1001,6 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { return LHS; } -Value *SCEVExpander::visitFieldOffsetExpr(const SCEVFieldOffsetExpr *S) { - return ConstantExpr::getOffsetOf(S->getStructType(), S->getFieldNo()); -} - -Value *SCEVExpander::visitAllocSizeExpr(const SCEVAllocSizeExpr *S) { - return ConstantExpr::getSizeOf(S->getAllocType()); -} - Value *SCEVExpander::expandCodeFor(const SCEV *SH, const Type *Ty) { // Expand the code for this SCEV. Value *V = expand(SH); diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index ddd55878cb9..24b78ae969a 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -415,9 +415,38 @@ Constant *llvm::ConstantFoldCastInstruction(LLVMContext &Context, return ConstantPointerNull::get(cast(DestTy)); return 0; // Other pointer types cannot be casted case Instruction::PtrToInt: // always treated as unsigned - if (V->isNullValue()) // is it a null pointer value? + // Is it a null pointer value? + if (V->isNullValue()) return ConstantInt::get(DestTy, 0); - return 0; // Other pointer types cannot be casted + // If this is a sizeof of an array or vector, pull out a multiplication + // by the element size to expose it to subsequent folding. + if (ConstantExpr *CE = dyn_cast(V)) + if (CE->getOpcode() == Instruction::GetElementPtr && + CE->getNumOperands() == 2 && + CE->getOperand(0)->isNullValue()) + if (ConstantInt *CI = dyn_cast(CE->getOperand(1))) + if (CI->isOne()) { + const Type *Ty = + cast(CE->getOperand(0)->getType())->getElementType(); + if (const ArrayType *ATy = dyn_cast(Ty)) { + Constant *N = ConstantInt::get(DestTy, ATy->getNumElements()); + Constant *E = ConstantExpr::getSizeOf(ATy->getElementType()); + E = ConstantExpr::getCast(CastInst::getCastOpcode(E, false, + DestTy, false), + E, DestTy); + return ConstantExpr::getMul(N, E); + } + if (const VectorType *VTy = dyn_cast(Ty)) { + Constant *N = ConstantInt::get(DestTy, VTy->getNumElements()); + Constant *E = ConstantExpr::getSizeOf(VTy->getElementType()); + E = ConstantExpr::getCast(CastInst::getCastOpcode(E, false, + DestTy, false), + E, DestTy); + return ConstantExpr::getMul(N, E); + } + } + // Other pointer types cannot be casted + return 0; case Instruction::UIToFP: case Instruction::SIToFP: if (ConstantInt *CI = dyn_cast(V)) { diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 436083f62b0..9e1154e95e3 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -1479,10 +1479,10 @@ Constant* ConstantExpr::getSizeOf(const Type* Ty) { } Constant* ConstantExpr::getAlignOf(const Type* Ty) { - // alignof is implemented as: (i64) gep ({i8,Ty}*)null, 0, 1 + // alignof is implemented as: (i64) gep ({i1,Ty}*)null, 0, 1 // Note that a non-inbounds gep is used, as null isn't within any object. const Type *AligningTy = StructType::get(Ty->getContext(), - Type::getInt8Ty(Ty->getContext()), Ty, NULL); + Type::getInt1Ty(Ty->getContext()), Ty, NULL); Constant *NullPtr = Constant::getNullValue(AligningTy->getPointerTo()); Constant *Zero = ConstantInt::get(Type::getInt32Ty(Ty->getContext()), 0); Constant *One = ConstantInt::get(Type::getInt32Ty(Ty->getContext()), 1);