freedreno/isa: decode: switch bitmask_t to BITSET_WORD's
This commit changes the underlying basetype of bitmask_t to a BITSET_WORD based one. Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com> Reviewed-by: Rob Clark <robdclark@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11321>
This commit is contained in:
parent
430dc08755
commit
9dc2ef7200
|
@ -472,11 +472,15 @@ disasm_handle_last(struct disasm_ctx *ctx)
|
|||
}
|
||||
|
||||
static void
|
||||
disasm_instr_cb(void *d, unsigned n, uint64_t instr)
|
||||
disasm_instr_cb(void *d, unsigned n, void *instr)
|
||||
{
|
||||
struct disasm_ctx *ctx = d;
|
||||
uint32_t *dwords = (uint32_t *)&instr;
|
||||
unsigned opc_cat = instr >> 61;
|
||||
uint32_t *dwords = (uint32_t *)instr;
|
||||
uint64_t val = dwords[1];
|
||||
val = val << 32;
|
||||
val |= dwords[0];
|
||||
|
||||
unsigned opc_cat = val >> 61;
|
||||
|
||||
/* There are some cases where we can get instr_cb called multiple
|
||||
* times per instruction (like when we need an extra line for branch
|
||||
|
@ -495,9 +499,9 @@ disasm_instr_cb(void *d, unsigned n, uint64_t instr)
|
|||
* some hand-coded parsing:
|
||||
*/
|
||||
if (opc_cat == 1) {
|
||||
unsigned opc = (instr >> 57) & 0x3;
|
||||
unsigned src_type = (instr >> 50) & 0x7;
|
||||
unsigned dst_type = (instr >> 46) & 0x7;
|
||||
unsigned opc = (val >> 57) & 0x3;
|
||||
unsigned src_type = (val >> 50) & 0x7;
|
||||
unsigned dst_type = (val >> 46) & 0x7;
|
||||
|
||||
if (opc == 0) {
|
||||
if (src_type == dst_type) {
|
||||
|
|
|
@ -40,9 +40,6 @@
|
|||
#include "decode.h"
|
||||
#include "isa.h"
|
||||
|
||||
#define BITSET_FORMAT "016"PRIx64
|
||||
#define BITSET_VALUE(v) v
|
||||
|
||||
/**
|
||||
* The set of leaf node bitsets in the bitset hiearchy which defines all
|
||||
* the possible instructions.
|
||||
|
@ -80,7 +77,7 @@ struct decode_scope {
|
|||
/**
|
||||
* Current bitset value being decoded
|
||||
*/
|
||||
uint64_t val;
|
||||
bitmask_t val;
|
||||
|
||||
/**
|
||||
* Current bitset.
|
||||
|
@ -215,11 +212,11 @@ pop_expr(struct decode_state *state)
|
|||
}
|
||||
|
||||
static struct decode_scope *
|
||||
push_scope(struct decode_state *state, const struct isa_bitset *bitset, uint64_t val)
|
||||
push_scope(struct decode_state *state, const struct isa_bitset *bitset, bitmask_t val)
|
||||
{
|
||||
struct decode_scope *scope = rzalloc_size(state, sizeof(*scope));
|
||||
|
||||
scope->val = val;
|
||||
BITSET_COPY(scope->val.bitset, val.bitset);
|
||||
scope->bitset = bitset;
|
||||
scope->parent = state->scope;
|
||||
scope->state = state;
|
||||
|
@ -273,7 +270,7 @@ evaluate_expr(struct decode_scope *scope, isa_expr_t expr)
|
|||
*/
|
||||
static const struct isa_bitset *
|
||||
find_bitset(struct decode_state *state, const struct isa_bitset **bitsets,
|
||||
uint64_t val)
|
||||
bitmask_t val)
|
||||
{
|
||||
const struct isa_bitset *match = NULL;
|
||||
for (int n = 0; bitsets[n]; n++) {
|
||||
|
@ -282,9 +279,18 @@ find_bitset(struct decode_state *state, const struct isa_bitset **bitsets,
|
|||
if (state->options->gpu_id < bitsets[n]->gen.min)
|
||||
continue;
|
||||
|
||||
uint64_t m = (val & bitsets[n]->mask) & ~bitsets[n]->dontcare;
|
||||
// m = (val & bitsets[n]->mask) & ~bitsets[n]->dontcare;
|
||||
bitmask_t m = { 0 };
|
||||
bitmask_t not_dontcare;
|
||||
|
||||
if (m != bitsets[n]->match) {
|
||||
BITSET_AND(m.bitset, val.bitset, bitsets[n]->mask.bitset);
|
||||
|
||||
BITSET_COPY(not_dontcare.bitset, bitsets[n]->dontcare.bitset);
|
||||
BITSET_NOT(not_dontcare.bitset);
|
||||
|
||||
BITSET_AND(m.bitset, m.bitset, not_dontcare.bitset);
|
||||
|
||||
if (!BITSET_EQUAL(m.bitset, bitsets[n]->match.bitset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -302,9 +308,14 @@ find_bitset(struct decode_state *state, const struct isa_bitset **bitsets,
|
|||
match = bitsets[n];
|
||||
}
|
||||
|
||||
if (match && (match->dontcare & val)) {
|
||||
decode_error(state, "dontcare bits in %s: %"BITSET_FORMAT,
|
||||
match->name, BITSET_VALUE(match->dontcare & val));
|
||||
if (match) {
|
||||
bitmask_t m = { 0 };
|
||||
BITSET_AND(m.bitset, match->dontcare.bitset, val.bitset);
|
||||
|
||||
if (BITSET_COUNT(m.bitset)) {
|
||||
decode_error(state, "dontcare bits in %s: %"BITSET_FORMAT,
|
||||
match->name, BITSET_VALUE(m.bitset));
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
|
@ -349,12 +360,19 @@ find_field(struct decode_scope *scope, const struct isa_bitset *bitset,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
static bitmask_t
|
||||
extract_field(struct decode_scope *scope, const struct isa_field *field)
|
||||
{
|
||||
uint64_t val = scope->val;
|
||||
val = (val >> field->low) & ((1ul << (1 + field->high - field->low)) - 1);
|
||||
return val;
|
||||
bitmask_t val, mask;
|
||||
|
||||
BITSET_COPY(val.bitset, scope->val.bitset);
|
||||
BITSET_ZERO(mask.bitset);
|
||||
|
||||
BITSET_SET_RANGE(mask.bitset, field->low, field->high);
|
||||
BITSET_AND(val.bitset, val.bitset, mask.bitset);
|
||||
BITSET_SHR(val.bitset, field->low);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,12 +392,14 @@ find_display(struct decode_scope *scope, const struct isa_bitset *bitset)
|
|||
for (unsigned j = 0; j < c->num_fields; j++) {
|
||||
if (c->fields[j].type == TYPE_ASSERT) {
|
||||
const struct isa_field *f = &c->fields[j];
|
||||
uint64_t val = extract_field(scope, f);
|
||||
if (val != f->val) {
|
||||
bitmask_t val;
|
||||
|
||||
val = extract_field(scope, f);
|
||||
if (!BITSET_EQUAL(val.bitset, f->val.bitset)) {
|
||||
decode_error(scope->state, "WARNING: unexpected "
|
||||
"bits[%u:%u] in %s: %"BITSET_FORMAT" vs %"BITSET_FORMAT,
|
||||
f->low, f->high, bitset->name,
|
||||
BITSET_VALUE(val), BITSET_VALUE(f->val));
|
||||
BITSET_VALUE(val.bitset), BITSET_VALUE(f->val.bitset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,12 +422,12 @@ find_display(struct decode_scope *scope, const struct isa_bitset *bitset)
|
|||
* Decode a field that is itself another bitset type
|
||||
*/
|
||||
static void
|
||||
display_bitset_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)
|
||||
display_bitset_field(struct decode_scope *scope, const struct isa_field *field, bitmask_t val)
|
||||
{
|
||||
const struct isa_bitset *b = find_bitset(scope->state, field->bitsets, val);
|
||||
if (!b) {
|
||||
decode_error(scope->state, "no match: FIELD: '%s.%s': %"BITSET_FORMAT,
|
||||
scope->bitset->name, field->name, BITSET_VALUE(val));
|
||||
scope->bitset->name, field->name, BITSET_VALUE(val.bitset));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -419,23 +439,25 @@ display_bitset_field(struct decode_scope *scope, const struct isa_field *field,
|
|||
}
|
||||
|
||||
static void
|
||||
display_enum_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)
|
||||
display_enum_field(struct decode_scope *scope, const struct isa_field *field, bitmask_t val)
|
||||
{
|
||||
FILE *out = scope->state->out;
|
||||
|
||||
const struct isa_enum *e = field->enums;
|
||||
const uint64_t ui = bitmask_to_uint64_t(val);
|
||||
|
||||
for (unsigned i = 0; i < e->num_values; i++) {
|
||||
if (e->values[i].val == val) {
|
||||
if (e->values[i].val == ui) {
|
||||
fprintf(out, "%s", e->values[i].display);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(out, "%u", (unsigned)val);
|
||||
fprintf(out, "%u", (unsigned)ui);
|
||||
}
|
||||
|
||||
static const struct isa_field *
|
||||
resolve_field(struct decode_scope *scope, const char *field_name, uint64_t *valp)
|
||||
resolve_field(struct decode_scope *scope, const char *field_name, bitmask_t *valp)
|
||||
{
|
||||
if (!scope) {
|
||||
/* We've reached the bottom of the stack! */
|
||||
|
@ -460,7 +482,9 @@ resolve_field(struct decode_scope *scope, const char *field_name, uint64_t *valp
|
|||
|
||||
/* extract out raw field value: */
|
||||
if (field->expr) {
|
||||
*valp = evaluate_expr(scope, field->expr);
|
||||
uint64_t val = evaluate_expr(scope, field->expr);
|
||||
|
||||
*valp = uint64_t_to_bitmask(val);
|
||||
} else {
|
||||
*valp = extract_field(scope, field);
|
||||
}
|
||||
|
@ -472,14 +496,14 @@ resolve_field(struct decode_scope *scope, const char *field_name, uint64_t *valp
|
|||
uint64_t
|
||||
isa_decode_field(struct decode_scope *scope, const char *field_name)
|
||||
{
|
||||
uint64_t val;
|
||||
bitmask_t val;
|
||||
const struct isa_field *field = resolve_field(scope, field_name, &val);
|
||||
if (!field) {
|
||||
decode_error(scope->state, "no field '%s'", field_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
return bitmask_to_uint64_t(val);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -500,13 +524,15 @@ display_field(struct decode_scope *scope, const char *field_name)
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t val;
|
||||
const struct isa_field *field = resolve_field(scope, field_name, &val);
|
||||
bitmask_t v;
|
||||
const struct isa_field *field = resolve_field(scope, field_name, &v);
|
||||
if (!field) {
|
||||
decode_error(scope->state, "no field '%s'", field_name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t val = bitmask_to_uint64_t(v);
|
||||
|
||||
if (options->field_cb) {
|
||||
options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){
|
||||
.num = val,
|
||||
|
@ -566,7 +592,7 @@ display_field(struct decode_scope *scope, const char *field_name)
|
|||
}
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
display_enum_field(scope, field, val);
|
||||
display_enum_field(scope, field, v);
|
||||
break;
|
||||
|
||||
case TYPE_ASSERT:
|
||||
|
@ -576,7 +602,7 @@ display_field(struct decode_scope *scope, const char *field_name)
|
|||
|
||||
/* For fields that are decoded with another bitset hierarchy: */
|
||||
case TYPE_BITSET:
|
||||
display_bitset_field(scope, field, val);
|
||||
display_bitset_field(scope, field, v);
|
||||
break;
|
||||
default:
|
||||
decode_error(scope->state, "Bad field type: %d (%s)",
|
||||
|
@ -616,22 +642,18 @@ display(struct decode_scope *scope)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
next_instruction(bitmask_t *instr, uint64_t *start)
|
||||
{
|
||||
*instr = *start;
|
||||
}
|
||||
|
||||
static void
|
||||
decode(struct decode_state *state, void *bin, int sz)
|
||||
{
|
||||
uint64_t *instrs = bin;
|
||||
BITSET_WORD *instrs = bin;
|
||||
unsigned errors = 0; /* number of consecutive unmatched instructions */
|
||||
|
||||
assert(sz % BITMASK_WORDS == 0);
|
||||
|
||||
for (state->n = 0; state->n < state->num_instr; state->n++) {
|
||||
bitmask_t instr = { 0 };
|
||||
|
||||
next_instruction(&instr, &instrs[state->n]);
|
||||
next_instruction(&instr, &instrs[state->n * BITMASK_WORDS]);
|
||||
|
||||
if (state->options->max_errors && (errors > state->options->max_errors)) {
|
||||
break;
|
||||
|
@ -641,18 +663,18 @@ decode(struct decode_state *state, void *bin, int sz)
|
|||
BITSET_TEST(state->branch_targets, state->n)) {
|
||||
if (state->options->instr_cb) {
|
||||
state->options->instr_cb(state->options->cbdata,
|
||||
state->n, instr);
|
||||
state->n, instr.bitset);
|
||||
}
|
||||
fprintf(state->out, "l%d:\n", state->n);
|
||||
}
|
||||
|
||||
if (state->options->instr_cb) {
|
||||
state->options->instr_cb(state->options->cbdata, state->n, instr);
|
||||
state->options->instr_cb(state->options->cbdata, state->n, instr.bitset);
|
||||
}
|
||||
|
||||
const struct isa_bitset *b = find_bitset(state, __instruction, instr);
|
||||
if (!b) {
|
||||
fprintf(state->out, "no match: %"BITSET_FORMAT"\n", BITSET_VALUE(instr));
|
||||
fprintf(state->out, "no match: %"BITSET_FORMAT"\n", BITSET_VALUE(instr.bitset));
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
@ -690,7 +712,7 @@ isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *option
|
|||
|
||||
state = rzalloc_size(NULL, sizeof(*state));
|
||||
state->options = options;
|
||||
state->num_instr = sz / 8;
|
||||
state->num_instr = sz / (BITMASK_WORDS * sizeof(BITSET_WORD));
|
||||
|
||||
if (state->options->branch_labels) {
|
||||
state->branch_targets = rzalloc_size(state,
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef _DECODE_H_
|
||||
#define _DECODE_H_
|
||||
|
||||
#include <isaspec-isa.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -32,13 +33,6 @@
|
|||
*/
|
||||
|
||||
struct decode_scope;
|
||||
|
||||
/* TODO we could maybe make this a uint8_t array, with some helpers, to
|
||||
* support arbitrary sized patterns.. or add AND/OR/SHIFT support to
|
||||
* util/bitset.h?
|
||||
*/
|
||||
typedef uint64_t bitmask_t;
|
||||
|
||||
struct isa_bitset;
|
||||
|
||||
/**
|
||||
|
@ -106,7 +100,7 @@ struct isa_field {
|
|||
} type;
|
||||
union {
|
||||
const struct isa_bitset **bitsets; /* if type==BITSET */
|
||||
uint64_t val; /* if type==ASSERT */
|
||||
bitmask_t val; /* if type==ASSERT */
|
||||
const struct isa_enum *enums; /* if type==ENUM */
|
||||
const char *display; /* if type==BOOL */
|
||||
};
|
||||
|
|
|
@ -144,7 +144,7 @@ static const struct isa_case ${case.get_c_name()} = {
|
|||
.enums = &${isa.enums[field.type].get_c_name()},
|
||||
% endif
|
||||
% if field.get_c_typename() == 'TYPE_ASSERT':
|
||||
.val = ${field.val},
|
||||
.val.bitset = { ${', '.join(isa.split_bits(field.val))} },
|
||||
% endif
|
||||
},
|
||||
% endfor
|
||||
|
@ -161,9 +161,9 @@ static const struct isa_bitset bitset_${bitset.get_c_name()} = {
|
|||
.min = ${bitset.gen_min},
|
||||
.max = ${bitset.gen_max},
|
||||
},
|
||||
.match = ${hex(pattern.match)},
|
||||
.dontcare = ${hex(pattern.dontcare)},
|
||||
.mask = ${hex(pattern.mask)},
|
||||
.match.bitset = { ${', '.join(isa.split_bits(pattern.match))} },
|
||||
.dontcare.bitset = { ${', '.join(isa.split_bits(pattern.dontcare))} },
|
||||
.mask.bitset = { ${', '.join(isa.split_bits(pattern.mask))} },
|
||||
.num_cases = ${len(bitset.cases)},
|
||||
.cases = {
|
||||
% for case in bitset.cases:
|
||||
|
@ -229,6 +229,14 @@ typedef struct {
|
|||
#define BITSET_FORMAT ${isa.format()}
|
||||
#define BITSET_VALUE(v) ${isa.value()}
|
||||
|
||||
static inline void
|
||||
next_instruction(bitmask_t *instr, BITSET_WORD *start)
|
||||
{
|
||||
%for i in range(0, int(isa.bitsize / 32)):
|
||||
instr->bitset[${i}] = *(start + ${i});
|
||||
%endfor
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
bitmask_to_uint64_t(bitmask_t mask)
|
||||
{
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
|
||||
|
||||
static void
|
||||
disasm_instr_cb(void *d, unsigned n, uint64_t instr)
|
||||
disasm_instr_cb(void *d, unsigned n, void *instr)
|
||||
{
|
||||
uint32_t *dwords = (uint32_t *)&instr;
|
||||
uint32_t *dwords = (uint32_t *)instr;
|
||||
printf("%3d[%08x_%08x] ", n, dwords[1], dwords[0]);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ struct isa_decode_options {
|
|||
/**
|
||||
* Callback prior to instruction decode
|
||||
*/
|
||||
void (*instr_cb)(void *data, unsigned n, uint64_t instr);
|
||||
void (*instr_cb)(void *data, unsigned n, void *instr);
|
||||
};
|
||||
|
||||
void isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *options);
|
||||
|
|
Loading…
Reference in New Issue