From dd6106c8bd685e937db48ebe4ba0fca16fbd500b Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 30 Aug 2023 16:25:02 -0400 Subject: [PATCH] agx: Add jumps to block ends jmp_exec_none variant that jumps to the last instruction of the target block, rather than the beginning. This is convenient for skipping over elses, while still executing the block-final pop_exec instruction. Similarly for skipping over loop bodies while still executing the block-final pop_exec, after break instructions. Signed-off-by: Alyssa Rosenzweig --- src/asahi/compiler/agx_compiler.h | 2 +- src/asahi/compiler/agx_opcodes.py | 2 +- src/asahi/compiler/agx_pack.c | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h index b4300813960..562a537c04c 100644 --- a/src/asahi/compiler/agx_compiler.h +++ b/src/asahi/compiler/agx_compiler.h @@ -373,7 +373,7 @@ typedef struct agx_block { bool loop_header; /* Offset of the block in the emitted binary */ - off_t offset; + off_t offset, last_offset; /** Available for passes to use for metadata */ uint8_t pass_flags; diff --git a/src/asahi/compiler/agx_opcodes.py b/src/asahi/compiler/agx_opcodes.py index b0b56205c15..40ce2d1dde3 100644 --- a/src/asahi/compiler/agx_opcodes.py +++ b/src/asahi/compiler/agx_opcodes.py @@ -334,7 +334,7 @@ op("st_tile", (0x09, 0x7F, 8, _), dests = 0, srcs = 2, can_eliminate = False, imms = [FORMAT, MASK, PIXEL_OFFSET], schedule_class = "coverage") -for (name, exact) in [("any", 0xC000), ("none", 0xC020)]: +for (name, exact) in [("any", 0xC000), ("none", 0xC020), ("none_after", 0xC020)]: op("jmp_exec_" + name, (exact, (1 << 16) - 1, 6, _), dests = 0, srcs = 0, can_eliminate = False, schedule_class = "invalid", imms = [TARGET]) diff --git a/src/asahi/compiler/agx_pack.c b/src/asahi/compiler/agx_pack.c index 6cf796a4d2c..5b28de58e56 100644 --- a/src/asahi/compiler/agx_pack.c +++ b/src/asahi/compiler/agx_pack.c @@ -12,6 +12,9 @@ struct agx_branch_fixup { /* Value to patch with will be block->offset */ agx_block *block; + + /* If true, skips to the last instruction of the target block */ + bool skip_to_end; }; static void @@ -939,13 +942,17 @@ agx_pack_instr(struct util_dynarray *emission, struct util_dynarray *fixups, } case AGX_OPCODE_JMP_EXEC_ANY: - case AGX_OPCODE_JMP_EXEC_NONE: { + case AGX_OPCODE_JMP_EXEC_NONE: + case AGX_OPCODE_JMP_EXEC_NONE_AFTER: { /* We don't implement indirect branches */ assert(I->target != NULL); /* We'll fix the offset later. */ - struct agx_branch_fixup fixup = {.block = I->target, - .offset = emission->size}; + struct agx_branch_fixup fixup = { + .block = I->target, + .offset = emission->size, + .skip_to_end = I->op == AGX_OPCODE_JMP_EXEC_NONE_AFTER, + }; util_dynarray_append(fixups, struct agx_branch_fixup, fixup); @@ -971,8 +978,10 @@ agx_fixup_branch(struct util_dynarray *emission, struct agx_branch_fixup fix) /* Branch offset is 2 bytes into the jump instruction */ uint8_t *location = ((uint8_t *)emission->data) + fix.offset + 2; + off_t target = fix.skip_to_end ? fix.block->last_offset : fix.block->offset; + /* Offsets are relative to the jump instruction */ - int32_t patch = (int32_t)fix.block->offset - (int32_t)fix.offset; + int32_t patch = (int32_t)target - (int32_t)fix.offset; /* Patch the binary */ memcpy(location, &patch, sizeof(patch)); @@ -990,6 +999,7 @@ agx_pack_binary(agx_context *ctx, struct util_dynarray *emission) block->offset = emission->size; agx_foreach_instr_in_block(block, ins) { + block->last_offset = emission->size; agx_pack_instr(emission, &fixups, ins, ctx->key->needs_g13x_coherency); } }