diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index a8d0b3bcd47..cb96a5f8058 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -2822,6 +2822,7 @@ agx_compile_function_nir(nir_shader *nir, nir_function_impl *impl, /* After DCE, use counts are right so we can run the optimizer. */ agx_optimizer(ctx); + agx_opt_compact_constants(ctx); /* After inlining constants, promote what's left */ if (key->promote_constants && !(agx_compiler_debug & AGX_DBG_NOPROMOTE)) { diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h index 76d60e945ae..fc0efc3aacd 100644 --- a/src/asahi/compiler/agx_compiler.h +++ b/src/asahi/compiler/agx_compiler.h @@ -939,6 +939,7 @@ void agx_lower_pseudo(agx_context *ctx); void agx_lower_spill(agx_context *ctx); void agx_lower_uniform_sources(agx_context *ctx); void agx_opt_cse(agx_context *ctx); +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); diff --git a/src/asahi/compiler/agx_opt_compact_constants.c b/src/asahi/compiler/agx_opt_compact_constants.c new file mode 100644 index 00000000000..6baad35e8f6 --- /dev/null +++ b/src/asahi/compiler/agx_opt_compact_constants.c @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Alyssa Rosenzweig + * SPDX-License-Identifier: MIT + */ + +#include "util/bitset.h" +#include "util/half_float.h" +#include "agx_builder.h" +#include "agx_compiler.h" +#include "agx_opcodes.h" + +/* + * AGX can convert 16-bit sources to 32-bit for free, so it's beneficial to + * compact 32-bit constants down to 16-bit when doing so is lossless. This + * reduces register pressure (GPR or uniform, depending on whether the constant + * is promoted). + */ +void +agx_opt_compact_constants(agx_context *ctx) +{ + /* TODO: Handle ints too */ + BITSET_WORD *src_float = calloc(ctx->alloc, sizeof(BITSET_WORD)); + BITSET_WORD *src_other = calloc(ctx->alloc, sizeof(BITSET_WORD)); + BITSET_WORD *replaced = calloc(ctx->alloc, sizeof(BITSET_WORD)); + + /* Analyze the types that we read constants as */ + agx_foreach_instr_global(ctx, I) { + agx_foreach_ssa_src(I, s) { + if (agx_is_float_src(I, s)) + BITSET_SET(src_float, I->src[s].value); + else + BITSET_SET(src_other, I->src[s].value); + } + } + + agx_foreach_instr_global(ctx, I) { + if (I->op == AGX_OPCODE_MOV_IMM && I->dest[0].size == AGX_SIZE_32) { + unsigned v = I->dest[0].value; + + if (BITSET_TEST(src_float, v) && !BITSET_TEST(src_other, v)) { + /* Try to compact to f16 */ + uint16_t compact = _mesa_float_to_half(uif(I->imm)); + + if (I->imm == fui(_mesa_half_to_float(compact))) { + I->dest[0].size = AGX_SIZE_16; + I->imm = compact; + BITSET_SET(replaced, v); + } + } + } else { + agx_foreach_ssa_src(I, s) { + if (BITSET_TEST(replaced, I->src[s].value)) { + I->src[s].size = AGX_SIZE_16; + } + } + } + } + + free(replaced); + free(src_float); + free(src_other); +} diff --git a/src/asahi/compiler/meson.build b/src/asahi/compiler/meson.build index b83e4a4e682..b397756b0fe 100644 --- a/src/asahi/compiler/meson.build +++ b/src/asahi/compiler/meson.build @@ -33,6 +33,7 @@ libasahi_agx_files = files( 'agx_opt_break_if.c', 'agx_opt_empty_else.c', 'agx_opt_jmp_none.c', + 'agx_opt_compact_constants.c', 'agx_opt_promote_constants.c', 'agx_optimizer.c', 'agx_repair_ssa.c',