fhahn created this revision.
Herald added a subscriber: tschuett.
Herald added a project: clang.

This patch adds a __builtin_matrix_insert builtin as described in
"Matrix Support in Clang" on cfe-dev [1]. The patch is not intended for
review yet, just to provide an idea how the implementation could look
like.

[1] http://lists.llvm.org/pipermail/cfe-dev/2019-December/064141.html


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72283

Files:
  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/builtin-matrix.c
  clang/test/CodeGenCXX/builtin-matrix.cpp
  clang/test/SemaCXX/builtin-matrix.cpp

Index: clang/test/SemaCXX/builtin-matrix.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/builtin-matrix.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -fenable-matrix -pedantic -std=c++11 -verify -triple=x86_64-apple-darwin9
+
+typedef float sx10x10_t __attribute__((matrix_type(10, 10)));
+sx10x10_t a;
+
+struct Foo {
+  char *s;
+};
+
+void insert(sx10x10_t *a, float f) {
+  *a = __builtin_matrix_insert(
+      10, // expected-error {{First argument must be a matrix}}
+      a,  // expected-error {{Row argument must be an unsigned integer}}
+      a,  // expected-error {{Column argument must be an unsigned integer}}
+      10);
+
+  int x = __builtin_matrix_insert(*a, 3u, 5u, 10.0); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10))) ')}}
+
+  // TODO: Should error here (index out of range).
+  *a = __builtin_matrix_insert(*a, -1u, 5u, 10.0);
+
+  // FIXME: Column argument is fine!
+  *a = __builtin_matrix_insert(*a, f,     // expected-error {{Row argument must be an unsigned integer}}
+                               5u, 10.0); // expected-error {{Column argument must be an unsigned integer}}
+}
Index: clang/test/CodeGenCXX/builtin-matrix.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/builtin-matrix.cpp
@@ -0,0 +1,150 @@
+// 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)));
+
+void insert_fp(dx5x5_t *a, double d, fx2x3_t *b, float e) {
+  *a = __builtin_matrix_insert(*a, 0u, 1u, d);
+  *b = __builtin_matrix_insert(*b, 1u, 0u, e);
+
+  // CHECK-LABEL: @_Z9insert_fpPDm5_5_ddPDm2_3_ff(
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT:    %a.addr = alloca [25 x double]*, align 8
+  // CHECK-NEXT:    %d.addr = alloca double, align 8
+  // CHECK-NEXT:    %b.addr = alloca [6 x float]*, align 8
+  // CHECK-NEXT:    %e.addr = alloca float, align 4
+  // CHECK-NEXT:    store [25 x double]* %a, [25 x double]** %a.addr, align 8
+  // CHECK-NEXT:    store double %d, double* %d.addr, align 8
+  // CHECK-NEXT:    store [6 x float]* %b, [6 x float]** %b.addr, align 8
+  // CHECK-NEXT:    store float %e, float* %e.addr, align 4
+  // CHECK-NEXT:    %0 = load [25 x double]*, [25 x double]** %a.addr, align 8
+  // CHECK-NEXT:    %1 = bitcast [25 x double]* %0 to <25 x double>*
+  // CHECK-NEXT:    %2 = load <25 x double>, <25 x double>* %1, align 8
+  // CHECK-NEXT:    %3 = load double, double* %d.addr, align 8
+  // CHECK-NEXT:    %4 = insertelement <25 x double> %2, double %3, i32 5
+  // CHECK-NEXT:    %5 = load [25 x double]*, [25 x double]** %a.addr, align 8
+  // CHECK-NEXT:    %6 = bitcast [25 x double]* %5 to <25 x double>*
+  // CHECK-NEXT:    store <25 x double> %4, <25 x double>* %6, align 8
+  // CHECK-NEXT:    %7 = load [6 x float]*, [6 x float]** %b.addr, align 8
+  // CHECK-NEXT:    %8 = bitcast [6 x float]* %7 to <6 x float>*
+  // CHECK-NEXT:    %9 = load <6 x float>, <6 x float>* %8, align 4
+  // CHECK-NEXT:    %10 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %11 = insertelement <6 x float> %9, float %10, i32 1
+  // CHECK-NEXT:    %12 = load [6 x float]*, [6 x float]** %b.addr, align 8
+  // CHECK-NEXT:    %13 = bitcast [6 x float]* %12 to <6 x float>*
+  // CHECK-NEXT:    store <6 x float> %11, <6 x float>* %13, align 4
+  // CHECK-NEXT:   ret void
+}
+
+typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
+
+void insert_int(ix9x3_t *a, int i) {
+  *a = __builtin_matrix_insert(*a, 4u, 1u, i);
+
+  // CHECK-LABEL: @_Z10insert_intPDm9_3_ii(
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT:    %a.addr = alloca [27 x i32]*, align 8
+  // CHECK-NEXT:    %i.addr = alloca i32, align 4
+  // CHECK-NEXT:    store [27 x i32]* %a, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    store i32 %i, i32* %i.addr, align 4
+  // CHECK-NEXT:    %0 = load [27 x i32]*, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    %1 = bitcast [27 x i32]* %0 to <27 x i32>*
+  // CHECK-NEXT:    %2 = load <27 x i32>, <27 x i32>* %1, align 4
+  // CHECK-NEXT:    %3 = load i32, i32* %i.addr, align 4
+  // CHECK-NEXT:    %4 = insertelement <27 x i32> %2, i32 %3, i32 13
+  // CHECK-NEXT:    %5 = load [27 x i32]*, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    %6 = bitcast [27 x i32]* %5 to <27 x i32>*
+  // CHECK-NEXT:    store <27 x i32> %4, <27 x i32>* %6, align 4
+  // CHECK-NEXT:   ret void
+}
+
+template <typename EltTy, unsigned Rows, unsigned Columns>
+struct MyMatrix {
+  using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns)));
+
+  matrix_t value;
+};
+
+template <typename EltTy, unsigned Rows, unsigned Columns>
+void insert(MyMatrix<EltTy, Rows, Columns> &Mat, EltTy e) {
+  Mat.value = __builtin_matrix_insert(Mat.value, 1u, 0u, e);
+}
+
+void test_template(unsigned *Ptr1, unsigned E1, float *Ptr2, float E2) {
+
+  // CHECK-LABEL: define void @_Z13test_templatePjjPff(i32* %Ptr1, i32 %E1, float* %Ptr2, float %E2)
+  // CHECK-NEXT:  entry:
+  // CHECK-NEXT:    %Ptr1.addr = alloca i32*, align 8
+  // CHECK-NEXT:    %E1.addr = alloca i32, align 4
+  // CHECK-NEXT:    %Ptr2.addr = alloca float*, align 8
+  // CHECK-NEXT:    %E2.addr = alloca float, align 4
+  // CHECK-NEXT:    %Mat1 = alloca %struct.MyMatrix, align 4
+  // CHECK-NEXT:    %Mat2 = alloca %struct.MyMatrix.0, align 4
+  // CHECK-NEXT:    store i32* %Ptr1, i32** %Ptr1.addr, align 8
+  // CHECK-NEXT:    store i32 %E1, i32* %E1.addr, align 4
+  // CHECK-NEXT:    store float* %Ptr2, float** %Ptr2.addr, align 8
+  // CHECK-NEXT:    store float %E2, float* %E2.addr, align 4
+  // CHECK-NEXT:    %0 = load i32*, i32** %Ptr1.addr, align 8
+  // CHECK-NEXT:    %1 = bitcast i32* %0 to [4 x i32]*
+  // CHECK-NEXT:    %2 = bitcast [4 x i32]* %1 to <4 x i32>*
+  // CHECK-NEXT:    %3 = load <4 x i32>, <4 x i32>* %2, align 4
+  // CHECK-NEXT:    %value = getelementptr inbounds %struct.MyMatrix, %struct.MyMatrix* %Mat1, i32 0, i32 0
+  // CHECK-NEXT:    %4 = bitcast [4 x i32]* %value to <4 x i32>*
+  // CHECK-NEXT:    store <4 x i32> %3, <4 x i32>* %4, align 4
+  // CHECK-NEXT:    %5 = load i32, i32* %E1.addr, align 4
+  // CHECK-NEXT:    call void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_(%struct.MyMatrix* dereferenceable(16) %Mat1, i32 %5)
+  // CHECK-NEXT:    %6 = load float*, float** %Ptr2.addr, align 8
+  // CHECK-NEXT:    %7 = bitcast float* %6 to [24 x float]*
+  // CHECK-NEXT:    %8 = bitcast [24 x float]* %7 to <24 x float>*
+  // CHECK-NEXT:    %9 = load <24 x float>, <24 x float>* %8, align 4
+  // CHECK-NEXT:    %value1 = getelementptr inbounds %struct.MyMatrix.0, %struct.MyMatrix.0* %Mat2, i32 0, i32 0
+  // CHECK-NEXT:    %10 = bitcast [24 x float]* %value1 to <24 x float>*
+  // CHECK-NEXT:    store <24 x float> %9, <24 x float>* %10, align 4
+  // CHECK-NEXT:    %11 = load float, float* %E2.addr, align 4
+  // CHECK-NEXT:    call void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_(%struct.MyMatrix.0* dereferenceable(96) %Mat2, float %11)
+  // CHECK-NEXT:    ret void
+
+  // CHECK-LABEL: define linkonce_odr void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_(%struct.MyMatrix* dereferenceable(16) %Mat, i32 %e)
+  // CHECK-NEXT:  entry:
+  // CHECK-NEXT:    %Mat.addr = alloca %struct.MyMatrix*, align 8
+  // CHECK-NEXT:    %e.addr = alloca i32, align 4
+  // CHECK-NEXT:    store %struct.MyMatrix* %Mat, %struct.MyMatrix** %Mat.addr, align 8
+  // CHECK-NEXT:    store i32 %e, i32* %e.addr, align 4
+  // CHECK-NEXT:    %0 = load %struct.MyMatrix*, %struct.MyMatrix** %Mat.addr, align 8
+  // CHECK-NEXT:    %value = getelementptr inbounds %struct.MyMatrix, %struct.MyMatrix* %0, i32 0, i32 0
+  // CHECK-NEXT:    %1 = bitcast [4 x i32]* %value to <4 x i32>*
+  // CHECK-NEXT:    %2 = load <4 x i32>, <4 x i32>* %1, align 4
+  // CHECK-NEXT:    %3 = load i32, i32* %e.addr, align 4
+  // CHECK-NEXT:    %4 = insertelement <4 x i32> %2, i32 %3, i32 1
+  // CHECK-NEXT:    %5 = load %struct.MyMatrix*, %struct.MyMatrix** %Mat.addr, align 8
+  // CHECK-NEXT:    %value1 = getelementptr inbounds %struct.MyMatrix, %struct.MyMatrix* %5, i32 0, i32 0
+  // CHECK-NEXT:    %6 = bitcast [4 x i32]* %value1 to <4 x i32>*
+  // CHECK-NEXT:    store <4 x i32> %4, <4 x i32>* %6, align 4
+  // CHECK-NEXT:    ret void
+
+  // CHECK-LABEL: define linkonce_odr void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_(%struct.MyMatrix.0* dereferenceable(96) %Mat, float %e)
+  // CHECK-NEXT:  entry:
+  // CHECK-NEXT:    %Mat.addr = alloca %struct.MyMatrix.0*, align 8
+  // CHECK-NEXT:    %e.addr = alloca float, align 4
+  // CHECK-NEXT:    store %struct.MyMatrix.0* %Mat, %struct.MyMatrix.0** %Mat.addr, align 8
+  // CHECK-NEXT:    store float %e, float* %e.addr, align 4
+  // CHECK-NEXT:    %0 = load %struct.MyMatrix.0*, %struct.MyMatrix.0** %Mat.addr, align 8
+  // CHECK-NEXT:    %value = getelementptr inbounds %struct.MyMatrix.0, %struct.MyMatrix.0* %0, i32 0, i32 0
+  // CHECK-NEXT:    %1 = bitcast [24 x float]* %value to <24 x float>*
+  // CHECK-NEXT:    %2 = load <24 x float>, <24 x float>* %1, align 4
+  // CHECK-NEXT:    %3 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %4 = insertelement <24 x float> %2, float %3, i32 1
+  // CHECK-NEXT:    %5 = load %struct.MyMatrix.0*, %struct.MyMatrix.0** %Mat.addr, align 8
+  // CHECK-NEXT:    %value1 = getelementptr inbounds %struct.MyMatrix.0, %struct.MyMatrix.0* %5, i32 0, i32 0
+  // CHECK-NEXT:    %6 = bitcast [24 x float]* %value1 to <24 x float>*
+  // CHECK-NEXT:    store <24 x float> %4, <24 x float>* %6, align 4
+  // CHECK-NEXT:    ret void
+
+  MyMatrix<unsigned, 2, 2> Mat1;
+  Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1);
+  insert(Mat1, E1);
+
+  MyMatrix<float, 3, 8> Mat2;
+  Mat2.value = *((decltype(Mat2)::matrix_t *)Ptr2);
+  insert(Mat2, E2);
+}
Index: clang/test/CodeGen/builtin-matrix.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/builtin-matrix.c
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+typedef double dx5x5_t __attribute__((matrix_type(5, 5)));
+typedef float fx2x3_t __attribute__((matrix_type(2, 3)));
+
+// Check that we can use __builtin_matrix_insert on different floating point
+// matrixes and
+void insert_fp(dx5x5_t a, double d, fx2x3_t b, float e) {
+  // CHECK-LABEL: @insert_fp(
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT:    %a.addr = alloca [25 x double], align 8
+  // CHECK-NEXT:    %d.addr = alloca double, align 8
+  // CHECK-NEXT:    %b.addr = alloca [6 x float], align 4
+  // CHECK-NEXT:    %e.addr = alloca float, align 4
+  // CHECK-NEXT:    %0 = bitcast [25 x double]* %a.addr to <25 x double>*
+  // CHECK-NEXT:    store <25 x double> %a, <25 x double>* %0, align 8
+  // CHECK-NEXT:    store double %d, double* %d.addr, align 8
+  // CHECK-NEXT:    %1 = bitcast [6 x float]* %b.addr to <6 x float>*
+  // CHECK-NEXT:    store <6 x float> %b, <6 x float>* %1, align 4
+  // CHECK-NEXT:    store float %e, float* %e.addr, align 4
+  // CHECK-NEXT:    %2 = load <25 x double>, <25 x double>* %0, align 8
+  // CHECK-NEXT:    %3 = load double, double* %d.addr, align 8
+  // CHECK-NEXT:    %4 = insertelement <25 x double> %2, double %3, i32 5
+  // CHECK-NEXT:    store <25 x double> %4, <25 x double>* %0, align 8
+  // CHECK-NEXT:    %5 = load <6 x float>, <6 x float>* %1, align 4
+  // CHECK-NEXT:    %6 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %7 = insertelement <6 x float> %5, float %6, i32 1
+  // CHECK-NEXT:    store <6 x float> %7, <6 x float>* %1, align 4
+  // CHECK-NEXT:    %8 = load <25 x double>, <25 x double>* %0, align 8
+  // CHECK-NEXT:    %9 = load double, double* %d.addr, align 8
+  // CHECK-NEXT:    %10 = insertelement <25 x double> %8, double %9, i32 1
+  // CHECK-NEXT:    store <25 x double> %10, <25 x double>* %0, align 8
+  // CHECK-NEXT:    %11 = load <6 x float>, <6 x float>* %1, align 4
+  // CHECK-NEXT:    %12 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %13 = insertelement <6 x float> %11, float %12, i32 3
+  // CHECK-NEXT:    store <6 x float> %13, <6 x float>* %1, align 4
+  // CHECK-NEXT:   ret void
+
+  a = __builtin_matrix_insert(a, 0u, 1u, d);
+  b = __builtin_matrix_insert(b, 1u, 0u, e);
+  a = __builtin_matrix_insert(a, 1u, 0u, d);
+  b = __builtin_matrix_insert(b, 1u, 1u, e);
+}
+
+// Check that we can can use __builtin_matrix_insert on integer matrixes.
+typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
+void insert_int(ix9x3_t a, int i) {
+  // CHECK-LABEL: @insert_int(
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT:   %a.addr = alloca [27 x i32], align 4
+  // CHECK-NEXT:   %i.addr = alloca i32, align 4
+  // CHECK-NEXT:   %0 = bitcast [27 x i32]* %a.addr to <27 x i32>*
+  // CHECK-NEXT:   store <27 x i32> %a, <27 x i32>* %0, align 4
+  // CHECK-NEXT:   store i32 %i, i32* %i.addr, align 4
+  // CHECK-NEXT:   %1 = load <27 x i32>, <27 x i32>* %0, align 4
+  // CHECK-NEXT:   %2 = load i32, i32* %i.addr, align 4
+  // CHECK-NEXT:   %3 = insertelement <27 x i32> %1, i32 %2, i32 13
+  // CHECK-NEXT:   store <27 x i32> %3, <27 x i32>* %0, align 4
+  // CHECK-NEXT:   ret void
+
+  a = __builtin_matrix_insert(a, 4u, 1u, i);
+}
+
+// Check that we can can use __builtin_matrix_insert on FP and integer
+// matrixes.
+typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
+void insert_int_fp(ix9x3_t *a, int i, fx2x3_t b, float e) {
+  // CHECK-LABEL: @insert_int_fp(
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT:    %a.addr = alloca [27 x i32]*, align 8
+  // CHECK-NEXT:    %i.addr = alloca i32, align 4
+  // CHECK-NEXT:    %b.addr = alloca [6 x float], align 4
+  // CHECK-NEXT:    %e.addr = alloca float, align 4
+  // CHECK-NEXT:    store [27 x i32]* %a, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    store i32 %i, i32* %i.addr, align 4
+  // CHECK-NEXT:    %0 = bitcast [6 x float]* %b.addr to <6 x float>*
+  // CHECK-NEXT:    store <6 x float> %b, <6 x float>* %0, align 4
+  // CHECK-NEXT:    store float %e, float* %e.addr, align 4
+  // CHECK-NEXT:    %1 = load [27 x i32]*, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    %2 = bitcast [27 x i32]* %1 to <27 x i32>*
+  // CHECK-NEXT:    %3 = load <27 x i32>, <27 x i32>* %2, align 4
+  // CHECK-NEXT:    %4 = load i32, i32* %i.addr, align 4
+  // CHECK-NEXT:    %5 = insertelement <27 x i32> %3, i32 %4, i32 13
+  // CHECK-NEXT:    %6 = load [27 x i32]*, [27 x i32]** %a.addr, align 8
+  // CHECK-NEXT:    %7 = bitcast [27 x i32]* %6 to <27 x i32>*
+  // CHECK-NEXT:    store <27 x i32> %5, <27 x i32>* %7, align 4
+  // CHECK-NEXT:    %8 = load <6 x float>, <6 x float>* %0, align 4
+  // CHECK-NEXT:    %9 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %10 = insertelement <6 x float> %8, float %9, i32 3
+  // CHECK-NEXT:    store <6 x float> %10, <6 x float>* %0, align 4
+  // CHECK-NEXT: ret void
+
+  *a = __builtin_matrix_insert(*a, 4u, 1u, i);
+  b = __builtin_matrix_insert(b, 1u, 1u, e);
+}
+
+// Check that we can use overloaded versions of __builtin_matrix_insert 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_dimensions(dx3x3_t a, double i, fx3x3_t b, float e) {
+  // CHECK-LABEL: @insert_matching_dimensions(
+  // CHECK-NEXT:  entry:
+  // CHECK-NEXT:    %a.addr = alloca [9 x double], align 8
+  // CHECK-NEXT:    %i.addr = alloca double, align 8
+  // CHECK-NEXT:    %b.addr = alloca [9 x float], align 4
+  // CHECK-NEXT:    %e.addr = alloca float, align 4
+  // CHECK-NEXT:    %0 = bitcast [9 x double]* %a.addr to <9 x double>*
+  // CHECK-NEXT:    store <9 x double> %a, <9 x double>* %0, align 8
+  // CHECK-NEXT:    store double %i, double* %i.addr, align 8
+  // CHECK-NEXT:    %1 = bitcast [9 x float]* %b.addr to <9 x float>*
+  // CHECK-NEXT:    store <9 x float> %b, <9 x float>* %1, align 4
+  // CHECK-NEXT:    store float %e, float* %e.addr, align 4
+  // CHECK-NEXT:    %2 = load <9 x double>, <9 x double>* %0, align 8
+  // CHECK-NEXT:    %3 = load double, double* %i.addr, align 8
+  // CHECK-NEXT:    %4 = insertelement <9 x double> %2, double %3, i32 5
+  // CHECK-NEXT:    store <9 x double> %4, <9 x double>* %0, align 8
+  // CHECK-NEXT:    %5 = load <9 x float>, <9 x float>* %1, align 4
+  // CHECK-NEXT:    %6 = load float, float* %e.addr, align 4
+  // CHECK-NEXT:    %7 = insertelement <9 x float> %5, float %6, i32 7
+  // CHECK-NEXT:    store <9 x float> %7, <9 x float>* %1, align 4
+  // CHECK-NEXT:   ret void
+
+  a = __builtin_matrix_insert(a, 2u, 1u, i);
+  b = __builtin_matrix_insert(b, 1u, 2u, e);
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -1522,6 +1522,19 @@
     if (SemaBuiltinOSLogFormat(TheCall))
       return ExprError();
     break;
+
+  case Builtin::BI__builtin_matrix_insert:
+    if (!getLangOpts().EnableMatrix) {
+      Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
+      return ExprError();
+    }
+
+    switch (BuiltinID) {
+    case Builtin::BI__builtin_matrix_insert:
+      return SemaBuiltinMatrixInsertOverload(TheCall, TheCallResult);
+    default:
+      llvm_unreachable("All matrix builtins should be handled here!");
+    }
   }
 
   // Since the target specific builtins for each arch overlap, only check those
@@ -14955,3 +14968,121 @@
       rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
                      _2, _3, _4));
 }
+
+//
+/// \brief Uses the call to create an overloaded matrix insertion decl
+///
+/// SemaBuiltinMatrixInsertOverload - Handle __builtin_matrix_insert.
+/// This builtin is declared as taking everything and returning nothing,
+/// so all inputs will need to be checked to ensure that things are correct.
+/// This function should take a matrix, a row and column to insert to, and
+/// a value (same type as a matrix element) that is being inserted.
+/// It then returns the matrix with that element inserted.
+ExprResult Sema::SemaBuiltinMatrixInsertOverload(CallExpr *TheCall,
+                                                 ExprResult CallResult) {
+  // This function take four parameters
+  // Matrix -- type matrix (row, column, elt)
+  // Row    -- type integer (constant int for now)
+  // Column -- type integer (constant int for now)
+  // Value  -- type same as elt type
+  //
+  // Returns: Matrix with the value inserted at that coordinate
+
+  // First part of this method focuses on handling the creation of the
+  // overloaded function type Second part focuses on setting up the call with
+  // the correct return type and parameters
+
+  // This builtin should have four parameters passed to it
+  if (checkArgCount(*this, TheCall, 4))
+    return ExprError();
+
+  Expr *Callee = TheCall->getCallee();
+  DeclRefExpr *DRE = cast<DeclRefExpr>(Callee->IgnoreParenCasts());
+  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+
+  // Some typechecking to ensure that the parameters are correct
+  Expr *MatArg = TheCall->getArg(0);
+  Expr *RowArg = TheCall->getArg(1);
+  Expr *ColArg = TheCall->getArg(2);
+  Expr *ValArg = TheCall->getArg(3);
+  {
+    QualType MTy = MatArg->getType();
+    QualType RTy = RowArg->getType();
+    QualType CTy = RowArg->getType();
+    QualType VTy = ValArg->getType();
+
+    bool ArgError = false;
+    if (!MTy->isMatrixType()) {
+      Diag(MatArg->getBeginLoc(), diag::err_builtin_matrix_arg) << 0;
+      ArgError = true;
+    }
+    if (!RTy->isUnsignedIntegerType()) {
+      Diag(RowArg->getBeginLoc(), diag::err_builtin_matrix_scalar_int_arg)
+          << 0 << 0;
+      ArgError = true;
+    }
+    if (!CTy->isUnsignedIntegerType()) {
+      Diag(ColArg->getBeginLoc(), diag::err_builtin_matrix_scalar_int_arg)
+          << 1 << 0;
+      ArgError = true;
+    }
+    if (ArgError)
+      return ExprError();
+
+    // Either the value type being inserted is the same as the matrix element
+    // type or it needs to be something that can be casted to the matrix element
+    // type.
+    QualType EltTy = cast<MatrixType>(MTy.getCanonicalType())->getElementType();
+
+    // We'll try to allow Itegral to floating point conversions.
+    // Otherwise it's an error!
+    if (EltTy != VTy) {
+      ExprResult TypeCastRes = ImplicitCastExpr::Create(
+          Context, EltTy, CK_IntegralToFloating, ValArg, nullptr, VK_RValue);
+
+      if (TypeCastRes.isInvalid()) {
+        Diag(MatArg->getBeginLoc(),
+             diag::err_builtin_matrix_implicit_cast_error)
+            << EltTy << VTy;
+        return ExprError();
+      }
+      ValArg = TypeCastRes.get();
+      TheCall->setArg(3, ValArg);
+    }
+  }
+
+  // Create new function prototype
+
+  // Convert l-value matrix input to r-value if necessary
+  if (!MatArg->isRValue()) {
+    ExprResult Res =
+        ImplicitCastExpr::Create(Context, MatArg->getType(), CK_LValueToRValue,
+                                 MatArg, nullptr, VK_RValue);
+    assert(!Res.isInvalid() && "Matrix Cast failed");
+    TheCall->setArg(0, Res.get());
+  }
+
+  llvm::SmallVector<QualType, 4> ParameterTypes = {
+      MatArg->getType().getCanonicalType(), RowArg->getType(),
+      ColArg->getType(), ValArg->getType()};
+
+  // Create a new DeclRefExpr to refer to the new decl.
+  DeclRefExpr *NewDRE = DeclRefExpr::Create(
+      Context, DRE->getQualifierLoc(), SourceLocation(), FDecl,
+      /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
+      DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
+
+  // Set the callee in the CallExpr.
+  // FIXME: This loses syntactic information.
+  QualType CalleePtrTy = Context.getPointerType(FDecl->getType());
+  ExprResult PromotedCall =
+      ImpCastExprToType(NewDRE, CalleePtrTy, CK_BuiltinFnToFnPtr);
+  TheCall->setCallee(PromotedCall.get());
+
+  // Change the result type of the call to match the original value type. This
+  // is arbitrary, but the codegen for these builtins ins design to handle it
+  // gracefully.
+  TheCall->setType(MatArg->getType());
+
+  return CallResult;
+}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -43,6 +43,7 @@
 #include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/IntrinsicsX86.h"
 #include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/MatrixBuilder.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/TargetParser.h"
@@ -1600,6 +1601,10 @@
   return RValue::get(Builder.CreateCall(F, { Src, Src, ShiftAmt }));
 }
 
+const clang::MatrixType *getMatrixTy(QualType Ty) {
+  return cast<clang::MatrixType>(Ty.getCanonicalType());
+};
+
 RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                         const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -2336,6 +2341,22 @@
     V = Builder.CreateFCmpUNO(V, V, "cmp");
     return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
   }
+  case Builtin::BI__builtin_matrix_insert: {
+    MatrixBuilder<CGBuilderTy> MB(Builder);
+    Value *MatValue = EmitScalarExpr(E->getArg(0));
+    const MatrixType *MatrixTy = getMatrixTy(E->getArg(0)->getType());
+    Value *RowValue = EmitScalarExpr(E->getArg(1));
+    Value *ColValue = EmitScalarExpr(E->getArg(2));
+    Value *ValValue = EmitScalarExpr(E->getArg(3));
+    // Check that the ValValue and the Matrix value match, or do an implict cast
+    // if they don't
+    assert(ValValue->getType() ==
+               cast<SequentialType>(MatValue->getType())->getElementType() &&
+           "Inserted type must match matrix data type");
+
+    return RValue::get(MB.CreateMatrixInsert(MatValue, ValValue, RowValue,
+                                             ColValue, MatrixTy->getNumRows()));
+  }
 
   case Builtin::BIfinite:
   case Builtin::BI__finite:
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -11562,6 +11562,11 @@
                                 int ArgNum, unsigned ExpectedFieldNum,
                                 bool AllowName);
   bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall);
+
+  // Matrix Builtin intrinsic handling.
+  ExprResult SemaBuiltinMatrixInsertOverload(CallExpr *TheCall,
+                                             ExprResult CallResult);
+
 public:
   enum FormatStringType {
     FST_Scanf,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10243,6 +10243,15 @@
 def err_builtin_matrix_disabled: Error<
   "Builtin matrix support is disabled. Pass -fenable-matrix to enable it.">;
 
+def err_builtin_matrix_arg: Error<
+  "%select{First|Second}0 argument must be a matrix">;
+
+def err_builtin_matrix_scalar_int_arg: Error<
+  "%select{Row|Column|Offset|Stride}0 argument must be %select{an unsigned integer|a constant unsigned integer expression}1">;
+
+def err_builtin_matrix_implicit_cast_error: Error<
+  "Implicit cast to from %0 to %1 failed">;
+
 def err_preserve_field_info_not_field : Error<
   "__builtin_preserve_field_info argument %0 not a field access">;
 def err_preserve_field_info_not_const: Error<
Index: clang/include/clang/Basic/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -573,6 +573,8 @@
 BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn")
 BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
 
+BUILTIN(__builtin_matrix_insert,  "v.", "nt")
+
 // "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
 // non-suffixed version of these (which has a bogus type) and transforms them to
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D72283: [Ma... Florian Hahn via Phabricator via cfe-commits

Reply via email to