Hello,

Please review the attached patch which adds support for casting between vector 
types with different sizes (but the same number of vector elements). LLVM 
supports these conversions for the underlying LLVM vector types (just as for 
the scalar types), and this adds support in Clang, requiring minor 
modifications in Sema and CodeGen.

For example, this patch allows the following to work:

typedef double vector4double __attribute__((__vector_size__(32)));
typedef float  vector4float  __attribute__((__vector_size__(16)));

vector4float flt_trunc(vector4double x) {
  return (vector4float) x;
}

On some targets the code generation for these conversions has been optimized 
(autovectorization can produce these conversions), and accessing these 
capabilities from Clang is important, for example, when writing intrinsics 
headers (which, when possible, we prefer to implement in terms of generic IR).

Thanks in advance,
Hal

-- 
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 287dc6c..b1f062f 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -753,9 +753,25 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
   }
 
   // Allow bitcast from vector to integer/fp of the same size.
+
+  llvm::Type *ScalarSrcTy = SrcTy,
+             *ScalarDstTy = DstTy;
   if (isa<llvm::VectorType>(SrcTy) ||
-      isa<llvm::VectorType>(DstTy))
-    return Builder.CreateBitCast(Src, DstTy, "conv");
+      isa<llvm::VectorType>(DstTy)) {
+    if (SrcTy->getPrimitiveSizeInBits() ==
+        DstTy->getPrimitiveSizeInBits())
+      return Builder.CreateBitCast(Src, DstTy, "conv");
+
+    if (isa<llvm::VectorType>(SrcTy))
+      ScalarSrcTy = SrcTy->getVectorElementType();
+    if (isa<llvm::VectorType>(DstTy))
+      ScalarDstTy = DstTy->getVectorElementType();
+  }
+
+  QualType ScalarSrcType = SrcType->isVectorType() ?
+             SrcType->getAs<VectorType>()->getElementType() : SrcType,
+           ScalarDstType = DstType->isVectorType() ?
+             DstType->getAs<VectorType>()->getElementType() : DstType;
 
   // Finally, we have the arithmetic types: real int/float.
   Value *Res = NULL;
@@ -772,24 +788,25 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
   if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
     DstTy = CGF.FloatTy;
 
-  if (isa<llvm::IntegerType>(SrcTy)) {
-    bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
-    if (isa<llvm::IntegerType>(DstTy))
+  if (isa<llvm::IntegerType>(ScalarSrcTy)) {
+    bool InputSigned = ScalarSrcType->isSignedIntegerOrEnumerationType();
+    if (isa<llvm::IntegerType>(ScalarDstTy))
       Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
     else if (InputSigned)
       Res = Builder.CreateSIToFP(Src, DstTy, "conv");
     else
       Res = Builder.CreateUIToFP(Src, DstTy, "conv");
-  } else if (isa<llvm::IntegerType>(DstTy)) {
-    assert(SrcTy->isFloatingPointTy() && "Unknown real conversion");
-    if (DstType->isSignedIntegerOrEnumerationType())
+  } else if (isa<llvm::IntegerType>(ScalarDstTy)) {
+    assert(ScalarSrcTy->isFloatingPointTy() && "Unknown real conversion");
+    if (ScalarDstType->isSignedIntegerOrEnumerationType())
       Res = Builder.CreateFPToSI(Src, DstTy, "conv");
     else
       Res = Builder.CreateFPToUI(Src, DstTy, "conv");
   } else {
-    assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() &&
+    assert(ScalarSrcTy->isFloatingPointTy() &&
+           ScalarDstTy->isFloatingPointTy() &&
            "Unknown real conversion");
-    if (DstTy->getTypeID() < SrcTy->getTypeID())
+    if (ScalarDstTy->getTypeID() < ScalarSrcTy->getTypeID())
       Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
     else
       Res = Builder.CreateFPExt(Src, DstTy, "conv");
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index e3227bc..d8d2750 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1819,6 +1819,28 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
           == Self.Context.getTypeSize(DestType)) {
       Kind = CK_BitCast;
       return TC_Success;
+    } else if (destIsVector && srcIsVector) {
+      const VectorType *Ty1 = SrcType->getAs<VectorType>(),
+                       *Ty2 = DestType->getAs<VectorType>();
+      if (Ty1->getNumElements() == Ty2->getNumElements()) {
+        if (Ty1->getElementType()->isFloatingType()) {
+          if (Ty2->getElementType()->isFloatingType()) {
+            Kind = CK_FloatingCast;
+            return TC_Success;
+          } else if (Ty2->getElementType()->isIntegerType()) {
+            Kind = CK_FloatingToIntegral;
+            return TC_Success;
+          }
+        } else if (Ty1->getElementType()->isIntegerType()) {
+          if (Ty2->getElementType()->isFloatingType()) {
+            Kind = CK_IntegralToFloating;
+            return TC_Success;
+          } else if (Ty2->getElementType()->isIntegerType()) {
+            Kind = CK_IntegralCast;
+            return TC_Success;
+          }
+        }
+      }
     }
     
     if (destIsScalar)
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e7061a6..24750e5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4931,12 +4931,37 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
   assert(VectorTy->isVectorType() && "Not a vector type!");
 
   if (Ty->isVectorType() || Ty->isIntegerType()) {
-    if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty))
+    if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty)) {
+      if (Ty->isVectorType()) {
+        const VectorType *Ty1 = VectorTy->getAs<VectorType>(),
+                         *Ty2 = Ty->getAs<VectorType>();
+        if (Ty1->getNumElements() == Ty2->getNumElements()) {
+          if (Ty1->getElementType()->isFloatingType()) {
+            if (Ty2->getElementType()->isFloatingType()) {
+              Kind = CK_FloatingCast;
+              return false;
+            } else if (Ty2->getElementType()->isIntegerType()) {
+              Kind = CK_FloatingToIntegral;
+              return false;
+            }
+          } else if (Ty1->getElementType()->isIntegerType()) {
+            if (Ty2->getElementType()->isFloatingType()) {
+              Kind = CK_IntegralToFloating;
+              return false;
+            } else if (Ty2->getElementType()->isIntegerType()) {
+              Kind = CK_IntegralCast;
+              return false;
+            }
+          }
+        }
+      }
+
       return Diag(R.getBegin(),
                   Ty->isVectorType() ?
                   diag::err_invalid_conversion_between_vectors :
                   diag::err_invalid_conversion_between_vector_and_integer)
         << VectorTy << Ty << R;
+    }
   } else
     return Diag(R.getBegin(),
                 diag::err_invalid_conversion_between_vector_and_scalar)
diff --git a/test/CodeGen/vector-casts.c b/test/CodeGen/vector-casts.c
new file mode 100644
index 0000000..33bcc4b
--- /dev/null
+++ b/test/CodeGen/vector-casts.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm -x c++ %s -o - | FileCheck %s
+
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float  vector4float  __attribute__((__vector_size__(16)));
+typedef long   vector4long   __attribute__((__vector_size__(32)));
+typedef short  vector4short  __attribute__((__vector_size__(8)));
+typedef unsigned long   vector4ulong   __attribute__((__vector_size__(32)));
+typedef unsigned short  vector4ushort  __attribute__((__vector_size__(8)));
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+vector4float flt_trunc(vector4double x) {
+  return (vector4float) x;
+  // CHECK-LABEL: @flt_trunc
+  // CHECK: fptrunc <4 x double> %{{[^ ]}} to <4 x float>
+}
+
+vector4double flt_ext(vector4float x) {
+  return (vector4double) x;
+  // CHECK-LABEL: @flt_ext
+  // CHECK: fpext <4 x float> %{{[^ ]}} to <4 x double>
+}
+
+vector4long flt_tosi(vector4float x) {
+  return (vector4long) x;
+  // CHECK-LABEL: @flt_tosi
+  // CHECK: fptosi <4 x float> %{{[^ ]}} to <4 x i64>
+}
+
+vector4ulong flt_toui(vector4float x) {
+  return (vector4ulong) x;
+  // CHECK-LABEL: @flt_toui
+  // CHECK: fptoui <4 x float> %{{[^ ]}} to <4 x i64>
+}
+
+vector4ulong int_zext(vector4ushort x) {
+  return (vector4ulong) x;
+  // CHECK-LABEL: @int_zext
+  // CHECK: zext <4 x i16> %{{[^ ]}} to <4 x i64>
+}
+
+vector4long int_sext(vector4short x) {
+  return (vector4long) x;
+  // CHECK-LABEL: @int_sext
+  // CHECK: sext <4 x i16> %{{[^ ]}} to <4 x i64>
+}
+
+vector4float int_tofp(vector4short x) {
+  return (vector4float) x;
+  // CHECK-LABEL: @int_tofp
+  // CHECK: sitofp <4 x i16> %{{[^ ]}} to <4 x float>
+}
+
+vector4float uint_tofp(vector4ushort x) {
+  return (vector4float) x;
+  // CHECK-LABEL: @uint_tofp
+  // CHECK: uitofp <4 x i16> %{{[^ ]}} to <4 x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to