[clang] 71ab6c9 - [Matrix] Implement C-style explicit type conversions for matrix types.

Florian Hahn via cfe-commits cfe-commits at lists.llvm.org
Sat Apr 10 03:49:46 PDT 2021


Author: Saurabh Jha
Date: 2021-04-10T11:48:41+01:00
New Revision: 71ab6c98a0d1b5590ed12f955dea6dfc714e9490

URL: https://github.com/llvm/llvm-project/commit/71ab6c98a0d1b5590ed12f955dea6dfc714e9490
DIFF: https://github.com/llvm/llvm-project/commit/71ab6c98a0d1b5590ed12f955dea6dfc714e9490.diff

LOG: [Matrix] Implement C-style explicit type conversions for matrix types.

This implements C-style type conversions for matrix types, as specified
in clang/docs/MatrixTypes.rst.

Fixes PR47141.

Reviewed By: fhahn

Differential Revision: https://reviews.llvm.org/D99037

Added: 
    clang/test/CodeGen/matrix-cast.c
    clang/test/Sema/matrix-cast.c
    clang/test/SemaCXX/matrix-casts.cpp

Modified: 
    clang/include/clang/AST/OperationKinds.def
    clang/include/clang/AST/Stmt.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/Expr.cpp
    clang/lib/AST/ExprConstant.cpp
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/CodeGen/CGExprAgg.cpp
    clang/lib/CodeGen/CGExprComplex.cpp
    clang/lib/CodeGen/CGExprConstant.cpp
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/lib/Edit/RewriteObjCFoundationAPI.cpp
    clang/lib/Sema/SemaCast.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 7c82ab6e57eff..b05b9d81569eb 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -181,6 +181,9 @@ CAST_OPERATION(PointerToBoolean)
 ///    (void) malloc(2048)
 CAST_OPERATION(ToVoid)
 
+/// CK_MatrixCast - A cast between matrix types of the same dimensions.
+CAST_OPERATION(MatrixCast)
+
 /// CK_VectorSplat - A conversion from an arithmetic type to a
 /// vector of that element type.  Fills all elements ("splats") with
 /// the source value.

diff  --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 2085904b7f01e..97cd903f3d6f4 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -518,7 +518,7 @@ class alignas(void *) Stmt {
 
     unsigned : NumExprBits;
 
-    unsigned Kind : 6;
+    unsigned Kind : 7;
     unsigned PartOfExplicitCast : 1; // Only set for ImplicitCastExpr.
 
     /// True if the call expression has some floating-point features.

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0e14f8204f566..5c27902da2502 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8580,6 +8580,12 @@ let CategoryName = "Inline Assembly Issue" in {
 
 let CategoryName = "Semantic Issue" in {
 
+def err_invalid_conversion_between_matrixes : Error<
+  "conversion between matrix types%
diff { $ and $|}0,1 of 
diff erent size is not allowed">;
+
+def err_invalid_conversion_between_matrix_and_type : Error<
+  "conversion between matrix type %0 and incompatible type %1 is not allowed">;
+
 def err_invalid_conversion_between_vectors : Error<
   "invalid conversion between vector type%
diff { $ and $|}0,1 of 
diff erent "
   "size">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ebf63764be1aa..77f716153feee 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11660,6 +11660,8 @@ class Sema final {
 
   bool isValidSveBitcast(QualType srcType, QualType destType);
 
+  bool areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy);
+
   bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType);
   bool isLaxVectorConversion(QualType srcType, QualType destType);
 
@@ -11718,6 +11720,13 @@ class Sema final {
   ExprResult checkUnknownAnyArg(SourceLocation callLoc,
                                 Expr *result, QualType &paramType);
 
+  // CheckMatrixCast - Check type constraints for matrix casts.
+  // We allow casting between matrixes of the same dimensions i.e. when they
+  // have the same number of rows and column. Returns true if the cast is
+  // invalid.
+  bool CheckMatrixCast(SourceRange R, QualType DestTy, QualType SrcTy,
+                       CastKind &Kind);
+
   // CheckVectorCast - check type constraints for vectors.
   // Since vectors are an extension, there are no C standard reference for this.
   // We allow casting between vectors and integer datatypes of the same size.

diff  --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index adb33036a1684..eccb42eeb7e74 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1708,6 +1708,7 @@ bool CastExpr::CastConsistency() const {
   case CK_FixedPointCast:
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
+  case CK_MatrixCast:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5a68b1c3cad17..17bfed5d435fd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13183,6 +13183,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointToFloating:
   case CK_FixedPointCast:
   case CK_IntegralToFixedPoint:
+  case CK_MatrixCast:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -13923,6 +13924,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_FixedPointToBoolean:
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
+  case CK_MatrixCast:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 18f1468dcb868..b5437e4971648 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4645,6 +4645,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_FixedPointToBoolean:
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
+  case CK_MatrixCast:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:

diff  --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index f3ab91559d302..3fdb8aaaec46c 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -901,6 +901,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_CopyAndAutoreleaseBlockObject:
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLOpaqueType:
+  case CK_MatrixCast:
 
   case CK_IntToOCLSampler:
   case CK_FloatingToFixedPoint:
@@ -1422,6 +1423,7 @@ static bool castPreservesZero(const CastExpr *CE) {
   case CK_PointerToIntegral:
     // Language extensions.
   case CK_VectorSplat:
+  case CK_MatrixCast:
   case CK_NonAtomicToAtomic:
   case CK_AtomicToNonAtomic:
     return true;

diff  --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 6b6b901e03766..5409e82d437e2 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -533,6 +533,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
   case CK_FixedPointToBoolean:
   case CK_FixedPointToIntegral:
   case CK_IntegralToFixedPoint:
+  case CK_MatrixCast:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:

diff  --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 497f9c04c9f80..734024149bbbe 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1170,6 +1170,7 @@ class ConstExprEmitter :
     case CK_FixedPointToIntegral:
     case CK_IntegralToFixedPoint:
     case CK_ZeroToOCLOpaqueType:
+    case CK_MatrixCast:
       return nullptr;
     }
     llvm_unreachable("Invalid CastKind");

diff  --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 7385440b4d730..603d9a6e7e84f 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1198,27 +1198,50 @@ Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType,
                                          QualType DstType, llvm::Type *SrcTy,
                                          llvm::Type *DstTy,
                                          ScalarConversionOpts Opts) {
-  if (isa<llvm::IntegerType>(SrcTy)) {
-    bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
-    if (SrcType->isBooleanType() && Opts.TreatBooleanAsSigned) {
+  // The Element types determine the type of cast to perform.
+  llvm::Type *SrcElementTy;
+  llvm::Type *DstElementTy;
+  QualType SrcElementType;
+  QualType DstElementType;
+  if (SrcType->isMatrixType() && DstType->isMatrixType()) {
+    // Allow bitcast between matrixes of the same size.
+    if (SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits())
+      return Builder.CreateBitCast(Src, DstTy, "conv");
+
+    SrcElementTy = cast<llvm::VectorType>(SrcTy)->getElementType();
+    DstElementTy = cast<llvm::VectorType>(DstTy)->getElementType();
+    SrcElementType = SrcType->castAs<MatrixType>()->getElementType();
+    DstElementType = DstType->castAs<MatrixType>()->getElementType();
+  } else {
+    assert(!SrcType->isMatrixType() && !DstType->isMatrixType() &&
+           "cannot cast between matrix and non-matrix types");
+    SrcElementTy = SrcTy;
+    DstElementTy = DstTy;
+    SrcElementType = SrcType;
+    DstElementType = DstType;
+  }
+
+  if (isa<llvm::IntegerType>(SrcElementTy)) {
+    bool InputSigned = SrcElementType->isSignedIntegerOrEnumerationType();
+    if (SrcElementType->isBooleanType() && Opts.TreatBooleanAsSigned) {
       InputSigned = true;
     }
 
-    if (isa<llvm::IntegerType>(DstTy))
+    if (isa<llvm::IntegerType>(DstElementTy))
       return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
     if (InputSigned)
       return Builder.CreateSIToFP(Src, DstTy, "conv");
     return Builder.CreateUIToFP(Src, DstTy, "conv");
   }
 
-  if (isa<llvm::IntegerType>(DstTy)) {
-    assert(SrcTy->isFloatingPointTy() && "Unknown real conversion");
-    if (DstType->isSignedIntegerOrEnumerationType())
+  if (isa<llvm::IntegerType>(DstElementTy)) {
+    assert(SrcElementTy->isFloatingPointTy() && "Unknown real conversion");
+    if (DstElementType->isSignedIntegerOrEnumerationType())
       return Builder.CreateFPToSI(Src, DstTy, "conv");
     return Builder.CreateFPToUI(Src, DstTy, "conv");
   }
 
-  if (DstTy->getTypeID() < SrcTy->getTypeID())
+  if (DstElementTy->getTypeID() < SrcElementTy->getTypeID())
     return Builder.CreateFPTrunc(Src, DstTy, "conv");
   return Builder.CreateFPExt(Src, DstTy, "conv");
 }
@@ -1350,6 +1373,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
     return Builder.CreateVectorSplat(NumElements, Src, "splat");
   }
 
+  if (SrcType->isMatrixType() && DstType->isMatrixType())
+    return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts);
+
   if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) {
     // Allow bitcast from vector to integer/fp of the same size.
     unsigned SrcSize = SrcTy->getPrimitiveSizeInBits();
@@ -2238,6 +2264,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     CGF.EmitIgnoredExpr(E);
     return nullptr;
   }
+  case CK_MatrixCast: {
+    return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+                                CE->getExprLoc());
+  }
   case CK_VectorSplat: {
     llvm::Type *DstTy = ConvertType(DestTy);
     Value *Elt = Visit(const_cast<Expr*>(E));

diff  --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 7565626cba990..a3d388a5ae449 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1080,6 +1080,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
     case CK_BuiltinFnToFnPtr:
     case CK_ZeroToOCLOpaqueType:
     case CK_IntToOCLSampler:
+    case CK_MatrixCast:
       return false;
 
     case CK_BooleanToSignedIntegral:

diff  --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 719cbf46bd5c2..d347975e1341b 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -2859,7 +2859,8 @@ void CastOperation::CheckCStyleCast() {
     return;
   }
 
-  if (!DestType->isScalarType() && !DestType->isVectorType()) {
+  if (!DestType->isScalarType() && !DestType->isVectorType() &&
+      !DestType->isMatrixType()) {
     const RecordType *DestRecordTy = DestType->getAs<RecordType>();
 
     if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){
@@ -2910,10 +2911,11 @@ void CastOperation::CheckCStyleCast() {
     return;
   }
 
-  // The type we're casting to is known to be a scalar or vector.
+  // The type we're casting to is known to be a scalar, a vector, or a matrix.
 
-  // Require the operand to be a scalar or vector.
-  if (!SrcType->isScalarType() && !SrcType->isVectorType()) {
+  // Require the operand to be a scalar, a vector, or a matrix.
+  if (!SrcType->isScalarType() && !SrcType->isVectorType() &&
+      !SrcType->isMatrixType()) {
     Self.Diag(SrcExpr.get()->getExprLoc(),
               diag::err_typecheck_expect_scalar_operand)
       << SrcType << SrcExpr.get()->getSourceRange();
@@ -2926,6 +2928,12 @@ void CastOperation::CheckCStyleCast() {
     return;
   }
 
+  if (DestType->getAs<MatrixType>() || SrcType->getAs<MatrixType>()) {
+    if (Self.CheckMatrixCast(OpRange, DestType, SrcType, Kind))
+      SrcExpr = ExprError();
+    return;
+  }
+
   if (const VectorType *DestVecTy = DestType->getAs<VectorType>()) {
     if (DestVecTy->getVectorKind() == VectorType::AltiVecVector &&
           (SrcType->isIntegerType() || SrcType->isFloatingType())) {

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 223fcf2a1f26a..c0b294f7f19d9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7345,6 +7345,19 @@ bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) {
          ValidScalableConversion(destTy, srcTy);
 }
 
+/// Are the two types matrix types and do they have the same dimensions i.e.
+/// do they have the same number of rows and the same number of columns?
+bool Sema::areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy) {
+  if (!destTy->isMatrixType() || !srcTy->isMatrixType())
+    return false;
+
+  const ConstantMatrixType *matSrcType = srcTy->getAs<ConstantMatrixType>();
+  const ConstantMatrixType *matDestType = destTy->getAs<ConstantMatrixType>();
+
+  return matSrcType->getNumRows() == matDestType->getNumRows() &&
+         matSrcType->getNumColumns() == matDestType->getNumColumns();
+}
+
 /// Are the two types lax-compatible vector types?  That is, given
 /// that one of them is a vector, do they have equal storage sizes,
 /// where the storage size is the number of elements times the element
@@ -7407,6 +7420,27 @@ bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
   return areLaxCompatibleVectorTypes(srcTy, destTy);
 }
 
+bool Sema::CheckMatrixCast(SourceRange R, QualType DestTy, QualType SrcTy,
+                           CastKind &Kind) {
+  if (SrcTy->isMatrixType() && DestTy->isMatrixType()) {
+    if (!areMatrixTypesOfTheSameDimension(SrcTy, DestTy)) {
+      return Diag(R.getBegin(), diag::err_invalid_conversion_between_matrixes)
+             << DestTy << SrcTy << R;
+    }
+  } else if (SrcTy->isMatrixType()) {
+    return Diag(R.getBegin(),
+                diag::err_invalid_conversion_between_matrix_and_type)
+           << SrcTy << DestTy << R;
+  } else if (DestTy->isMatrixType()) {
+    return Diag(R.getBegin(),
+                diag::err_invalid_conversion_between_matrix_and_type)
+           << DestTy << SrcTy << R;
+  }
+
+  Kind = CK_MatrixCast;
+  return false;
+}
+
 bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
                            CastKind &Kind) {
   assert(VectorTy->isVectorType() && "Not a vector type!");

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index c0aae596c702a..a1c8128f1650a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -543,6 +543,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
         state = handleLVectorSplat(state, LCtx, CastE, Bldr, Pred);
         continue;
       }
+      case CK_MatrixCast: {
+        // TODO: Handle MatrixCast here.
+        continue;
+      }
     }
   }
 }

diff  --git a/clang/test/CodeGen/matrix-cast.c b/clang/test/CodeGen/matrix-cast.c
new file mode 100644
index 0000000000000..8871232f76b11
--- /dev/null
+++ b/clang/test/CodeGen/matrix-cast.c
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+typedef char cx5x5 __attribute__((matrix_type(5, 5)));
+typedef int ix5x5 __attribute__((matrix_type(5, 5)));
+typedef short sx5x5 __attribute__((matrix_type(5, 5)));
+typedef float fx5x5 __attribute__((matrix_type(5, 5)));
+typedef double dx5x5 __attribute__((matrix_type(5, 5)));
+typedef unsigned short unsigned_short_int_5x5 __attribute__((matrix_type(5, 5)));
+typedef unsigned int unsigned_int_5x5 __attribute__((matrix_type(5, 5)));
+typedef unsigned long unsigned_long_int_5x5 __attribute__((matrix_type(5, 5)));
+
+void cast_char_matrix_to_int(cx5x5 c, ix5x5 i) {
+  // CHECK-LABEL: define{{.*}} void @cast_char_matrix_to_int(<25 x i8> %c, <25 x i32> %i)
+  // CHECK:       [[C:%.*]] = load <25 x i8>, <25 x i8>* {{.*}}, align 1
+  // CHECK-NEXT:  [[CONV:%.*]] = sext <25 x i8> [[C]] to <25 x i32>
+  // CHECK-NEXT:  store <25 x i32> [[CONV]], <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  i = (ix5x5)c;
+}
+
+void cast_char_matrix_to_unsigned_int(cx5x5 c, unsigned_int_5x5 u) {
+  // CHECK-LABEL: define{{.*}} void @cast_char_matrix_to_unsigned_int(<25 x i8> %c, <25 x i32> %u)
+  // CHECK:       [[C:%.*]] = load <25 x i8>, <25 x i8>* {{.*}}, align 1
+  // CHECK-NEXT:  [[CONV:%.*]] = sext <25 x i8> [[C]] to <25 x i32>
+  // CHECK-NEXT:  store <25 x i32> [[CONV]], <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  u = (unsigned_int_5x5)c;
+}
+
+void cast_unsigned_long_int_matrix_to_short(unsigned_long_int_5x5 u, sx5x5 s) {
+  // CHECK-LABEL: define{{.*}} void @cast_unsigned_long_int_matrix_to_short(<25 x i64> %u, <25 x i16> %s)
+  // CHECK:       [[U:%.*]] = load <25 x i64>, <25 x i64>* {{.*}}, align 8
+  // CHECK-NEXT:  [[CONV:%.*]] = trunc <25 x i64> [[U]] to <25 x i16>
+  // CHECK-NEXT:  store <25 x i16> [[CONV]], <25 x i16>* {{.*}}, align 2
+  // CHECK-NEXT:  ret void
+
+  s = (sx5x5)u;
+}
+
+void cast_int_matrix_to_short(ix5x5 i, sx5x5 s) {
+  // CHECK-LABEL: define{{.*}} void @cast_int_matrix_to_short(<25 x i32> %i, <25 x i16> %s)
+  // CHECK:       [[I:%.*]] = load <25 x i32>, <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  [[CONV:%.*]] = trunc <25 x i32> [[I]] to <25 x i16>
+  // CHECK-NEXT:  store <25 x i16> [[CONV]], <25 x i16>* {{.*}}, align 2
+  // CHECK-NEXT:  ret void
+
+  s = (sx5x5)i;
+}
+
+void cast_int_matrix_to_float(ix5x5 i, fx5x5 f) {
+  // CHECK-LABEL: define{{.*}} void @cast_int_matrix_to_float(<25 x i32> %i, <25 x float> %f)
+  // CHECK:       [[I:%.*]] = load <25 x i32>, <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  [[CONV:%.*]] = bitcast <25 x i32> [[I]] to <25 x float>
+  // CHECK-NEXT:  store <25 x float> [[CONV]], <25 x float>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  f = (fx5x5)i;
+}
+
+void cast_double_matrix_to_int(dx5x5 d, ix5x5 i) {
+  // CHECK-LABEL: define{{.*}} void @cast_double_matrix_to_int(<25 x double> %d, <25 x i32> %i)
+  // CHECK:       [[D:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:  [[CONV:%.*]] = fptosi <25 x double> [[D]] to <25 x i32>
+  // CHECK-NEXT:  store <25 x i32> [[CONV]], <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  i = (ix5x5)d;
+}
+
+void cast_float_matrix_to_unsigned_short_int(fx5x5 f, unsigned_short_int_5x5 i) {
+  // CHECK-LABEL: define{{.*}} void @cast_float_matrix_to_unsigned_short_int(<25 x float> %f, <25 x i16> %i)
+  // CHECK:       [[F:%.*]] = load <25 x float>, <25 x float>* {{.*}}, align 4
+  // CHECK-NEXT:  [[CONV:%.*]] = fptoui <25 x float> [[F]] to <25 x i16>
+  // CHECK-NEXT:  store <25 x i16> [[CONV]], <25 x i16>* %1, align 2
+  // CHECK-NEXT:  ret void
+
+  i = (unsigned_short_int_5x5)f;
+}
+
+void cast_double_matrix_to_float(dx5x5 d, fx5x5 f) {
+  // CHECK-LABEL: define{{.*}} void @cast_double_matrix_to_float(<25 x double> %d, <25 x float> %f)
+  // CHECK:       [[D:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:  [[CONV:%.*]] = fptrunc <25 x double> [[D]] to <25 x float>
+  // CHECK-NEXT:  store <25 x float> [[CONV]], <25 x float>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  f = (fx5x5)d;
+}
+
+void cast_unsigned_short_int_to_unsigned_int(unsigned_short_int_5x5 s, unsigned_int_5x5 i) {
+  // CHECK-LABEL: define{{.*}} void @cast_unsigned_short_int_to_unsigned_int(<25 x i16> %s, <25 x i32> %i)
+  // CHECK:       [[S:%.*]] = load <25 x i16>, <25 x i16>* {{.*}}, align 2
+  // CHECK-NEXT:  [[CONV:%.*]] = zext <25 x i16> [[S]] to <25 x i32>
+  // CHECK-NEXT:  store <25 x i32> [[CONV]], <25 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:  ret void
+
+  i = (unsigned_int_5x5)s;
+}
+
+void cast_unsigned_long_int_to_unsigned_short_int(unsigned_long_int_5x5 l, unsigned_short_int_5x5 s) {
+  // CHECK-LABEL: define{{.*}} void @cast_unsigned_long_int_to_unsigned_short_int(<25 x i64> %l, <25 x i16> %s)
+  // CHECK:       [[L:%.*]] = load <25 x i64>, <25 x i64>* %0, align 8
+  // CHECK-NEXT:  [[CONV:%.*]] = trunc <25 x i64> [[L]] to <25 x i16>
+  // CHECK-NEXT:  store <25 x i16> [[CONV]], <25 x i16>* {{.*}}, align 2
+  // CHECK-NEXT:  ret void
+
+  s = (unsigned_short_int_5x5)l;
+}

diff  --git a/clang/test/Sema/matrix-cast.c b/clang/test/Sema/matrix-cast.c
new file mode 100644
index 0000000000000..72428da6c530f
--- /dev/null
+++ b/clang/test/Sema/matrix-cast.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fenable-matrix -fsyntax-only %s -verify
+
+typedef char cx4x4 __attribute__((matrix_type(4, 4)));
+typedef int ix4x4 __attribute__((matrix_type(4, 4)));
+typedef short sx4x4 __attribute__((matrix_type(4, 4)));
+typedef int ix5x5 __attribute__((matrix_type(5, 5)));
+typedef float fx5x5 __attribute__((matrix_type(5, 5)));
+typedef int vec __attribute__((vector_size(4)));
+typedef struct test_struct {
+} test_struct;
+
+void f1() {
+  cx4x4 m1;
+  ix4x4 m2;
+  sx4x4 m3;
+  ix5x5 m4;
+  fx5x5 m5;
+  int i;
+  vec v;
+  test_struct *s;
+
+  m2 = (ix4x4)m1;
+  m3 = (sx4x4)m2;
+  m4 = (ix5x5)m3;        // expected-error {{conversion between matrix types 'ix5x5' (aka 'int __attribute__\
+((matrix_type(5, 5)))') and 'sx4x4' (aka 'short __attribute__((matrix_type(4, 4)))') of 
diff erent size \
+is not allowed}}
+  m5 = (ix5x5)m4;        // expected-error {{assigning to 'fx5x5' (aka \
+'float __attribute__((matrix_type(5, 5)))') from incompatible type 'ix5x5' (aka 'int __attribute__((matrix_type(5, 5)))')}}
+  i = (int)m4;           // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\
+((matrix_type(5, 5)))') and incompatible type 'int' is not allowed}}
+  m4 = (ix5x5)i;         // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\
+((matrix_type(5, 5)))') and incompatible type 'int' is not allowed}}
+  v = (vec)m4;           // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\
+((matrix_type(5, 5)))') and incompatible type 'vec' (vector of 1 'int' value) is not allowed}}
+  m4 = (ix5x5)v;         // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\
+((matrix_type(5, 5)))') and incompatible type 'vec' (vector of 1 'int' value) is not allowed}}
+  s = (test_struct *)m3; // expected-error {{conversion between matrix type 'sx4x4' (aka 'short \
+__attribute__((matrix_type(4, 4)))') and incompatible type 'test_struct *' (aka 'struct test_struct *') is not allowed}}
+  m3 = (sx4x4)s;         // expected-error {{conversion between matrix type 'sx4x4' (aka 'short \
+__attribute__((matrix_type(4, 4)))') and incompatible type 'test_struct *' (aka 'struct test_struct *') is not allowed}}
+
+  m4 = (ix5x5)m5;
+}
+
+typedef float float2_8x8 __attribute__((matrix_type(8, 8)));
+typedef double double_10x10 __attribute__((matrix_type(10, 10)));
+typedef double double_8x8 __attribute__((matrix_type(8, 8)));
+typedef signed int signed_int_12x12 __attribute__((matrix_type(12, 12)));
+typedef unsigned int unsigned_int_12x12 __attribute__((matrix_type(12, 12)));
+typedef unsigned int unsigned_int_10x10 __attribute__((matrix_type(10, 10)));
+
+void f2() {
+  float2_8x8 m1;
+  double_10x10 m2;
+  double_8x8 m3;
+  signed_int_12x12 m4;
+  unsigned_int_12x12 m5;
+  unsigned_int_10x10 m6;
+  float f;
+
+  m2 = (double_10x10)m1; // expected-error {{conversion between matrix types 'double_10x10' \
+(aka 'double __attribute__((matrix_type(10, 10)))') and 'float2_8x8' (aka 'float __attribute__\
+((matrix_type(8, 8)))') of 
diff erent size is not allowed}}
+  m3 = (double_8x8)m1;
+
+  m5 = (unsigned_int_12x12)m4;
+  m4 = (signed_int_12x12)m5;
+  m6 = (unsigned_int_10x10)m4; // expected-error {{conversion between matrix types 'unsigned_int_10x10' \
+(aka 'unsigned int __attribute__((matrix_type(10, 10)))') and 'signed_int_12x12' (aka 'int __attribute__\
+((matrix_type(12, 12)))') of 
diff erent size is not allowed}}
+  f = (float)m4;               // expected-error {{conversion between matrix type 'signed_int_12x12' \
+(aka 'int __attribute__((matrix_type(12, 12)))') and incompatible type 'float' is not allowed}}
+  m4 = (signed_int_12x12)f;    // expected-error {{conversion between matrix type 'signed_int_12x12' \
+(aka 'int __attribute__((matrix_type(12, 12)))') and incompatible type 'float' is not allowed}}
+}
\ No newline at end of file

diff  --git a/clang/test/SemaCXX/matrix-casts.cpp b/clang/test/SemaCXX/matrix-casts.cpp
new file mode 100644
index 0000000000000..bb03f3ab8d239
--- /dev/null
+++ b/clang/test/SemaCXX/matrix-casts.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -std=c++11 -fenable-matrix -fsyntax-only -verify %s
+
+template <typename X>
+
+using matrix_4_4 = X __attribute__((matrix_type(4, 4)));
+
+template <typename Y>
+
+using matrix_5_5 = Y __attribute__((matrix_type(5, 5)));
+
+typedef struct test_struct {
+} test_struct;
+
+typedef int vec __attribute__((vector_size(4)));
+
+void f1() {
+  // TODO: Update this test once the support of C-style casts for C++ is implemented.
+  matrix_4_4<char> m1;
+  matrix_4_4<int> m2;
+  matrix_4_4<short> m3;
+  matrix_5_5<int> m4;
+  int i;
+  vec v;
+  test_struct *s;
+
+  (matrix_4_4<int>)m1;   // expected-error {{C-style cast from 'matrix_4_4<char>' (aka 'char __attribute__((matrix_type(4, \
+4)))') to 'matrix_4_4<int>' (aka 'int __attribute__((matrix_type(4, 4)))') is not allowed}}
+  (matrix_4_4<short>)m2; // expected-error {{C-style cast from 'matrix_4_4<int>' (aka 'int __attribute__((matrix_type(4, \
+4)))') to 'matrix_4_4<short>' (aka 'short __attribute__((matrix_type(4, 4)))') is not allowed}}
+  (matrix_5_5<int>)m3;   // expected-error {{C-style cast from 'matrix_4_4<short>' (aka 'short __attribute__((matrix_type(4, \
+4)))') to 'matrix_5_5<int>' (aka 'int __attribute__((matrix_type(5, 5)))') is not allowed}}
+
+  (int)m3;            // expected-error {{C-style cast from 'matrix_4_4<short>' (aka 'short __attribute__((matrix_type(4, \
+4)))') to 'int'}}
+  (matrix_4_4<int>)i; // expected-error {{C-style cast from 'int' to 'matrix_4_4<int>' (aka 'int __attribute__((\
+matrix_type(4, 4)))') is not allowed}}
+
+  (vec) m2;            // expected-error {{C-style cast from 'matrix_4_4<int>' (aka 'int __attribute__((matrix_type(4, 4)))') \
+to 'vec' (vector of 1 'int' value) is not allowed}}
+  (matrix_4_4<char>)v; // expected-error {{C-style cast from 'vec' (vector of 1 'int' value) to 'matrix_4_4<char>' \
+(aka 'char __attribute__((matrix_type(4, 4)))') is not allowed}}
+
+  (test_struct *)m1;    // expected-error {{cannot cast from type 'matrix_4_4<char>' (aka 'char __attribute__\
+((matrix_type(4, 4)))') to pointer type 'test_struct *}}'
+  (matrix_5_5<float>)s; // expected-error {{C-style cast from 'test_struct *' to 'matrix_5_5<float>' (aka 'float __attribute__\
+((matrix_type(5, 5)))') is not allowed}}'
+}
+
+void f2() {
+  // TODO: Update this test once the support of C-style casts for C++ is implemented.
+  matrix_4_4<float> m1;
+  matrix_5_5<double> m2;
+  matrix_5_5<signed int> m3;
+  matrix_4_4<unsigned int> m4;
+  float f;
+
+  (matrix_4_4<double>)m1;       // expected-error {{C-style cast from 'matrix_4_4<float>' (aka 'float __attribute__\
+((matrix_type(4, 4)))') to 'matrix_4_4<double>' (aka 'double __attribute__((matrix_type(4, 4)))') is not allowed}}
+  (matrix_5_5<float>)m2;        // expected-error {{C-style cast from 'matrix_5_5<double>' (aka 'double __attribute__\
+((matrix_type(5, 5)))') to 'matrix_5_5<float>' (aka 'float __attribute__((matrix_type(5, 5)))') is not allowed}}
+  (matrix_5_5<unsigned int>)m3; // expected-error {{C-style cast from 'matrix_5_5<int>' (aka 'int __attribute__\
+((matrix_type(5, 5)))') to 'matrix_5_5<unsigned int>' (aka 'unsigned int __attribute__((matrix_type(5, 5)))') \
+is not allowed}}
+  (matrix_4_4<int>)m4;          // expected-error {{C-style cast from 'matrix_4_4<unsigned int>' (aka 'unsigned int \
+__attribute__((matrix_type(4, 4)))') to 'matrix_4_4<int>' (aka 'int __attribute__((matrix_type(4, 4)))') is not \
+allowed}}
+}


        


More information about the cfe-commits mailing list