diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def --- a/clang/include/clang/AST/OperationKinds.def +++ b/clang/include/clang/AST/OperationKinds.def @@ -181,6 +181,9 @@ /// (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/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8577,6 +8577,13 @@ let CategoryName = "Semantic Issue" in { +def err_invalid_conversion_between_matrices : Error< + "invalid conversion between matrix type%diff{ $ and $|}0,1 of different " + "size">; + +def err_invalid_conversion_between_matrix_and_scalar : Error< + "invalid conversion between matrix type %0 and scalar type%1">; + def err_invalid_conversion_between_vectors : Error< "invalid conversion between vector type%diff{ $ and $|}0,1 of different " "size">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11648,6 +11648,8 @@ bool isValidSveBitcast(QualType srcType, QualType destType); + bool areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy); + bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); @@ -11706,6 +11708,13 @@ ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); + // CheckMatrixCast - Check type constraints for matrices. + // We allow casting between matrices 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 MatrixTy, QualType Tr, + 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 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1708,6 +1708,7 @@ 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 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13183,6 +13183,7 @@ 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 @@ 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 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4645,6 +4645,7 @@ 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 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -901,6 +901,7 @@ case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLOpaqueType: + case CK_MatrixCast: case CK_IntToOCLSampler: case CK_FloatingToFixedPoint: @@ -1422,6 +1423,7 @@ 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 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -533,6 +533,7 @@ 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 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1170,6 +1170,7 @@ 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 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2237,6 +2237,10 @@ unsigned NumElements = cast(DstTy)->getNumElements(); return Builder.CreateVectorSplat(NumElements, Elt, "splat"); } + case CK_MatrixCast: { + // TODO: Implement code generation for matrix cast here. + break; + } case CK_FixedPointCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy, diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1080,6 +1080,7 @@ 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 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2859,7 +2859,8 @@ return; } - if (!DestType->isScalarType() && !DestType->isVectorType()) { + if (!DestType->isScalarType() && !DestType->isVectorType() && + !DestType->isMatrixType()) { const RecordType *DestRecordTy = DestType->getAs(); if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){ @@ -2910,10 +2911,11 @@ 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()) { + 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,13 @@ return; } + if (const MatrixType *DestMatTy = DestType->getAs()) { + if (Self.CheckMatrixCast(OpRange, DestType, SrcType, Kind)) { + SrcExpr = ExprError(); + } + return; + } + if (const VectorType *DestVecTy = DestType->getAs()) { if (DestVecTy->getVectorKind() == VectorType::AltiVecVector && (SrcType->isIntegerType() || SrcType->isFloatingType())) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7312,6 +7312,19 @@ ValidScalableConversion(destTy, srcTy); } +/// Are the two types matrix types and do they have the same dimensions i.e. +/// and do they both 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) { + assert(destTy->isMatrixType() && srcTy->isMatrixType()); + + const ConstantMatrixType *matSrcType = srcTy->getAs(); + const ConstantMatrixType *matDestType = destTy->getAs(); + + 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 @@ -7374,6 +7387,25 @@ return areLaxCompatibleVectorTypes(srcTy, destTy); } +bool Sema::CheckMatrixCast(SourceRange R, QualType DestMatrixTy, QualType SrcTy, + CastKind &Kind) { + assert(DestMatrixTy->isMatrixType() && "Not a matrix type!"); + + if (SrcTy->isMatrixType()) { + if (!areMatrixTypesOfTheSameDimension(SrcTy, DestMatrixTy)) { + return Diag(R.getBegin(), diag::err_invalid_conversion_between_matrices) + << DestMatrixTy << SrcTy << R; + } + } else { + return Diag(R.getBegin(), + diag::err_invalid_conversion_between_matrix_and_scalar) + << DestMatrixTy << 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 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -543,6 +543,9 @@ state = handleLVectorSplat(state, LCtx, CastE, Bldr, Pred); continue; } + case CK_MatrixCast: { + // TODO: Handle MatrixCast here. + } } } } diff --git a/clang/test/CodeGen/matrix-cast.c b/clang/test/CodeGen/matrix-cast.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/matrix-cast.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s + +typedef char cx4x4 __attribute__((matrix_type(4, 4))); +typedef int ix4x4 __attribute__((matrix_type(4, 4))); + +void cast_char_matrix_to_int_same_size(cx4x4 c, ix4x4 i) { + c = (cx4x4)i; +} \ No newline at end of file diff --git a/clang/test/Sema/matrix-cast.c b/clang/test/Sema/matrix-cast.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/matrix-cast.c @@ -0,0 +1,51 @@ +// 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))); + +void f1() { + cx4x4 m1; + ix4x4 m2; + sx4x4 m3; + ix5x5 m4; + fx5x5 m5; + + m2 = (ix4x4)m1; + m3 = (sx4x4)m2; + m4 = (ix5x5)m3; // expected-error {{invalid conversion between matrix type \ +'ix5x5' (aka 'int __attribute__((matrix_type(5, 5)))') and 'sx4x4' \ +(aka 'short __attribute__((matrix_type(4, 4)))') of different size}} + 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)))')}} + 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; + + m2 = (double_10x10)m1; // expected-error {{invalid conversion between matrix type \ +'double_10x10' (aka 'double __attribute__((matrix_type(10, 10)))') and 'float2_8x8' \ +(aka 'float __attribute__((matrix_type(8, 8)))') of different size}} + m3 = (double_8x8)m1; + + m5 = (unsigned_int_12x12)m4; + m4 = (signed_int_12x12)m5; + m6 = (unsigned_int_10x10)m4; // expected-error {{invalid conversion between matrix type \ +'unsigned_int_10x10' (aka 'unsigned int __attribute__((matrix_type(10, 10)))') and 'signed_int_12x12' \ +(aka 'int __attribute__((matrix_type(12, 12)))') of different size}} +} \ No newline at end of file