Remove SCEVAllocSizeExpr and SCEVFieldOffsetExpr, and in their place
authorDan Gohman <gohman@apple.com>
Thu, 28 Jan 2010 02:15:55 +0000 (02:15 +0000)
committerDan Gohman <gohman@apple.com>
Thu, 28 Jan 2010 02:15:55 +0000 (02:15 +0000)
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

include/llvm/Analysis/ScalarEvolutionExpander.h
include/llvm/Analysis/ScalarEvolutionExpressions.h
lib/Analysis/ScalarEvolution.cpp
lib/Analysis/ScalarEvolutionExpander.cpp
lib/VMCore/ConstantFold.cpp
lib/VMCore/Constants.cpp

index 01df503a5e1921191e0ad998cff172137494b247..796b1685a7ff4db4b24eecbce5480e199c8e79a7 100644 (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();
     }
index 64b8b0bf7866c2391db36c956116b03a1635b86e..5b93458f11d925b1892aa5ed5da176846ec82da0 100644 (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:
index b2395af9243b4facd11fa3e11cf1d17f6645cceb..f19e153e0d40b3f278ee922d1660f8612fda91e1 100644 (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;
 }
index a72f58f64faecd231ffaf33c772a3360889d6225..9e2e712cdd03bf64826d6ef1d5cd6304789c76fa 100644 (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);
index ddd55878cb9d62eec5be4dbbd841d4dbfa636992..24b78ae969af66ee7f6b5a5011459ff29bc0541f 100644 (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)) {
index 436083f62b0e975238799df72ca3e7f2419e9aa8..9e1154e95e33d517aee6bd717588914306d29d70 100644 (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);