You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ktir-mlir-frontend#57 adds the spyreop dialect — the IBM Spyre intrinsics the
frontend is allowed to emit. Nothing in this repo emits them yet. Triton's frontend
has no vocabulary for a Spyre intrinsic, so a primitive that Spyre implements as one
instruction reaches KTIR as a chain of arith/math ops.
We need a pass that recognizes those chains and lowers them to the matching spyreop intrinsic.
The canonical case is precision-widened math. tl.rsqrt on f16 arrives as:
The extf/truncf pair is not arithmetic the user asked for — it is the frontend
expressing "compute this at higher precision". spyreop provides sqrt and reciprocal operating on !spyreop.df16, so if the intrinsic already carries the
needed internal precision, the widening ops are pure overhead: they cost tile memory
for the intermediate f32 values and hide the single instruction the hardware wants.
These are scalar ops, not tensor ops. Every signature in #57 is scalar — e.g. spyreop.gelu %arg0 : !spyreop.df16. That is the single most important constraint
on this work, and it decides the shape of the pass:
So we are not replacing a tensor-level chain with a tensor-level spyreop. The
intrinsic goes inside a linalg.generic region, replacing the scalar body ops
while the surrounding structured op — its iteration space, indexing maps, and
operands — stays as it is. That keeps physicalization, tiling, and the dataflow
scheduler working on a shape they already understand.
!spyreop.df16 vs f16 needs a decision. A linalg.generic body yielding !spyreop.df16 while its output tensor is tensor<...xf16> will not verify
without a conversion at the region boundary. Whether we convert at the boundary,
carry tensor<...x!spyreop.df16>, or treat df16 as bitwise-compatible with f16 is an open question I can't answer from Remove GIT_PAT requirement from Spyre build #57 alone.
Proposed pass
A pattern set over linalg.generic bodies, after LowerComputeOps (and after #90's
normalization, if that lands first):
Precision-widening elision — extf → math.op → truncf collapsing to one
intrinsic where the intrinsic's internal precision matches. sqrt, reciprocal, exp are the immediate candidates.
Composite primitives — chains that map to one intrinsic even without a widen: sigmoid, gelu, softplus, layernormscale are each several arith/math ops
as Triton emits them.
Guards. Fuse only when every intermediate value is single-use inside the
region. An extf result read by anything else must not be elided, or that other
consumer silently loses precision.
Numerics are the real risk
Eliding a widen changes results. extf → rsqrt → truncf computes at f32 and rounds
once; spyreop.sqrt + reciprocal on df16 computes at whatever the hardware does
internally. Those agree only if the intrinsic's internal precision is at least f32,
and df16 is not f32 — so this needs confirming per intrinsic against ktir-cpu or
the hardware spec, not assumed from the op names. A fusion that quietly changes
numerics is worse than no fusion.
Note also that rsqrt has no direct spyreop equivalent: it would be sqrt + reciprocal, i.e. two intrinsics, with its own rounding question. A
single-intrinsic pattern (exp, or sigmoid) may be the better first target.
PR RewriteDescriptorLayout: report consumers no pattern can physicalize #95 / RewriteDescriptorLayout: because the intrinsic sits inside a linalg.generic and does not change the structured op's shape, physicalization
should be unaffected — retypeChain handles a generic by rank-bumping the tensor
type without touching the body. Worth an explicit test rather than an assumption,
since Phase 3 will now report a mismatch loudly if that is wrong.
ktir-mlir-frontend#57 must merge and the submodule pin move before any of this
can build.
Proposed scope for a first PR
Narrow on purpose, to settle the representation questions before building a table of
patterns:
Pick one intrinsic — I'd suggest exp or sigmoid over rsqrt, since both
are a single intrinsic and avoid the two-op rounding question.
Confirm numerically against ktir-cpu that the intrinsic agrees with the chain it
replaces, at the precision the frontend emits.
Resolve the df16/f16 boundary question for that one case.
Lit coverage: the fused match; a case where an intermediate has a second use and
must not fuse; a precision case that must not fuse.
A numerical test comparing fused vs unfused.
Explicitly out of scope: a general fusion framework or a full pattern table. One
intrinsic end-to-end tells us whether the df16 boundary and the in-region approach
are right; a framework built first would bake in whatever we guessed.
What I need from reviewers
The df16 boundary question — convert at the region boundary, carry tensor<...x!spyreop.df16>, or treat it as f16-compatible? This is the main
blocker on writing anything.
Per-intrinsic internal precision. Is there a spec for what spyreop.sqrt et al.
do internally, or does this need measuring against ktir-cpu?
First intrinsic — is exp/sigmoid the right start, or is there one with
measured impact on a real kernel worth prioritizing?
Summary
ktir-mlir-frontend#57adds thespyreopdialect — the IBM Spyre intrinsics thefrontend is allowed to emit. Nothing in this repo emits them yet. Triton's frontend
has no vocabulary for a Spyre intrinsic, so a primitive that Spyre implements as one
instruction reaches KTIR as a chain of
arith/mathops.We need a pass that recognizes those chains and lowers them to the matching
spyreopintrinsic.The canonical case is precision-widened math.
tl.rsqrtonf16arrives as:The
extf/truncfpair is not arithmetic the user asked for — it is the frontendexpressing "compute this at higher precision".
spyreopprovidessqrtandreciprocaloperating on!spyreop.df16, so if the intrinsic already carries theneeded internal precision, the widening ops are pure overhead: they cost tile memory
for the intermediate
f32values and hide the single instruction the hardware wants.What #57 gives us
From the PR's tests, the initial op surface:
plus the
!spyreop.df16type.These are scalar ops, not tensor ops. Every signature in #57 is scalar — e.g.
spyreop.gelu %arg0 : !spyreop.df16. That is the single most important constrainton this work, and it decides the shape of the pass:
So we are not replacing a tensor-level chain with a tensor-level
spyreop. Theintrinsic goes inside a
linalg.genericregion, replacing the scalar body opswhile the surrounding structured op — its iteration space, indexing maps, and
operands — stays as it is. That keeps physicalization, tiling, and the dataflow
scheduler working on a shape they already understand.
Two consequences worth stating early:
well with [Discussion] Normalize to
linalg.genericup front so layout physicalization emits no synthesized loops #90 (normalize everything tolinalg.genericup front): after that, thematcher has one surface instead of several. Ordering between the two should be
agreed before either is implemented.
!spyreop.df16vsf16needs a decision. Alinalg.genericbody yielding!spyreop.df16while its output tensor istensor<...xf16>will not verifywithout a conversion at the region boundary. Whether we convert at the boundary,
carry
tensor<...x!spyreop.df16>, or treatdf16as bitwise-compatible withf16is an open question I can't answer from Remove GIT_PAT requirement from Spyre build #57 alone.Proposed pass
A pattern set over
linalg.genericbodies, afterLowerComputeOps(and after #90'snormalization, if that lands first):
extf → math.op → truncfcollapsing to oneintrinsic where the intrinsic's internal precision matches.
sqrt,reciprocal,expare the immediate candidates.sigmoid,gelu,softplus,layernormscaleare each severalarith/mathopsas Triton emits them.
region. An
extfresult read by anything else must not be elided, or that otherconsumer silently loses precision.
Numerics are the real risk
Eliding a widen changes results.
extf → rsqrt → truncfcomputes at f32 and roundsonce;
spyreop.sqrt+reciprocalondf16computes at whatever the hardware doesinternally. Those agree only if the intrinsic's internal precision is at least f32,
and
df16is not f32 — so this needs confirming per intrinsic against ktir-cpu orthe hardware spec, not assumed from the op names. A fusion that quietly changes
numerics is worse than no fusion.
Note also that
rsqrthas no directspyreopequivalent: it would besqrt+reciprocal, i.e. two intrinsics, with its own rounding question. Asingle-intrinsic pattern (
exp, orsigmoid) may be the better first target.Interaction with in-flight work
linalg.genericup front so layout physicalization emits no synthesized loops #90 (normalize tolinalg.generic): should probably land first — it gives thispass one matching surface instead of several named op forms.
relieves pressure rather than adding to it. Worth checking whether collapsing
chains fixes some of KTIR lowering admits only one linalg op per compute group; frontend output routinely has several #84's violating fixtures outright.
RewriteDescriptorLayout: because the intrinsic sits inside alinalg.genericand does not change the structured op's shape, physicalizationshould be unaffected —
retypeChainhandles a generic by rank-bumping the tensortype without touching the body. Worth an explicit test rather than an assumption,
since Phase 3 will now report a mismatch loudly if that is wrong.
can build.
Proposed scope for a first PR
Narrow on purpose, to settle the representation questions before building a table of
patterns:
exporsigmoidoverrsqrt, since bothare a single intrinsic and avoid the two-op rounding question.
replaces, at the precision the frontend emits.
df16/f16boundary question for that one case.must not fuse; a precision case that must not fuse.
Explicitly out of scope: a general fusion framework or a full pattern table. One
intrinsic end-to-end tells us whether the
df16boundary and the in-region approachare right; a framework built first would bake in whatever we guessed.
What I need from reviewers
df16boundary question — convert at the region boundary, carrytensor<...x!spyreop.df16>, or treat it asf16-compatible? This is the mainblocker on writing anything.
spyreop.sqrtet al.do internally, or does this need measuring against ktir-cpu?
exp/sigmoidthe right start, or is there one withmeasured impact on a real kernel worth prioritizing?
linalg.genericup front so layout physicalization emits no synthesized loops #90.