diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -978,6 +978,7 @@ #include "clang/Basic/OpenCLImageTypes.def" CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLReserveIDTy; + CanQualType IncompleteMatrixIdxTy; CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ CanQualType Id##Ty; diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -310,6 +310,9 @@ // context. PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) +// A placeholder type for incomplete matrix index expressions. +PLACEHOLDER_TYPE(IncompleteMatrixIdx, IncompleteMatrixIdxTy) + // A placeholder type for OpenMP array sections. PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -28,6 +28,7 @@ class UnaryOperator; class UnaryExprOrTypeTraitExpr; class ArraySubscriptExpr; +class MatrixSubscriptExpr; class CompoundLiteralExpr; class CastExpr; class BinaryOperator; @@ -108,6 +109,7 @@ ExprDependence computeDependence(UnaryOperator *E); ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E); ExprDependence computeDependence(ArraySubscriptExpr *E); +ExprDependence computeDependence(MatrixSubscriptExpr *E); ExprDependence computeDependence(CompoundLiteralExpr *E); ExprDependence computeDependence(CastExpr *E); ExprDependence computeDependence(BinaryOperator *E); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -476,6 +476,11 @@ /// Returns whether this expression refers to a vector element. bool refersToVectorElement() const; + /// Returns whether this expression refers to a matrix element. + bool refersToMatrixElement() const { + return getObjectKind() == OK_MatrixComponent; + } + /// Returns whether this expression refers to a global register /// variable. bool refersToGlobalRegisterVar() const; @@ -2589,7 +2594,7 @@ : Expr(ArraySubscriptExprClass, t, VK, OK) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - ArraySubscriptExprBits.RBracketLoc = rbracketloc; + ArrayOrMatrixSubscriptExprBits.RBracketLoc = rbracketloc; setDependence(computeDependence(this)); } @@ -2626,10 +2631,10 @@ SourceLocation getEndLoc() const { return getRBracketLoc(); } SourceLocation getRBracketLoc() const { - return ArraySubscriptExprBits.RBracketLoc; + return ArrayOrMatrixSubscriptExprBits.RBracketLoc; } void setRBracketLoc(SourceLocation L) { - ArraySubscriptExprBits.RBracketLoc = L; + ArrayOrMatrixSubscriptExprBits.RBracketLoc = L; } SourceLocation getExprLoc() const LLVM_READONLY { @@ -2649,6 +2654,84 @@ } }; +/// MatrixSubscriptExpr - Matrix subscript expression for the MatrixType +/// extension. +/// MatrixSubscriptExpr can be either incomplete (only Base and RowIdx are set +/// so far, the type is IncompleteMatrixIdx) or complete (Base, RowIdx and +/// ColumnIdx refer to valid expressions). Incomplete matrix expressions only +/// exist during the initial construction of the AST. +class MatrixSubscriptExpr : public Expr { + enum { BASE, ROW_IDX, COLUMN_IDX, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + +public: + MatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, QualType T, + SourceLocation RBracketLoc) + : Expr(MatrixSubscriptExprClass, T, Base->getValueKind(), + OK_MatrixComponent) { + SubExprs[BASE] = Base; + SubExprs[ROW_IDX] = RowIdx; + SubExprs[COLUMN_IDX] = ColumnIdx; + ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc; + setDependence(computeDependence(this)); + } + + /// Create an empty matrix subscript expression. + explicit MatrixSubscriptExpr(EmptyShell Shell) + : Expr(MatrixSubscriptExprClass, Shell) {} + + bool isIncomplete() const { + bool IsIncomplete = hasPlaceholderType(BuiltinType::IncompleteMatrixIdx); + assert((SubExprs[COLUMN_IDX] || IsIncomplete) && + "expressions without column index must be marked as incomplete"); + return IsIncomplete; + } + Expr *getBase() { return cast(SubExprs[BASE]); } + const Expr *getBase() const { return cast(SubExprs[BASE]); } + void setBase(Expr *E) { SubExprs[BASE] = E; } + + Expr *getRowIdx() { return cast(SubExprs[ROW_IDX]); } + const Expr *getRowIdx() const { return cast(SubExprs[ROW_IDX]); } + void setRowIdx(Expr *E) { SubExprs[ROW_IDX] = E; } + + Expr *getColumnIdx() { return cast_or_null(SubExprs[COLUMN_IDX]); } + const Expr *getColumnIdx() const { + assert(!isIncomplete() && + "cannot get the column index of an incomplete expression"); + return cast(SubExprs[COLUMN_IDX]); + } + void setColumnIdx(Expr *E) { SubExprs[COLUMN_IDX] = E; } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); + } + + SourceLocation getEndLoc() const { return getRBracketLoc(); } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + SourceLocation getRBracketLoc() const { + return ArrayOrMatrixSubscriptExprBits.RBracketLoc; + } + void setRBracketLoc(SourceLocation L) { + ArrayOrMatrixSubscriptExprBits.RBracketLoc = L; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MatrixSubscriptExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } +}; + /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). /// CallExpr itself represents a normal function call, e.g., "f(x, 2)", /// while its subclasses may represent alternative syntax that (semantically) diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2588,6 +2588,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {}) DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {}) DEF_TRAVERSE_STMT(OMPIteratorExpr, {}) 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 @@ -445,8 +445,9 @@ unsigned IsType : 1; // true if operand is a type, false if an expression. }; - class ArraySubscriptExprBitfields { + class ArrayOrMatrixSubscriptExprBitfields { friend class ArraySubscriptExpr; + friend class MatrixSubscriptExpr; unsigned : NumExprBits; @@ -999,7 +1000,7 @@ CharacterLiteralBitfields CharacterLiteralBits; UnaryOperatorBitfields UnaryOperatorBits; UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; - ArraySubscriptExprBitfields ArraySubscriptExprBits; + ArrayOrMatrixSubscriptExprBitfields ArrayOrMatrixSubscriptExprBits; CallExprBitfields CallExprBits; MemberExprBitfields MemberExprBits; CastExprBitfields CastExprBits; 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 @@ -2032,6 +2032,8 @@ "bit-field%select{| %1}2">; def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; +def err_reference_bind_to_matrix_element : Error< + "%select{non-const|volatile}0 reference cannot bind to matrix element">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_reference_without_init : Error< @@ -6375,7 +6377,7 @@ def err_static_block_func : Error< "function declared in block scope cannot have 'static' storage class">; def err_typecheck_address_of : Error<"address of %select{bit-field" - "|vector element|property expression|register variable}0 requested">; + "|vector element|property expression|register variable|matrix element}0 requested">; def ext_typecheck_addrof_void : Extension< "ISO C forbids taking the address of an expression of type 'void'">; def err_unqualified_pointer_member_function : Error< @@ -10751,6 +10753,16 @@ def err_builtin_matrix_disabled: Error< "matrix types extension is disabled. Pass -fenable-matrix to enable it">; +def err_matrix_index_not_integer: Error< + "matrix %select{row|column}0 index is not an integer">; +def err_matrix_index_outside_range: Error< + "matrix %select{row|column}0 index is outside the allowed range [0, %1)">; +def err_matrix_incomplete_index: Error< + "single subscript expressions are not allowed for matrix values">; +def err_matrix_separate_incomplete_index: Error< + "matrix row and column subscripts cannot be separated by any expression">; +def err_matrix_subscript_comma: Error< + "comma expressions are not allowed as indices in matrix subscript expressions">; def err_preserve_field_info_not_field : Error< "__builtin_preserve_field_info argument %0 not a field access">; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -154,7 +154,10 @@ /// An Objective-C array/dictionary subscripting which reads an /// object or writes at the subscripted array/dictionary element via /// Objective-C method calls. - OK_ObjCSubscript + OK_ObjCSubscript, + + /// A matrix component is a single element of a matrix. + OK_MatrixComponent }; /// The reason why a DeclRefExpr does not constitute an odr-use. diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -69,6 +69,7 @@ def OffsetOfExpr : StmtNode; def UnaryExprOrTypeTraitExpr : StmtNode; def ArraySubscriptExpr : StmtNode; +def MatrixSubscriptExpr : StmtNode; def OMPArraySectionExpr : StmtNode; def OMPIteratorExpr : StmtNode; def CallExpr : StmtNode; diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -999,6 +999,9 @@ /// Non-const lvalue reference binding to a vector element. FK_NonConstLValueReferenceBindingToVectorElement, + /// Non-const lvalue reference binding to a matrix element. + FK_NonConstLValueReferenceBindingToMatrixElement, + /// Non-const lvalue reference binding to an lvalue of unrelated /// type. FK_NonConstLValueReferenceBindingToUnrelated, 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 @@ -4904,6 +4904,11 @@ Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); + + ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBLoc); + ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1057,7 +1057,10 @@ /// The placeholder type for OpenMP iterator expression. PREDEF_TYPE_OMP_ITERATOR = 71, - /// OpenCL image types with auto numeration + /// A placeholder type for incomplete matrix index operations. + PREDEF_TYPE_INCOMPLETE_MATRIX_IDX = 72, + + /// OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, #include "clang/Basic/OpenCLImageTypes.def" @@ -1597,6 +1600,9 @@ /// An ArraySubscriptExpr record. EXPR_ARRAY_SUBSCRIPT, + /// An MatrixSubscriptExpr record. + EXPR_MATRIX_SUBSCRIPT, + /// A CallExpr record. EXPR_CALL, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1388,6 +1388,8 @@ InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping); InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); } + if (LangOpts.MatrixTypes) + InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -83,6 +83,12 @@ return E->getLHS()->getDependence() | E->getRHS()->getDependence(); } +ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) { + return E->getBase()->getDependence() | E->getRowIdx()->getDependence() | + (E->getColumnIdx() ? E->getColumnIdx()->getDependence() + : ExprDependence::None); +} + ExprDependence clang::computeDependence(CompoundLiteralExpr *E) { return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()) | turnTypeToValueDependence(E->getInitializer()->getDependence()); 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 @@ -3508,6 +3508,7 @@ case ParenExprClass: case ArraySubscriptExprClass: + case MatrixSubscriptExprClass: case OMPArraySectionExprClass: case OMPArrayShapingExprClass: case OMPIteratorExprClass: diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -224,6 +224,10 @@ } return Cl::CL_LValue; + // Subscripting matrix types behaves like member accesses. + case Expr::MatrixSubscriptExprClass: + return ClassifyInternal(Ctx, cast(E)->getBase()); + // C++ [expr.prim.general]p3: The result is an lvalue if the entity is a // function or variable and a prvalue otherwise. case Expr::DeclRefExprClass: 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 @@ -14184,6 +14184,7 @@ case Expr::ImaginaryLiteralClass: case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: + case Expr::MatrixSubscriptExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4234,6 +4234,15 @@ break; } + case Expr::MatrixSubscriptExprClass: { + const MatrixSubscriptExpr *ME = cast(E); + Out << "ixix"; + mangleExpression(ME->getBase()); + mangleExpression(ME->getRowIdx()); + mangleExpression(ME->getColumnIdx()); + break; + } + case Expr::CompoundAssignOperatorClass: // fallthrough case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast(E); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -482,6 +482,7 @@ case BuiltinType::Half: case BuiltinType::PseudoObject: case BuiltinType::BuiltinFn: + case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1337,6 +1337,16 @@ OS << "]"; } +void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) { + PrintExpr(Node->getBase()); + OS << "["; + PrintExpr(Node->getRowIdx()); + OS << "]"; + OS << "["; + PrintExpr(Node->getColumnIdx()); + OS << "]"; +} + void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { PrintExpr(Node->getBase()); OS << "["; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1208,6 +1208,10 @@ VisitExpr(S); } +void StmtProfiler::VisitMatrixSubscriptExpr(const MatrixSubscriptExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -163,6 +163,9 @@ case OK_VectorComponent: OS << " vectorcomponent"; break; + case OK_MatrixComponent: + OS << " matrixcomponent"; + break; } } } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3025,6 +3025,8 @@ return "queue_t"; case OCLReserveID: return "reserve_id_t"; + case IncompleteMatrixIdx: + return ""; case OMPArraySection: return ""; case OMPArrayShaping: @@ -4045,6 +4047,7 @@ #include "clang/Basic/AArch64SVEACLETypes.def" case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: + case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -403,6 +403,7 @@ case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" case BuiltinType::BuiltinFn: + case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: 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 @@ -1369,6 +1369,8 @@ return EmitUnaryOpLValue(cast(E)); case Expr::ArraySubscriptExprClass: return EmitArraySubscriptExpr(cast(E)); + case Expr::MatrixSubscriptExprClass: + return EmitMatrixSubscriptExpr(cast(E)); case Expr::OMPArraySectionExprClass: return EmitOMPArraySectionExpr(cast(E)); case Expr::ExtVectorElementExprClass: @@ -1886,13 +1888,21 @@ // If this is a reference to a subset of the elements of a vector, either // shuffle the input or extract/insert them as appropriate. - if (LV.isExtVectorElt()) + if (LV.isExtVectorElt()) { return EmitLoadOfExtVectorElementLValue(LV); + } // Global Register variables always invoke intrinsics if (LV.isGlobalReg()) return EmitLoadOfGlobalRegLValue(LV); + if (LV.isMatrixElt()) { + llvm::LoadInst *Load = + Builder.CreateLoad(LV.getMatrixAddress(), LV.isVolatileQualified()); + return RValue::get( + Builder.CreateExtractElement(Load, LV.getMatrixIdx(), "matrixext")); + } + assert(LV.isBitField() && "Unknown LValue type!"); return EmitLoadOfBitfieldLValue(LV, Loc); } @@ -1998,7 +2008,6 @@ return RValue::get(Call); } - /// EmitStoreThroughLValue - Store the specified rvalue into the specified /// lvalue, where both are guaranteed to the have the same type, and that type /// is 'Ty'. @@ -2024,6 +2033,15 @@ if (Dst.isGlobalReg()) return EmitStoreThroughGlobalRegLValue(Src, Dst); + if (Dst.isMatrixElt()) { + llvm::Value *Vec = Builder.CreateLoad(Dst.getMatrixAddress()); + Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), + Dst.getMatrixIdx(), "matins"); + Builder.CreateStore(Vec, Dst.getMatrixAddress(), + Dst.isVolatileQualified()); + return; + } + assert(Dst.isBitField() && "Unknown LValue type"); return EmitStoreThroughBitfieldLValue(Src, Dst); } @@ -3754,6 +3772,23 @@ return LV; } +LValue CodeGenFunction::EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E) { + assert( + !E->isIncomplete() && + "incomplete matrix subscript expressions should be rejected during Sema"); + LValue Base = EmitLValue(E->getBase()); + llvm::Value *RowIdx = EmitScalarExpr(E->getRowIdx()); + llvm::Value *ColIdx = EmitScalarExpr(E->getColumnIdx()); + llvm::Value *NumRows = Builder.getIntN( + RowIdx->getType()->getScalarSizeInBits(), + E->getBase()->getType()->getAs()->getNumRows()); + llvm::Value *FinalIdx = + Builder.CreateAdd(Builder.CreateMul(ColIdx, NumRows), RowIdx); + return LValue::MakeMatrixElt( + MaybeConvertMatrixAddress(Base.getAddress(*this), *this), FinalIdx, + E->getBase()->getType(), Base.getBaseInfo(), TBAAAccessInfo()); +} + static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, LValueBaseInfo &BaseInfo, TBAAAccessInfo &TBAAInfo, 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 @@ -578,6 +578,7 @@ } Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); + Value *VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitConvertVectorExpr(ConvertVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); @@ -1809,6 +1810,22 @@ return Builder.CreateExtractElement(Base, Idx, "vecext"); } +Value *ScalarExprEmitter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { + TestAndClearIgnoreResultAssign(); + + // Handle the vector case. The base must be a vector, the index must be an + // integer value. + Value *RowIdx = Visit(E->getRowIdx()); + Value *ColumnIdx = Visit(E->getColumnIdx()); + Value *Matrix = Visit(E->getBase()); + + // TODO: Should we emit bounds checks with SanitizerKind::ArrayBounds? + llvm::MatrixBuilder MB(Builder); + return MB.CreateExtractElement( + Matrix, RowIdx, ColumnIdx, + E->getBase()->getType()->getAs()->getNumRows()); +} + static int getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, unsigned Off) { int MV = SVI->getMaskValue(Idx); diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -170,7 +170,8 @@ VectorElt, // This is a vector element l-value (V[i]), use getVector* BitField, // This is a bitfield l-value, use getBitfield*. ExtVectorElt, // This is an extended vector subset, use getExtVectorComp - GlobalReg // This is a register l-value, use getGlobalReg() + GlobalReg, // This is a register l-value, use getGlobalReg() + MatrixElt // This is a matrix element, use getVector* } LVType; llvm::Value *V; @@ -254,6 +255,7 @@ bool isBitField() const { return LVType == BitField; } bool isExtVectorElt() const { return LVType == ExtVectorElt; } bool isGlobalReg() const { return LVType == GlobalReg; } + bool isMatrixElt() const { return LVType == MatrixElt; } bool isVolatileQualified() const { return Quals.hasVolatile(); } bool isRestrictQualified() const { return Quals.hasRestrict(); } @@ -337,8 +339,26 @@ Address getVectorAddress() const { return Address(getVectorPointer(), getAlignment()); } - llvm::Value *getVectorPointer() const { assert(isVectorElt()); return V; } - llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; } + llvm::Value *getVectorPointer() const { + assert(isVectorElt()); + return V; + } + llvm::Value *getVectorIdx() const { + assert(isVectorElt()); + return VectorIdx; + } + + Address getMatrixAddress() const { + return Address(getMatrixPointer(), getAlignment()); + } + llvm::Value *getMatrixPointer() const { + assert(isMatrixElt()); + return V; + } + llvm::Value *getMatrixIdx() const { + assert(isMatrixElt()); + return VectorIdx; + } // extended vector elements. Address getExtVectorAddress() const { @@ -430,6 +450,18 @@ return R; } + static LValue MakeMatrixElt(Address matAddress, llvm::Value *Idx, + QualType type, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo) { + LValue R; + R.LVType = MatrixElt; + R.V = matAddress.getPointer(); + R.VectorIdx = Idx; + R.Initialize(type, type.getQualifiers(), matAddress.getAlignment(), + BaseInfo, TBAAInfo); + return R; + } + RValue asAggregateRValue(CodeGenFunction &CGF) const { return RValue::getAggregate(getAddress(CGF), isVolatileQualified()); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3628,6 +3628,7 @@ LValue EmitUnaryOpLValue(const UnaryOperator *E); LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed = false); + LValue EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E); LValue EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, bool IsLowerBound = true); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); 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 @@ -2089,6 +2089,9 @@ return TC_NotApplicable; // FIXME: Use a specific diagnostic for the rest of these cases. case OK_VectorComponent: inappropriate = "vector element"; break; + case OK_MatrixComponent: + inappropriate = "matrix element"; + break; case OK_ObjCProperty: inappropriate = "property expression"; break; case OK_ObjCSubscript: inappropriate = "container subscripting expression"; break; diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1299,6 +1299,7 @@ // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: + case Expr::MatrixSubscriptExprClass: case Expr::OMPArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: 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 @@ -4553,6 +4553,53 @@ base = result.get(); } + // Check if base and idx form a MatrixSubscriptExpr. + // + // Helper to check for comma expressions, which are not allowed as indices for + // matrix subscript expressions. + auto CheckAndReportCommaError = [this, base, rbLoc](Expr *E) { + if (isa(E) && cast(E)->isCommaOp()) { + Diag(E->getExprLoc(), diag::err_matrix_subscript_comma) + << SourceRange(base->getBeginLoc(), rbLoc); + return true; + } + return false; + }; + // The matrix subscript operator ([][])is considered a single operator. + // Separating the index expressions by parenthesis is not allowed. + if (base->getType()->isSpecificPlaceholderType( + BuiltinType::IncompleteMatrixIdx) && + !isa(base)) { + Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index) + << SourceRange(base->getBeginLoc(), rbLoc); + return ExprError(); + } + // If the base is either a MatrixSubscriptExpr or a matrix type, try to create + // a new MatrixSubscriptExpr. + auto *matSubscriptE = dyn_cast(base); + if (matSubscriptE) { + if (CheckAndReportCommaError(idx)) + return ExprError(); + + assert(matSubscriptE->isIncomplete() && + "base has to be an incomplete matrix subscript"); + return CreateBuiltinMatrixSubscriptExpr( + matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc); + } + Expr *matrixBase = base; + bool IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); + if (!IsMSPropertySubscript) { + ExprResult result = CheckPlaceholderExpr(base); + if (!result.isInvalid()) + matrixBase = result.get(); + } + if (matrixBase->getType()->isMatrixType()) { + if (CheckAndReportCommaError(idx)) + return ExprError(); + + return CreateBuiltinMatrixSubscriptExpr(matrixBase, idx, nullptr, rbLoc); + } + // A comma-expression as the index is deprecated in C++2a onwards. if (getLangOpts().CPlusPlus20 && ((isa(idx) && cast(idx)->isCommaOp()) || @@ -4567,7 +4614,6 @@ // operand might be an overloadable type, in which case the overload // resolution for the operator overload should get the first crack // at the overload. - bool IsMSPropertySubscript = false; if (base->getType()->isNonOverloadPlaceholderType()) { IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); if (!IsMSPropertySubscript) { @@ -4628,6 +4674,82 @@ return Res; } +static bool tryConvertToTy(Sema &S, QualType ElementType, ExprResult *Scalar) { + InitializedEntity Entity = + InitializedEntity::InitializeTemporary(ElementType); + InitializationKind Kind = InitializationKind::CreateCopy( + Scalar->get()->getBeginLoc(), SourceLocation()); + Expr *Arg = Scalar->get(); + InitializationSequence InitSeq(S, Entity, Kind, Arg); + *Scalar = InitSeq.Perform(S, Entity, Kind, Arg); + return !Scalar->isInvalid(); +} + +ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBLoc) { + ExprResult BaseR = CheckPlaceholderExpr(Base); + if (BaseR.isInvalid()) + return BaseR; + Base = BaseR.get(); + + ExprResult RowR = CheckPlaceholderExpr(RowIdx); + if (RowR.isInvalid()) + return RowR; + RowIdx = RowR.get(); + + if (!ColumnIdx) + return new (Context) MatrixSubscriptExpr( + Base, RowIdx, ColumnIdx, Context.IncompleteMatrixIdxTy, RBLoc); + + // Build an unanalyzed expression if any of the operands is type-dependent. + if (Base->isTypeDependent() || RowIdx->isTypeDependent() || + ColumnIdx->isTypeDependent()) + return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + Context.DependentTy, RBLoc); + + ExprResult ColumnR = CheckPlaceholderExpr(ColumnIdx); + if (ColumnR.isInvalid()) + return ColumnR; + ColumnIdx = ColumnR.get(); + + // Check that IndexExpr is an integer expression. If it is a constant + // expression, check that it is less than Dim (= the number of elements in the + // corresponding dimension). + auto IsIndexValid = [&](Expr *IndexExpr, unsigned Dim, + bool IsColumnIdx) -> Expr * { + if (!IndexExpr->getType()->isIntegerType() && + !IndexExpr->isTypeDependent()) { + Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_not_integer) + << IsColumnIdx; + return nullptr; + } + + llvm::APSInt Idx; + if (IndexExpr->isIntegerConstantExpr(Idx, Context) && + (Idx < 0 || Idx >= Dim)) { + Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range) + << IsColumnIdx << Dim; + return nullptr; + } + + ExprResult ConvExpr = IndexExpr; + bool ConversionOk = tryConvertToTy(*this, Context.getSizeType(), &ConvExpr); + assert(ConversionOk && + "should be able to convert any integer type to size type"); + return ConvExpr.get(); + }; + + auto *MTy = Base->getType()->getAs(); + RowIdx = IsIndexValid(RowIdx, MTy->getNumRows(), false); + ColumnIdx = IsIndexValid(ColumnIdx, MTy->getNumColumns(), true); + if (!RowIdx || !ColumnIdx) + return ExprError(); + + return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + MTy->getElementType(), RBLoc); +} + void Sema::CheckAddressOfNoDeref(const Expr *E) { ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back(); const Expr *StrippedExpr = E->IgnoreParenImpCasts(); @@ -5942,6 +6064,7 @@ // These are always invalid as call arguments and should be reported. case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: + case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: @@ -11943,18 +12066,6 @@ return GetSignedVectorType(LHS.get()->getType()); } -static bool tryConvertScalarToMatrixElementTy(Sema &S, QualType ElementType, - ExprResult *Scalar) { - InitializedEntity Entity = - InitializedEntity::InitializeTemporary(ElementType); - InitializationKind Kind = InitializationKind::CreateCopy( - Scalar->get()->getBeginLoc(), SourceLocation()); - Expr *Arg = Scalar->get(); - InitializationSequence InitSeq(S, Entity, Kind, Arg); - *Scalar = InitSeq.Perform(S, Entity, Kind, Arg); - return !Scalar->isInvalid(); -} - QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { @@ -11984,15 +12095,13 @@ ExprResult OriginalLHS = LHS; ExprResult OriginalRHS = RHS; if (LHSMatType && !RHSMatType) { - if (tryConvertScalarToMatrixElementTy(*this, LHSMatType->getElementType(), - &RHS)) + if (tryConvertToTy(*this, LHSMatType->getElementType(), &RHS)) return LHSType; return InvalidOperands(Loc, OriginalLHS, OriginalRHS); } if (!LHSMatType && RHSMatType) { - if (tryConvertScalarToMatrixElementTy(*this, RHSMatType->getElementType(), - &LHS)) + if (tryConvertToTy(*this, RHSMatType->getElementType(), &LHS)) return RHSType; return InvalidOperands(Loc, OriginalLHS, OriginalRHS); } @@ -12971,13 +13080,14 @@ } namespace { - enum { - AO_Bit_Field = 0, - AO_Vector_Element = 1, - AO_Property_Expansion = 2, - AO_Register_Variable = 3, - AO_No_Error = 4 - }; +enum { + AO_Bit_Field = 0, + AO_Vector_Element = 1, + AO_Property_Expansion = 2, + AO_Register_Variable = 3, + AO_Matrix_Element = 4, + AO_No_Error = 5 +}; } /// Diagnose invalid operand for address of operations. /// @@ -13144,6 +13254,9 @@ } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector AddressOfError = AO_Vector_Element; + } else if (op->getObjectKind() == OK_MatrixComponent) { + // The operand cannot be an element of a matrix. + AddressOfError = AO_Matrix_Element; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -18925,6 +19038,13 @@ return ExprError(); } + case BuiltinType::IncompleteMatrixIdx: + Diag(cast(E->IgnoreParens()) + ->getRowIdx() + ->getBeginLoc(), + diag::err_matrix_incomplete_index); + return ExprError(); + // Expressions of unknown type. case BuiltinType::OMPArraySection: Diag(E->getBeginLoc(), diag::err_omp_array_section_use); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3494,6 +3494,7 @@ case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToBitfield: case FK_NonConstLValueReferenceBindingToVectorElement: + case FK_NonConstLValueReferenceBindingToMatrixElement: case FK_NonConstLValueReferenceBindingToUnrelated: case FK_RValueReferenceBindingToLValue: case FK_ReferenceAddrspaceMismatchTemporary: @@ -4687,7 +4688,8 @@ /// which a reference can never bind). Attempting to bind a reference to /// such a glvalue will always create a temporary. static bool isNonReferenceableGLValue(Expr *E) { - return E->refersToBitField() || E->refersToVectorElement(); + return E->refersToBitField() || E->refersToVectorElement() || + E->refersToMatrixElement(); } /// Reference initialization without resolving overloaded functions. @@ -4808,6 +4810,9 @@ else if (Initializer->refersToVectorElement()) FK = InitializationSequence:: FK_NonConstLValueReferenceBindingToVectorElement; + else if (Initializer->refersToMatrixElement()) + FK = InitializationSequence:: + FK_NonConstLValueReferenceBindingToMatrixElement; else llvm_unreachable("unexpected kind of compatible initializer"); break; @@ -8925,6 +8930,11 @@ << Args[0]->getSourceRange(); break; + case FK_NonConstLValueReferenceBindingToMatrixElement: + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_matrix_element) + << DestType.isVolatileQualified() << Args[0]->getSourceRange(); + break; + case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) << DestType.getNonReferenceType() << OnlyArg->getType() @@ -9270,6 +9280,10 @@ OS << "non-const lvalue reference bound to vector element"; break; + case FK_NonConstLValueReferenceBindingToMatrixElement: + OS << "non-const lvalue reference bound to matrix element"; + break; + case FK_NonConstLValueReferenceBindingToUnrelated: OS << "non-const lvalue reference bound to unrelated type"; break; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2419,6 +2419,17 @@ RBracketLoc); } + /// Build a new matrix subscript expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBracketLoc) { + return getSema().CreateBuiltinMatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + RBracketLoc); + } + /// Build a new array section expression. /// /// By default, performs semantic analysis to build the new expression. @@ -10279,6 +10290,29 @@ template ExprResult +TreeTransform::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + ExprResult RowIdx = getDerived().TransformExpr(E->getRowIdx()); + if (RowIdx.isInvalid()) + return ExprError(); + + ExprResult ColumnIdx = getDerived().TransformExpr(E->getColumnIdx()); + if (ColumnIdx.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && + RowIdx.get() == E->getRowIdx() && ColumnIdx.get() == E->getColumnIdx()) + return E; + + return getDerived().RebuildMatrixSubscriptExpr( + Base.get(), RowIdx.get(), ColumnIdx.get(), E->getRBracketLoc()); +} + +template +ExprResult TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -240,6 +240,9 @@ case BuiltinType::BuiltinFn: ID = PREDEF_TYPE_BUILTIN_FN; break; + case BuiltinType::IncompleteMatrixIdx: + ID = PREDEF_TYPE_INCOMPLETE_MATRIX_IDX; + break; case BuiltinType::OMPArraySection: ID = PREDEF_TYPE_OMP_ARRAY_SECTION; break; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7007,6 +7007,9 @@ case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; + case PREDEF_TYPE_INCOMPLETE_MATRIX_IDX: + T = Context.IncompleteMatrixIdxTy; + break; case PREDEF_TYPE_OMP_ARRAY_SECTION: T = Context.OMPArraySectionTy; break; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -907,6 +907,14 @@ E->setRBracketLoc(readSourceLocation()); } +void ASTStmtReader::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { + VisitExpr(E); + E->setBase(Record.readSubExpr()); + E->setRowIdx(Record.readSubExpr()); + E->setColumnIdx(Record.readSubExpr()); + E->setRBracketLoc(readSourceLocation()); +} + void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { VisitExpr(E); E->setBase(Record.readSubExpr()); @@ -2926,6 +2934,10 @@ S = new (Context) ArraySubscriptExpr(Empty); break; + case EXPR_MATRIX_SUBSCRIPT: + S = new (Context) MatrixSubscriptExpr(Empty); + break; + case EXPR_OMP_ARRAY_SECTION: S = new (Context) OMPArraySectionExpr(Empty); break; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -772,6 +772,15 @@ Code = serialization::EXPR_ARRAY_SUBSCRIPT; } +void ASTStmtWriter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddStmt(E->getRowIdx()); + Record.AddStmt(E->getColumnIdx()); + Record.AddSourceLocation(E->getRBracketLoc()); + Code = serialization::EXPR_ARRAY_SUBSCRIPT; +} + void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { VisitExpr(E); Record.AddStmt(E->getBase()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1515,6 +1515,10 @@ Bldr.addNodes(Dst); break; + case Stmt::MatrixSubscriptExprClass: + llvm_unreachable("Support for MatrixSubscriptExpr is not implemented."); + break; + case Stmt::GCCAsmStmtClass: Bldr.takeNodes(Pred); VisitGCCAsmStmt(cast(S), Pred, Dst); diff --git a/clang/test/CodeGen/matrix-type-operators.c b/clang/test/CodeGen/matrix-type-operators.c --- a/clang/test/CodeGen/matrix-type-operators.c +++ b/clang/test/CodeGen/matrix-type-operators.c @@ -172,3 +172,286 @@ // CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8 b = vulli + b; } + +// Tests for the matrix type operators. + +typedef double dx5x5_t __attribute__((matrix_type(5, 5))); +typedef float fx2x3_t __attribute__((matrix_type(2, 3))); + +// Check that we can use matrix index expression on different floating point +// matrixes and indices. +void insert_double_matrix_const_idx_ll_u_double(dx5x5_t a, double d, fx2x3_t b, float e, int j, unsigned k) { + // CHECK-LABEL: @insert_double_matrix_const_idx_ll_u_double( + // CHECK: [[D:%.*]] = load double, double* %d.addr, align 8 + // CHECK-NEXT: [[MAT:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x double> [[MAT]], double [[D]], i64 5 + // CHECK-NEXT: store <25 x double> [[MATINS]], <25 x double>* {{.*}}, align 8 + // CHECK-NEXT: ret void + + a[0ll][1u] = d; +} + +void insert_double_matrix_const_idx_i_u_double(dx5x5_t a, double d) { + // CHECK-LABEL: @insert_double_matrix_const_idx_i_u_double( + // CHECK: [[D:%.*]] = load double, double* %d.addr, align 8 + // CHECK-NEXT: [[MAT:%.*]] = load <25 x double>, <25 x double>* [[MAT_ADDR:%.*]], align 8 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x double> [[MAT]], double [[D]], i64 21 + // CHECK-NEXT: store <25 x double> [[MATINS]], <25 x double>* [[MAT_ADDR]], align 8 + // CHECK-NEXT: ret void + + a[1][4u] = d; +} + +void insert_float_matrix_const_idx_ull_i_float(fx2x3_t b, float e) { + // CHECK-LABEL: @insert_float_matrix_const_idx_ull_i_float( + // CHECK: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 3 + // CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + b[1ull][1] = e; +} + +void insert_float_matrix_idx_i_u_float(fx2x3_t b, float e, int j, unsigned k) { + // CHECK-LABEL: @insert_float_matrix_idx_i_u_float( + // CHECK: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J_EXT:%.*]] = sext i32 [[J]] to i64 + // CHECK-NEXT: [[K:%.*]] = load i32, i32* %k.addr, align 4 + // CHECK-NEXT: [[K_EXT:%.*]] = zext i32 [[K]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K_EXT]], 2 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J_EXT]] + // CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 [[IDX2]] + // CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + b[j][k] = e; +} + +void insert_float_matrix_idx_s_ull_float(fx2x3_t b, float e, short j, unsigned long long k) { + // CHECK-LABEL: @insert_float_matrix_idx_s_ull_float( + // CHECK: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK-NEXT: [[J:%.*]] = load i16, i16* %j.addr, align 2 + // CHECK-NEXT: [[J_EXT:%.*]] = sext i16 [[J]] to i64 + // CHECK-NEXT: [[K:%.*]] = load i64, i64* %k.addr, align 8 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K]], 2 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J_EXT]] + // CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 [[IDX2]] + // CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + (b)[j][k] = e; +} + +// Check that we can can use matrix index expressions on integer matrixes. +typedef int ix9x3_t __attribute__((matrix_type(9, 3))); +void insert_int_idx_expr(ix9x3_t a, int i) { + // CHECK-LABEL: @insert_int_idx_expr( + // CHECK: [[I1:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I2_ADD:%.*]] = add nsw i32 4, [[I2]] + // CHECK-NEXT: [[ADD_EXT:%.*]] = sext i32 [[I2_ADD]] to i64 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 18, [[ADD_EXT]] + // CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <27 x i32> [[MAT]], i32 [[I1]], i64 [[IDX2]] + // CHECK-NEXT: store <27 x i32> [[MATINS]], <27 x i32>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + a[4 + i][1 + 1u] = i; +} + +// Check that we can can use matrix index expressions on FP and integer +// matrixes. +typedef int ix9x3_t __attribute__((matrix_type(9, 3))); +void insert_float_into_int_matrix(ix9x3_t *a, int i) { + // CHECK-LABEL: @insert_float_into_int_matrix( + // CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[MAT_ADDR1:%.*]] = load [27 x i32]*, [27 x i32]** %a.addr, align 8 + // CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [27 x i32]* [[MAT_ADDR1]] to <27 x i32>* + // CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR2]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <27 x i32> [[MAT]], i32 [[I]], i64 13 + // CHECK-NEXT: store <27 x i32> [[MATINS]], <27 x i32>* [[MAT_ADDR2]], align 4 + // CHECK-NEXT: ret void + + (*a)[4][1] = i; +} + +// Check that we can use overloaded matrix index expressions on matrixes with +// matching dimensions, but different element types. +typedef double dx3x3_t __attribute__((matrix_type(3, 3))); +typedef float fx3x3_t __attribute__((matrix_type(3, 3))); +void insert_matching_dimensions1(dx3x3_t a, double i) { + // CHECK-LABEL: @insert_matching_dimensions1( + // CHECK: [[I:%.*]] = load double, double* %i.addr, align 8 + // CHECK-NEXT: [[MAT:%.*]] = load <9 x double>, <9 x double>* [[MAT_ADDR:%.*]], align 8 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x double> [[MAT]], double [[I]], i64 5 + // CHECK-NEXT: store <9 x double> [[MATINS]], <9 x double>* [[MAT_ADDR]], align 8 + // CHECK-NEXT: ret void + + a[2u][1u] = i; +} + +void insert_matching_dimensions(fx3x3_t b, float e) { + // CHECK-LABEL: @insert_matching_dimensions( + // CHECK: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK-NEXT: [[MAT:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x float> [[MAT]], float [[E]], i64 7 + // CHECK-NEXT: store <9 x float> [[MATINS]], <9 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + b[1u][2u] = e; +} + +double extract_double(dx5x5_t a) { + // CHECK-LABEL: @extract_double( + // CHECK: [[MAT:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <25 x double> [[MAT]], i64 12 + // CHECK-NEXT: ret double [[MATEXT]] + + return a[2][3 - 1u]; +} + +double extract_float(fx3x3_t b) { + // CHECK-LABEL: @extract_float( + // CHECK: [[MAT:%.*]] = load <9 x float>, <9 x float>* {{.*}}, align 4 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <9 x float> [[MAT]], i64 5 + // CHECK-NEXT: [[TO_DOUBLE:%.*]] = fpext float [[MATEXT]] to double + // CHECK-NEXT: ret double [[TO_DOUBLE]] + + return b[2][1]; +} + +int extract_int(ix9x3_t c, unsigned long j) { + // CHECK-LABEL: @extract_int( + // CHECK: [[J1:%.*]] = load i64, i64* %j.addr, align 8 + // CHECK-NEXT: [[J2:%.*]] = load i64, i64* %j.addr, align 8 + // CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J2]], 9 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J1]] + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <27 x i32> [[MAT]], i64 [[IDX2]] + // CHECK-NEXT: ret i32 [[MATEXT]] + + return c[j][j]; +} + +typedef double dx3x2_t __attribute__((matrix_type(3, 2))); + +double test_extract_matrix_pointer1(dx3x2_t **ptr, unsigned j) { + // CHECK-LABEL: @test_extract_matrix_pointer1( + // CHECK: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64 + // CHECK-NEXT: [[PTR:%.*]] = load [6 x double]**, [6 x double]*** %ptr.addr, align 8 + // CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr inbounds [6 x double]*, [6 x double]** [[PTR]], i64 1 + // CHECK-NEXT: [[PTR2:%.*]] = load [6 x double]*, [6 x double]** [[PTR_IDX]], align 8 + // CHECK-NEXT: [[PTR2_IDX:%.*]] = getelementptr inbounds [6 x double], [6 x double]* [[PTR2]], i64 2 + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [6 x double]* [[PTR2_IDX]] to <6 x double>* + // CHECK-NEXT: [[MAT:%.*]] = load <6 x double>, <6 x double>* [[MAT_ADDR]], align 8 + // CHECK-NEXT: [[IDX:%.*]] = add i64 3, [[J_EXT]] + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <6 x double> [[MAT]], i64 [[IDX]] + // CHECK-NEXT: ret double [[MATEXT]] + + return ptr[1][2][j][1]; +} + +double test_extract_matrix_pointer2(dx3x2_t **ptr) { + // CHECK-LABEL: @test_extract_matrix_pointer2( + // CHECK-NEXT: entry: + // CHECK: [[PTR:%.*]] = load [6 x double]**, [6 x double]*** %ptr.addr, align 8 + // CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr inbounds [6 x double]*, [6 x double]** [[PTR]], i64 4 + // CHECK-NEXT: [[PTR2:%.*]] = load [6 x double]*, [6 x double]** [[PTR_IDX]], align 8 + // CHECK-NEXT: [[PTR2_IDX:%.*]] = getelementptr inbounds [6 x double], [6 x double]* [[PTR2]], i64 6 + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [6 x double]* [[PTR2_IDX]] to <6 x double>* + // CHECK-NEXT: [[MAT:%.*]] = load <6 x double>, <6 x double>* [[MAT_ADDR]], align 8 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <6 x double> [[MAT]], i64 5 + // CHECK-NEXT: ret double [[MATEXT]] + + return (*(*(ptr + 4) + 6))[2][1 * 3 - 2]; +} + +void insert_extract(dx5x5_t a, fx3x3_t b, unsigned long j, short k) { + // CHECK-LABEL: @insert_extract( + // CHECK: [[K:%.*]] = load i16, i16* %k.addr, align 2 + // CHECK-NEXT: [[K_EXT:%.*]] = sext i16 [[K]] to i64 + // CHECK-NEXT: [[MAT:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR:%.*]], align 4 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K_EXT]], 3 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], 0 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <9 x float> [[MAT]], i64 [[IDX]] + // CHECK-NEXT: [[J:%.*]] = load i64, i64* %j.addr, align 8 + // CHECK-NEXT: [[IDX3:%.*]] = mul i64 [[J]], 3 + // CHECK-NEXT: [[IDX4:%.*]] = add i64 [[IDX3]], 2 + // CHECK-NEXT: [[MAT2:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x float> [[MAT2]], float [[MATEXT]], i64 [[IDX4]] + // CHECK-NEXT: store <9 x float> [[MATINS]], <9 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + b[2][j] = b[0][k]; +} + +void insert_compound_stmt(dx5x5_t a) { + // CHECK-LABEL: define void @insert_compound_stmt(<25 x double> %a) + // CHECK: [[A:%.*]] = load <25 x double>, <25 x double>* [[A_PTR:%.*]], align 8 + // CHECK-NEXT: [[EXT:%.*]] = extractelement <25 x double> [[A]], i64 17 + // CHECK-NEXT: [[SUB:%.*]] = fsub double [[EXT]], 1.000000e+00 + // CHECK-NEXT: [[A2:%.*]] = load <25 x double>, <25 x double>* [[A_PTR]], align 8 + // CHECK-NEXT: [[INS:%.*]] = insertelement <25 x double> [[A2]], double [[SUB]], i64 17 + // CHECK-NEXT: store <25 x double> [[INS]], <25 x double>* [[A_PTR]], align 8 + // CHECK-NEXT: ret void + + a[2][3] -= 1.0; +} + +struct Foo { + fx2x3_t mat; +}; + +void insert_compound_stmt_field(struct Foo *a, float f, unsigned i, unsigned j) { + // CHECK-LABEL: define void @insert_compound_stmt_field(%struct.Foo* %a, float %f, i32 %i, i32 %j) + // CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64 + // CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 2 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]] + // CHECK-NEXT: [[MAT_PTR:%.*]] = bitcast [6 x float]* %mat to <6 x float>* + // CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_PTR]], align 4 + // CHECK-NEXT: [[EXT:%.*]] = extractelement <6 x float> [[MAT]], i64 [[IDX2]] + // CHECK-NEXT: [[SUM:%.*]] = fadd float [[EXT]], {{.*}} + // CHECK-NEXT: [[MAT2:%.*]] = load <6 x float>, <6 x float>* [[MAT_PTR]], align 4 + // CHECK-NEXT: [[INS:%.*]] = insertelement <6 x float> [[MAT2]], float [[SUM]], i64 [[IDX2]] + // CHECK-NEXT: store <6 x float> [[INS]], <6 x float>* [[MAT_PTR]], align 4 + // CHECK-NEXT: ret void + + a->mat[i][j] += f; +} + +void matrix_as_idx(ix9x3_t a, int i, int j, dx5x5_t b) { + // CHECK-LABEL: define void @matrix_as_idx(<27 x i32> %a, i32 %i, i32 %j, <25 x double> %b) + // CHECK: [[I1:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I1_EXT:%.*]] = sext i32 [[I1]] to i64 + // CHECK-NEXT: [[J1:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J1_EXT:%.*]] = sext i32 [[J1]] to i64 + // CHECK-NEXT: [[A:%.*]] = load <27 x i32>, <27 x i32>* %0, align 4 + // CHECK-NEXT: [[IDX1_1:%.*]] = mul i64 [[J1_EXT]], 9 + // CHECK-NEXT: [[IDX1_2:%.*]] = add i64 [[IDX1_1]], [[I1_EXT]] + // CHECK-NEXT: [[MI1:%.*]] = extractelement <27 x i32> [[A]], i64 [[IDX1_2]] + // CHECK-NEXT: [[MI1_EXT:%.*]] = sext i32 [[MI1]] to i64 + // CHECK-NEXT: [[J2:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J2_EXT:%.*]] = sext i32 [[J2]] to i64 + // CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I2_EXT:%.*]] = sext i32 [[I2]] to i64 + // CHECK-NEXT: [[A2:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4 + // CHECK-NEXT: [[IDX2_1:%.*]] = mul i64 [[I2_EXT]], 9 + // CHECK-NEXT: [[IDX2_2:%.*]] = add i64 [[IDX2_1]], [[J2_EXT]] + // CHECK-NEXT: [[MI2:%.*]] = extractelement <27 x i32> [[A2]], i64 [[IDX2_2]] + // CHECK-NEXT: [[MI3:%.*]] = add nsw i32 [[MI2]], 2 + // CHECK-NEXT: [[MI3_EXT:%.*]] = sext i32 [[MI3]] to i64 + // CHECK-NEXT: [[IDX3_1:%.*]] = mul i64 [[MI3_EXT]], 5 + // CHECK-NEXT: [[IDX3_2:%.*]] = add i64 [[IDX3_1]], [[MI1_EXT]] + // CHECK-NEXT: [[B:%.*]] = load <25 x double>, <25 x double>* [[B_PTR:%.*]], align 8 + // CHECK-NEXT: [[INS:%.*]] = insertelement <25 x double> [[B]], double 1.500000e+00, i64 [[IDX3_2]] + // CHECK-NEXT: store <25 x double> [[INS]], <25 x double>* [[B_PTR]], align 8 + b[a[i][j]][a[j][i] + 2] = 1.5; +} diff --git a/clang/test/CodeGenCXX/matrix-type-operators.cpp b/clang/test/CodeGenCXX/matrix-type-operators.cpp --- a/clang/test/CodeGenCXX/matrix-type-operators.cpp +++ b/clang/test/CodeGenCXX/matrix-type-operators.cpp @@ -1,6 +1,8 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - -std=c++11 | FileCheck %s +typedef double dx5x5_t __attribute__((matrix_type(5, 5))); +using fx2x3_t = float __attribute__((matrix_type(2, 3))); + template struct MyMatrix { using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns))); @@ -154,3 +156,201 @@ w3.x = 'c'; m.value = w3 - m.value; } + +template +void insert(MyMatrix &Mat, EltTy e, unsigned i, unsigned j) { + Mat.value[i][j] = e; +} + +void test_insert_template1(MyMatrix &Mat, unsigned e, unsigned i, unsigned j) { + // CHECK-LABEL: @_Z21test_insert_template1R8MyMatrixIjLj2ELj2EEjjj( + // CHECK: [[MAT_ADDR:%.*]] = load %struct.MyMatrix.1*, %struct.MyMatrix.1** %Mat.addr, align 8 + // CHECK-NEXT: [[E:%.*]] = load i32, i32* %e.addr, align 4 + // CHECK-NEXT: [[I:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: call void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(%struct.MyMatrix.1* nonnull align 4 dereferenceable(16) [[MAT_ADDR]], i32 [[E]], i32 [[I]], i32 [[J]]) + // CHECK-NEXT: ret void + // + // CHECK-LABEL: define linkonce_odr void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_jj( + // CHECK: [[E:%.*]] = load i32, i32* %e.addr, align 4 + // CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64 + // CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 2 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]] + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [4 x i32]* {{.*}} to <4 x i32>* + // CHECK-NEXT: [[MAT:%.*]] = load <4 x i32>, <4 x i32>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <4 x i32> [[MAT]], i32 [[E]], i64 [[IDX2]] + // CHECK-NEXT: store <4 x i32> [[MATINS]], <4 x i32>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + insert(Mat, e, i, j); +} + +void test_insert_template2(MyMatrix &Mat, float e) { + // CHECK-LABEL: @_Z21test_insert_template2R8MyMatrixIfLj3ELj8EEf( + // CHECK: [[MAT_ADDR:%.*]] = load %struct.MyMatrix.2*, %struct.MyMatrix.2** %Mat.addr, align 8 + // CHECK-NEXT: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK-NEXT: call void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(%struct.MyMatrix.2* nonnull align 4 dereferenceable(96) [[MAT_ADDR]], float [[E]], i32 2, i32 5) + // CHECK-NEXT: ret void + // + // CHECK-LABEL: define linkonce_odr void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_jj( + // CHECK: [[E:%.*]] = load float, float* %e.addr, align 4 + // CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4 + // CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64 + // CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4 + // CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 3 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]] + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [24 x float]* {{.*}} to <24 x float>* + // CHECK-NEXT: [[MAT:%.*]] = load <24 x float>, <24 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <24 x float> [[MAT]], float [[E]], i64 [[IDX2]] + // CHECK-NEXT: store <24 x float> [[MATINS]], <24 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: ret void + + insert(Mat, e, 2, 5); +} + +template +EltTy extract(MyMatrix &Mat) { + return Mat.value[1u][0u]; +} + +int test_extract_template(MyMatrix Mat1) { + // CHECK-LABEL: @_Z21test_extract_template8MyMatrixIiLj2ELj2EE( + // CHECK-NEXT: entry: + // CHECK-NEXT: [[CALL:%.*]] = call i32 @_Z7extractIiLj2ELj2EET_R8MyMatrixIS0_XT0_EXT1_EE(%struct.MyMatrix.3* nonnull align 4 dereferenceable(16) [[MAT1:%.*]]) + // CHECK-NEXT: ret i32 [[CALL]] + // + // CHECK-LABEL: define linkonce_odr i32 @_Z7extractIiLj2ELj2EET_R8MyMatrixIS0_XT0_EXT1_EE( + // CHECK: [[MAT:%.*]] = load <4 x i32>, <4 x i32>* {{.*}}, align 4 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <4 x i32> [[MAT]], i64 1 + // CHECK-NEXT: ret i32 [[MATEXT]] + + return extract(Mat1); +} + +using double4x4 = double __attribute__((matrix_type(4, 4))); + +template +auto matrix_subscript(double4x4 m, R r, C c) -> decltype(m[r][c]) {} + +double test_matrix_subscript(double4x4 m) { + // CHECK-LABEL: @_Z21test_matrix_subscriptU11matrix_typeLm4ELm4Ed( + // CHECK: [[MAT:%.*]] = load <16 x double>, <16 x double>* {{.*}}, align 8 + // CHECK-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) double* @_Z16matrix_subscriptIiiEDTixixfp_fp0_fp1_EU11matrix_typeLm4ELm4EdT_T0_(<16 x double> [[MAT]], i32 1, i32 2) + // CHECK-NEXT: [[RES:%.*]] = load double, double* [[CALL]], align 8 + // CHECK-NEXT: ret double [[RES]] + + return matrix_subscript(m, 1, 2); +} + +const double &test_matrix_subscript_reference(const double4x4 m) { + // CHECK-LABEL: @_Z31test_matrix_subscript_referenceU11matrix_typeLm4ELm4Ed( + // CHECK-NEXT: entry: + // CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x double], align 8 + // CHECK-NEXT: [[REF_TMP:%.*]] = alloca double, align 8 + // CHECK-NEXT: [[NAMELESS0:%.*]] = bitcast [16 x double]* [[M_ADDR]] to <16 x double>* + // CHECK-NEXT: store <16 x double> [[M:%.*]], <16 x double>* [[NAMELESS0]], align 8 + // CHECK-NEXT: [[NAMELESS1:%.*]] = load <16 x double>, <16 x double>* [[NAMELESS0]], align 8 + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[NAMELESS1]], i64 4 + // CHECK-NEXT: store double [[MATEXT]], double* [[REF_TMP]], align 8 + // CHECK-NEXT: ret double* [[REF_TMP]] + + return m[0][1]; +} + +struct UnsignedWrapper { + char x; + operator unsigned() { + return x; + } +}; + +double extract_IntWrapper_idx(double4x4 &m, IntWrapper i, UnsignedWrapper j) { + // CHECK-LABEL: define double @_Z22extract_IntWrapper_idxRU11matrix_typeLm4ELm4Ed10IntWrapper15UnsignedWrapper( + // CHECK: [[I:%.*]] = call i32 @_ZN10IntWrappercviEv(%struct.IntWrapper* %i) + // CHECK-NEXT: [[I_ADD:%.*]] = add nsw i32 [[I]], 1 + // CHECK-NEXT: [[I_ADD_EXT:%.*]] = sext i32 [[I_ADD]] to i64 + // CHECK-NEXT: [[J:%.*]] = call i32 @_ZN15UnsignedWrappercvjEv(%struct.UnsignedWrapper* %j) + // CHECK-NEXT: [[J_SUB:%.*]] = sub i32 [[J]], 1 + // CHECK-NEXT: [[J_SUB_EXT:%.*]] = zext i32 [[J_SUB]] to i64 + // CHECK-NEXT: [[MAT_ADDR:%.*]] = load [16 x double]*, [16 x double]** %m.addr, align 8 + // CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [16 x double]* [[MAT_ADDR]] to <16 x double>* + // CHECK-NEXT: [[MAT:%.*]] = load <16 x double>, <16 x double>* [[MAT_ADDR2]], align 8 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_SUB_EXT]], 4 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_ADD_EXT]] + // CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]] + // CHECK-NEXT: ret double [[MATEXT]] + return m[i + 1][j - 1]; +} + +template +using matrix_type = T __attribute__((matrix_type(R, C))); +struct identmatrix_t { + template + operator matrix_type() const { + matrix_type result; + for (unsigned i = 0; i != N; ++i) + result[i][i] = 1; + return result; + } +}; + +constexpr identmatrix_t identmatrix; + +void test_constexpr1(matrix_type &m) { + // CHECK-LABEL: define void @_Z15test_constexpr1RU11matrix_typeLm4ELm4Ef([16 x float]* nonnull align 4 dereferenceable(64) %m) #3 { + // CHECK: [[MAT:%.*]] = load <16 x float>, <16 x float>* {{.*}}, align 4 + // CHECK-NEXT: [[IM:%.*]] = call <16 x float> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IfLj4EEEv(%struct.identmatrix_t* @_ZL11identmatrix) + // CHECK-NEXT: [[ADD:%.*]] = fadd <16 x float> [[MAT]], [[IM]] + // CHECK-NEXT: [[MAT_ADDR:%.*]] = load [16 x float]*, [16 x float]** %m.addr, align 8 + // CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [16 x float]* [[MAT_ADDR]] to <16 x float>* + // CHECK-NEXT: store <16 x float> [[ADD]], <16 x float>* [[MAT_ADDR2]], align 4 + // CHECK-NEXT: ret voi + + // CHECK-LABEL: define linkonce_odr <16 x float> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IfLj4EEEv( + // CHECK-LABEL: for.body: ; preds = %for.cond + // CHECK-NEXT: [[I:%.*]] = load i32, i32* %i, align 4 + // CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64 + // CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i, align 4 + // CHECK-NEXT: [[I2_EXT:%.*]] = zext i32 [[I2]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[I2_EXT]], 4 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]] + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [16 x float]* %result to <16 x float>* + // CHECK-NEXT: [[MAT:%.*]] = load <16 x float>, <16 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <16 x float> [[MAT]], float 1.000000e+00, i64 [[IDX2]] + // CHECK-NEXT: store <16 x float> [[MATINS]], <16 x float>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: br label %for.inc + m = m + identmatrix; +} + +void test_constexpr2(matrix_type &m) { + // CHECK-LABEL: define void @_Z15test_constexpr2RU11matrix_typeLm5ELm5Ei([25 x i32]* nonnull align 4 dereferenceable(100) %m) #4 { + // CHECK: [[IM:%.*]] = call <25 x i32> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IiLj5EEEv(%struct.identmatrix_t* @_ZL11identmatrix) + // CHECK: [[MAT:%.*]] = load <25 x i32>, <25 x i32>* {{.*}}, align 4 + // CHECK-NEXT: [[SUB:%.*]] = sub <25 x i32> [[IM]], [[MAT]] + // CHECK-NEXT: [[SUB2:%.*]] = add <25 x i32> [[SUB]], + // CHECK-NEXT: [[MAT_ADDR:%.*]] = load [25 x i32]*, [25 x i32]** %m.addr, align 8 + // CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [25 x i32]* [[MAT_ADDR]] to <25 x i32>* + // CHECK-NEXT: store <25 x i32> [[SUB2]], <25 x i32>* [[MAT_ADDR2]], align 4 + // CHECK-NEXT: ret void + // + + // CHECK-LABEL: define linkonce_odr <25 x i32> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IiLj5EEEv( + // CHECK-LABEL: for.body: ; preds = %for.cond + // CHECK-NEXT: [[I:%.*]] = load i32, i32* %i, align 4 + // CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64 + // CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i, align 4 + // CHECK-NEXT: [[I2_EXT:%.*]] = zext i32 [[I2]] to i64 + // CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[I2_EXT]], 5 + // CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]] + // CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [25 x i32]* %result to <25 x i32>* + // CHECK-NEXT: [[MAT:%.*]] = load <25 x i32>, <25 x i32>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x i32> [[MAT]], i32 1, i64 [[IDX2]] + // CHECK-NEXT: store <25 x i32> [[MATINS]], <25 x i32>* [[MAT_ADDR]], align 4 + // CHECK-NEXT: br label %for.inc + + m = identmatrix - m + 1; +} diff --git a/clang/test/CodeGenObjC/matrix-type-operators.m b/clang/test/CodeGenObjC/matrix-type-operators.m new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenObjC/matrix-type-operators.m @@ -0,0 +1,64 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fenable-matrix -emit-llvm -disable-llvm-optzns -o - %s | FileCheck %s + +__attribute__((objc_root_class)) +@interface IntValue +@property int value; +@end + +typedef double double4x4 __attribute__((matrix_type(4, 4))); + +// Check that we correctly deal with placeholder expressions. + +// CHECK-LABEL: @test_index_placeholders( +// CHECK-NEXT: entry: +// CHECK: [[IV:%.*]] = load %0*, %0** [[IV_ADDR:%.*]], align 8 +// CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[IV_PTR:%.*]] = bitcast %0* [[IV]] to i8* +// CHECK-NEXT: [[CALL:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV_PTR]], i8* [[SEL]]) +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 +// CHECK-NEXT: [[IV2:%.*]] = load %0*, %0** [[IV_ADDR]], align 8 +// CHECK-NEXT: [[SEL2:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[IV2_PTR:%.*]] = bitcast %0* [[IV2]] to i8* +// CHECK-NEXT: [[CALL1:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV2_PTR]], i8* [[SEL2]]) +// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 +// CHECK-NEXT: [[MAT:%.*]] = load <16 x double>, <16 x double>* {{.*}} align 8 +// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4 +// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]] +// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]] +// CHECK-NEXT: ret double [[MATEXT]] +// +double test_index_placeholders(double4x4 m, IntValue *iv) { + + return m[iv.value][iv.value]; +} + +__attribute__((objc_root_class)) +@interface MatrixValue +@property double4x4 value; +@end + +// CHECK-LABEL: @test_base_and_index_placeholders( +// CHECK: [[IV:%.*]] = load %0*, %0** [[IV_ADDR:%.*]], align 8 +// CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[IV_PTR:%.*]] = bitcast %0* [[IV]] to i8* +// CHECK-NEXT: [[CALL:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV_PTR]], i8* [[SEL]]) +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64 +// CHECK-NEXT: [[IV2:%.*]] = load %0*, %0** [[IV_ADDR]], align 8 +// CHECK-NEXT: [[SEL2:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[IV2_PTR:%.*]] = bitcast %0* [[IV2]] to i8* +// CHECK-NEXT: [[CALL1:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV2_PTR]], i8* [[SEL2]]) +// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64 +// CHECK-NEXT: [[M:%.*]] = load %1*, %1** %m.addr, align 8 +// CHECK-NEXT: [[SEL3:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7 +// CHECK-NEXT: [[M_PTR:%.*]] = bitcast %1* [[M]] to i8* +// CHECK-NEXT: [[MAT:%.*]] = call <16 x double> bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to <16 x double> (i8*, i8*)*)(i8* [[M_PTR]], i8* [[SEL3]]) +// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4 +// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]] +// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]] +// CHECK-NEXT: ret double [[MATEXT]] +// +double test_base_and_index_placeholders(MatrixValue *m, IntValue *iv) { + + return m.value[iv.value][iv.value]; +} diff --git a/clang/test/Sema/matrix-type-operators.c b/clang/test/Sema/matrix-type-operators.c --- a/clang/test/Sema/matrix-type-operators.c +++ b/clang/test/Sema/matrix-type-operators.c @@ -31,3 +31,104 @@ // expected-error@-1 {{invalid operands to binary expression ('sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') and 'sx10x5_t *' (aka 'float __attribute__((matrix_type(10, 5)))*'))}} // expected-error@-2 {{casting 'sx10x5_t *' (aka 'float __attribute__((matrix_type(10, 5)))*') to incompatible type 'float'}} } + +sx5x10_t get_matrix(); + +void insert(sx5x10_t a, float f) { + // Non integer indexes. + a[3][f] = 0; + // expected-error@-1 {{matrix column index is not an integer}} + a[f][9] = 0; + // expected-error@-1 {{matrix row index is not an integer}} + a[f][f] = 0; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} + a[0][f] = 0; + // expected-error@-1 {{matrix column index is not an integer}} + + a[f][f] = 0; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} + + // Invalid element type. + a[3][4] = &f; + // expected-error@-1 {{assigning to 'float' from incompatible type 'float *'; remove &}} + + // Indexes outside allowed dimensions. + a[-1][3] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[3][-1] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[3][-1u] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[-1u][3] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[5][2] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[4][10] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[5][0] = f; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + (a[1])[1] = f; + // expected-error@-1 {{matrix row and column subscripts cannot be separated by any expression}} + + a[3] = 5.0; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + + (a[3]) = 5.0; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + + get_matrix()[0][0] = f; + // expected-error@-1 {{expression is not assignable}} + get_matrix()[5][1] = f; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + get_matrix()[3] = 5.0; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + + (get_matrix()[5])[10.0] = f; + // expected-error@-1 {{matrix row and column subscripts cannot be separated by any expression}} + (get_matrix()[3]) = 5.0; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + + a([0])[0] = f; + // expected-error@-1 {{expected expression}} + a[0]([0]) = f; + // expected-error@-1 {{expected expression}} +} + +void extract(sx5x10_t a, float f) { + // Non integer indexes. + float v1 = a[3][f]; + // expected-error@-1 {{matrix column index is not an integer}} + float v2 = a[f][9]; + // expected-error@-1 {{matrix row index is not an integer}} + float v3 = a[f][f]; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} + + // Invalid element type. + char *v4 = a[3][4]; + // expected-error@-1 {{initializing 'char *' with an expression of incompatible type 'float'}} + + // Indexes outside allowed dimensions. + float v5 = a[-1][3]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v6 = a[3][-1]; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + float v8 = a[-1u][3]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v9 = a[5][2]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v10 = a[4][10]; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + float v11 = a[5][9]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + + float v12 = a[3]; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} +} + +float *address_of_element(sx5x10_t *a) { + return &(*a)[0][1]; + // expected-error@-1 {{address of matrix element requested}} +} diff --git a/clang/test/SemaCXX/matrix-type-operators.cpp b/clang/test/SemaCXX/matrix-type-operators.cpp --- a/clang/test/SemaCXX/matrix-type-operators.cpp +++ b/clang/test/SemaCXX/matrix-type-operators.cpp @@ -91,3 +91,116 @@ // expected-error@-1 {{no viable conversion from 'StructWithC' to 'double'}} // expected-error@-2 {{invalid operands to binary expression ('StructWithC' and 'MyMatrix::matrix_t' (aka 'double __attribute__((matrix_type(10, 9)))'))}} } + +sx5x10_t get_matrix(); + +void insert(sx5x10_t a, float f) { + // Non integer indexes. + a[3][f] = 0; + // expected-error@-1 {{matrix column index is not an integer}} + a[f][9] = 0; + // expected-error@-1 {{matrix row index is not an integer}} + a[f][f] = 0; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} + a[0][f] = 0; + // expected-error@-1 {{matrix column index is not an integer}} + + // Invalid element type. + a[3][4] = &f; + // expected-error@-1 {{assigning to 'float' from incompatible type 'float *'; remove &}} + + // Indexes outside allowed dimensions. + a[-1][3] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[3][-1] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[3][-1u] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[-1u][3] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[5][2] = 10.0; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + a[4][10] = 10.0; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + a[5][10.0] = f; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + // expected-error@-2 {{matrix column index is not an integer}} + + get_matrix()[0][0] = f; + // expected-error@-1 {{expression is not assignable}} + get_matrix()[5][10.0] = f; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + // expected-error@-2 {{matrix column index is not an integer}} + get_matrix()[3] = 5.0; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + + float &x = reinterpret_cast(a[3][3]); + // expected-error@-1 {{reinterpret_cast of a matrix element to 'float &' needs its address, which is not allowed}} + + a[4, 5] = 5.0; + // expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}} + // expected-warning@-2 {{expression result unused}} + + a[4, 5, 4] = 5.0; + // expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}} + // expected-warning@-2 {{expression result unused}} + // expected-warning@-3 {{expression result unused}} +} + +void extract(sx5x10_t a, float f) { + // Non integer indexes. + float v1 = a[3][f]; + // expected-error@-1 {{matrix column index is not an integer}} + float v2 = a[f][9]; + // expected-error@-1 {{matrix row index is not an integer}} + float v3 = a[f][f]; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} + + // Invalid element type. + char *v4 = a[3][4]; + // expected-error@-1 {{cannot initialize a variable of type 'char *' with an lvalue of type 'float'}} + + // Indexes outside allowed dimensions. + float v5 = a[-1][3]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v6 = a[3][-1]; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + float v8 = a[-1u][3]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v9 = a[5][2]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + float v10 = a[4][10]; + // expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}} + float v11 = a[5][10.0]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + // expected-error@-2 {{matrix column index is not an integer}} + + float v12 = get_matrix()[0][0]; + float v13 = get_matrix()[5][10.0]; + // expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}} + // expected-error@-2 {{matrix column index is not an integer}} +} + +const float &const_subscript_reference(sx5x10_t m) { + return m[2][2]; + // expected-warning@-1 {{returning reference to local temporary object}} +} + +const float &const_subscript_reference(const sx5x10_t &m) { + return m[2][2]; + // expected-warning@-1 {{returning reference to local temporary object}} +} + +float &nonconst_subscript_reference(sx5x10_t m) { + return m[2][2]; + // expected-error@-1 {{non-const reference cannot bind to matrix element}} +} + +void incomplete_matrix_index_expr(sx5x10_t a, float f) { + float x = a[3]; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} + a[2] = f; + // expected-error@-1 {{single subscript expressions are not allowed for matrix values}} +} diff --git a/clang/test/SemaObjC/matrix-type-operators.m b/clang/test/SemaObjC/matrix-type-operators.m new file mode 100644 --- /dev/null +++ b/clang/test/SemaObjC/matrix-type-operators.m @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fenable-matrix %s + +struct Foo {}; +__attribute__((objc_root_class)) +@interface FooValue +@property struct Foo value; +@end + +typedef double double4x4 __attribute__((matrix_type(4, 4))); + +// Check that we generate proper error messages for invalid placeholder types. +// +double test_index_placeholders(double4x4 m, FooValue *iv) { + return m[iv.value][iv.value]; + // expected-error@-1 {{matrix row index is not an integer}} + // expected-error@-2 {{matrix column index is not an integer}} +} + +double test_base_and_index_placeholders(FooValue *m, FooValue *iv) { + return m.value[iv.value][iv.value]; + // expected-error@-1 {{subscripted value is not an array, pointer, or vector}} +} diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -419,6 +419,11 @@ K = CXCursor_ArraySubscriptExpr; break; + case Stmt::MatrixSubscriptExprClass: + // TODO: add support for MatrixSubscriptExpr. + K = CXCursor_UnexposedExpr; + break; + case Stmt::OMPArraySectionExprClass: K = CXCursor_OMPArraySectionExpr; break; diff --git a/llvm/include/llvm/IR/MatrixBuilder.h b/llvm/include/llvm/IR/MatrixBuilder.h --- a/llvm/include/llvm/IR/MatrixBuilder.h +++ b/llvm/include/llvm/IR/MatrixBuilder.h @@ -175,15 +175,19 @@ return B.CreateMul(LHS, ScalarVector); } - /// Extracts the element at (\p Row, \p Column) from \p Matrix. - Value *CreateExtractMatrix(Value *Matrix, Value *Row, Value *Column, - unsigned NumRows, Twine const &Name = "") { - + /// Extracts the element at (\p RowIdx, \p ColumnIdx) from \p Matrix. + Value *CreateExtractElement(Value *Matrix, Value *RowIdx, Value *ColumnIdx, + unsigned NumRows, Twine const &Name = "") { + + unsigned MaxWidth = std::max(RowIdx->getType()->getScalarSizeInBits(), + ColumnIdx->getType()->getScalarSizeInBits()); + Type *IntTy = IntegerType::get(RowIdx->getType()->getContext(), MaxWidth); + RowIdx = B.CreateZExt(RowIdx, IntTy); + ColumnIdx = B.CreateZExt(ColumnIdx, IntTy); + Value *NumRowsV = B.getIntN(MaxWidth, NumRows); return B.CreateExtractElement( - Matrix, - B.CreateAdd( - B.CreateMul(Column, ConstantInt::get(Column->getType(), NumRows)), - Row)); + Matrix, B.CreateAdd(B.CreateMul(ColumnIdx, NumRowsV), RowIdx), + "matext"); } };