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
83
84
85
86
//! 2D convolution sub-dialect.
//!
//! ROADMAP H3 - Im2col/direct-conv decision by shape and memory
//! budget. Both ops are one algorithm: `im2col::patch_taps` owns the
//! zero-padded 3x3 patch of a pixel, `im2col_3x3` writes those patches into an
//! `[H*W, 9]` matrix for a caller-supplied gemm, and `conv2d_3x3_direct`
//! contracts the same patch against the kernel in place.
//!
//! ## Why the patch algebra is the owner
//!
//! Convolution's ground truth is the canonical sum
//! `out[y, x] = sum_{ky=0..3, kx=0..3} input[y+ky-1, x+kx-1] * kernel[ky, kx]`.
//! Im2col's contribution is to reshape that sum into a matmul so a tiled /
//! vectorised gemm can carry it, at the cost of materialising the patch
//! matrix. Sharing the patch definition makes the parity gate "im2col output
//! contracted with the kernel equals `conv2d_3x3_direct`" structural rather
//! than a coincidence between two hand-written walks.
pub use conv2d_3x3_direct;
pub use im2col_3x3;
/// Decision wrapper: choose the fused patch contraction in
/// `conv2d_3x3_direct` vs a materialised `im2col_3x3` matrix handed to a
/// tiled gemm, based on image area. Crossover threshold derived from a simple
/// memory vs compute tradeoff: im2col materialises an `H·W·9` patch matrix
/// (vs `H·W` for the input), so it pays an extra `8·H·W·sizeof(f32)`
/// of memory traffic. The matmul tile/vectorisation win recovers
/// that cost once the per-pixel work amortises across enough output
/// pixels - empirically the crossover is around 64x64 (4096
/// pixels). Below that threshold the fused form wins.
///
/// Returns the same Program as `conv2d_3x3_direct(input, kernel,
/// output, h, w)` regardless of the decision; the choice is
/// expressed via the Region's `generator` ident so a downstream
/// pass can route the dispatch differently if the runtime chooses
/// to honour the hint.
///
/// # Errors
///
/// Returns `Err` when `h * w` overflows `u32`.