Rewrite cast->cast elimination code completely based on the information we
authorChris Lattner <sabre@nondot.org>
Tue, 20 Jul 2004 00:59:32 +0000 (00:59 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 20 Jul 2004 00:59:32 +0000 (00:59 +0000)
actually care about.  Someday when the cast instruction is gone, we can do
better here, but this will do for now.  This implements
instcombine/cast.ll:test17/18 as well.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15018 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp

index d53cdbf87dfc6a10ae2e771bdb6e9dae18cd2fc0..6b993750a3fc613ed1283b38801ca100b097352c 100644 (file)
@@ -1938,6 +1938,29 @@ Instruction *InstCombiner::visitShiftInst(ShiftInst &I) {
   return 0;
 }
 
+enum CastType {
+  Noop     = 0,
+  Truncate = 1,
+  Signext  = 2,
+  Zeroext  = 3
+};
+
+/// getCastType - In the future, we will split the cast instruction into these
+/// various types.  Until then, we have to do the analysis here.
+static CastType getCastType(const Type *Src, const Type *Dest) {
+  assert(Src->isIntegral() && Dest->isIntegral() &&
+         "Only works on integral types!");
+  unsigned SrcSize = Src->getPrimitiveSize()*8;
+  if (Src == Type::BoolTy) SrcSize = 1;
+  unsigned DestSize = Dest->getPrimitiveSize()*8;
+  if (Dest == Type::BoolTy) DestSize = 1;
+
+  if (SrcSize == DestSize) return Noop;
+  if (SrcSize > DestSize)  return Truncate;
+  if (Src->isSigned()) return Signext;
+  return Zeroext;
+}
+
 
 // isEliminableCastOfCast - Return true if it is valid to eliminate the CI
 // instruction.
@@ -1954,50 +1977,37 @@ static inline bool isEliminableCastOfCast(const Type *SrcTy, const Type *MidTy,
   // Allow free casting and conversion of sizes as long as the sign doesn't
   // change...
   if (SrcTy->isIntegral() && MidTy->isIntegral() && DstTy->isIntegral()) {
-    unsigned SrcSize = SrcTy->getPrimitiveSize();
-    unsigned MidSize = MidTy->getPrimitiveSize();
-    unsigned DstSize = DstTy->getPrimitiveSize();
-
-    // Cases where we are monotonically decreasing the size of the type are
-    // always ok, regardless of what sign changes are going on.
-    //
-    if (SrcSize >= MidSize && MidSize >= DstSize)
+    CastType FirstCast = getCastType(SrcTy, MidTy);
+    CastType SecondCast = getCastType(MidTy, DstTy);
+
+    // Capture the effect of these two casts.  If the result is a legal cast,
+    // the CastType is stored here, otherwise a special code is used.
+    static const unsigned CastResult[] = {
+      // First cast is noop
+      0, 1, 2, 3,
+      // First cast is a truncate
+      1, 1, 4, 4,         // trunc->extend is not safe to eliminate
+      // First cast is a sign ext
+      2, 5, 2, 4,         // signext->trunc always ok, signext->zeroext never ok
+      // First cast is a zero ext
+      3, 5, 3, 3,         // zeroext->trunc always ok
+    };
+
+    unsigned Result = CastResult[FirstCast*4+SecondCast];
+    switch (Result) {
+    default: assert(0 && "Illegal table value!");
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      // FIXME: in the future, when LLVM has explicit sign/zeroextends and
+      // truncates, we could eliminate more casts.
+      return (unsigned)getCastType(SrcTy, DstTy) == Result;
+    case 4:
+      return false;  // Not possible to eliminate this here.
+    case 5:
+      // Sign or zero extend followed by truncate is always ok
       return true;
-
-    // Cases where the source and destination type are the same, but the middle
-    // type is bigger are noops.
-    //
-    if (SrcSize == DstSize && MidSize > SrcSize)
-      return true;
-
-    // If we are monotonically growing, things are more complex.
-    //
-    if (SrcSize <= MidSize && MidSize <= DstSize) {
-      // We have eight combinations of signedness to worry about. Here's the
-      // table:
-      static const int SignTable[8] = {
-        // CODE, SrcSigned, MidSigned, DstSigned, Comment
-        1,     //   U          U          U       Always ok
-        1,     //   U          U          S       Always ok
-        3,     //   U          S          U       Ok iff SrcSize != MidSize
-        3,     //   U          S          S       Ok iff SrcSize != MidSize
-        0,     //   S          U          U       Never ok
-        2,     //   S          U          S       Ok iff MidSize == DstSize
-        1,     //   S          S          U       Always ok
-        1,     //   S          S          S       Always ok
-      };
-
-      // Choose an action based on the current entry of the signtable that this
-      // cast of cast refers to...
-      unsigned Row = SrcTy->isSigned()*4+MidTy->isSigned()*2+DstTy->isSigned();
-      switch (SignTable[Row]) {
-      case 0: return false;              // Never ok
-      case 1: return true;               // Always ok
-      case 2: return MidSize == DstSize; // Ok iff MidSize == DstSize
-      case 3:                            // Ok iff SrcSize != MidSize
-        return SrcSize != MidSize || SrcTy == Type::BoolTy;
-      default: assert(0 && "Bad entry in sign table!");
-      }
     }
   }