| 89 | } // namespace |
| 90 | |
| 91 | void MakeBlockMap(int rows, int cols, int depth, int kernel_rows, |
| 92 | int kernel_cols, int lhs_scalar_size, int rhs_scalar_size, |
| 93 | int cache_friendly_traversal_threshold, BlockMap* block_map) { |
| 94 | gemmlowp::ScopedProfilingLabel label("MakeBlockMap"); |
| 95 | RUY_DCHECK_GE(rows, kernel_rows); |
| 96 | RUY_DCHECK_GE(cols, kernel_cols); |
| 97 | RUY_DCHECK_EQ(rows % kernel_rows, 0); |
| 98 | RUY_DCHECK_EQ(cols % kernel_cols, 0); |
| 99 | |
| 100 | block_map->traversal_order = BlockMapTraversalOrder::kLinear; |
| 101 | if (RUY_OPT_ENABLED(RUY_OPT_FRACTAL) && |
| 102 | (rows * lhs_scalar_size + cols * rhs_scalar_size) * depth >= |
| 103 | cache_friendly_traversal_threshold) { |
| 104 | block_map->traversal_order = RUY_OPT_ENABLED(RUY_OPT_FRACTAL_U) |
| 105 | ? BlockMapTraversalOrder::kFractalU |
| 106 | : BlockMapTraversalOrder::kFractalZ; |
| 107 | } |
| 108 | |
| 109 | // See the comment on BlockMap in block_map.h. |
| 110 | // The destination matrix shape (rows x cols) is to be subdivided into a |
| 111 | // square (N x N) grid of blocks, whose shapes must be multiples of the |
| 112 | // kernel block shape (kernel_rows x kernel_cols). |
| 113 | // Inside each of these N*N blocks, we may have one further level of |
| 114 | // subdivision either along rows or along cols but not both, to handle |
| 115 | // better the highly rectangular cases. That is what we call |
| 116 | // 'rectangularness'. This extra level of subdivision is into |
| 117 | // (1 << rows_rectangularness_log2) blocks along rows dimension, or into |
| 118 | // (1 << cols_rectangularness_log2) blocks along cols dimension. |
| 119 | int rows_rectangularness_log2 = 0; |
| 120 | int cols_rectangularness_log2 = 0; |
| 121 | // In order to compute these rectangularness values, we need to divide |
| 122 | // the destination matrix's aspect ratio, |
| 123 | // rows / cols |
| 124 | // by the kernel block's aspect ratio, |
| 125 | // kernel_block_rows / kernel_block_cols. |
| 126 | // The quotient of these two quotients simplifies to |
| 127 | // (rows * kernel_cols) / (cols * kernel_rows) |
| 128 | // Whence the introduction of the following products: |
| 129 | const int rows_times_kernel_cols = rows * kernel_cols; |
| 130 | const int cols_times_kernel_rows = cols * kernel_rows; |
| 131 | if (rows_times_kernel_cols > cols_times_kernel_rows) { |
| 132 | rows_rectangularness_log2 = |
| 133 | floor_log2_quotient(rows_times_kernel_cols, cols_times_kernel_rows); |
| 134 | // Sanity check that we did not over-estimate rows_rectangularness_log2. |
| 135 | RUY_DCHECK_GE(rows_times_kernel_cols >> rows_rectangularness_log2, |
| 136 | cols_times_kernel_rows); |
| 137 | } else if (cols_times_kernel_rows > rows_times_kernel_cols) { |
| 138 | cols_rectangularness_log2 = |
| 139 | floor_log2_quotient(cols_times_kernel_rows, rows_times_kernel_cols); |
| 140 | // Sanity check that we did not over-estimate cols_rectangularness_log2. |
| 141 | RUY_DCHECK_GE(cols_times_kernel_rows >> cols_rectangularness_log2, |
| 142 | rows_times_kernel_cols); |
| 143 | } |
| 144 | |
| 145 | RUY_DCHECK(!rows_rectangularness_log2 || !cols_rectangularness_log2); |
| 146 | |
| 147 | const int size = std::min(rows, cols); |
| 148 | const int size_floor_log2 = floor_log2(size); |
no test coverage detected