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/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -518,7 +518,7 @@ 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 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8580,6 +8580,12 @@ let CategoryName = "Semantic Issue" in { +def err_invalid_conversion_between_matrixes : Error< + "conversion between matrix type%diff{ $ and $|}0,1 of different size is not allowed">; + +def err_invalid_conversion_between_matrix_and_type : Error< + "conversion between matrix type %0 and type %1 is not allowed">; + 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 @@ -11651,6 +11651,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); @@ -11709,6 +11711,13 @@ ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); + // CheckMatrixCast - Check type constraints for matrix casts. + // 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 @@ -13180,6 +13180,7 @@ case CK_FixedPointToFloating: case CK_FixedPointCast: case CK_IntegralToFixedPoint: + case CK_MatrixCast: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -13920,6 +13921,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 @@ -1198,27 +1198,52 @@ QualType DstType, llvm::Type *SrcTy, llvm::Type *DstTy, ScalarConversionOpts Opts) { - if (isa(SrcTy)) { - bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); - if (SrcType->isBooleanType() && Opts.TreatBooleanAsSigned) { + // If the types are non-matrix, the element types and the types are the same. + // The assignments in this condition are used in the code following this + // condition where we use element types to determine the kind of cast and + // original types for actual casting. + llvm::Type *SrcElementTy; + llvm::Type *DstElementTy; + QualType SrcElementType; + QualType DstElementType; + if (SrcType->isMatrixType() && DstType->isMatrixType()) { + // Allow bitcast between matrices of the same size. + if (SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits()) + return Builder.CreateBitCast(Src, DstTy, "conv"); + + SrcElementTy = cast(SrcTy)->getElementType(); + DstElementTy = cast(DstTy)->getElementType(); + SrcElementType = SrcType->castAs()->getElementType(); + DstElementType = DstType->castAs()->getElementType(); + } else { + assert(!SrcType->isMatrixType() && !DstType->isMatrixType()); + SrcElementTy = SrcTy; + DstElementTy = DstTy; + SrcElementType = SrcType; + DstElementType = DstType; + } + + if (isa(SrcElementTy)) { + bool InputSigned = SrcElementType->isSignedIntegerOrEnumerationType(); + if (SrcElementType->isBooleanType() && Opts.TreatBooleanAsSigned) { InputSigned = true; } - if (isa(DstTy)) + if (isa(DstElementTy)) return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); if (InputSigned) return Builder.CreateSIToFP(Src, DstTy, "conv"); return Builder.CreateUIToFP(Src, DstTy, "conv"); } - if (isa(DstTy)) { - assert(SrcTy->isFloatingPointTy() && "Unknown real conversion"); - if (DstType->isSignedIntegerOrEnumerationType()) + if (isa(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 +1375,9 @@ return Builder.CreateVectorSplat(NumElements, Src, "splat"); } + if (SrcType->isMatrixType() && DstType->isMatrixType()) + return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts); + if (isa(SrcTy) || isa(DstTy)) { // Allow bitcast from vector to integer/fp of the same size. unsigned SrcSize = SrcTy->getPrimitiveSizeInBits(); @@ -2238,6 +2266,10 @@ 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(E)); 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()) { + // 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,13 @@ return; } + if (DestType->getAs() || SrcType->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 @@ -7345,6 +7345,19 @@ 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(); + 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 @@ -7407,6 +7420,27 @@ 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 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -543,6 +543,10 @@ 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 --- /dev/null +++ b/clang/test/CodeGen/matrix-cast.c @@ -0,0 +1,100 @@ +// 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_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 --- /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 type 'ix5x5' (aka 'int __attribute__\ +((matrix_type(5, 5)))') and 'sx4x4' (aka 'short __attribute__((matrix_type(4, 4)))') of different 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 type 'int' is not allowed}} + m4 = (ix5x5)i; // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\ +((matrix_type(5, 5)))') and type 'int' is not allowed}} + v = (vec)m4; // expected-error {{conversion between matrix type 'ix5x5' (aka 'int __attribute__\ +((matrix_type(5, 5)))') and 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 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 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 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 type 'double_10x10' \ +(aka 'double __attribute__((matrix_type(10, 10)))') and 'float2_8x8' (aka 'float __attribute__\ +((matrix_type(8, 8)))') of different 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 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 is not allowed}} + f = (float)m4; // expected-error {{conversion between matrix type 'signed_int_12x12' \ +(aka 'int __attribute__((matrix_type(12, 12)))') and 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 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 --- /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 + +using matrix_4_4 = X __attribute__((matrix_type(4, 4))); + +template + +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 m1; + matrix_4_4 m2; + matrix_4_4 m3; + matrix_5_5 m4; + int i; + vec v; + test_struct *s; + + (matrix_4_4)m1; // expected-error {{C-style cast from 'matrix_4_4' (aka 'char __attribute__((matrix_type(4, \ +4)))') to 'matrix_4_4' (aka 'int __attribute__((matrix_type(4, 4)))') is not allowed}} + (matrix_4_4)m2; // expected-error {{C-style cast from 'matrix_4_4' (aka 'int __attribute__((matrix_type(4, \ +4)))') to 'matrix_4_4' (aka 'short __attribute__((matrix_type(4, 4)))') is not allowed}} + (matrix_5_5)m3; // expected-error {{C-style cast from 'matrix_4_4' (aka 'short __attribute__((matrix_type(4, \ +4)))') to 'matrix_5_5' (aka 'int __attribute__((matrix_type(5, 5)))') is not allowed}} + + (int)m3; // expected-error {{C-style cast from 'matrix_4_4' (aka 'short __attribute__((matrix_type(4, \ +4)))') to 'int'}} + (matrix_4_4)i; // expected-error {{C-style cast from 'int' to 'matrix_4_4' (aka 'int __attribute__((\ +matrix_type(4, 4)))') is not allowed}} + + (vec) m2; // expected-error {{C-style cast from 'matrix_4_4' (aka 'int __attribute__((matrix_type(4, 4)))') \ +to 'vec' (vector of 1 'int' value) is not allowed}} + (matrix_4_4)v; // expected-error {{C-style cast from 'vec' (vector of 1 'int' value) to 'matrix_4_4' \ +(aka 'char __attribute__((matrix_type(4, 4)))') is not allowed}} + + (test_struct *)m1; // expected-error {{cannot cast from type 'matrix_4_4' (aka 'char __attribute__\ +((matrix_type(4, 4)))') to pointer type 'test_struct *}}' + (matrix_5_5)s; // expected-error {{C-style cast from 'test_struct *' to 'matrix_5_5' (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 m1; + matrix_5_5 m2; + matrix_5_5 m3; + matrix_4_4 m4; + float f; + + (matrix_4_4)m1; // expected-error {{C-style cast from 'matrix_4_4' (aka 'float __attribute__\ +((matrix_type(4, 4)))') to 'matrix_4_4' (aka 'double __attribute__((matrix_type(4, 4)))') is not allowed}} + (matrix_5_5)m2; // expected-error {{C-style cast from 'matrix_5_5' (aka 'double __attribute__\ +((matrix_type(5, 5)))') to 'matrix_5_5' (aka 'float __attribute__((matrix_type(5, 5)))') is not allowed}} + (matrix_5_5)m3; // expected-error {{C-style cast from 'matrix_5_5' (aka 'int __attribute__\ +((matrix_type(5, 5)))') to 'matrix_5_5' (aka 'unsigned int __attribute__((matrix_type(5, 5)))') \ +is not allowed}} + (matrix_4_4)m4; // expected-error {{C-style cast from 'matrix_4_4' (aka 'unsigned int \ +__attribute__((matrix_type(4, 4)))') to 'matrix_4_4' (aka 'int __attribute__((matrix_type(4, 4)))') is not \ +allowed}} +}