ir3/legalize: prevent infinite loop when inserting (ss)nop

We need to insert a (ss)nop when an instruction that doesn't support
(ss) needs it. However, when this happens in a block that needs to be
legalized more than once (e.g., because it is in a loop), the (ss)nop
would be inserted every iteration, causing an infinite loop.

Fix this by checking if the previous instructions is a nop and applying
(ss) there.

Signed-off-by: Job Noorman <jnoorman@igalia.com>
Fixes: 5993723471 ("freedreno/a3xx/compiler: scheduling/legalize fixes")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36440>
(cherry picked from commit c8f9990733)
This commit is contained in:
Job Noorman 2025-07-29 13:04:19 +02:00 committed by Eric Engestrom
parent 7995ec9c46
commit 3fb8f1066f
2 changed files with 19 additions and 6 deletions

View file

@ -2564,7 +2564,7 @@
"description": "ir3/legalize: prevent infinite loop when inserting (ss)nop",
"nominated": true,
"nomination_type": 2,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "5993723471a81003bd82d189836ccdd8d085a7b5",
"notes": null

View file

@ -722,12 +722,25 @@ legalize_block(struct ir3_legalize_ctx *ctx, struct ir3_block *block)
* this should be a pretty rare case:
*/
if ((n->flags & IR3_INSTR_SS) && !supports_ss(n)) {
struct ir3_instruction *nop;
nop = ir3_NOP(&build);
nop->flags |= IR3_INSTR_SS;
if (last_n && last_n->opc == OPC_NOP) {
/* Note that reusing the previous nop isn't just an optimization
* but prevents infinitely adding nops when this block is in a loop
* and needs to be legalized more than once.
*/
last_n->flags |= IR3_INSTR_SS;
/* If we reuse the last nop, we shouldn't do a full state update as
* its delay has already been taken into account.
*/
sync_update(state, ctx->compiler, last_n);
} else {
struct ir3_instruction *nop = ir3_NOP(&build);
nop->flags |= IR3_INSTR_SS;
ir3_update_legalize_state(state, ctx->compiler, nop);
last_n = nop;
}
n->flags &= ~IR3_INSTR_SS;
last_n = nop;
ir3_update_legalize_state(state, ctx->compiler, nop);
}
unsigned delay = ir3_required_delay(state, ctx->compiler, n);