[clang] b5e082e - [Matrix] Add __builtin_matrix_column_store to Clang.

Florian Hahn via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 18 04:01:39 PDT 2020


Author: Florian Hahn
Date: 2020-06-18T11:39:02+01:00
New Revision: b5e082e7289197bf82c9a28c6336b51d7999b419

URL: https://github.com/llvm/llvm-project/commit/b5e082e7289197bf82c9a28c6336b51d7999b419
DIFF: https://github.com/llvm/llvm-project/commit/b5e082e7289197bf82c9a28c6336b51d7999b419.diff

LOG: [Matrix] Add __builtin_matrix_column_store to Clang.

This patch add __builtin_matrix_column_major_store to Clang,
as described in clang/docs/MatrixTypes.rst. In the initial version,
the stride is not optional yet.

Reviewers: rjmccall, jfb, rsmith, Bigcheese

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D72782

Added: 
    

Modified: 
    clang/include/clang/Basic/Builtins.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/test/CodeGen/matrix-type-builtins.c
    clang/test/CodeGenCXX/matrix-type-builtins.cpp
    clang/test/CodeGenObjC/matrix-type-builtins.m
    clang/test/Sema/matrix-type-builtins.c
    clang/test/SemaCXX/matrix-type-builtins.cpp
    clang/test/SemaObjC/matrix-type-builtins.m

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 61a195bf5bf8..ac9af6028867 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -579,6 +579,7 @@ BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
 
 BUILTIN(__builtin_matrix_transpose, "v.", "nFt")
 BUILTIN(__builtin_matrix_column_major_load, "v.", "nFt")
+BUILTIN(__builtin_matrix_column_major_store, "v.", "nFt")
 
 // "Overloaded" Atomic operator builtins.  These are overloaded to support data
 // types of i8, i16, i32, i64, and i128.  The front-end sees calls to the

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fb45ad8d44d9..a7b8a992f745 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10783,14 +10783,19 @@ def warn_import_on_definition : Warning<
   "import %select{module|name}0 cannot be applied to a function with a definition">,
   InGroup<IgnoredAttributes>;
 
-def err_builtin_matrix_arg: Error<
-  "%select{first|second}0 argument must be a matrix">;
+def err_builtin_matrix_arg: Error<"first argument must be a matrix">;
 
 def err_builtin_matrix_scalar_unsigned_arg: Error<
   "%0 argument must be a constant unsigned integer expression">;
 
 def err_builtin_matrix_pointer_arg: Error<
-  "%select{first|second}0 argument must be a pointer to a valid matrix element type">;
+  "%0 argument must be a pointer to a valid matrix element type">;
+
+def err_builtin_matrix_pointer_arg_mismatch: Error<
+  "the pointee of the second argument must match the element type of the first argument (%0 != %1)">;
+
+def err_builtin_matrix_store_to_const: Error<
+  "cannot store matrix to read-only pointer">;
 
 def err_builtin_matrix_stride_too_small: Error<
   "stride must be greater or equal to the number of rows">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4f8289d70747..85c5ab476b5f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12129,6 +12129,8 @@ class Sema final {
                                         ExprResult CallResult);
   ExprResult SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
                                               ExprResult CallResult);
+  ExprResult SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
+                                               ExprResult CallResult);
 
 public:
   enum FormatStringType {

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 7a138c54fb36..2339446609f6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2406,6 +2406,25 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     return RValue::get(Result);
   }
 
+  case Builtin::BI__builtin_matrix_column_major_store: {
+    MatrixBuilder<CGBuilderTy> MB(Builder);
+    Value *Matrix = EmitScalarExpr(E->getArg(0));
+    Address Dst = EmitPointerWithAlignment(E->getArg(1));
+    Value *Stride = EmitScalarExpr(E->getArg(2));
+
+    const auto *MatrixTy = E->getArg(0)->getType()->getAs<ConstantMatrixType>();
+    auto *PtrTy = E->getArg(1)->getType()->getAs<PointerType>();
+    assert(PtrTy && "arg1 must be of pointer type");
+    bool IsVolatile = PtrTy->getPointeeType().isVolatileQualified();
+
+    EmitNonNullArgCheck(RValue::get(Dst.getPointer()), E->getArg(1)->getType(),
+                        E->getArg(1)->getExprLoc(), FD, 0);
+    Value *Result = MB.CreateColumnMajorStore(
+        Matrix, Dst.getPointer(), Align(Dst.getAlignment().getQuantity()),
+        Stride, IsVolatile, MatrixTy->getNumRows(), MatrixTy->getNumColumns());
+    return RValue::get(Result);
+  }
+
   case Builtin::BIfinite:
   case Builtin::BI__finite:
   case Builtin::BIfinitef:

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 821074d8b57f..accce8527c01 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1930,6 +1930,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
 
   case Builtin::BI__builtin_matrix_column_major_load:
     return SemaBuiltinMatrixColumnMajorLoad(TheCall, TheCallResult);
+
+  case Builtin::BI__builtin_matrix_column_major_store:
+    return SemaBuiltinMatrixColumnMajorStore(TheCall, TheCallResult);
   }
 
   // Since the target specific builtins for each arch overlap, only check those
@@ -15092,7 +15095,7 @@ ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall,
 
   auto *MType = Matrix->getType()->getAs<ConstantMatrixType>();
   if (!MType) {
-    Diag(Matrix->getBeginLoc(), diag::err_builtin_matrix_arg) << 0;
+    Diag(Matrix->getBeginLoc(), diag::err_builtin_matrix_arg);
     return ExprError();
   }
 
@@ -15161,13 +15164,15 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
   auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
   QualType ElementTy;
   if (!PtrTy) {
-    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) << 0;
+    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+        << "first";
     ArgError = true;
   } else {
     ElementTy = PtrTy->getPointeeType().getUnqualifiedType();
 
     if (!ConstantMatrixType::isValidElementType(ElementTy)) {
-      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) << 0;
+      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+          << "first";
       ArgError = true;
     }
   }
@@ -15237,3 +15242,97 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
       Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns));
   return CallResult;
 }
+
+ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
+                                                   ExprResult CallResult) {
+  if (checkArgCount(*this, TheCall, 3))
+    return ExprError();
+
+  Expr *MatrixExpr = TheCall->getArg(0);
+  Expr *PtrExpr = TheCall->getArg(1);
+  Expr *StrideExpr = TheCall->getArg(2);
+
+  bool ArgError = false;
+
+  {
+    ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr);
+    if (MatrixConv.isInvalid())
+      return MatrixConv;
+    MatrixExpr = MatrixConv.get();
+    TheCall->setArg(0, MatrixExpr);
+  }
+  if (MatrixExpr->isTypeDependent()) {
+    TheCall->setType(Context.DependentTy);
+    return TheCall;
+  }
+
+  auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>();
+  if (!MatrixTy) {
+    Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_matrix_arg) << 0;
+    ArgError = true;
+  }
+
+  {
+    ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
+    if (PtrConv.isInvalid())
+      return PtrConv;
+    PtrExpr = PtrConv.get();
+    TheCall->setArg(1, PtrExpr);
+    if (PtrExpr->isTypeDependent()) {
+      TheCall->setType(Context.DependentTy);
+      return TheCall;
+    }
+  }
+
+  // Check pointer argument.
+  auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
+  if (!PtrTy) {
+    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+        << "second";
+    ArgError = true;
+  } else {
+    QualType ElementTy = PtrTy->getPointeeType();
+    if (ElementTy.isConstQualified()) {
+      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const);
+      ArgError = true;
+    }
+    ElementTy = ElementTy.getUnqualifiedType().getCanonicalType();
+    if (MatrixTy &&
+        !Context.hasSameType(ElementTy, MatrixTy->getElementType())) {
+      Diag(PtrExpr->getBeginLoc(),
+           diag::err_builtin_matrix_pointer_arg_mismatch)
+          << ElementTy << MatrixTy->getElementType();
+      ArgError = true;
+    }
+  }
+
+  // Apply default Lvalue conversions and convert the stride expression to
+  // size_t.
+  {
+    ExprResult StrideConv = DefaultLvalueConversion(StrideExpr);
+    if (StrideConv.isInvalid())
+      return StrideConv;
+
+    StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType());
+    if (StrideConv.isInvalid())
+      return StrideConv;
+    StrideExpr = StrideConv.get();
+    TheCall->setArg(2, StrideExpr);
+  }
+
+  // Check stride argument.
+  llvm::APSInt Value(64);
+  if (MatrixTy && StrideExpr->isIntegerConstantExpr(Value, Context)) {
+    uint64_t Stride = Value.getZExtValue();
+    if (Stride < MatrixTy->getNumRows()) {
+      Diag(StrideExpr->getBeginLoc(),
+           diag::err_builtin_matrix_stride_too_small);
+      ArgError = true;
+    }
+  }
+
+  if (ArgError)
+    return ExprError();
+
+  return CallResult;
+}

diff  --git a/clang/test/CodeGen/matrix-type-builtins.c b/clang/test/CodeGen/matrix-type-builtins.c
index b607bccc9900..58fde6f01cc3 100644
--- a/clang/test/CodeGen/matrix-type-builtins.c
+++ b/clang/test/CodeGen/matrix-type-builtins.c
@@ -179,3 +179,81 @@ void column_major_load_volatile(volatile double *Ptr) {
 
   dx5x5_t m_a1 = __builtin_matrix_column_major_load(Ptr, 5, 5, 5);
 }
+
+void column_major_store_with_const_stride_double(double *Ptr) {
+  // CHECK-LABEL: define void @column_major_store_with_const_stride_double(double* %Ptr)
+  // CHECK:         [[M:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v25f64.p0f64(<25 x double> [[M]], double* align 8 [[PTR]], i64 5, i1 false, i32 5, i32 5)
+
+  dx5x5_t m;
+  __builtin_matrix_column_major_store(m, Ptr, 5);
+}
+
+void column_major_store_with_const_stride2_double(double *Ptr) {
+  // CHECK-LABEL: define void @column_major_store_with_const_stride2_double(double* %Ptr)
+  // CHECK:         [[M:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v25f64.p0f64(<25 x double> [[M]], double* align 8 [[PTR]], i64 15, i1 false, i32 5, i32 5)
+  //
+  dx5x5_t m;
+  __builtin_matrix_column_major_store(m, Ptr, 2 * 3 + 9);
+}
+
+void column_major_store_with_stride_math_int(int *Ptr, int S) {
+  // CHECK-LABEL: define void @column_major_store_with_stride_math_int(i32* %Ptr, i32 %S)
+  // CHECK:         [[M:%.*]] = load <80 x i32>, <80 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:    [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    [[S:%.*]] = load i32, i32* %S.addr, align 4
+  // CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[S]], 32
+  // CHECK-NEXT:    [[IDX:%.*]] = sext i32 [[ADD]] to i64
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v80i32.p0i32(<80 x i32> [[M]], i32* align 4 [[PTR]], i64 [[IDX]], i1 false, i32 4, i32 20)
+
+  ix4x20_t m;
+  __builtin_matrix_column_major_store(m, Ptr, S + 32);
+}
+
+void column_major_store_with_stride_math_s_int(int *Ptr, short S) {
+  // CHECK-LABEL: define void @column_major_store_with_stride_math_s_int(i32* %Ptr, i16 signext %S)
+  // CHECK:         [[M:%.*]] = load <80 x i32>, <80 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:    [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    [[S:%.*]] = load i16, i16* %S.addr, align 2
+  // CHECK-NEXT:    [[EXT:%.*]] = sext i16 [[S]] to i32
+  // CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[EXT]], 2
+  // CHECK-NEXT:    [[IDX:%.*]] = sext i32 [[ADD]] to i64
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v80i32.p0i32(<80 x i32> [[M]], i32* align 4 [[PTR]], i64 [[IDX]], i1 false, i32 4, i32 20)
+
+  ix4x20_t m;
+  __builtin_matrix_column_major_store(m, Ptr, S + 2);
+}
+
+void column_major_store_array1(double Ptr[25]) {
+  // CHECK-LABEL: define void @column_major_store_array1(double* %Ptr)
+  // CHECK:         [[M:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v25f64.p0f64(<25 x double> [[M]], double* align 8 [[PTR]], i64 5, i1 false, i32 5, i32 5)
+
+  dx5x5_t m;
+  __builtin_matrix_column_major_store(m, Ptr, 5);
+}
+
+void column_major_store_array2() {
+  // CHECK-LABEL: define void @column_major_store_array2()
+  // CHECK:         [[M:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds [25 x double], [25 x double]* %Ptr, i64 0, i64 0
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v25f64.p0f64(<25 x double> [[M]], double* align 16 [[PTR]], i64 5, i1 false, i32 5, i32 5)
+
+  double Ptr[25];
+  dx5x5_t m;
+  __builtin_matrix_column_major_store(m, Ptr, 5);
+}
+
+void column_major_store_volatile(volatile double *Ptr) {
+  // CHECK-LABEL: define void @column_major_store_volatile(double* %Ptr) #0 {
+  // CHECK:         [[M:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v25f64.p0f64(<25 x double> [[M]], double* align 8 [[PTR]], i64 5, i1 true, i32 5, i32 5)
+
+  dx5x5_t m;
+  __builtin_matrix_column_major_store(m, Ptr, 5);
+}

diff  --git a/clang/test/CodeGenCXX/matrix-type-builtins.cpp b/clang/test/CodeGenCXX/matrix-type-builtins.cpp
index 1aa696df4735..314168701793 100644
--- a/clang/test/CodeGenCXX/matrix-type-builtins.cpp
+++ b/clang/test/CodeGenCXX/matrix-type-builtins.cpp
@@ -186,3 +186,61 @@ matrix_t<typename remove_pointer<PtrT>::type, R, C> column_major_load_with_strid
 void call_column_major_load_with_stride2(float *Ptr) {
   matrix_t<float, 2, 2> m = column_major_load_with_stride2<float *, 2, 2, 2>(Ptr);
 }
+
+template <typename T, unsigned R, unsigned C, unsigned S>
+void column_major_store_with_stride(matrix_t<T, R, C> &m, T *Ptr) {
+  __builtin_matrix_column_major_store(m, Ptr, S);
+}
+
+void test_column_major_store_with_stride_template_double(double *Ptr) {
+  // CHECK-LABEL: define void @_Z51test_column_major_store_with_stride_template_doublePd(double* %Ptr)
+  // CHECK:         [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @_Z30column_major_store_with_strideIdLj10ELj4ELj15EEvRU11matrix_typeXT0_EXT1_ET_PS0_([40 x double]* nonnull align 8 dereferenceable(320) %M1, double* [[PTR]])
+
+  // CHECK-LABEL:  define linkonce_odr void @_Z30column_major_store_with_strideIdLj10ELj4ELj15EEvRU11matrix_typeXT0_EXT1_ET_PS0_([40 x double]* nonnull align 8 dereferenceable(320) %m, double* %Ptr)
+  // CHECK:         [[M:%.*]] = load <40 x double>, <40 x double>* {{.*}}, align 8
+  // CHECK-NEXT:    [[PTR:%.*]] = load double*, double** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v40f64.p0f64(<40 x double> [[M]], double* align 8 [[PTR]], i64 15, i1 false, i32 10, i32 4)
+
+  matrix_t<double, 10, 4> M1;
+  column_major_store_with_stride<double, 10, 4, 15>(M1, Ptr);
+}
+
+void test_column_major_store_with_stride_template_int(int *Ptr) {
+  // CHECK-LABEL: define void @_Z48test_column_major_store_with_stride_template_intPi(i32* %Ptr)
+  // CHECK:         [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @_Z30column_major_store_with_strideIiLj3ELj2ELj3EEvRU11matrix_typeXT0_EXT1_ET_PS0_([6 x i32]* nonnull align 4 dereferenceable(24) %M1, i32* [[PTR]])
+
+  // CHECK-LABEL:  define linkonce_odr void @_Z30column_major_store_with_strideIiLj3ELj2ELj3EEvRU11matrix_typeXT0_EXT1_ET_PS0_([6 x i32]* nonnull align 4 dereferenceable(24) %m, i32* %Ptr)
+  // CHECK:         [[M:%.*]] = load <6 x i32>, <6 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:    [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v6i32.p0i32(<6 x i32> [[M]], i32* align 4 [[PTR]], i64 3, i1 false, i32 3, i32 2)
+
+  matrix_t<int, 3, 2> M1;
+  column_major_store_with_stride<int, 3, 2, 3>(M1, Ptr);
+}
+
+void test_column_major_store_stride_wrapper(int *Ptr, UnsignedWrapper &W) {
+  // CHECK-LABEL: define void @_Z38test_column_major_store_stride_wrapperPiR15UnsignedWrapper(i32* %Ptr, %struct.UnsignedWrapper* nonnull align 1 dereferenceable(1) %W)
+  // CHECK:         [[M:%.*]] = load <4 x i32>, <4 x i32>* {{.*}}, align 4
+  // CHECK-NEXT:    [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    [[W:%.*]] = load %struct.UnsignedWrapper*, %struct.UnsignedWrapper** %W.addr, align 8
+  // CHECK-NEXT:    [[IDX:%.*]] = call i32 @_ZN15UnsignedWrappercvjEv(%struct.UnsignedWrapper* [[W]])
+  // CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v4i32.p0i32(<4 x i32> [[M]], i32* align 4 [[PTR]], i64 [[IDX_EXT]], i1 false, i32 2, i32 2)
+
+  matrix_t<int, 2, 2> M1;
+  __builtin_matrix_column_major_store(M1, Ptr, W);
+}
+
+void test_column_major_store_constexpr_stride_constexpr(int *Ptr) {
+  // CHECK-LABEL: define void @_Z50test_column_major_store_constexpr_stride_constexprPi(i32* %Ptr)
+  // CHECK:         [[M:%.*]] = load <4 x i32>, <4 x i32>* %0, align 4
+  // CHECK-NEXT:    [[PTR:%.*]] = load i32*, i32** %Ptr.addr, align 8
+  // CHECK-NEXT:    [[IDX:%.*]] = call i32 @_Z10constexpr3v()
+  // CHECK-NEXT:    [[IDX_EXT:%.*]] = sext i32 [[IDX]] to i64
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v4i32.p0i32(<4 x i32> [[M]], i32* align 4 [[PTR]], i64 [[IDX_EXT]], i1 false, i32 2, i32 2)
+
+  matrix_t<int, 2, 2> M;
+  __builtin_matrix_column_major_store(M, Ptr, constexpr3());
+}

diff  --git a/clang/test/CodeGenObjC/matrix-type-builtins.m b/clang/test/CodeGenObjC/matrix-type-builtins.m
index ba8f4c3a1305..78dfad262b91 100644
--- a/clang/test/CodeGenObjC/matrix-type-builtins.m
+++ b/clang/test/CodeGenObjC/matrix-type-builtins.m
@@ -60,3 +60,14 @@ void test_column_major_load(PtrValue *Ptr, IntValue *Stride) {
 
   u3x4 m = __builtin_matrix_column_major_load(Ptr.value, 3, 4, Stride.value);
 }
+
+void test_column_major_store(UnsignedMatrixValue *M, PtrValue *Ptr, IntValue *Stride) {
+  // CHECK-LABEL: define void @test_column_major_store(%1* %M, %2* %Ptr, %3* %Stride) #3 {
+  // CHECK:         [[M:%.*]] = call <12 x i32> bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to <12 x i32> (i8*, i8*)*)
+  // CHECK:         [[PTR:%.*]] = call i32* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32* (i8*, i8*)*)
+  // CHECK:         [[IDX:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)
+  // CHECK-NEXT:    [[IDX_EXT:%.*]] = sext i32 [[IDX]] to i64
+  // CHECK-NEXT:    call void @llvm.matrix.column.major.store.v12i32.p0i32(<12 x i32> [[M]], i32* align 4 [[PTR]], i64 [[IDX_EXT]], i1 false, i32 3, i32 4)
+
+  __builtin_matrix_column_major_store(M.value, Ptr.value, Stride.value);
+}

diff  --git a/clang/test/Sema/matrix-type-builtins.c b/clang/test/Sema/matrix-type-builtins.c
index 5f0c0e4f7829..d8da11aa05aa 100644
--- a/clang/test/Sema/matrix-type-builtins.c
+++ b/clang/test/Sema/matrix-type-builtins.c
@@ -66,3 +66,33 @@ void column_major_load(float *p1, int *p2, _Bool *p3, struct Foo *p4) {
            // expected-warning at -1 {{incompatible pointer to integer conversion casting 'char [1]' to type 'unsigned long'}}
       10);
 }
+
+void column_major_store(sx5x10_t *m1, ix3x2_t *m2, float *p1, int *p2, struct Foo *p3, const float *p4) {
+  __builtin_matrix_column_major_store(*m1, p1, 1);
+  // expected-error at -1 {{stride must be greater or equal to the number of rows}}
+  __builtin_matrix_column_major_store(*m1, p1, 0);
+  // expected-error at -1 {{stride must be greater or equal to the number of rows}}
+  __builtin_matrix_column_major_store(*m1, p2, 10);
+  // expected-error at -1 {{the pointee of the second argument must match the element type of the first argument ('int' != 'float')}}
+  __builtin_matrix_column_major_store(p1, p2, 10);
+  // expected-error at -1 {{first argument must be a matrix}}
+
+  __builtin_matrix_column_major_store(
+      "",   // expected-error {{first argument must be a matrix}}
+      10,   // expected-error {{second argument must be a pointer to a valid matrix element type}}
+      *p3); // expected-error {{casting 'struct Foo' to incompatible type 'unsigned long'}}
+
+  __builtin_matrix_column_major_store(
+      *m1,
+      10, // expected-error {{second argument must be a pointer to a valid matrix element type}}
+      10);
+
+  *m1 = __builtin_matrix_column_major_store(*m1, p1, 10);
+  // expected-error at -1 {{assigning to 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') from incompatible type 'void'}}
+
+  int x = __builtin_matrix_column_major_store(*m1, p1, 10);
+  // expected-error at -1 {{initializing 'int' with an expression of incompatible type 'void'}}
+
+  __builtin_matrix_column_major_store(*m1, p4, 20);
+  // expected-error at -1 {{cannot store matrix to read-only pointer}}
+}

diff  --git a/clang/test/SemaCXX/matrix-type-builtins.cpp b/clang/test/SemaCXX/matrix-type-builtins.cpp
index f2ad53ad3778..3850e4ff901b 100644
--- a/clang/test/SemaCXX/matrix-type-builtins.cpp
+++ b/clang/test/SemaCXX/matrix-type-builtins.cpp
@@ -101,3 +101,66 @@ void call_column_major_load_temp(unsigned *Ptr, unsigned X) {
   (void)__builtin_matrix_column_major_load(X, 2, 2, 2);
   // expected-error at -1 {{first argument must be a pointer to a valid matrix element type}}
 }
+
+template <typename EltTy0, unsigned R0, unsigned C0, typename PtrTy>
+void column_major_store(MyMatrix<EltTy0, R0, C0> &A, PtrTy Ptr, unsigned Stride) {
+  __builtin_matrix_column_major_store(A.value, Ptr, Stride);
+  // expected-error at -1 {{the pointee of the second argument must match the element type of the first argument ('float' != 'unsigned int')}}
+}
+
+template <typename MTy, typename PtrTy, unsigned Stride>
+void column_major_store(MTy &A, PtrTy Ptr) {
+  __builtin_matrix_column_major_store(A.value, Ptr, Stride);
+  // expected-error at -1 {{stride must be greater or equal to the number of rows}}
+}
+
+void test_column_major_stores_template(MyMatrix<unsigned, 2, 3> &M1, unsigned *Ptr1, MyMatrix<float, 3, 4> &M2, float *Ptr2) {
+  column_major_store(M1, Ptr2, 10);
+  // expected-note at -1 {{in instantiation of function template specialization 'column_major_store<unsigned int, 2, 3, float *>' requested here}}
+
+  column_major_store<decltype(M2), float *, 1>(M2, Ptr2);
+  // expected-note at -1 {{in instantiation of function template specialization 'column_major_store<MyMatrix<float, 3, 4> &, float *, 1>' requested here}}
+}
+
+template <typename EltTy0, unsigned R0, unsigned C0, typename EltTy1>
+void column_major_store(MyMatrix<EltTy0, R0, C0> &A, EltTy1 *Ptr) {
+  __builtin_matrix_column_major_store(A.value, Ptr, 1);
+  // expected-error at -1 3 {{stride must be greater or equal to the number of rows}}
+  // expected-error at -2 {{the pointee of the second argument must match the element type of the first argument ('float' != 'unsigned int')}}
+  // expected-error at -3 {{the pointee of the second argument must match the element type of the first argument ('unsigned int' != 'float')}}
+
+  char *s;
+  return __builtin_matrix_column_major_store(A.value, s, 20);
+  // expected-error at -1 {{the pointee of the second argument must match the element type of the first argument ('char' != 'unsigned int')}}
+  // expected-error at -2 {{the pointee of the second argument must match the element type of the first argument ('char' != 'unsigned int')}}
+  // expected-error at -3 {{he pointee of the second argument must match the element type of the first argument ('char' != 'float')}}
+}
+
+void test_column_major_store_template(unsigned *Ptr1, float *Ptr2) {
+  MyMatrix<unsigned, 2, 3> Mat1;
+  column_major_store<unsigned, 2, 3, unsigned>(Mat1, Ptr1);
+  // expected-note at -1 {{in instantiation of function template specialization 'column_major_store<unsigned int, 2, 3, unsigned int>'}}
+  column_major_store<unsigned, 2, 3, float>(Mat1, Ptr2);
+  // expected-note at -1 {{in instantiation of function template specialization 'column_major_store<unsigned int, 2, 3, float>'}}
+
+  MyMatrix<float, 2, 3> Mat2;
+  column_major_store<float, 2, 3, unsigned>(Mat2, Ptr1);
+  // expected-note at -1 {{in instantiation of function template specialization 'column_major_store<float, 2, 3, unsigned int>'}}
+}
+
+void test_column_major_store_constexpr(unsigned *Ptr, MyMatrix<unsigned, 3, 3> &M) {
+  __builtin_matrix_column_major_store(M.value, Ptr, constexpr1());
+  // expected-error at -1 {{stride must be greater or equal to the number of rows}}
+  __builtin_matrix_column_major_store(constexpr1(), Ptr, 1);
+  // expected-error at -1 {{first argument must be a matrix}}
+  __builtin_matrix_column_major_store(M.value, constexpr1(), 1);
+  // expected-error at -1 {{second argument must be a pointer to a valid matrix element type}}
+  // expected-error at -2 {{stride must be greater or equal to the number of rows}}
+}
+
+void test_column_major_store_wrapper(unsigned *Ptr, MyMatrix<unsigned, 3, 3> &M, IntWrapper &W) {
+  __builtin_matrix_column_major_store(M.value, Ptr, W);
+
+  __builtin_matrix_column_major_store(W, Ptr, W);
+  // expected-error at -1 {{first argument must be a matrix}}
+}

diff  --git a/clang/test/SemaObjC/matrix-type-builtins.m b/clang/test/SemaObjC/matrix-type-builtins.m
index bac7008f74e2..63193574ca45 100644
--- a/clang/test/SemaObjC/matrix-type-builtins.m
+++ b/clang/test/SemaObjC/matrix-type-builtins.m
@@ -19,3 +19,13 @@ void test_element_type_mismatch(u4x4 m, MatrixValue *mv) {
   m = __builtin_matrix_transpose(mv.value);
   // expected-error at -1 {{assigning to 'double3x3' (aka 'double __attribute__((matrix_type(3, 3)))') from incompatible type 'double __attribute__((matrix_type(4, 4)))'}}
 }
+
+double test_store(MatrixValue *mv, float *Ptr) {
+  __builtin_matrix_column_major_store(mv.value, Ptr, 1);
+  // expected-error at -1 {{the pointee of the second argument must match the element type of the first argument ('float' != 'double')}}
+  // expected-error at -2 {{stride must be greater or equal to the number of rows}}
+
+  __builtin_matrix_column_major_store(mv.value, mv.value, mv.value);
+  // expected-error at -1 {{second argument must be a pointer to a valid matrix element type}}
+  // expected-error at -2 {{casting 'double4x4' (aka 'double __attribute__((matrix_type(4, 4)))') to incompatible type 'unsigned long'}}
+}


        


More information about the cfe-commits mailing list