Skip to content

Add fixed-point IR rewrites before TileArray program replacement - #10

Merged
ShangkunLi merged 2 commits into
mainfrom
feature/add-rewrite-patterns
Oct 16, 2026
Merged

ShangkunLi merged 2 commits into
mainfrom
feature/add-rewrite-patterns

Conversation

@ShangkunLi

Copy link
Copy Markdown
Collaborator

Adds Python IR rewrites before TileArray program replacement at both the Linalg and Affine stages.

  • IRRewritePattern transforms computation IR. Rules repeat until a complete round makes no changes.
  • TileArrayProgramReplacePattern selects TileArray kernel implementations.
  • compile() accepts custom rewrite_patterns and replace_patterns.

A configurable test example rewrites CONV into im2col + matmul. For a length-5 input and three length-3 filters:

input = [a, b, c, d, e]

patches = [[a, b, c],
           [b, c, d],
           [c, d, e]]

output[3,3] += patches[3,3] @ weights[3,3]

The rewrite packs overlapping windows into patches and creates matrix views of the filter and output. Tests compare the rewritten IR with expected IR and cover stride, dilation, dtype, and configurable GEMM dimensions.

@tancheng

Copy link
Copy Markdown
  • explain the diff between rewrite_patterns and replace_patterns?
  • how input and patches become patches and weights? Is it a 1D conv? plz elaborate on the math.

@ShangkunLi

Copy link
Copy Markdown
Collaborator Author
  • explain the diff between rewrite_patterns and replace_patterns?

rewrite_patterns transform the computation IR (e.g., CONV → im2col + matmul). replace_patterns select a TileArray program/kernel implementation for a matching computation (e.g., matmul → a GEMM template kernel). Rewrites run to a fixed point before template replacement at each source level.

  • how input and patches become patches and weights? Is it a 1D conv? plz elaborate on the math.

The operand correspondence is:

CONV(input, filter, output)
    ↓
patches = im2col(input)
weights = matrix view of filter
C       = matrix view of output
    ↓
C += patches @ weights

So patches comes from input, while weights comes from filter. Only the input windows are copied; the filter and output use views.

Yes, this example is 1D convolution: the kernel has height 1 and width 3, with one input channel and three output channels.

For input X = [a, b, c, d, e], unit stride and dilation produce three windows:

patches = [[a, b, c],
           [b, c, d],
           [c, d, e]]

Let weights[k,j] = filter[0,k,0,j]. Each column contains the three weights for output channel j.

The original convolution computes:

output[0,0,x,j] += Σ_k X[x+k] × filter[0,k,0,j]

Since patches[x,k] = X[x+k], this becomes:

C[x,j] += Σ_k patches[x,k] × weights[k,j]

That is exactly C += patches @ weights. Here x, j, and k each range from 0 to 2, giving a 3×3 GEMM.

@ShangkunLi
ShangkunLi merged commit 26da2bd into main Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants