Core: Iterate one-packet GEBP row panels inside the column loop

libeigen/eigen!3428

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h
index 160940e..3bebe2a 100644
--- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h
+++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h
@@ -1691,7 +1691,8 @@
   }
 
   //---------- Process 1 * LhsProgress rows at once ----------
-  EIGEN_IF_CONSTEXPR (mr >= 1 * Traits::LhsProgress) {
+  // With a wider mr, at most one row panel is left here.
+  EIGEN_IF_CONSTEXPR (mr > 1 * Traits::LhsProgress) {
     for (Index i = peeled_mc2; i < peeled_mc1; i += LhsProgress) {
       EIGEN_IF_CONSTEXPR (nr >= 8) {
         for (Index j2 = 0; j2 < packet_cols8; j2 += 8) {
@@ -1705,6 +1706,36 @@
         micro_panel(fix<1>, fix<1>, traits, i, j2);
       }
     }
+  } else EIGEN_IF_CONSTEXPR (mr == 1 * Traits::LhsProgress) {
+    // Every row comes here, blocked like the wider panels above: rows inside columns keep the rhs panel in cache
+    // and walk C down its columns.
+    const Index rhs_block1 = sizeof(ResScalar) * mr * nr + depth * nr * sizeof(RhsScalar);
+    const Index lhs_strip1 = depth * sizeof(LhsScalar) * LhsProgress;
+    const Index lhs_avail1 = (lhs_budget > rhs_block1) ? (lhs_budget - rhs_block1) : 0;
+    const Index mc1_range = peeled_mc1 - peeled_mc2;
+    const Index actual_panel_rows = (lhs_avail1 >= mc1_range * depth * static_cast<Index>(sizeof(LhsScalar)))
+                                        ? mc1_range
+                                        : LhsProgress * std::max<Index>(1, lhs_avail1 / lhs_strip1);
+    for (Index i1 = peeled_mc2; i1 < peeled_mc1; i1 += actual_panel_rows) {
+      const Index actual_panel_end = (std::min)(i1 + actual_panel_rows, peeled_mc1);
+      EIGEN_IF_CONSTEXPR (nr >= 8) {
+        for (Index j2 = 0; j2 < packet_cols8; j2 += 8) {
+          for (Index i = i1; i < actual_panel_end; i += LhsProgress) {
+            micro_panel(fix<1>, fix<8>, traits, i, j2);
+          }
+        }
+      }
+      for (Index j2 = packet_cols8; j2 < packet_cols4; j2 += 4) {
+        for (Index i = i1; i < actual_panel_end; i += LhsProgress) {
+          micro_panel(fix<1>, fix<4>, traits, i, j2);
+        }
+      }
+      for (Index j2 = packet_cols4; j2 < cols; j2++) {
+        for (Index i = i1; i < actual_panel_end; i += LhsProgress) {
+          micro_panel(fix<1>, fix<1>, traits, i, j2);
+        }
+      }
+    }
   }
 
   //---------- Process LhsProgressHalf rows at once ----------
diff --git a/benchmarks/Core/bench_gemm.cpp b/benchmarks/Core/bench_gemm.cpp
index ffc6c1e..cb9329a 100644
--- a/benchmarks/Core/bench_gemm.cpp
+++ b/benchmarks/Core/bench_gemm.cpp
@@ -114,9 +114,14 @@
 #define TAIL_PANEL_SIZES \
     ->Args({15, 17, 1024})->Args({17, 15, 1024})->Args({31, 31, 1024}) \
     ->Args({60, 60, 1024})->Args({60, 64, 1024})->Args({64, 60, 1024})->Args({120, 120, 1024})->Args({252, 252, 252})
+
+// Shallow depth: loading and storing c costs about as much as the k multiply-adds, so these measure the order in which
+// gebp's micro panels walk c.
+#define SHALLOW_DEPTH_SIZES \
+    ->ArgsProduct({{256}, {256}, {4, 8, 16}})->Args({1024, 256, 8})->Args({1024, 1024, 4})
 // clang-format on
 
-BENCHMARK(BM_EigenGemm) GEMM_SIZES DEPTH_SWEEP_SIZES TAIL_PANEL_SIZES;
+BENCHMARK(BM_EigenGemm) GEMM_SIZES DEPTH_SWEEP_SIZES TAIL_PANEL_SIZES SHALLOW_DEPTH_SIZES;
 BENCHMARK(BM_EigenGemmRowMajorLhs)->Args({256, 256, 256})->Args({1024, 1024, 1024}) DEPTH_SWEEP_SIZES TAIL_PANEL_SIZES;
 BENCHMARK(BM_EigenGemmRowMajorRhs)
     ->Args({64, 64, 1024})