mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-08 06:20:19 +01:00
agx: Fix up branch offsets at pack time
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11023>
This commit is contained in:
parent
4fb964ccb8
commit
3def66e8aa
1 changed files with 56 additions and 2 deletions
|
|
@ -23,6 +23,15 @@
|
|||
|
||||
#include "agx_compiler.h"
|
||||
|
||||
/* Binary patches needed for branch offsets */
|
||||
struct agx_branch_fixup {
|
||||
/* Offset into the binary to patch */
|
||||
off_t offset;
|
||||
|
||||
/* Value to patch with will be block->offset */
|
||||
agx_block *block;
|
||||
};
|
||||
|
||||
/* Texturing has its own operands */
|
||||
static unsigned
|
||||
agx_pack_sample_coords(agx_index index, bool *flag)
|
||||
|
|
@ -357,7 +366,7 @@ agx_pack_alu(struct util_dynarray *emission, agx_instr *I)
|
|||
}
|
||||
|
||||
static void
|
||||
agx_pack_instr(struct util_dynarray *emission, agx_instr *I)
|
||||
agx_pack_instr(struct util_dynarray *emission, struct util_dynarray *fixups, agx_instr *I)
|
||||
{
|
||||
switch (I->op) {
|
||||
case AGX_OPCODE_LD_TILE:
|
||||
|
|
@ -547,22 +556,67 @@ agx_pack_instr(struct util_dynarray *emission, agx_instr *I)
|
|||
break;
|
||||
}
|
||||
|
||||
case AGX_OPCODE_JMP_EXEC_ANY:
|
||||
case AGX_OPCODE_JMP_EXEC_NONE:
|
||||
{
|
||||
/* 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
|
||||
};
|
||||
|
||||
util_dynarray_append(fixups, struct agx_branch_fixup, fixup);
|
||||
|
||||
/* The rest of the instruction is fixed */
|
||||
struct agx_opcode_info info = agx_opcodes_info[I->op];
|
||||
uint64_t raw = info.encoding.exact;
|
||||
memcpy(util_dynarray_grow_bytes(emission, 1, 6), &raw, 6);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
agx_pack_alu(emission, I);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Relative branches may be emitted before their targets, so we patch the
|
||||
* binary to fix up the branch offsets after the main emit */
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
/* Offsets are relative to the jump instruction */
|
||||
int32_t patch = (int32_t) fix.block->offset - (int32_t) fix.offset;
|
||||
|
||||
/* Patch the binary */
|
||||
memcpy(location, &patch, sizeof(patch));
|
||||
}
|
||||
|
||||
void
|
||||
agx_pack(agx_context *ctx, struct util_dynarray *emission)
|
||||
{
|
||||
struct util_dynarray fixups;
|
||||
util_dynarray_init(&fixups, ctx);
|
||||
|
||||
agx_foreach_block(ctx, block) {
|
||||
/* Relative to the start of the binary, the block begins at the current
|
||||
* number of bytes emitted */
|
||||
block->offset = emission->size;
|
||||
|
||||
agx_foreach_instr_in_block(block, ins) {
|
||||
agx_pack_instr(emission, ins);
|
||||
agx_pack_instr(emission, &fixups, ins);
|
||||
}
|
||||
}
|
||||
|
||||
util_dynarray_foreach(&fixups, struct agx_branch_fixup, fixup)
|
||||
agx_fixup_branch(emission, *fixup);
|
||||
|
||||
util_dynarray_fini(&fixups);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue