From 8f3f88d2f50d97011bf48ccc507bef033715e566 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 1 Jun 2020 19:42:03 +0100 Subject: [PATCH] [Matrix] Implement matrix index expressions ([][]). This patch implements matrix index expressions (matrix[RowIdx][ColumnIdx]). It does so by introducing a new MatrixSubscriptExpr(Base, RowIdx, ColumnIdx). MatrixSubscriptExprs are built in 2 steps in ActOnMatrixSubscriptExpr. First, if the base of a subscript is of matrix type, we create a incomplete MatrixSubscriptExpr(base, idx, nullptr). Second, if the base is an incomplete MatrixSubscriptExpr, we create a complete MatrixSubscriptExpr(base->getBase(), base->getRowIdx(), idx) Similar to vector elements, it is not possible to take the address of a MatrixSubscriptExpr. For CodeGen, a new MatrixElt type is added to LValue, which is very similar to VectorElt. The only difference is that we may need to cast the type of the base from an array to a vector type when accessing it. Reviewers: rjmccall, anemet, Bigcheese, rsmith, martong Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D76791 --- clang/include/clang/AST/ASTContext.h | 1 + clang/include/clang/AST/BuiltinTypes.def | 3 + clang/include/clang/AST/ComputeDependence.h | 2 + clang/include/clang/AST/Expr.h | 89 ++++++- clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/AST/Stmt.h | 5 +- clang/include/clang/Basic/DiagnosticSemaKinds.td | 14 +- clang/include/clang/Basic/Specifiers.h | 5 +- clang/include/clang/Basic/StmtNodes.td | 1 + clang/include/clang/Sema/Initialization.h | 3 + clang/include/clang/Sema/Sema.h | 5 + clang/include/clang/Serialization/ASTBitCodes.h | 8 +- clang/lib/AST/ASTContext.cpp | 2 + clang/lib/AST/ComputeDependence.cpp | 6 + clang/lib/AST/Expr.cpp | 1 + clang/lib/AST/ExprClassification.cpp | 4 + clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/AST/ItaniumMangle.cpp | 9 + clang/lib/AST/NSAPI.cpp | 1 + clang/lib/AST/StmtPrinter.cpp | 10 + clang/lib/AST/StmtProfile.cpp | 4 + clang/lib/AST/TextNodeDumper.cpp | 3 + clang/lib/AST/Type.cpp | 3 + clang/lib/AST/TypeLoc.cpp | 1 + clang/lib/CodeGen/CGExpr.cpp | 39 +++- clang/lib/CodeGen/CGExprScalar.cpp | 17 ++ clang/lib/CodeGen/CGValue.h | 38 ++- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/Sema/SemaCast.cpp | 3 + clang/lib/Sema/SemaExceptionSpec.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 168 ++++++++++++-- clang/lib/Sema/SemaInit.cpp | 16 +- clang/lib/Sema/TreeTransform.h | 34 +++ clang/lib/Serialization/ASTCommon.cpp | 3 + clang/lib/Serialization/ASTReader.cpp | 3 + clang/lib/Serialization/ASTReaderStmt.cpp | 12 + clang/lib/Serialization/ASTWriterStmt.cpp | 9 + clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 4 + clang/test/CodeGen/matrix-type-operators.c | 283 +++++++++++++++++++++++ clang/test/CodeGenCXX/matrix-type-operators.cpp | 202 +++++++++++++++- clang/test/CodeGenObjC/matrix-type-operators.m | 64 +++++ clang/test/Sema/matrix-type-operators.c | 101 ++++++++ clang/test/SemaCXX/matrix-type-operators.cpp | 113 +++++++++ clang/test/SemaObjC/matrix-type-operators.m | 22 ++ clang/tools/libclang/CXCursor.cpp | 5 + llvm/include/llvm/IR/MatrixBuilder.h | 20 +- 46 files changed, 1293 insertions(+), 47 deletions(-) create mode 100644 clang/test/CodeGenObjC/matrix-type-operators.m create mode 100644 clang/test/SemaObjC/matrix-type-operators.m diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a5bb9a3..4463ffc 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -978,6 +978,7 @@ public: #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 index f8eb4ec..5112382 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -310,6 +310,9 @@ PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy) // 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 index ab742c9..ac2daf9 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -28,6 +28,7 @@ class ParenExpr; class UnaryOperator; class UnaryExprOrTypeTraitExpr; class ArraySubscriptExpr; +class MatrixSubscriptExpr; class CompoundLiteralExpr; class CastExpr; class BinaryOperator; @@ -108,6 +109,7 @@ ExprDependence computeDependence(ParenExpr *E); 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 index deca0b8..4de2259 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -476,6 +476,11 @@ public: /// 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 @@ public: : Expr(ArraySubscriptExprClass, t, VK, OK) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - ArraySubscriptExprBits.RBracketLoc = rbracketloc; + ArrayOrMatrixSubscriptExprBits.RBracketLoc = rbracketloc; setDependence(computeDependence(this)); } @@ -2626,10 +2631,10 @@ public: 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 @@ public: } }; +/// 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 index 83ff49e..f980009 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2588,6 +2588,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {}) // 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 index 5db3ad3..530fb10 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -445,8 +445,9 @@ protected: 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 @@ protected: 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 index 63af9f4..dd45b21 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2032,6 +2032,8 @@ def err_reference_bind_to_bitfield : Error< "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_typecheck_sclass_func : Error<"illegal storage class on function">; 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_launder_invalid_arg : Error< 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 index 2c80dd4..69c2de3 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -154,7 +154,10 @@ namespace clang { /// 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 index 0368aa0..5965e8b 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -69,6 +69,7 @@ def UnaryOperator : StmtNode; 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 index f726f38..d50ec2a 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -999,6 +999,9 @@ public: /// 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 index 03977d2..8409abc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4904,6 +4904,11 @@ public: 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 index 4d6c17f..01d6112 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1057,7 +1057,10 @@ namespace serialization { /// 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 @@ namespace serialization { /// 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 index bfb6014..eccc3e2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1388,6 +1388,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, 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 index 56c3b91..3dcb9ba 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -83,6 +83,12 @@ ExprDependence clang::computeDependence(ArraySubscriptExpr *E) { 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 index feb0517..71cc159 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3508,6 +3508,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, 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 index 6d5c39b..42873d0 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -224,6 +224,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { } 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 index 9be3e99..c8f1a92 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14184,6 +14184,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { 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 index 221a6a5..487ff8f 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4234,6 +4234,15 @@ recurse: 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 index 3bb3605..ac06d33 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -482,6 +482,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { 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 index 27835fd..4231b3f 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1337,6 +1337,16 @@ void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { 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 index e573c04..cd8c265 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1208,6 +1208,10 @@ void StmtProfiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *S) { 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 index 1b640a8..1e567e2 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -163,6 +163,9 @@ void TextNodeDumper::Visit(const Stmt *Node) { 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 index e4d8af9..deb2186 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3025,6 +3025,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "queue_t"; case OCLReserveID: return "reserve_id_t"; + case IncompleteMatrixIdx: + return ""; case OMPArraySection: return ""; case OMPArrayShaping: @@ -4045,6 +4047,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { #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 index 50391db..366f4d8 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -403,6 +403,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { 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 index 5cf3055..c7c1fbb 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1369,6 +1369,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { 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 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { // 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 @@ RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) { 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 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, 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 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, 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 index 2406cb3..69b6001 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -578,6 +578,7 @@ public: } Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); + Value *VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitConvertVectorExpr(ConvertVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); @@ -1809,6 +1810,22 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { 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 index 9fd07bd..70e6fed 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -170,7 +170,8 @@ class LValue { 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 @@ public: 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 @@ public: 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 @@ public: 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 index 2b5871d..766912d 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3628,6 +3628,7 @@ public: 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 index fe4fcdd..f5bc4bd 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2089,6 +2089,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, 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 index cece58b..504a48b 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1299,6 +1299,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // 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 index f4e8c2d..e177c9d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4553,6 +4553,53 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, 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 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { // 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 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, 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 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, 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 @@ static ValueDecl *getPrimaryDecl(Expr *E) { } 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 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } 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 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { 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 index e64b6d6..56d7ac8 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3494,6 +3494,7 @@ bool InitializationSequence::isAmbiguous() const { 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 @@ static void TryReferenceInitialization(Sema &S, /// 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 @@ static void TryReferenceInitializationCore(Sema &S, 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 @@ bool InitializationSequence::Diagnose(Sema &S, << 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 @@ void InitializationSequence::dump(raw_ostream &OS) const { 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 index e4c7155..bfbdfbf 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2419,6 +2419,17 @@ public: 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 @@ TreeTransform::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { 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 index 84d1947..a7fd5de 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -240,6 +240,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { 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 index a5a1276..1fc09da 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7007,6 +7007,9 @@ QualType ASTReader::GetType(TypeID ID) { 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 index ffd3e77..5c7bc7a 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -907,6 +907,14 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { 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 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { 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 index afc8175..5e445b6 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -772,6 +772,15 @@ void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { 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 index 6fce27b..81caf0f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1515,6 +1515,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, 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 index a92b7eb..c649922 100644 --- a/clang/test/CodeGen/matrix-type-operators.c +++ b/clang/test/CodeGen/matrix-type-operators.c @@ -172,3 +172,286 @@ void add_matrix_scalar_long_long_int_unsigned_long_long(ullx4x2_t b, unsigned lo // 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 index fe2f8e2..a9eec96 100644 --- 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 @@ void test_IntWrapper_Sub(MyMatrix &m) { 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 index 0000000..56ddee8 --- /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 index 41bcea5..0de0dda 100644 --- a/clang/test/Sema/matrix-type-operators.c +++ b/clang/test/Sema/matrix-type-operators.c @@ -31,3 +31,104 @@ void sub(sx10x10_t a, sx5x10_t b, sx10x5_t c) { // 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 index 153f89a..337d44f 100644 --- a/clang/test/SemaCXX/matrix-type-operators.cpp +++ b/clang/test/SemaCXX/matrix-type-operators.cpp @@ -91,3 +91,116 @@ void test_DoubleWrapper(MyMatrix &m, StructWithC &c) { // 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 index 0000000..45718ab --- /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 index 811f72e..180cf18 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -419,6 +419,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, 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 index 8414884..e6cfa7a 100644 --- a/llvm/include/llvm/IR/MatrixBuilder.h +++ b/llvm/include/llvm/IR/MatrixBuilder.h @@ -175,15 +175,19 @@ public: 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"); } }; -- 2.7.4