[llvm-commits] [llvm] r45657 - in /llvm/trunk: include/llvm/InstrTypes.h lib/Transforms/Scalar/InstructionCombining.cpp lib/VMCore/Instructions.cpp test/Transforms/InstCombine/2008-01-06-CastCrash.ll test/Transforms/InstCombine/2008-01-06-VoidCast.ll

Duncan Sands baldrick at free.fr
Sun Jan 6 02:12:37 PST 2008


Author: baldrick
Date: Sun Jan  6 04:12:28 2008
New Revision: 45657

URL: http://llvm.org/viewvc/llvm-project?rev=45657&view=rev
Log:
When transforming a call to a bitcast function into
a direct call with cast parameters and cast return
value (if any), instcombine was prepared to cast any
non-void return value into any other, whether castable
or not.  Add a new predicate for testing whether casting
is valid, and check it both for the return value and
(as a cleanup) for the parameters.

Added:
    llvm/trunk/test/Transforms/InstCombine/2008-01-06-CastCrash.ll
    llvm/trunk/test/Transforms/InstCombine/2008-01-06-VoidCast.ll
Modified:
    llvm/trunk/include/llvm/InstrTypes.h
    llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp
    llvm/trunk/lib/VMCore/Instructions.cpp

Modified: llvm/trunk/include/llvm/InstrTypes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InstrTypes.h?rev=45657&r1=45656&r2=45657&view=diff

==============================================================================
--- llvm/trunk/include/llvm/InstrTypes.h (original)
+++ llvm/trunk/include/llvm/InstrTypes.h Sun Jan  6 04:12:28 2008
@@ -398,8 +398,14 @@
     BasicBlock *InsertAtEnd  ///< The block to insert the instruction into
   );
 
+  /// @brief Check whether it is valid to call getCastOpcode for these types.
+  static bool isCastable(
+    const Type *SrcTy, ///< The Type from which the value should be cast.
+    const Type *DestTy ///< The Type to which the value should be cast.
+  );
+
   /// Returns the opcode necessary to cast Val into Ty using usual casting
-  /// rules. 
+  /// rules.
   /// @brief Infer the opcode for cast operand and type
   static Instruction::CastOps getCastOpcode(
     const Value *Val, ///< The value to cast

Modified: llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp?rev=45657&r1=45656&r2=45657&view=diff

==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp Sun Jan  6 04:12:28 2008
@@ -8082,11 +8082,7 @@
   const FunctionType *FT = Callee->getFunctionType();
   const Type *OldRetTy = Caller->getType();
 
-  const ParamAttrsList* CallerPAL = 0;
-  if (CallInst *CallerCI = dyn_cast<CallInst>(Caller))
-    CallerPAL = CallerCI->getParamAttrs();
-  else if (InvokeInst *CallerII = dyn_cast<InvokeInst>(Caller))
-    CallerPAL = CallerII->getParamAttrs();
+  const ParamAttrsList* CallerPAL = CS.getParamAttrs();
 
   // If the parameter attributes are not compatible, don't do the xform.  We
   // don't want to lose an sret attribute or something.
@@ -8101,6 +8097,12 @@
           TD->getIntPtrType() == OldRetTy))
       return false;   // Cannot transform this return value.
 
+    if (!Caller->use_empty() &&
+        !CastInst::isCastable(FT->getReturnType(), OldRetTy) &&
+        // void -> non-void is handled specially
+        FT->getReturnType() != Type::VoidTy)
+      return false;   // Cannot transform this return value.
+
     // If the callsite is an invoke instruction, and the return value is used by
     // a PHI node in a successor, we cannot change the return type of the call
     // because there is no place to put the cast instruction (without breaking
@@ -8122,9 +8124,13 @@
   for (unsigned i = 0, e = NumCommonArgs; i != e; ++i, ++AI) {
     const Type *ParamTy = FT->getParamType(i);
     const Type *ActTy = (*AI)->getType();
+
+    if (!CastInst::isCastable(ActTy, ParamTy))
+      return false;
+
     ConstantInt *c = dyn_cast<ConstantInt>(*AI);
-    //Some conversions are safe even if we do not have a body.
-    //Either we can cast directly, or we can upconvert the argument
+    // Some conversions are safe even if we do not have a body.
+    // Either we can cast directly, or we can upconvert the argument
     bool isConvertible = ActTy == ParamTy ||
       (isa<PointerType>(ParamTy) && isa<PointerType>(ActTy)) ||
       (ParamTy->isInteger() && ActTy->isInteger() &&
@@ -8132,40 +8138,6 @@
       (c && ParamTy->getPrimitiveSizeInBits() >= ActTy->getPrimitiveSizeInBits()
        && c->getValue().isStrictlyPositive());
     if (Callee->isDeclaration() && !isConvertible) return false;
-
-    // Most other conversions can be done if we have a body, even if these
-    // lose information, e.g. int->short.
-    // Some conversions cannot be done at all, e.g. float to pointer.
-    // Logic here parallels CastInst::getCastOpcode (the design there
-    // requires legality checks like this be done before calling it).
-    if (ParamTy->isInteger()) {
-      if (const VectorType *VActTy = dyn_cast<VectorType>(ActTy)) {
-        if (VActTy->getBitWidth() != ParamTy->getPrimitiveSizeInBits())
-          return false;
-      }
-      if (!ActTy->isInteger() && !ActTy->isFloatingPoint() &&
-          !isa<PointerType>(ActTy))
-        return false;
-    } else if (ParamTy->isFloatingPoint()) {
-      if (const VectorType *VActTy = dyn_cast<VectorType>(ActTy)) {
-        if (VActTy->getBitWidth() != ParamTy->getPrimitiveSizeInBits())
-          return false;
-      }
-      if (!ActTy->isInteger() && !ActTy->isFloatingPoint())
-        return false;
-    } else if (const VectorType *VParamTy = dyn_cast<VectorType>(ParamTy)) {
-      if (const VectorType *VActTy = dyn_cast<VectorType>(ActTy)) {
-        if (VActTy->getBitWidth() != VParamTy->getBitWidth())
-          return false;
-      }
-      if (VParamTy->getBitWidth() != ActTy->getPrimitiveSizeInBits())      
-        return false;
-    } else if (isa<PointerType>(ParamTy)) {
-      if (!ActTy->isInteger() && !isa<PointerType>(ActTy))
-        return false;
-    } else {
-      return false;
-    }
   }
 
   if (FT->getNumParams() < NumActualArgs && !FT->isVarArg() &&
@@ -8238,12 +8210,11 @@
 
   // Insert a cast of the return type as necessary.
   Value *NV = NC;
-  if (Caller->getType() != NV->getType() && !Caller->use_empty()) {
+  if (OldRetTy != NV->getType() && !Caller->use_empty()) {
     if (NV->getType() != Type::VoidTy) {
-      const Type *CallerTy = Caller->getType();
       Instruction::CastOps opcode = CastInst::getCastOpcode(NC, false, 
-                                                            CallerTy, false);
-      NV = NC = CastInst::create(opcode, NC, CallerTy, "tmp");
+                                                            OldRetTy, false);
+      NV = NC = CastInst::create(opcode, NC, OldRetTy, "tmp");
 
       // If this is an invoke instruction, we should insert it after the first
       // non-phi, instruction in the normal successor block.

Modified: llvm/trunk/lib/VMCore/Instructions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/VMCore/Instructions.cpp?rev=45657&r1=45656&r2=45657&view=diff

==============================================================================
--- llvm/trunk/lib/VMCore/Instructions.cpp (original)
+++ llvm/trunk/lib/VMCore/Instructions.cpp Sun Jan  6 04:12:28 2008
@@ -1895,12 +1895,70 @@
   return create(opcode, C, Ty, Name, InsertAtEnd);
 }
 
+// Check whether it is valid to call getCastOpcode for these types.
+// This routine must be kept in sync with getCastOpcode.
+bool CastInst::isCastable(const Type *SrcTy, const Type *DestTy) {
+  if (!SrcTy->isFirstClassType() || !DestTy->isFirstClassType())
+    return false;
+
+  if (SrcTy == DestTy)
+    return true;
+
+  // Get the bit sizes, we'll need these
+  unsigned SrcBits = SrcTy->getPrimitiveSizeInBits();   // 0 for ptr/vector
+  unsigned DestBits = DestTy->getPrimitiveSizeInBits(); // 0 for ptr/vector
+
+  // Run through the possibilities ...
+  if (DestTy->isInteger()) {                      // Casting to integral
+    if (SrcTy->isInteger()) {                     // Casting from integral
+        return true;
+    } else if (SrcTy->isFloatingPoint()) {        // Casting from floating pt
+      return true;
+    } else if (const VectorType *PTy = dyn_cast<VectorType>(SrcTy)) {
+                                                  // Casting from vector
+      return DestBits == PTy->getBitWidth();
+    } else {                                      // Casting from something else
+      return isa<PointerType>(SrcTy);
+    }
+  } else if (DestTy->isFloatingPoint()) {         // Casting to floating pt
+    if (SrcTy->isInteger()) {                     // Casting from integral
+      return true;
+    } else if (SrcTy->isFloatingPoint()) {        // Casting from floating pt
+      return true;
+    } else if (const VectorType *PTy = dyn_cast<VectorType>(SrcTy)) {
+                                                  // Casting from vector
+      return DestBits == PTy->getBitWidth();
+    } else {                                      // Casting from something else
+      return false;
+    }
+  } else if (const VectorType *DestPTy = dyn_cast<VectorType>(DestTy)) {
+                                                   // Casting to vector
+    if (const VectorType *SrcPTy = dyn_cast<VectorType>(SrcTy)) {
+                                                   // Casting from vector
+      return DestPTy->getBitWidth() == SrcPTy->getBitWidth();
+    } else {                                       // Casting from something else
+      return DestPTy->getBitWidth() == SrcBits;
+    }
+  } else if (isa<PointerType>(DestTy)) {           // Casting to pointer
+    if (isa<PointerType>(SrcTy)) {                 // Casting from pointer
+      return true;
+    } else if (SrcTy->isInteger()) {               // Casting from integral
+      return true;
+    } else {                                       // Casting from something else
+      return false;
+    }
+  } else {                                         // Casting to something else
+    return false;
+  }
+}
+
 // Provide a way to get a "cast" where the cast opcode is inferred from the 
 // types and size of the operand. This, basically, is a parallel of the 
 // logic in the castIsValid function below.  This axiom should hold:
 //   castIsValid( getCastOpcode(Val, Ty), Val, Ty)
 // should not assert in castIsValid. In other words, this produces a "correct"
 // casting opcode for the arguments passed to it.
+// This routine must be kept in sync with isCastable.
 Instruction::CastOps
 CastInst::getCastOpcode(
   const Value *Src, bool SrcIsSigned, const Type *DestTy, bool DestIsSigned) {
@@ -1909,6 +1967,9 @@
   unsigned SrcBits = SrcTy->getPrimitiveSizeInBits();   // 0 for ptr/vector
   unsigned DestBits = DestTy->getPrimitiveSizeInBits(); // 0 for ptr/vector
 
+  assert(SrcTy->isFirstClassType() && DestTy->isFirstClassType() &&
+         "Only first class types are castable!");
+
   // Run through the possibilities ...
   if (DestTy->isInteger()) {                       // Casting to integral
     if (SrcTy->isInteger()) {                      // Casting from integral
@@ -2050,7 +2111,7 @@
     if (isa<PointerType>(SrcTy) != isa<PointerType>(DstTy))
       return false;
 
-    // Now we know we're not dealing with a pointer/non-poiner mismatch. In all
+    // Now we know we're not dealing with a pointer/non-pointer mismatch. In all
     // these cases, the cast is okay if the source and destination bit widths
     // are identical.
     return SrcBitSize == DstBitSize;

Added: llvm/trunk/test/Transforms/InstCombine/2008-01-06-CastCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/2008-01-06-CastCrash.ll?rev=45657&view=auto

==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/2008-01-06-CastCrash.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/2008-01-06-CastCrash.ll Sun Jan  6 04:12:28 2008
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | opt -instcombine -disable-output
+
+define <2 x i32> @f() {
+	ret <2 x i32> undef
+}
+
+define i32 @g() {
+	%x = call i32 bitcast (<2 x i32> ()* @f to i32 ()*)( )		; <i32> [#uses=1]
+	ret i32 %x
+}

Added: llvm/trunk/test/Transforms/InstCombine/2008-01-06-VoidCast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/2008-01-06-VoidCast.ll?rev=45657&view=auto

==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/2008-01-06-VoidCast.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/2008-01-06-VoidCast.ll Sun Jan  6 04:12:28 2008
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep bitcast
+
+define void @f(i16 %y) {
+	ret void
+}
+
+define i32 @g(i32 %y) {
+	%x = call i32 bitcast (void (i16)* @f to i32 (i32)*)( i32 %y )		; <i32> [#uses=1]
+	ret i32 %x
+}





More information about the llvm-commits mailing list