/home/noah/src/trueno/src/tiling/calculator.rs
Line | Count | Source |
1 | | //! TCB index calculation utilities. |
2 | | |
3 | | use super::config::TilingConfig; |
4 | | |
5 | | /// Index calculator for hierarchical tiling |
6 | | /// |
7 | | /// Converts between linear indices and (row, col) coordinates at each tiling level. |
8 | | #[derive(Debug, Clone)] |
9 | | pub struct TcbIndexCalculator { |
10 | | /// Tiling configuration |
11 | | pub config: TilingConfig, |
12 | | /// Problem dimensions |
13 | | problem_m: u32, |
14 | | problem_n: u32, |
15 | | problem_k: u32, |
16 | | } |
17 | | |
18 | | impl TcbIndexCalculator { |
19 | | /// Create a new index calculator for the given problem size |
20 | | #[must_use] |
21 | 0 | pub fn new(config: TilingConfig, m: u32, n: u32, k: u32) -> Self { |
22 | 0 | Self { |
23 | 0 | config, |
24 | 0 | problem_m: m, |
25 | 0 | problem_n: n, |
26 | 0 | problem_k: k, |
27 | 0 | } |
28 | 0 | } |
29 | | |
30 | | /// Get macro-tile offset for a given block index |
31 | | /// |
32 | | /// Returns (row_offset, col_offset) in the output matrix. |
33 | | #[must_use] |
34 | 0 | pub fn macro_tile_offset(&self, block_idx: u32) -> (u32, u32) { |
35 | 0 | let tiles_per_row = (self.problem_n + self.config.macro_tile.n - 1) / self.config.macro_tile.n; |
36 | 0 | let row = (block_idx / tiles_per_row) * self.config.macro_tile.m; |
37 | 0 | let col = (block_idx % tiles_per_row) * self.config.macro_tile.n; |
38 | 0 | (row, col) |
39 | 0 | } |
40 | | |
41 | | /// Get midi-tile offset within a macro-tile |
42 | | #[must_use] |
43 | 0 | pub fn midi_tile_offset(&self, midi_idx: u32) -> (u32, u32) { |
44 | 0 | let tiles_per_row = self.config.macro_tile.n / self.config.midi_tile.n; |
45 | 0 | let row = (midi_idx / tiles_per_row) * self.config.midi_tile.m; |
46 | 0 | let col = (midi_idx % tiles_per_row) * self.config.midi_tile.n; |
47 | 0 | (row, col) |
48 | 0 | } |
49 | | |
50 | | /// Get micro-tile offset within a midi-tile |
51 | | #[must_use] |
52 | 0 | pub fn micro_tile_offset(&self, micro_idx: u32) -> (u32, u32) { |
53 | 0 | let tiles_per_row = self.config.midi_tile.n / self.config.micro_tile.n; |
54 | 0 | let row = (micro_idx / tiles_per_row) * self.config.micro_tile.m; |
55 | 0 | let col = (micro_idx % tiles_per_row) * self.config.micro_tile.n; |
56 | 0 | (row, col) |
57 | 0 | } |
58 | | |
59 | | /// Convert block index to linear memory offset |
60 | | /// |
61 | | /// For row-major C matrix with given stride. |
62 | | #[must_use] |
63 | | #[inline] |
64 | 0 | pub fn block_to_linear_offset(&self, block_idx: u32, stride: u32) -> usize { |
65 | 0 | let (row, col) = self.macro_tile_offset(block_idx); |
66 | 0 | (row * stride + col) as usize |
67 | 0 | } |
68 | | |
69 | | /// Calculate A matrix offset for K-dimension blocking |
70 | | #[must_use] |
71 | | #[inline] |
72 | 0 | pub fn a_offset(&self, macro_row: u32, k_block: u32) -> usize { |
73 | 0 | let row = macro_row * self.config.macro_tile.m; |
74 | 0 | let col = k_block * self.config.macro_tile.k; |
75 | 0 | (row * self.problem_k + col) as usize |
76 | 0 | } |
77 | | |
78 | | /// Calculate B matrix offset for K-dimension blocking |
79 | | #[must_use] |
80 | | #[inline] |
81 | 0 | pub fn b_offset(&self, k_block: u32, macro_col: u32) -> usize { |
82 | 0 | let row = k_block * self.config.macro_tile.k; |
83 | 0 | let col = macro_col * self.config.macro_tile.n; |
84 | 0 | (row * self.problem_n + col) as usize |
85 | 0 | } |
86 | | |
87 | | /// Get number of K blocks needed |
88 | | #[must_use] |
89 | 0 | pub fn num_k_blocks(&self) -> u32 { |
90 | 0 | (self.problem_k + self.config.macro_tile.k - 1) / self.config.macro_tile.k |
91 | 0 | } |
92 | | |
93 | | /// Check if this is a boundary tile (may need masking) |
94 | | #[must_use] |
95 | 0 | pub fn is_boundary_tile(&self, block_idx: u32) -> bool { |
96 | 0 | let (row, col) = self.macro_tile_offset(block_idx); |
97 | 0 | row + self.config.macro_tile.m > self.problem_m |
98 | 0 | || col + self.config.macro_tile.n > self.problem_n |
99 | 0 | } |
100 | | |
101 | | /// Get actual tile dimensions (may be smaller at boundaries) |
102 | | #[must_use] |
103 | 0 | pub fn actual_tile_dims(&self, block_idx: u32) -> (u32, u32) { |
104 | 0 | let (row, col) = self.macro_tile_offset(block_idx); |
105 | 0 | let actual_m = (self.problem_m - row).min(self.config.macro_tile.m); |
106 | 0 | let actual_n = (self.problem_n - col).min(self.config.macro_tile.n); |
107 | 0 | (actual_m, actual_n) |
108 | 0 | } |
109 | | } |