george.burgess.iv created this revision.
george.burgess.iv added a reviewer: rsmith.
george.burgess.iv added a subscriber: cfe-commits.

When evaluating constexpr vector splats, we weren't doing appropriate type 
conversions on the literal we were splatting, causing assertion failures in 
cases like:

```
void foo(vector float FloatInput, vector short ShortInput) {
  (void)(FloatInput == (vector float)0); // OK
  (void)(ShortInput == (vector short)0); // OK

  constexpr vector float Floats = (vector float)0;
  (void)(FloatInput == Floats); // ICE -- fcmp between [4 x i32] and [4 x f32]

  constexpr vector short Shorts = (vector short)0;
  (void)(ShortInput == Shorts); // ICE -- fcmp between vec of i16 and vec of i32
}
```

(The same issue applied for cases like `(vector short)0`; it would be lowered 
as a vector of `i32`.)

This patch fixes these in ExprConstant rather than CodeGen, because it allows 
us to more sanely model overflow/complain to the user/... in the evaluator. 

This patch also contains a few generic code cleanliness changes. I'm happy to 
drop any/all of them if we decide they're not helpful. :)

http://reviews.llvm.org/D14877

Files:
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/builtins-systemz-zvector.cpp

Index: test/CodeGenCXX/builtins-systemz-zvector.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/builtins-systemz-zvector.cpp
@@ -0,0 +1,52 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
+// RUN: -fzvector -fno-lax-vector-conversions -std=c++11 \
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+
+#include <vecintrin.h>
+
+bool gb;
+
+// There was an issue where we weren't properly converting constexprs to
+// vectors with elements of the appropriate width. (e.g.
+// (vector signed short)0 would be lowered as [4 x i32] in some cases)
+
+// CHECK-LABEL: @_Z8testIntsDv4_i
+void testInts(vector int VI) {
+  constexpr vector int CI1 = (vector int)0LL;
+  // CHECK: icmp
+  gb = (VI == CI1)[0];
+
+  // Likewise for float inits.
+  constexpr vector int CI2 = (vector int)char(0);
+  // CHECK: icmp
+  gb = (VI == CI2)[0];
+
+  constexpr vector int CF1 = (vector int)0.0;
+  // CHECK: icmp
+  gb = (VI == CF1)[0];
+
+  constexpr vector int CF2 = (vector int)0.0f;
+  // CHECK: icmp
+  gb = (VI == CF2)[0];
+}
+
+// CHECK-LABEL: @_Z10testFloatsDv2_d
+void testFloats(vector double VD) {
+  constexpr vector double CI1 = (vector double)0LL;
+  // CHECK: fcmp
+  gb = (VD == CI1)[0];
+
+  // Likewise for float inits.
+  constexpr vector double CI2 = (vector double)char(0);
+  // CHECK: fcmp
+  gb = (VD == CI2)[0];
+
+  constexpr vector double CF1 = (vector double)0.0;
+  // CHECK: fcmp
+  gb = (VD == CF1)[0];
+
+  constexpr vector double CF2 = (vector double)0.0f;
+  // CHECK: fcmp
+  gb = (VD == CF2)[0];
+}
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1350,15 +1350,17 @@
     return llvm::ConstantStruct::get(STy, Complex);
   }
   case APValue::Vector: {
-    SmallVector<llvm::Constant *, 4> Inits;
     unsigned NumElts = Value.getVectorLength();
+    SmallVector<llvm::Constant *, 4> Inits(NumElts);
 
-    for (unsigned i = 0; i != NumElts; ++i) {
-      const APValue &Elt = Value.getVectorElt(i);
+    for (unsigned I = 0; I != NumElts; ++I) {
+      const APValue &Elt = Value.getVectorElt(I);
       if (Elt.isInt())
-        Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
+        Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt());
+      else if (Elt.isFloat())
+        Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat());
       else
-        Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
+        llvm_unreachable("unsupported vector element type");
     }
     return llvm::ConstantVector::get(Inits);
   }
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1150,7 +1150,7 @@
 static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
                                   EvalInfo &Info);
 static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
-static bool EvaluateInteger(const Expr *E, APSInt  &Result, EvalInfo &Info);
+static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
 static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
                                     EvalInfo &Info);
 static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
@@ -1575,7 +1575,7 @@
 
 static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
                                  QualType DestType, QualType SrcType,
-                                 APSInt &Value) {
+                                 const APSInt &Value) {
   unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
   APSInt Result = Value;
   // Figure out if this is a truncate, extend or noop cast.
@@ -5619,7 +5619,54 @@
   return VectorExprEvaluator(Info, Result).Visit(E);
 }
 
-bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
+/// Performs implicit conversions on the APValue given for a vector splat
+/// operation. This is necessary given code like `(vector float)0`.
+///
+/// Returns true on success, false on failure.
+static bool convertVectorSplatLiteral(EvalInfo &Info, const CastExpr *E,
+                                      APValue &Result) {
+  QualType DestTy = E->getType()->castAs<VectorType>()->getElementType();
+  QualType SrcTy = E->getSubExpr()->getType();
+
+  // If the types are the same (ignoring qualifiers), then we don't need to do
+  // anything.
+  if (SrcTy.getTypePtr() == DestTy.getTypePtr())
+    return true;
+
+  assert((SrcTy->isIntegerType() || SrcTy->isFloatingType()) &&
+         "unsupported literal type");
+
+  if (DestTy->isIntegerType()) {
+    if (Result.isInt()) {
+      Result =
+          APValue(HandleIntToIntCast(Info, E, DestTy, SrcTy, Result.getInt()));
+      return true;
+    }
+
+    APSInt IntResult;
+    if (!HandleFloatToIntCast(Info, E, SrcTy, Result.getFloat(), DestTy,
+                              IntResult))
+      return false;
+    Result = APValue(std::move(IntResult));
+    return true;
+  }
+
+  if (DestTy->isFloatingType()) {
+    if (Result.isFloat())
+      return HandleFloatToFloatCast(Info, E, SrcTy, DestTy, Result.getFloat());
+
+    APFloat FloatResult(0.0);
+    if (!HandleIntToFloatCast(Info, E, SrcTy, Result.getInt(), DestTy,
+                              FloatResult))
+      return false;
+    Result = APValue(std::move(FloatResult));
+    return true;
+  }
+
+  llvm_unreachable("unsupported vector element type");
+}
+
+bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
   const VectorType *VTy = E->getType()->castAs<VectorType>();
   unsigned NElts = VTy->getNumElements();
 
@@ -5632,17 +5679,20 @@
     if (SETy->isIntegerType()) {
       APSInt IntResult;
       if (!EvaluateInteger(SE, IntResult, Info))
-         return false;
-      Val = APValue(IntResult);
+        return false;
+      Val = APValue(std::move(IntResult));
     } else if (SETy->isRealFloatingType()) {
-       APFloat F(0.0);
-       if (!EvaluateFloat(SE, F, Info))
-         return false;
-       Val = APValue(F);
+      APFloat FloatResult(0.0);
+      if (!EvaluateFloat(SE, FloatResult, Info))
+        return false;
+      Val = APValue(std::move(FloatResult));
     } else {
       return Error(E);
     }
 
+    if (!convertVectorSplatLiteral(Info, E, Val))
+      return Error(E);
+
     // Splat and create vector APValue.
     SmallVector<APValue, 4> Elts(NElts, Val);
     return Success(Elts, E);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to