1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Logical and padded shapes.
//!
//! Every lattice tracks two shapes at once: the *logical* shape the user cares
//! about, and the *padded* shape the hardware actually stores. Keeping both lets
//! the lattice mask away the padding when it converts back to a dense view.
use crate::geometry::Geometry;
/// A two-dimensional shape together with the padding implied by a [`Geometry`].
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Shape {
/// The number of rows the user asked for.
pub rows: usize,
/// The number of columns the user asked for.
pub cols: usize,
/// The row count after padding up to a sublane-tile boundary.
pub padded_rows: usize,
/// The column count after padding up to a lane-tile boundary.
pub padded_cols: usize,
}
impl Shape {
/// Derive a padded shape from a logical `rows x cols` and a geometry.
pub fn new(rows: usize, cols: usize, geom: &Geometry) -> Self {
Shape {
rows,
cols,
padded_rows: geom.pad_rows(rows),
padded_cols: geom.pad_cols(cols),
}
}
/// Number of logical elements (`rows * cols`).
#[inline]
pub const fn logical_len(&self) -> usize {
self.rows * self.cols
}
/// Number of stored elements after padding (`padded_rows * padded_cols`).
#[inline]
pub const fn padded_len(&self) -> usize {
self.padded_rows * self.padded_cols
}
/// Number of padding elements that exist only to fill out edge tiles.
#[inline]
pub const fn padding_len(&self) -> usize {
self.padded_len() - self.logical_len()
}
/// Fraction of stored elements that are pure padding, in `0.0..=1.0`.
#[inline]
pub fn padding_ratio(&self) -> f64 {
if self.padded_len() == 0 {
0.0
} else {
self.padding_len() as f64 / self.padded_len() as f64
}
}
/// True if the logical shape needs no padding under this geometry.
#[inline]
pub const fn is_exact(&self) -> bool {
self.rows == self.padded_rows && self.cols == self.padded_cols
}
/// True if `(row, col)` falls inside the logical (non-padding) region.
#[inline]
pub const fn contains(&self, row: usize, col: usize) -> bool {
row < self.rows && col < self.cols
}
}
impl core::fmt::Debug for Shape {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Shape {{ {}x{} logical -> {}x{} padded }}",
self.rows, self.cols, self.padded_rows, self.padded_cols
)
}
}