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 <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig 2023-08-30 16:25:02 -04:00
parent 22ab505a3d
commit dd6106c8bd
3 changed files with 16 additions and 6 deletions

View file

@ -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;

View file

@ -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])

View file

@ -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);
}
}