diff --git a/src/freedreno/isa/decode.c b/src/freedreno/isa/decode.c index 92d2664ee09..89575d17244 100644 --- a/src/freedreno/isa/decode.c +++ b/src/freedreno/isa/decode.c @@ -32,6 +32,7 @@ #include "util/bitset.h" #include "util/compiler.h" #include "util/half_float.h" +#include "util/hash_table.h" #include "util/ralloc.h" #include "util/u_debug.h" #include "util/u_math.h" @@ -92,6 +93,21 @@ struct decode_scope { * Pointer back to decode state, for convenience. */ struct decode_state *state; + + /** + * Cache expression evaluation results. Expressions for overrides can + * be repeatedly evaluated for each field being resolved. And each + * field reference to a derived field (potentially from another expr) + * would require re-evaluation. But for a given scope, each evaluation + * of an expression gives the same result. So we can cache to speed + * things up. + * + * TODO we could maybe be clever and assign a unique idx to each expr + * and use a direct lookup table? Would be a bit more clever if it was + * smart enough to allow unrelated expressions that are never involved + * in a given scope to have overlapping cache lookup idx's. + */ + struct hash_table *cache; }; /** @@ -225,6 +241,15 @@ pop_scope(struct decode_scope *scope) static uint64_t evaluate_expr(struct decode_scope *scope, isa_expr_t expr) { + if (scope->cache) { + struct hash_entry *entry = _mesa_hash_table_search(scope->cache, expr); + if (entry) { + return *(uint64_t *)entry->data; + } + } else { + scope->cache = _mesa_pointer_hash_table_create(scope); + } + if (!push_expr(scope->state, expr)) return 0; @@ -232,6 +257,10 @@ evaluate_expr(struct decode_scope *scope, isa_expr_t expr) pop_expr(scope->state); + uint64_t *retp = ralloc_size(scope->cache, sizeof(*retp)); + *retp = ret; + _mesa_hash_table_insert(scope->cache, expr, retp); + return ret; }