This revision was automatically updated to reflect the committed changes. Closed by commit rG8f3f88d2f50d: [Matrix] Implement matrix index expressions ([][]). (authored by fhahn).
Changed prior to commit: https://reviews.llvm.org/D76791?vs=267601&id=267701#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D76791/new/ https://reviews.llvm.org/D76791 Files: clang/include/clang/AST/ASTContext.h clang/include/clang/AST/BuiltinTypes.def clang/include/clang/AST/ComputeDependence.h clang/include/clang/AST/Expr.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/Stmt.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/Specifiers.h clang/include/clang/Basic/StmtNodes.td clang/include/clang/Sema/Initialization.h clang/include/clang/Sema/Sema.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ComputeDependence.cpp clang/lib/AST/Expr.cpp clang/lib/AST/ExprClassification.cpp clang/lib/AST/ExprConstant.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/NSAPI.cpp clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/AST/Type.cpp clang/lib/AST/TypeLoc.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGValue.h clang/lib/CodeGen/CodeGenFunction.h clang/lib/Sema/SemaCast.cpp clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaInit.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/CodeGen/matrix-type-operators.c clang/test/CodeGenCXX/matrix-type-operators.cpp clang/test/CodeGenObjC/matrix-type-operators.m clang/test/Sema/matrix-type-operators.c clang/test/SemaCXX/matrix-type-operators.cpp clang/test/SemaObjC/matrix-type-operators.m clang/tools/libclang/CXCursor.cpp llvm/include/llvm/IR/MatrixBuilder.h
Index: llvm/include/llvm/IR/MatrixBuilder.h =================================================================== --- llvm/include/llvm/IR/MatrixBuilder.h +++ 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"); } }; Index: clang/tools/libclang/CXCursor.cpp =================================================================== --- clang/tools/libclang/CXCursor.cpp +++ 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; Index: clang/test/SemaObjC/matrix-type-operators.m =================================================================== --- /dev/null +++ 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}} +} Index: clang/test/SemaCXX/matrix-type-operators.cpp =================================================================== --- clang/test/SemaCXX/matrix-type-operators.cpp +++ 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<double, 10, 9>::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<float &>(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}} +} Index: clang/test/Sema/matrix-type-operators.c =================================================================== --- clang/test/Sema/matrix-type-operators.c +++ 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}} +} Index: clang/test/CodeGenObjC/matrix-type-operators.m =================================================================== --- /dev/null +++ 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]; +} Index: clang/test/CodeGenCXX/matrix-type-operators.cpp =================================================================== --- clang/test/CodeGenCXX/matrix-type-operators.cpp +++ 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 <typename EltTy, unsigned Rows, unsigned Columns> struct MyMatrix { using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns))); @@ -154,3 +156,201 @@ w3.x = 'c'; m.value = w3 - m.value; } + +template <typename EltTy, unsigned Rows, unsigned Columns> +void insert(MyMatrix<EltTy, Rows, Columns> &Mat, EltTy e, unsigned i, unsigned j) { + Mat.value[i][j] = e; +} + +void test_insert_template1(MyMatrix<unsigned, 2, 2> &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<float, 3, 8> &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 <typename EltTy, unsigned Rows, unsigned Columns> +EltTy extract(MyMatrix<EltTy, Rows, Columns> &Mat) { + return Mat.value[1u][0u]; +} + +int test_extract_template(MyMatrix<int, 2, 2> 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 <class R, class C> +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 <class T, unsigned R, unsigned C> +using matrix_type = T __attribute__((matrix_type(R, C))); +struct identmatrix_t { + template <class T, unsigned N> + operator matrix_type<T, N, N>() const { + matrix_type<T, N, N> result; + for (unsigned i = 0; i != N; ++i) + result[i][i] = 1; + return result; + } +}; + +constexpr identmatrix_t identmatrix; + +void test_constexpr1(matrix_type<float, 4, 4> &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<int, 5, 5> &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]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1> + // 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; +} Index: clang/test/CodeGen/matrix-type-operators.c =================================================================== --- clang/test/CodeGen/matrix-type-operators.c +++ 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; +} Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ 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<GCCAsmStmt>(S), Pred, Dst); Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ 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()); Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ 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; Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ 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; Index: clang/lib/Serialization/ASTCommon.cpp =================================================================== --- clang/lib/Serialization/ASTCommon.cpp +++ 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; Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ 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 <typename Derived> ExprResult +TreeTransform<Derived>::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 <typename Derived> +ExprResult TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ 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; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ 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<BinaryOperator>(E) && cast<BinaryOperator>(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<MatrixSubscriptExpr>(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<MatrixSubscriptExpr>(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<BinaryOperator>(idx) && cast<BinaryOperator>(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<ConstantMatrixType>(); + 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<MatrixSubscriptExpr>(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); Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ 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: Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ 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; Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ 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); Index: clang/lib/CodeGen/CGValue.h =================================================================== --- clang/lib/CodeGen/CGValue.h +++ 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()); } Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ 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<CGBuilderTy> MB(Builder); + return MB.CreateExtractElement( + Matrix, RowIdx, ColumnIdx, + E->getBase()->getType()->getAs<ConstantMatrixType>()->getNumRows()); +} + static int getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, unsigned Off) { int MV = SVI->getMaskValue(Idx); Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -1369,6 +1369,8 @@ return EmitUnaryOpLValue(cast<UnaryOperator>(E)); case Expr::ArraySubscriptExprClass: return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E)); + case Expr::MatrixSubscriptExprClass: + return EmitMatrixSubscriptExpr(cast<MatrixSubscriptExpr>(E)); case Expr::OMPArraySectionExprClass: return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(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<ConstantMatrixType>()->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, Index: clang/lib/AST/TypeLoc.cpp =================================================================== --- clang/lib/AST/TypeLoc.cpp +++ 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: Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -3025,6 +3025,8 @@ return "queue_t"; case OCLReserveID: return "reserve_id_t"; + case IncompleteMatrixIdx: + return "<incomplete matrix index type>"; case OMPArraySection: return "<OpenMP array section type>"; 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: Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -163,6 +163,9 @@ case OK_VectorComponent: OS << " vectorcomponent"; break; + case OK_MatrixComponent: + OS << " matrixcomponent"; + break; } } } Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ 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); } Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ 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 << "["; Index: clang/lib/AST/NSAPI.cpp =================================================================== --- clang/lib/AST/NSAPI.cpp +++ 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: Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -4234,6 +4234,15 @@ break; } + case Expr::MatrixSubscriptExprClass: { + const MatrixSubscriptExpr *ME = cast<MatrixSubscriptExpr>(E); + Out << "ixix"; + mangleExpression(ME->getBase()); + mangleExpression(ME->getRowIdx()); + mangleExpression(ME->getColumnIdx()); + break; + } + case Expr::CompoundAssignOperatorClass: // fallthrough case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(E); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ 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: Index: clang/lib/AST/ExprClassification.cpp =================================================================== --- clang/lib/AST/ExprClassification.cpp +++ 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<MatrixSubscriptExpr>(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: Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -3508,6 +3508,7 @@ case ParenExprClass: case ArraySubscriptExprClass: + case MatrixSubscriptExprClass: case OMPArraySectionExprClass: case OMPArrayShapingExprClass: case OMPIteratorExprClass: Index: clang/lib/AST/ComputeDependence.cpp =================================================================== --- clang/lib/AST/ComputeDependence.cpp +++ 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()); Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ 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); Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ 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, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ 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); Index: clang/include/clang/Sema/Initialization.h =================================================================== --- clang/include/clang/Sema/Initialization.h +++ 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, Index: clang/include/clang/Basic/StmtNodes.td =================================================================== --- clang/include/clang/Basic/StmtNodes.td +++ clang/include/clang/Basic/StmtNodes.td @@ -69,6 +69,7 @@ def OffsetOfExpr : StmtNode<Expr>; def UnaryExprOrTypeTraitExpr : StmtNode<Expr>; def ArraySubscriptExpr : StmtNode<Expr>; +def MatrixSubscriptExpr : StmtNode<Expr>; def OMPArraySectionExpr : StmtNode<Expr>; def OMPIteratorExpr : StmtNode<Expr>; def CallExpr : StmtNode<Expr>; Index: clang/include/clang/Basic/Specifiers.h =================================================================== --- clang/include/clang/Basic/Specifiers.h +++ 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. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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">; Index: clang/include/clang/AST/Stmt.h =================================================================== --- clang/include/clang/AST/Stmt.h +++ 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; Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ 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, {}) Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ 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<Expr>(SubExprs[BASE]); } + const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); } + void setBase(Expr *E) { SubExprs[BASE] = E; } + + Expr *getRowIdx() { return cast<Expr>(SubExprs[ROW_IDX]); } + const Expr *getRowIdx() const { return cast<Expr>(SubExprs[ROW_IDX]); } + void setRowIdx(Expr *E) { SubExprs[ROW_IDX] = E; } + + Expr *getColumnIdx() { return cast_or_null<Expr>(SubExprs[COLUMN_IDX]); } + const Expr *getColumnIdx() const { + assert(!isIncomplete() && + "cannot get the column index of an incomplete expression"); + return cast<Expr>(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) Index: clang/include/clang/AST/ComputeDependence.h =================================================================== --- clang/include/clang/AST/ComputeDependence.h +++ 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); Index: clang/include/clang/AST/BuiltinTypes.def =================================================================== --- clang/include/clang/AST/BuiltinTypes.def +++ 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) Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ 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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits