Support changing the pointer type of a store for the case where we are
[oota-llvm.git] / lib / Transforms / ExprTypeConvert.cpp
index b61903578dc45e283bfe46df71b5942694479314..cbf22b035a81ab3c303a98974dabdf5bdc6bb5b8 100644 (file)
@@ -307,8 +307,7 @@ bool ExpressionConvertableToType(Value *V, const Type *Ty,
       //
       std::vector<Value*> Indices;
       const Type *ElTy = ConvertableToGEP(PTy, I->getOperand(1), Indices);
-      if (ElTy) {
-        assert(ElTy == PVTy && "Internal error, setup wrong!");
+      if (ElTy == PVTy) {
         if (!ExpressionConvertableToType(I->getOperand(0),
                                          PointerType::get(ElTy), CTMap))
           return false;  // Can't continue, ExConToTy might have polluted set!
@@ -586,9 +585,11 @@ bool ValueConvertableToType(Value *V, const Type *Ty,
   // It is safe to convert the specified value to the specified type IFF all of
   // the uses of the value can be converted to accept the new typed value.
   //
-  for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I)
-    if (!OperandConvertableToType(*I, V, Ty, ConvertedTypes))
-      return false;
+  if (V->getType() != Ty) {
+    for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I)
+      if (!OperandConvertableToType(*I, V, Ty, ConvertedTypes))
+        return false;
+  }
 
   return true;
 }
@@ -720,6 +721,18 @@ static bool OperandConvertableToType(User *U, Value *V, const Type *Ty,
       const Type *ElTy = PT->getElementType();
       assert(V == I->getOperand(1));
 
+      if (isa<StructType>(ElTy)) {
+        // We can change the destination pointer if we can store our first
+        // argument into the first element of the structure...
+        //
+        unsigned Offset = 0;
+        std::vector<Value*> Indices;
+        ElTy = getStructOffsetType(ElTy, Offset, Indices, false);
+        assert(Offset == 0 && "Offset changed!");
+        if (ElTy == 0)    // Element at offset zero in struct doesn't exist!
+          return false;   // Can only happen for {}*
+      }
+
       // Must move the same amount of data...
       if (TD.getTypeSize(ElTy) != TD.getTypeSize(I->getOperand(0)->getType()))
         return false;
@@ -780,8 +793,44 @@ static bool OperandConvertableToType(User *U, Value *V, const Type *Ty,
     assert (OI != I->op_end() && "Not using value!");
     unsigned OpNum = OI - I->op_begin();
 
-    if (OpNum == 0)
-      return false; // Can't convert method pointer type yet.  FIXME
+    // Are we trying to change the method pointer value to a new type?
+    if (OpNum == 0) {
+      PointerType *PTy = dyn_cast<PointerType>(Ty);
+      if (PTy == 0) return false;  // Can't convert to a non-pointer type...
+      MethodType *MTy = dyn_cast_or_null<MethodType>(PTy->getElementType());
+      if (MTy == 0) return false;  // Can't convert to a non ptr to method...
+
+      // Perform sanity checks to make sure that new method type has the
+      // correct number of arguments...
+      //
+      unsigned NumArgs = I->getNumOperands()-1;  // Don't include method ptr
+
+      // Cannot convert to a type that requires more fixed arguments than
+      // the call provides...
+      //
+      if (NumArgs < MTy->getParamTypes().size()) return false;
+      
+      // Unless this is a vararg method type, we cannot provide more arguments
+      // than are desired...
+      //
+      if (!MTy->isVarArg() && NumArgs > MTy->getParamTypes().size())
+        return false;
+
+      // Okay, at this point, we know that the call and the method type match
+      // number of arguments.  Now we see if we can convert the arguments
+      // themselves.
+      //
+      const MethodType::ParamTypes &PTs = MTy->getParamTypes();
+      for (unsigned i = 0, NA = PTs.size(); i < NA; ++i)
+        if (!PTs[i]->isLosslesslyConvertableTo(I->getOperand(i+1)->getType()))
+          return false;   // Operands must have compatible types!
+
+      // Okay, at this point, we know that all of the arguments can be
+      // converted.  We succeed if we can change the return type if
+      // neccesary...
+      //
+      return ValueConvertableToType(I, MTy->getReturnType(), CTMap);
+    }
     
     const PointerType *MPtr = cast<PointerType>(I->getOperand(0)->getType());
     const MethodType *MTy = cast<MethodType>(MPtr->getElementType());
@@ -922,13 +971,14 @@ static void ConvertOperandToType(User *U, Value *OldVal, Value *NewVal,
     } else {                           // Replace the source pointer
       const Type *ValTy = cast<PointerType>(NewTy)->getElementType();
       std::vector<Value*> Indices;
-#if 0
-      Indices.push_back(ConstantUInt::get(Type::UIntTy, 0));
-      while (ArrayType *AT = dyn_cast<ArrayType>(ValTy)) {
+
+      if (isa<StructType>(ValTy)) {
+        unsigned Offset = 0;
         Indices.push_back(ConstantUInt::get(Type::UIntTy, 0));
-        ValTy = AT->getElementType();
+        ValTy = getStructOffsetType(ValTy, Offset, Indices, false);
+        assert(Offset == 0 && ValTy);
       }
-#endif
+
       Res = new StoreInst(Constant::getNullConstant(ValTy), NewVal, Indices);
       VMC.ExprMap[I] = Res;
       Res->setOperand(0, ConvertExpressionToType(I->getOperand(0), ValTy, VMC));
@@ -1010,11 +1060,26 @@ static void ConvertOperandToType(User *U, Value *OldVal, Value *NewVal,
     Value *Meth = I->getOperand(0);
     std::vector<Value*> Params(I->op_begin()+1, I->op_end());
 
-    std::vector<Value*>::iterator OI =
-      find(Params.begin(), Params.end(), OldVal);
-    assert (OI != Params.end() && "Not using value!");
+    if (Meth == OldVal) {   // Changing the method pointer?
+      PointerType *NewPTy = cast<PointerType>(NewVal->getType());
+      MethodType *NewTy = cast<MethodType>(NewPTy->getElementType());
+      const MethodType::ParamTypes &PTs = NewTy->getParamTypes();
+
+      // Convert over all of the call operands to their new types... but only
+      // convert over the part that is not in the vararg section of the call.
+      //
+      for (unsigned i = 0; i < PTs.size(); ++i)
+        Params[i] = ConvertExpressionToType(Params[i], PTs[i], VMC);
+      Meth = NewVal;  // Update call destination to new value
+
+    } else {                   // Changing an argument, must be in vararg area
+      std::vector<Value*>::iterator OI =
+        find(Params.begin(), Params.end(), OldVal);
+      assert (OI != Params.end() && "Not using value!");
+
+      *OI = NewVal;
+    }
 
-    *OI = NewVal;
     Res = new CallInst(Meth, Params, Name);
     break;
   }