Skip to content

[xegpu] Generalize fused attention schedule for KernelBench - #266

Merged
tkarna merged 11 commits into
llvm:mainfrom
tkarna:xegpu-kb-attention
Aug 26, 2026
Merged

[xegpu] Generalize fused attention schedule for KernelBench#266
tkarna merged 11 commits into
llvm:mainfrom
tkarna:xegpu-kb-attention

Conversation

@tkarna

@tkarna tkarna commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Generalizes fused_attention_schedule so that it works for KernelBench level1-97 ScaledDotProductAttention kernel.

The schedule can consume 4D attention kernels [batch_size, n_head, n_ctx, d_head] as well as versions where the 2 leading dimensions have been collapsed to a single batch dimension batch_size, n_head within the payload function (e.g., in the examples/xegpu/fused_attention.py).

At the moment, the KernelBench problem shape must be simplified from the original [32, 32, 512, 1024] to [32, 32, 512, 64] because we do not yet have a good strategy for distributing the last dimension (head dimension).

  • fused_attention_schedule uses common xegpu helper utils where possible.
  • Updates lowering_common and inspect_kernel methods.
  • replace_with_fused_attention transform ext op is generalized to handle bf16/mixed data types and 2 leading dimensions.
  • The attention layer related docs and variable names are unified across examples/schedules/payload generation. For example, now the dimensions are called [batch_size, n_head, n_ctx, d_head] consistently everywhere.
  • examples/xegpu/kernel_bench.py supports level1-97 attention kernel. Currently the kernel file must be manually patched to set embedding_dimension = 64.

Assisted-by: Claude

@tkarna
tkarna requested review from adam-smnk and a lite review from Copilot August 24, 2026 16:41
@tkarna

tkarna commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

FYI @charithaintc

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Generalizes the XeGPU fused-attention lowering pipeline to support KernelBench’s level1-97 ScaledDotProductAttention-style kernels, including support for both true 4D attention shapes and payloads that collapse the leading batch dimensions.

Changes:

  • Refactors common lowering utilities (get_payload_func, vectorization/bufferization/GPU launch conversion helpers) and updates existing schedules to use them.
  • Generalizes fused attention scheduling and the replace_with_fused_attention transform to handle additional shapes and mixed/bf16-related type flows.
  • Extends KernelBench example driver to recognize attention-like kernels and route them through the fused-attention schedule.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
lighthouse/utils/mlir.py Extends layer metadata extraction for batch_matmul to include element-type info.
lighthouse/schedule/xegpu/reduction_schedule.py Updates schedule to use get_payload_func and updated helper signatures.
lighthouse/schedule/xegpu/mlp_schedule.py Updates schedule to use get_payload_func.
lighthouse/schedule/xegpu/lowering_common.py Introduces get_payload_func and refactors helper APIs; adds vector cleanup patterns and LICM pass in vector→xegpu.
lighthouse/schedule/xegpu/fused_attention_schedule.py Reworks fused attention schedule to support more shapes and reuse common lowering helpers.
lighthouse/schedule/xegpu/elemwise_schedule.py Updates schedule to use get_payload_func.
lighthouse/ingress/mlir_gen/gpu_attention_payload.py Unifies attention dimension naming and updates payload generation for collapsed-batch handling.
lighthouse/dialects/transform/transform_ext/ops/replace_with_fused_attention.py Generalizes fused-attention replacement for batch dims and mixed/bf16-related typing behavior.
examples/xegpu/nanoGPT_schedule.py Updates callsite to updated convert_to_gpu_launch signature.
examples/xegpu/kernel_bench.py Adds attention schedule path, adds CPU reference option, and adjusts verification tolerances.
examples/xegpu/fused_attention.py Unifies naming, extends CLI params, and updates schedule parameter plumbing.
Suppressed comments (1)

lighthouse/dialects/transform/transform_ext/ops/replace_with_fused_attention.py:516

  • Call site uses the misspelled helper name normalize_ouput_by_sum; rename it to match the corrected helper name.
                output_normalized = normalize_ouput_by_sum(
                    pv_out, l_i_out, batch_shape, wg_rows, d_head, compute_type
                )

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread examples/xegpu/kernel_bench.py Outdated
Comment thread lighthouse/utils/mlir.py
Comment thread lighthouse/dialects/transform/transform_ext/ops/replace_with_fused_attention.py Outdated
Comment thread lighthouse/schedule/xegpu/lowering_common.py Outdated
Comment thread examples/xegpu/kernel_bench.py Outdated
@tkarna
tkarna force-pushed the xegpu-kb-attention branch from dc69604 to 7a92481 Compare August 24, 2026 17:19

@charithaintc charithaintc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. some nit comments.

I will continue the review tomorrow.

compute_type,
)
# Truncate Q@K^T (f32 accumulator) to the softmax type before scaling.
if reduction_type != compute_type:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 364 sets the reduction_type = compute_type. this this branch is never taken?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, it's actually dead code. I'm inclined to keep the code as it is, however, because one can change the reduction data type to a narrower one just by changing the assignment reduction_type = compute_type. The generated IR is still valid. Added a comment.

# Rescale running P@V accumulator by alpha; the accumulator is
# kept in f32, so widen the softmax-type alpha to match.
alpha_wide = alpha
if reduction_type != compute_type:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here.

with ir.InsertionPoint.after(loop):
# The sum accumulator is in the softmax type; widen it to the f32
# accumulator type before dividing the f32 P@V result.
if reduction_type != compute_type:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here also.

- Q @ K^T: 2 * n_ctx^2 * n_head FLOPs
- Attention @ V: 2 * n_ctx^2 * n_head FLOPs
The softmax is left out: it is O(n_ctx^2) (~2% of the above at n_head = 64) and
- Q @ K^T: 2 * n_ctx^2 * d_head FLOPs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: n_head -> d_head change also need to be reflected on nanoGPT case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated all nanoGPT files to use the same variable naming convention


# Check values match reference
values_ok = np.allclose(output, output_ref, rtol=1e-3, atol=1e-3)
values_ok = np.allclose(output, output_ref, rtol=1e-3, atol=5e-3)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the reason for atol change?

@tkarna tkarna Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After updating llvm version the tests no longer passed, even with LH main. After scratching my head for a while I realized it's just a tolerance issue (test failed even with older llvm version if inputs were filled differently). So I think the tolerance was too tight. This kernel has two matmuls and a reduction so errors accumulate.

# loads, but are distributed over the subgroups.
prefetch_sg_data = layer_params["prefetch_tile"]
prefetch_sg_layout = [
reduction_tile // prefetch_sg_data[0],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init: maybe validate against num_sgs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, in principle you can use different number of sgs for the computation and prefetches? Might not be optimal config but who knows. The hardware limits should not be exceeded but those are not validated in the schedule.

op_attrs=op_attrs,
)
# Return the first function
func = transform_ext.extract_handle(func_ops, 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would fail silently if none matched. what is the reason for removing match_and_split?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract_handle raises an IndexError if the index is out of bounds so it's a definitive failure at lowering time.

@charithaintc charithaintc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. thanks!

result_ref = torch_model(*torch_inputs).to("cpu")
else:
# execute torch model on the device
torch_inputs = [inp.to("xpu") for inp in torch_inputs]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the recent results discrepancy only for GPU?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this script only targets xegpu

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I mean I usually cross check xegpu output with CPU output. it seems here you use pytoch with xpu support to cross validate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, in this script we indeed run the reference solution on the GPU with torch xpu backend. The new attention kernel is an exception though because torch xpu doesn't currently support torch's scaled_dot_product_attention op. That's why I added the --compute-reference-on-cpu flag to enable testing against torch CPU backend.

@tkarna
tkarna merged commit 8fb00f7 into llvm:main Aug 26, 2026
3 checks passed
@tkarna
tkarna deleted the xegpu-kb-attention branch August 26, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants