[gcc r17-2877] Inline MATMUL(TRANSPOSE(A),B) for rank 1 B.

Thomas Koenig via Gcc-cvs <[email protected]> Sat, 1 Aug 2026 17:11:13 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:f0241f047bb0858964119e3aaad2bbd61e7d757f

commit r17-2877-gf0241f047bb0858964119e3aaad2bbd61e7d757f
Author: Thomas Koenig <[email protected]>
Date:   Sat Aug 1 10:47:27 2026 +0200

    Inline MATMUL(TRANSPOSE(A),B) for rank 1 B.
    
    This patch implements inlining MATMUL(TRANSPOSE(A),B).  For ordering
    of the loops, this is an unpleasant problem because of the dependence
    of c(i) on the previous iteration, but gcc was able to fully unroll
    the loops at least for small sizes, and the version in the patch generated
    better code.
    
    gcc/fortran/ChangeLog:
    
            * frontend-passes.cc (enum matrix_case): Add case A2TB1.
            (matmul_lhs_realloc): Add condition for reallocation and
            size checks.
            (inline_matmul_assign): Handle A2TB1.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/inline_matmul_29.f90: New test.

Diff:
---
 gcc/fortran/frontend-passes.cc                 | 62 +++++++++++++++++++++++++-
 gcc/testsuite/gfortran.dg/inline_matmul_29.f90 | 28 ++++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 8abe07e8f59f..f32d055c0619 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -133,7 +133,7 @@ static int var_num = 1;
 
 /* What sort of matrix we are dealing with when inlining MATMUL.  */
 
-enum matrix_case { none=0, A2B2, A2B1, A1B2, A2B2T, A2TB2, A2TB2T };
+enum matrix_case { none=0, A2B2, A2B1, A1B2, A2B2T, A2TB2, A2TB2T, A2TB1 };
 
 /* Keep track of the number of expressions we have inserted so far
    using create_var.  */
@@ -3572,6 +3572,13 @@ matmul_lhs_realloc (gfc_expr *c, gfc_expr *a, gfc_expr *b,
 				 get_array_inq_function (GFC_ISYM_SIZE, a, 1));
       break;
 
+    case A2TB1:
+      ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 2);
+      cond = build_logical_expr (INTRINSIC_NE,
+				 get_array_inq_function (GFC_ISYM_SIZE, c, 1),
+				 get_array_inq_function (GFC_ISYM_SIZE, a, 2));
+      break;
+
     case A1B2:
       ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, b, 2);
       cond = build_logical_expr (INTRINSIC_NE,
@@ -4222,6 +4229,8 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 	{
 	  if (matrix_b->rank == 2 && !transpose_b)
 	    m_case = A2TB2;
+	  else if (matrix_b->rank == 1)
+	    m_case = A2TB1;
 	}
       else
 	{
@@ -4376,6 +4385,23 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 	    }
 	  break;
 
+	case A2TB1:
+	  b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
+	  a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
+	  test = runtime_error_ne (b1, a1, B_ERROR_1);
+	  *next_code_point = test;
+	  next_code_point = &test->next;
+
+	  if (!realloc_c)
+	    {
+	      c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
+	      a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
+	      test = runtime_error_ne (c1, a2, C_ERROR_1);
+	      *next_code_point = test;
+	      next_code_point = &test->next;
+	    }
+	  break;
+
 	case A1B2:
 
 	  b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
@@ -4619,6 +4645,40 @@ inline_matmul_assign (gfc_code **c, int *walk_subtrees,
 
       break;
 
+    case A2TB1:
+
+      /* Ordering here is
+	   do i=1,size(a,2)
+	     do j=1,size(b,1)
+	       c(i) = c(i) + a(j,i) * b(j)
+	     end do
+	   end do
+      where i is var_1 and j is var_2.  */
+
+      u1 = get_size_m1 (matrix_a, 2);
+      u2 = get_size_m1 (matrix_b, 1);
+
+      do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
+      do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
+
+      do_1->block->next = do_2;
+      do_2->block->next = assign_matmul;
+
+      var_1 = do_1->ext.iterator->var;
+      var_2 = do_2->ext.iterator->var;
+
+      list[0] = var_1;
+      cscalar = scalarized_expr (co->expr1, list, 1);
+
+      list[0] = var_2;
+      list[1] = var_1;
+      ascalar = scalarized_expr (matrix_a, list, 2);
+
+      list[0] = var_2;
+      bscalar = scalarized_expr (matrix_b, list, 1);
+
+      break;
+
     case A1B2:
       u1 = get_size_m1 (matrix_b, 2);
       u2 = get_size_m1 (matrix_a, 1);
diff --git a/gcc/testsuite/gfortran.dg/inline_matmul_29.f90 b/gcc/testsuite/gfortran.dg/inline_matmul_29.f90
new file mode 100644
index 000000000000..9372a0524d4b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/inline_matmul_29.f90
@@ -0,0 +1,28 @@
+! { dg-do run }
+! { dg-additional-options "-ffrontend-optimize -fdump-tree-original" }
+
+PROGRAM memain
+  implicit none
+  REAL(8), DIMENSION(3) :: b
+  REAL(8), DIMENSION(3,2) :: A
+  real(8), dimension(:), allocatable :: y
+  real(8), dimension(2) :: z
+  integer :: i, j
+
+  A(:,1) = [1,-2,3]
+  A(:,2) = [-4,5,6]
+    
+  b =  [7,-8,9]
+  y = matmul(transpose(A),b)
+  z = 0
+  do i=1,2
+    do j=1,3
+       z(i) = z(i) + a(j,i) * b(j)
+     end do
+  end do
+  if (size(z,1) /= size(y,1)) stop 1
+  if (any(abs(z - y) > 1e-12)) stop 2
+    
+END PROGRAM memain
+! { dg-final { scan-tree-dump-not "_gfortran_matmul_r8" "original" } }
+! { dg-final { scan-tree-dump-not "_gfortran_transpose_r8" "original" } }