Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions src/asahi/compiler/agx_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,15 @@ agx_optimizer_fmov_rev(agx_context *ctx, agx_instr *I, agx_instr *use)
(I->src[0].abs || I->src[0].neg || I->src[1].abs || I->src[1].neg))
return false;

/* M5 (AGX3C): the native perspective multiply only encodes a word
* destination (agx3_persp_mul_encode). Folding the f32-to-f16 move that
* narrows a mediump varying into it made the binary packer refuse the
* shader and the draw was skipped. Keep the explicit move. */
if (ctx->key && ctx->key->dev.encoding == AGX_ISA_ENCODING_AGX3C &&
I->op == AGX_OPCODE_PERSP_MUL_AGX3 &&
I->dest[0].size == AGX_SIZE_32 && use->dest[0].size == AGX_SIZE_16)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A saturating same-width move can still fold into this opcode on AGX3C, and the packer refuses that too (agx3_pack_binary.c:10717). Suggest (use->saturate || use->dest[0].size == AGX_SIZE_16) here, or a follow-up.

— Marcelo's agent

return false;

/* saturate(saturate(x)) = saturate(x) */
I->saturate |= use->saturate;
I->dest[0] = use->dest[0];
Expand Down
25 changes: 25 additions & 0 deletions src/asahi/compiler/test/test-optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,31 @@ TEST_F(Optimizer, G17PPreservesHalfWidenBeforeFltnorm)
ASSERT_SHADER_EQUAL(actual->shader, expected->shader);
}

/*
* The native projective f32mul (PERSP_MUL) has no 16-bit destination form. A
* mediump varying narrows its product with an f32 to f16 move; folding that
* move into the multiply made the shader unencodable on M5 (AGX3C), so the
* move stays a separate instruction.
*/
TEST_F(Optimizer, G17CKeepsPerspMulNarrowingMove)
{
agx_builder *actual = agx_test_builder(mem_ctx);
agx_builder *expected = agx_test_builder(mem_ctx);
struct agx_shader_key key = {};
key.dev.encoding = AGX_ISA_ENCODING_AGX3C;
key.dev.chip = AGX_CHIP_G17C;
for (agx_builder *b : {actual, expected}) {
b->shader->key = &key;
agx_index product = agx_temp(b->shader, AGX_SIZE_32);
agx_persp_mul_agx3_to(b, product, wx, wy, 1);
agx_index narrow = agx_temp(b->shader, AGX_SIZE_16);
agx_fmov_to(b, narrow, product);
agx_unit_test(b, narrow);
}
agx_optimize_and_dce(actual->shader);
ASSERT_SHADER_EQUAL(actual->shader, expected->shader);
}

/*
* AGX3 has no select form without a register compare operand, so a select of
* two immediates -- here fused out of a compare of two constants -- has to
Expand Down
Loading