Introduce implicit conversions between AltiVec vectors and GCC
vectors, from Anton Yartsev!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110437 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 3c94970..df96de0 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -906,6 +906,11 @@
   ///
   Qualifiers::GC getObjCGCAttrKind(const QualType &Ty) const;
 
+  /// areCompatibleVectorTypes - Return true if the given vector types either
+  /// are of the same unqualified type or if one is GCC and other - equivalent
+  /// AltiVec vector type.
+  bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);
+
   /// isObjCNSObjectType - Return true if this is an NSObject object with
   /// its NSObject attribute set.
   bool isObjCNSObjectType(QualType Ty) const;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 43873a4..22e1ebf 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1540,10 +1540,7 @@
   // If the element type isn't canonical, this won't be a canonical type either,
   // so fill in the canonical type field.
   QualType Canonical;
-  if (!vecType.isCanonical() || (AltiVecSpec == VectorType::AltiVec)) {
-    // pass VectorType::NotAltiVec for AltiVecSpec to make AltiVec canonical
-    // vector type (except 'vector bool ...' and 'vector Pixel') the same as
-    // the equivalent GCC vector types
+  if (!vecType.isCanonical()) {
     Canonical = getVectorType(getCanonicalType(vecType), NumElts,
       VectorType::NotAltiVec);
 
@@ -4170,6 +4167,28 @@
          LHS->getNumElements() == RHS->getNumElements();
 }
 
+bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
+                                          QualType SecondVec) {
+  assert(FirstVec->isVectorType() && "FirstVec should be a vector type");
+  assert(SecondVec->isVectorType() && "SecondVec should be a vector type");
+
+  if (hasSameUnqualifiedType(FirstVec, SecondVec))
+    return true;
+
+  // AltiVec vectors types are identical to equivalent GCC vector types
+  const VectorType *First = FirstVec->getAs<VectorType>();
+  const VectorType *Second = SecondVec->getAs<VectorType>();
+  if ((((First->getAltiVecSpecific() == VectorType::AltiVec) &&
+        (Second->getAltiVecSpecific() == VectorType::NotAltiVec)) ||
+       ((First->getAltiVecSpecific() == VectorType::NotAltiVec) &&
+        (Second->getAltiVecSpecific() == VectorType::AltiVec))) &&
+      hasSameType(First->getElementType(), Second->getElementType()) &&
+      (First->getNumElements() == Second->getNumElements()))
+    return true;
+
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
 //===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 28b2e99..46c5a65 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4731,13 +4731,18 @@
   }
 
   if (lhsType->isVectorType() || rhsType->isVectorType()) {
-    // If we are allowing lax vector conversions, and LHS and RHS are both
-    // vectors, the total size only needs to be the same. This is a bitcast;
-    // no bits are changed but the result type is different.
-    if (getLangOptions().LaxVectorConversions &&
-        lhsType->isVectorType() && rhsType->isVectorType()) {
-      if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))
+    if (lhsType->isVectorType() && rhsType->isVectorType()) {
+      // If we are allowing lax vector conversions, and LHS and RHS are both
+      // vectors, the total size only needs to be the same. This is a bitcast;
+      // no bits are changed but the result type is different.
+      if (getLangOptions().LaxVectorConversions &&
+         (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)))
         return IncompatibleVectors;
+
+      // Allow assignments of an AltiVec vector type to an equivalent GCC
+      // vector type and vice versa
+      if (Context.areCompatibleVectorTypes(lhsType, rhsType))
+        return Compatible;
     }
     return Incompatible;
   }
@@ -5012,6 +5017,13 @@
     }
   }
 
+  // Handle the case of equivalent AltiVec and GCC vector types
+  if (lhsType->isVectorType() && rhsType->isVectorType() &&
+      Context.areCompatibleVectorTypes(lhsType, rhsType)) {
+    ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast);
+    return rhsType;
+  }
+
   // Canonicalize the ExtVector to the LHS, remember if we swapped so we can
   // swap back (so that we don't reverse the inputs to a subtract, for instance.
   bool swapped = false;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 037bc7b..5dfbe09 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -850,16 +850,20 @@
       return true;
     }
   }
-  
-  // If lax vector conversions are permitted and the vector types are of the
-  // same size, we can perform the conversion.
-  if (Context.getLangOptions().LaxVectorConversions &&
-      FromType->isVectorType() && ToType->isVectorType() &&
-      Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) {
-    ICK = ICK_Vector_Conversion;
-    return true;
+
+  // We can perform the conversion between vector types in the following cases:
+  // 1)vector types are equivalent AltiVec and GCC vector types
+  // 2)lax vector conversions are permitted and the vector types are of the
+  //   same size
+  if (ToType->isVectorType() && FromType->isVectorType()) {
+    if (Context.areCompatibleVectorTypes(FromType, ToType) ||
+       Context.getLangOptions().LaxVectorConversions &&
+       (Context.getTypeSize(FromType) == Context.getTypeSize(ToType))) {
+      ICK = ICK_Vector_Conversion;
+      return true;
+    }
   }
-  
+
   return false;
 }
   
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
index 57abc93..b5758bc 100644
--- a/test/Sema/altivec-init.c
+++ b/test/Sema/altivec-init.c
@@ -14,3 +14,22 @@
   // FIXME: test that (type)(fn)(args) still works with -faltivec
   // FIXME: test that c++ overloaded commas still work -faltivec
 }
+
+void __attribute__((__overloadable__)) f(v4 a)
+{
+}
+
+void __attribute__((__overloadable__)) f(int a)
+{
+}
+
+void test()
+{
+  v4 vGCC;
+  vector int vAltiVec;
+
+  f(vAltiVec);
+  vGCC = vAltiVec;
+  vGCC = vGCC > vAltiVec;
+  vAltiVec = 0 ? vGCC : vGCC;
+}
diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp
new file mode 100644
index 0000000..cdfc00a
--- /dev/null
+++ b/test/SemaCXX/altivec.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -faltivec -fno-lax-vector-conversions -triple powerpc-unknown-unknown -verify %s
+
+typedef int V4i __attribute__((vector_size(16)));
+
+void f(V4i a)
+{
+}
+
+void test()
+{
+  V4i vGCC;
+  vector int vAltiVec;
+
+  f(vAltiVec);
+  vGCC = vAltiVec;
+  vGCC = vGCC > vAltiVec;
+  vAltiVec = 0 ? vGCC : vGCC;
+}