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
This commit is contained in:
Dan Gohman 2010-01-28 02:15:55 +00:00
parent edfe776ac2
commit 0f5efe5625
6 changed files with 144 additions and 207 deletions

View File

@ -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();
}

View File

@ -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:

View File

@ -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<ConstantExpr>(V))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr)
if (CE->getOperand(0)->isNullValue()) {
const Type *Ty =
cast<PointerType>(CE->getOperand(0)->getType())->getElementType();
if (const StructType *StructTy = dyn_cast<StructType>(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<ConstantExpr>(V))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr)
if (CE->getOperand(0)->isNullValue()) {
const Type *Ty =
cast<PointerType>(CE->getOperand(0)->getType())->getElementType();
if (CE->getNumOperands() == 2)
if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(1)))
if (CI->isOne()) {
AllocTy = Ty;
return true;
}
}
return false;
}
bool SCEVUnknown::isAlignOf(const Type *&AllocTy) const {
if (ConstantExpr *VCE = dyn_cast<ConstantExpr>(V))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr)
if (CE->getOperand(0)->isNullValue()) {
const Type *Ty =
cast<PointerType>(CE->getOperand(0)->getType())->getElementType();
if (const StructType *STy = dyn_cast<StructType>(Ty))
if (CE->getNumOperands() == 3 &&
CE->getOperand(1)->isNullValue()) {
if (ConstantInt *CI = dyn_cast<ConstantInt>(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<SCEVFieldOffsetExpr>(LHS)) {
const SCEVFieldOffsetExpr *RA = cast<SCEVFieldOffsetExpr>(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<SCEVAllocSizeExpr>(LHS)) {
const SCEVAllocSizeExpr *RA = cast<SCEVAllocSizeExpr>(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<SCEVFieldOffsetExpr>();
Constant *C = ConstantExpr::getOffsetOf(STy, FieldNo);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(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<ArrayType>(AllocTy)) {
const SCEV *E = getAllocSizeExpr(ATy->getElementType());
return getMulExpr(
E, getConstant(ConstantInt::get(cast<IntegerType>(E->getType()),
ATy->getNumElements())));
}
// Expand a vector size into the element size times the number
// of elements.
if (const VectorType *VTy = dyn_cast<VectorType>(AllocTy)) {
const SCEV *E = getAllocSizeExpr(VTy->getElementType());
return getMulExpr(
E, getConstant(ConstantInt::get(cast<IntegerType>(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<SCEVAllocSizeExpr>();
Constant *C = ConstantExpr::getSizeOf(AllocTy);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(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<SCEVTargetDataConstant>(V))
return V;
llvm_unreachable("Unknown SCEV type!");
return 0;
}

View File

@ -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<SCEVFieldOffsetExpr>(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<SCEVUnknown>(Ops[i])) {
const StructType *StructTy;
Constant *FieldNo;
if (U->isOffsetOf(StructTy, FieldNo) && StructTy == STy) {
GepIndices.push_back(FieldNo);
ElTy =
STy->getTypeAtIndex(cast<ConstantInt>(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);

View File

@ -415,9 +415,38 @@ Constant *llvm::ConstantFoldCastInstruction(LLVMContext &Context,
return ConstantPointerNull::get(cast<PointerType>(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<ConstantExpr>(V))
if (CE->getOpcode() == Instruction::GetElementPtr &&
CE->getNumOperands() == 2 &&
CE->getOperand(0)->isNullValue())
if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(1)))
if (CI->isOne()) {
const Type *Ty =
cast<PointerType>(CE->getOperand(0)->getType())->getElementType();
if (const ArrayType *ATy = dyn_cast<ArrayType>(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<VectorType>(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<ConstantInt>(V)) {

View File

@ -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);