Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5701aa8
honeykrisp: hardware 8x8x8 fp32 cooperative matrix via simd_matrix_fm…
joshuaswarren Sep 7, 2026
8d93327
honeykrisp: match generated nir_simd_matrix_fmadd_agx(fp32) signature
joshuaswarren Sep 7, 2026
5f4b553
agx/isa: disassemble simd_matrix_fmadd32/16 so debug builds can compi…
joshuaswarren Sep 7, 2026
d6f3635
agx/isa: include bit6 of opcode 0x6f in simd_matrix exact mask
joshuaswarren Sep 7, 2026
5da2559
honeykrisp: advertise 16x16x16 and fp16 cooperative matrix shapes
joshuaswarren Sep 8, 2026
cc4c415
agx: keep the mod-32 shift count when fusing ushr+iand into ubfe
joshuaswarren Sep 8, 2026
4a1ceff
agx: correctly rounded fdiv/frcp, faithful log/log2, exact sin/cos re…
joshuaswarren Sep 8, 2026
ebcc3ca
agx: lower the fdiv that int64 lowering and the perspective divide em…
joshuaswarren Sep 8, 2026
2315de0
honeykrisp: enable VK_KHR_cooperative_matrix by default (AGX_SIMDMAT=…
joshuaswarren Sep 8, 2026
0facecf
honeykrisp: dependency-track the per-launch CDM barrier on the Vulkan…
joshuaswarren Sep 29, 2026
d597ce2
hk: opt-in bounded poll before blocking syncobj waits (HK_SUBMIT_POLL…
joshuaswarren Sep 29, 2026
9019bd6
agx: lower cooperative matrices in software outside full subgroups
joshuaswarren Sep 13, 2026
9599a3c
agx: address cooperative matrix memory in component units
joshuaswarren Sep 13, 2026
a016f02
agx: return a flushed signed zero from sin under DenormFlushToZero
joshuaswarren Sep 20, 2026
f06b1b2
honeykrisp: key the shader cache on the cooperative matrix compiler s…
joshuaswarren Sep 30, 2026
a2e0a48
honeykrisp: restore the norobust perftest option
joshuaswarren Sep 30, 2026
90b8a24
agx: index software cooperative matrix memory at the pointer width
joshuaswarren Sep 30, 2026
96f4036
agx: represent the fused shift-then-mask as ubfe, not ubitfield_extract
joshuaswarren Sep 11, 2026
7c8edf7
agx/isa: decode the matrix instructions with a cached destination
joshuaswarren Sep 13, 2026
1d382d7
honeykrisp: advertise cooperative matrices on G13 only
joshuaswarren Sep 30, 2026
f884173
honeykrisp: dependency-track the CDM barrier on G13 only
joshuaswarren Sep 30, 2026
fa3b70b
honeykrisp: keep the kitchen-sink CDM barrier on G13G
joshuaswarren Sep 30, 2026
79994c2
agx/simdmat: load paired (col,col+1) fragments by default
joshuaswarren Sep 29, 2026
50cf059
agx: fold constant shared-memory address deltas into the lload/lstore…
joshuaswarren Sep 29, 2026
ff01378
agx: skip the register-pressure scheduler for compute shaders
joshuaswarren Sep 29, 2026
b7551fd
agx: apply the M1 compute codegen defaults on G13 only
joshuaswarren Sep 30, 2026
0eb5f65
honeykrisp: defer the CDM barrier to the end of the batch on G13G
joshuaswarren Sep 30, 2026
5fbd5e9
hk: enable cooperative matrices by default on G14X
joshuaswarren Oct 1, 2026
0537a51
agx: flush the exact quotient in precise fp32 division, not the corre…
joshuaswarren Oct 5, 2026
b2c157f
nir: pass FP_MATH_CTRL to the builder generator
joshuaswarren Sep 13, 2026
355c19b
tests: cooperative matrix and precise math regressions for AGX
joshuaswarren Sep 13, 2026
77025cf
agx: lower log() the same way regardless of where ln2 comes from
joshuaswarren Oct 5, 2026
304f019
hk: order internal full-barrier precomp launches with surrounding CDM…
joshuaswarren Oct 5, 2026
e2f46e8
agx: only adopt an early-killed source region when it is free
joshuaswarren Oct 5, 2026
7d66ea0
honeykrisp: shorten normalized precise division
joshuaswarren Oct 6, 2026
5058212
honeykrisp: use direct reciprocal for normalized division
joshuaswarren Oct 6, 2026
e672f37
tests: pin the 2.5 ulp default-division bound for AGX
joshuaswarren Oct 6, 2026
76d1f5e
honeykrisp: exact reciprocal without the division machinery
joshuaswarren Oct 6, 2026
c434c73
agx: round log() once unless the multiply is exact
joshuaswarren Oct 6, 2026
00df31f
honeykrisp: let the hardware rcp give the reciprocal edge cases
joshuaswarren Oct 7, 2026
be2d8e3
honeykrisp: fold sub-format lea offsets into the access index on sing…
joshuaswarren Oct 6, 2026
e17ce7a
agx: test the sub-format address fold
joshuaswarren Oct 7, 2026
fe6a9a5
agx: pin float-control keying of division, not its op counts
joshuaswarren Oct 7, 2026
ed30194
hk: launch buffer copies and fills without an internal full barrier
joshuaswarren Oct 7, 2026
91dd75e
nir/opt_large_constants: allow a re-store of the same constants from …
joshuaswarren Oct 7, 2026
52cecbf
hk: compute-shader large constant arrays as constant data
joshuaswarren Oct 7, 2026
ad8932b
hk: expose VK_KHR_shader_bfloat16 with bf16 cooperative matrices
joshuaswarren Oct 7, 2026
fcd28f4
hk: dependency-tracked CDM barrier by default on gen-14 G14X (M2 Pro/…
joshuaswarren Oct 8, 2026
be1c268
spirv: make image texels available after the write and visible before…
joshuaswarren Oct 8, 2026
8fc2e45
agx: hoist compute device loads over independent ALU and barriers, on…
joshuaswarren Oct 9, 2026
5f3f7e4
hk: default the device heap to 90% of system memory
joshuaswarren Oct 9, 2026
a54d9c1
hk: refuse device memory that would leave too little system memory
joshuaswarren Oct 9, 2026
839f1d1
agx: use the whole user address window for the heap
joshuaswarren Oct 9, 2026
02765a8
hk: give the BO cache back before refusing for the free-memory reserve
joshuaswarren Oct 10, 2026
69bde15
hk: flush every CDM launch in command buffers that record graphics or…
joshuaswarren Oct 11, 2026
795ae42
tests: use a neutral lock file name in the GPU test scripts
joshuaswarren Oct 11, 2026
5c8d6b9
hk: use the full CDM barrier word after graphics or meta
joshuaswarren Oct 12, 2026
a5a7723
hk: close the graphics batch before a query-pool copy
joshuaswarren Oct 12, 2026
807dc2b
Revert "hk: close the graphics batch before a query-pool copy"
joshuaswarren Oct 12, 2026
43aaf80
Revert "hk: use the full CDM barrier word after graphics or meta"
joshuaswarren Oct 12, 2026
f144c79
honeykrisp: keep a compute batch open across a barrier only when it i…
joshuaswarren Oct 12, 2026
8fe35ac
tests: measure the 2.5 ULP bound in float32 spacing
joshuaswarren Oct 25, 2026
5ce4451
tests: repair fp32 error oracle and complete numerical fixtures
chriskearney Oct 25, 2026
cbb46d1
hk: return an error when a shader's code or constant buffer cannot be…
joshuaswarren Oct 25, 2026
23f25ee
vk/drm_syncobj: never poll past the caller's deadline
joshuaswarren Oct 25, 2026
8b95ec3
tests: one GPU lock for the harnesses, 8-bit storage for the u8 matri…
joshuaswarren Oct 25, 2026
9323171
agx: keep the sign of shared-memory constant addends, prove the align…
joshuaswarren Oct 25, 2026
0c82971
agx: take a non-const alu in is_one (#6)
joshuaswarren Nov 12, 2026
7b81213
honeykrisp: default CDM barrier word 0x1FF on gen-14 G14X (#5)
joshuaswarren Nov 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
363 changes: 262 additions & 101 deletions src/asahi/compiler/agx_compile.c

Large diffs are not rendered by default.

29 changes: 28 additions & 1 deletion src/asahi/compiler/agx_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "compiler/nir/nir.h"
#include "util/shader_stats.h"
#include "util/u_debug.h"
#include "util/u_dynarray.h"
#include "util/u_tristate.h"
#include "shader_enums.h"
Expand Down Expand Up @@ -268,6 +269,24 @@ struct agx_device_key {
* kernel, but that's functionally a hardware feature.
*/
bool soft_fault;

/* Is the target GPU generation 13 (M1 family)? Selects the compute
* codegen defaults that are measured on G13 only.
*/
bool g13;

/* Hoist device loads of compute shaders above independent ALU, barriers
* and workgroup memory accesses (agx_hoist_loads). Measured on G13 and
* G14 only.
*/
bool hoist_loads;

/* Index global accesses whose lea shift is below the format shift (the
* cooperative-matrix loads) by the scaled offset instead of a 64-bit
* address. Measured per device: on for the single-cluster G13 (M1), off
* on the multi-cluster G13C, where it slows dense GEMM.
*/
bool fold_subformat_address;
};

struct agx_shader_key {
Expand Down Expand Up @@ -317,6 +336,15 @@ struct agx_shader_key {
uint64_t agx_gather_texcoords(nir_shader *nir);

void agx_preprocess_nir(nir_shader *nir);

/* VK_KHR_cooperative_matrix on the G13 simd_matrix unit, with a software
* fallback for partial subgroups. On by default; AGX_SIMDMAT=0 disables it.
*/
static inline bool
agx_simdmat_enabled(void)
{
return debug_get_bool_option("AGX_SIMDMAT", true);
}
bool agx_nir_lower_discard_zs_emit(nir_shader *s);
bool agx_nir_lower_sample_mask(nir_shader *s);
bool agx_nir_lower_interpolation(nir_shader *s);
Expand Down Expand Up @@ -347,7 +375,6 @@ agx_round_registers(unsigned halfregs)
}

static const nir_shader_compiler_options agx_nir_options = {
.lower_fdiv = true,
.float_mul_add16 = nir_float_muladd_support_has_ffma | nir_float_muladd_support_fuse,
.float_mul_add32 = nir_float_muladd_support_has_ffma | nir_float_muladd_support_fuse,
.lower_flrp16 = true,
Expand Down
8 changes: 8 additions & 0 deletions src/asahi/compiler/agx_compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,7 @@ void agx_opt_compact_constants(agx_context *ctx);
void agx_opt_promote_constants(agx_context *ctx);
void agx_dce(agx_context *ctx, bool partial);
void agx_pressure_schedule(agx_context *ctx);
void agx_hoist_loads(agx_context *ctx);
void agx_spill(agx_context *ctx, unsigned k, bool remat_only);
void agx_repair_ssa(agx_context *ctx);
void agx_reindex_ssa(agx_context *ctx);
Expand Down Expand Up @@ -1096,6 +1097,13 @@ bool agx_nir_opt_preamble(nir_shader *s, unsigned *sizes);
bool agx_nir_lower_load_mask(nir_shader *shader);
bool agx_nir_lower_ubo(nir_shader *shader);
bool agx_nir_lower_shared_bitsize(nir_shader *shader);
bool agx_nir_lower_simdmat(nir_shader *shader, unsigned subgroup_size);
bool agx_nir_lower_cmat(nir_shader *shader);
nir_def *agx_cmat_convert(struct nir_builder *b, nir_def *src,
enum glsl_base_type from, enum glsl_base_type to);
nir_def *agx_cmat_alu(struct nir_builder *b, nir_op op, enum glsl_base_type t,
nir_def *x, nir_def *y);
bool agx_nir_lower_bf16_conversions(nir_shader *shader);
bool agx_nir_lower_frag_sidefx(nir_shader *s);

struct agx_cycle_estimate {
Expand Down
2 changes: 2 additions & 0 deletions src/asahi/compiler/agx_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ agx_allows_16bit_immediate(agx_instr *I)
{
return (I->op == AGX_OPCODE_DEVICE_LOAD) ||
(I->op == AGX_OPCODE_DEVICE_STORE) ||
(I->op == AGX_OPCODE_LOCAL_LOAD) ||
(I->op == AGX_OPCODE_LOCAL_STORE) ||
(I->op == AGX_OPCODE_STACK_LOAD) ||
(I->op == AGX_OPCODE_STACK_STORE) ||
(I->op == AGX_OPCODE_UNIFORM_STORE) || (I->op == AGX_OPCODE_ATOMIC) ||
Expand Down
8 changes: 7 additions & 1 deletion src/asahi/compiler/agx_nir.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
struct nir_shader;
struct nir_instr;

bool agx_nir_lower_address(struct nir_shader *shader);
bool agx_nir_lower_address(struct nir_shader *shader,
bool fold_subformat_address);
bool agx_nir_lower_algebraic_late(struct nir_shader *shader);
bool agx_nir_cleanup_amul(struct nir_shader *shader);
bool agx_nir_fuse_lea(struct nir_shader *shader);
Expand All @@ -22,6 +23,11 @@ bool agx_nir_lower_layer(struct nir_shader *s);
bool agx_nir_lower_clip_distance(struct nir_shader *s);
bool agx_nir_lower_subgroups(struct nir_shader *s);
bool agx_nir_lower_fminmax(struct nir_shader *s);
bool agx_nir_lower_fdiv(struct nir_shader *s);
bool agx_nir_lower_fdiv_late(struct nir_shader *s);
bool agx_nir_lower_log(struct nir_shader *s);
bool agx_nir_lower_sincos(struct nir_shader *s);
bool agx_nir_fold_shared_offsets(struct nir_shader *s);

bool agx_nir_lower_texture_early(struct nir_shader *s, bool support_lod_bias);
bool agx_nir_lower_texture(struct nir_shader *s);
Expand Down
17 changes: 15 additions & 2 deletions src/asahi/compiler/agx_nir_algebraic.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,24 @@
('extr_agx', a, b, start, 0)),
])

# ushr uses only the low 5 bits of its count (SM5 semantics), and the main
# nir_opt_algebraic has already stripped explicit masks on that basis. Fuse to
# ubfe, not ubitfield_extract: ubfe is defined to take its offset and width
# modulo 32, which is exactly ushr's behaviour, so the fused form cannot be
# poisoned by a later pass reasoning about an out-of-range bitfield_extract.
#
# The hardware is the part that does not wrap: bfeil reads zero for an offset
# >= 32, and lower_sm5_shift runs after this pass, so a ushr consumed here is
# never masked by it. Keep an explicit modulo unless the count is a constant
# already in range; it costs nothing, because it CSEs with the mask the shader
# had before the fusion.
fuse_ubfe = []
for bits in range(1, 32):
fuse_ubfe.extend([
(('iand', ('ushr', 'a@32', b), (1 << bits) - 1),
('ubitfield_extract', a, b, bits))
(('iand', ('ushr', 'a@32', '#b(is_ult_32)'), (1 << bits) - 1),
('ubfe', a, b, bits)),
(('iand', ('ushr', 'a@32', 'b(is_not_const)'), (1 << bits) - 1),
('ubfe', a, ('iand', b, 31), bits)),
])

# (x * y) + s = (x * y) + (s << 0)
Expand Down
88 changes: 85 additions & 3 deletions src/asahi/compiler/agx_nir_lower_address.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,63 @@ format_for_bitsize(unsigned bitsize)
}
}

/* True when the scalar is provably a multiple of 2^k. The sub-format fold
* indexes by the byte offset scaled down, which equals the byte offset only
* when its low bits are zero; an access that is aligned as a whole does not
* say that the offset alone is (base P + 2 with offset 2 for a 32-bit access
* is aligned, and scaling the offset down drops the 2). Unknown means no fold.
*/
static bool
scalar_multiple_of(nir_scalar s, unsigned k, unsigned depth)
{
if (k == 0)
return true;

s = nir_scalar_resolved(s.def, s.comp);
if (nir_scalar_is_const(s))
return (nir_scalar_as_uint(s) & BITFIELD64_MASK(k)) == 0;

if (!nir_scalar_is_alu(s) || depth == 0)
return false;

switch (nir_scalar_alu_op(s)) {
case nir_op_ishl: {
nir_scalar amount = nir_scalar_chase_alu_src(s, 1);
nir_scalar value = nir_scalar_chase_alu_src(s, 0);
if (nir_scalar_is_const(amount)) {
unsigned a = nir_scalar_as_uint(amount);
if (a >= k)
return true;
return scalar_multiple_of(value, k - a, depth - 1);
}
return scalar_multiple_of(value, k, depth - 1);
}
case nir_op_imul:
return scalar_multiple_of(nir_scalar_chase_alu_src(s, 0), k, depth - 1) ||
scalar_multiple_of(nir_scalar_chase_alu_src(s, 1), k, depth - 1);
case nir_op_iadd:
case nir_op_isub:
return scalar_multiple_of(nir_scalar_chase_alu_src(s, 0), k, depth - 1) &&
scalar_multiple_of(nir_scalar_chase_alu_src(s, 1), k, depth - 1);
case nir_op_iand: {
nir_scalar mask = nir_scalar_chase_alu_src(s, 1);
if (nir_scalar_is_const(mask) &&
(nir_scalar_as_uint(mask) & BITFIELD64_MASK(k)) == 0)
return true;
return scalar_multiple_of(nir_scalar_chase_alu_src(s, 0), k, depth - 1) ||
scalar_multiple_of(nir_scalar_chase_alu_src(s, 1), k, depth - 1);
}
case nir_op_u2u32:
case nir_op_i2i32:
case nir_op_u2u64:
case nir_op_i2i64:
case nir_op_mov:
return scalar_multiple_of(nir_scalar_chase_alu_src(s, 0), k, depth - 1);
default:
return false;
}
}

static bool
pass(struct nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
Expand Down Expand Up @@ -61,12 +118,37 @@ pass(struct nir_builder *b, nir_intrinsic_instr *intr, void *data)
nir_op op = nir_scalar_alu_op(base);
if (op == nir_op_ulea_agx || op == nir_op_ilea_agx) {
unsigned shift = nir_scalar_as_uint(nir_scalar_chase_alu_src(base, 2));
bool sign_extend = (op == nir_op_ilea_agx);
if (shift >= format_shift && shift <= max_shift) {
match = (struct match){
.base = nir_scalar_chase_alu_src(base, 0),
.offset = nir_scalar_chase_alu_src(base, 1),
.shift = shift - format_shift,
.sign_extend = (op == nir_op_ilea_agx),
.sign_extend = sign_extend,
};
} else if (shift < format_shift && *(const bool *)data &&
scalar_multiple_of(nir_scalar_chase_alu_src(base, 1),
format_shift - shift, 4)) {
/* A byte (or half-element) offset, as the cooperative matrix
* loads produce. The offset is provably a multiple of the element
* size (scalar_multiple_of; an aligned access does not imply it):
* index by the offset scaled down instead of materializing the
* 64-bit sum (a 64-bit add plus the moves that build its
* operands). Per device
* (agx_device_key::fold_subformat_address): measured +15 % on
* dense f16 GEMM on the single-cluster M1, -13..17 % on the M1
* Max, bit-identical on both.
*/
nir_scalar off = nir_scalar_chase_alu_src(base, 1);
nir_def *index = nir_channel(b, off.def, off.comp);
unsigned down = format_shift - shift;
index = sign_extend ? nir_ishr_imm(b, index, down)
: nir_ushr_imm(b, index, down);
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved
match = (struct match){
.base = nir_scalar_chase_alu_src(base, 0),
.offset = nir_get_scalar(index, 0),
.shift = 0,
.sign_extend = sign_extend,
};
}
} else if (op == nir_op_iadd) {
Expand Down Expand Up @@ -151,7 +233,7 @@ pass(struct nir_builder *b, nir_intrinsic_instr *intr, void *data)
}

bool
agx_nir_lower_address(nir_shader *nir)
agx_nir_lower_address(nir_shader *nir, bool fold_subformat_address)
{
bool progress = false;

Expand All @@ -169,7 +251,7 @@ agx_nir_lower_address(nir_shader *nir)

/* Next, lower load/store using the lea's */
NIR_PASS(progress, nir, nir_shader_intrinsics_pass, pass,
nir_metadata_control_flow, NULL);
nir_metadata_control_flow, &fold_subformat_address);

/* Finally, lower any leftover lea instructions back to ALU to let
* nir_opt_algebraic simplify them from here.
Expand Down
Loading