1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <assert.h> 25bf215546Sopenharmony_ci#include <inttypes.h> 26bf215546Sopenharmony_ci#include <stdbool.h> 27bf215546Sopenharmony_ci#include <stdint.h> 28bf215546Sopenharmony_ci#include <stdio.h> 29bf215546Sopenharmony_ci#include <stdlib.h> 30bf215546Sopenharmony_ci#include <string.h> 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "util/bitset.h" 33bf215546Sopenharmony_ci#include "util/compiler.h" 34bf215546Sopenharmony_ci#include "util/half_float.h" 35bf215546Sopenharmony_ci#include "util/hash_table.h" 36bf215546Sopenharmony_ci#include "util/ralloc.h" 37bf215546Sopenharmony_ci#include "util/u_debug.h" 38bf215546Sopenharmony_ci#include "util/u_math.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "decode.h" 41bf215546Sopenharmony_ci#include "isa.h" 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci/** 44bf215546Sopenharmony_ci * The set of leaf node bitsets in the bitset hiearchy which defines all 45bf215546Sopenharmony_ci * the possible instructions. 46bf215546Sopenharmony_ci * 47bf215546Sopenharmony_ci * TODO maybe we want to pass this in as parameter so this same decoder 48bf215546Sopenharmony_ci * can work with multiple different instruction sets. 49bf215546Sopenharmony_ci */ 50bf215546Sopenharmony_ciextern const struct isa_bitset *__instruction[]; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistruct decode_state; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci/** 55bf215546Sopenharmony_ci * Decode scope. When parsing a field that is itself a bitset, we push a 56bf215546Sopenharmony_ci * new scope to the stack. A nested bitset is allowed to resolve fields 57bf215546Sopenharmony_ci * from an enclosing scope (needed, for example, to decode src register 58bf215546Sopenharmony_ci * bitsets, where half/fullness is determined by fields outset if bitset 59bf215546Sopenharmony_ci * in the instruction containing the bitset. 60bf215546Sopenharmony_ci * 61bf215546Sopenharmony_ci * But the field being resolved could be a derived field, or different 62bf215546Sopenharmony_ci * depending on an override at a higher level of the stack, requiring 63bf215546Sopenharmony_ci * expression evaluation which could in turn reference variables which 64bf215546Sopenharmony_ci * triggers a recursive field lookup. But those lookups should not start 65bf215546Sopenharmony_ci * from the top of the stack, but instead the current stack level. This 66bf215546Sopenharmony_ci * prevents a field from accidentally resolving to different values 67bf215546Sopenharmony_ci * depending on the starting point of the lookup. (Not only causing 68bf215546Sopenharmony_ci * confusion, but this is behavior we don't want to depend on if we 69bf215546Sopenharmony_ci * wanted to optimize things by caching field lookup results.) 70bf215546Sopenharmony_ci */ 71bf215546Sopenharmony_cistruct decode_scope { 72bf215546Sopenharmony_ci /** 73bf215546Sopenharmony_ci * Enclosing scope 74bf215546Sopenharmony_ci */ 75bf215546Sopenharmony_ci struct decode_scope *parent; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /** 78bf215546Sopenharmony_ci * Current bitset value being decoded 79bf215546Sopenharmony_ci */ 80bf215546Sopenharmony_ci bitmask_t val; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci /** 83bf215546Sopenharmony_ci * Current bitset. 84bf215546Sopenharmony_ci */ 85bf215546Sopenharmony_ci const struct isa_bitset *bitset; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci /** 88bf215546Sopenharmony_ci * Field name remapping. 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_ci const struct isa_field_params *params; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci /** 93bf215546Sopenharmony_ci * Pointer back to decode state, for convenience. 94bf215546Sopenharmony_ci */ 95bf215546Sopenharmony_ci struct decode_state *state; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci /** 98bf215546Sopenharmony_ci * Cache expression evaluation results. Expressions for overrides can 99bf215546Sopenharmony_ci * be repeatedly evaluated for each field being resolved. And each 100bf215546Sopenharmony_ci * field reference to a derived field (potentially from another expr) 101bf215546Sopenharmony_ci * would require re-evaluation. But for a given scope, each evaluation 102bf215546Sopenharmony_ci * of an expression gives the same result. So we can cache to speed 103bf215546Sopenharmony_ci * things up. 104bf215546Sopenharmony_ci * 105bf215546Sopenharmony_ci * TODO we could maybe be clever and assign a unique idx to each expr 106bf215546Sopenharmony_ci * and use a direct lookup table? Would be a bit more clever if it was 107bf215546Sopenharmony_ci * smart enough to allow unrelated expressions that are never involved 108bf215546Sopenharmony_ci * in a given scope to have overlapping cache lookup idx's. 109bf215546Sopenharmony_ci */ 110bf215546Sopenharmony_ci struct hash_table *cache; 111bf215546Sopenharmony_ci}; 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci/** 114bf215546Sopenharmony_ci * Current decode state 115bf215546Sopenharmony_ci */ 116bf215546Sopenharmony_cistruct decode_state { 117bf215546Sopenharmony_ci const struct isa_decode_options *options; 118bf215546Sopenharmony_ci FILE *out; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci /** 121bf215546Sopenharmony_ci * Current instruction being decoded: 122bf215546Sopenharmony_ci */ 123bf215546Sopenharmony_ci unsigned n; 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci /** 126bf215546Sopenharmony_ci * Number of instructions being decoded 127bf215546Sopenharmony_ci */ 128bf215546Sopenharmony_ci unsigned num_instr; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci /** 131bf215546Sopenharmony_ci * Column number of current line 132bf215546Sopenharmony_ci */ 133bf215546Sopenharmony_ci unsigned line_column; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci /** 136bf215546Sopenharmony_ci * Bitset of instructions that are branch targets (if options->branch_labels 137bf215546Sopenharmony_ci * is enabled) 138bf215546Sopenharmony_ci */ 139bf215546Sopenharmony_ci BITSET_WORD *branch_targets; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /** 142bf215546Sopenharmony_ci * We allow a limited amount of expression evaluation recursion, but 143bf215546Sopenharmony_ci * not recursive evaluation of any given expression, to prevent infinite 144bf215546Sopenharmony_ci * recursion. 145bf215546Sopenharmony_ci */ 146bf215546Sopenharmony_ci int expr_sp; 147bf215546Sopenharmony_ci isa_expr_t expr_stack[8]; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci /** 150bf215546Sopenharmony_ci * Current topmost/innermost level of scope used for decoding fields, 151bf215546Sopenharmony_ci * including derived fields which may in turn rely on decoding other 152bf215546Sopenharmony_ci * fields, potentially from a lower/out level in the stack. 153bf215546Sopenharmony_ci */ 154bf215546Sopenharmony_ci struct decode_scope *scope; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci /** 157bf215546Sopenharmony_ci * A small fixed upper limit on # of decode errors to capture per- 158bf215546Sopenharmony_ci * instruction seems reasonable. 159bf215546Sopenharmony_ci */ 160bf215546Sopenharmony_ci unsigned num_errors; 161bf215546Sopenharmony_ci char *errors[4]; 162bf215546Sopenharmony_ci}; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_cistatic void 165bf215546Sopenharmony_ciprint(struct decode_state *state, const char *fmt, ...) 166bf215546Sopenharmony_ci{ 167bf215546Sopenharmony_ci char *buffer; 168bf215546Sopenharmony_ci va_list args; 169bf215546Sopenharmony_ci int ret; 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci va_start(args, fmt); 172bf215546Sopenharmony_ci ret = vasprintf(&buffer, fmt, args); 173bf215546Sopenharmony_ci va_end(args); 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci if (ret != -1) { 176bf215546Sopenharmony_ci const size_t len = strlen(buffer); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci for (size_t i = 0; i < len; i++) { 179bf215546Sopenharmony_ci const char c = buffer[i]; 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci fputc(c, state->out); 182bf215546Sopenharmony_ci state->line_column++; 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci if (c == '\n') { 185bf215546Sopenharmony_ci state->line_column = 0; 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci free(buffer); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci return; 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci} 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_cistatic void display(struct decode_scope *scope); 196bf215546Sopenharmony_cistatic void decode_error(struct decode_state *state, const char *fmt, ...) _util_printf_format(2,3); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_cistatic void 199bf215546Sopenharmony_cidecode_error(struct decode_state *state, const char *fmt, ...) 200bf215546Sopenharmony_ci{ 201bf215546Sopenharmony_ci if (!state->options->show_errors) { 202bf215546Sopenharmony_ci return; 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (state->num_errors == ARRAY_SIZE(state->errors)) { 206bf215546Sopenharmony_ci /* too many errors, bail */ 207bf215546Sopenharmony_ci return; 208bf215546Sopenharmony_ci } 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci va_list ap; 211bf215546Sopenharmony_ci va_start(ap, fmt); 212bf215546Sopenharmony_ci vasprintf(&state->errors[state->num_errors++], fmt, ap); 213bf215546Sopenharmony_ci va_end(ap); 214bf215546Sopenharmony_ci} 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_cistatic unsigned 217bf215546Sopenharmony_ciflush_errors(struct decode_state *state) 218bf215546Sopenharmony_ci{ 219bf215546Sopenharmony_ci unsigned num_errors = state->num_errors; 220bf215546Sopenharmony_ci if (num_errors > 0) 221bf215546Sopenharmony_ci print(state, "\t; "); 222bf215546Sopenharmony_ci for (unsigned i = 0; i < num_errors; i++) { 223bf215546Sopenharmony_ci print(state, "%s%s", (i > 0) ? ", " : "", state->errors[i]); 224bf215546Sopenharmony_ci free(state->errors[i]); 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci state->num_errors = 0; 227bf215546Sopenharmony_ci return num_errors; 228bf215546Sopenharmony_ci} 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_cistatic bool 232bf215546Sopenharmony_cipush_expr(struct decode_state *state, isa_expr_t expr) 233bf215546Sopenharmony_ci{ 234bf215546Sopenharmony_ci for (int i = state->expr_sp - 1; i > 0; i--) { 235bf215546Sopenharmony_ci if (state->expr_stack[i] == expr) { 236bf215546Sopenharmony_ci return false; 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci state->expr_stack[state->expr_sp++] = expr; 240bf215546Sopenharmony_ci return true; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_cistatic void 244bf215546Sopenharmony_cipop_expr(struct decode_state *state) 245bf215546Sopenharmony_ci{ 246bf215546Sopenharmony_ci assert(state->expr_sp > 0); 247bf215546Sopenharmony_ci state->expr_sp--; 248bf215546Sopenharmony_ci} 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_cistatic struct decode_scope * 251bf215546Sopenharmony_cipush_scope(struct decode_state *state, const struct isa_bitset *bitset, bitmask_t val) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci struct decode_scope *scope = rzalloc_size(state, sizeof(*scope)); 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci BITSET_COPY(scope->val.bitset, val.bitset); 256bf215546Sopenharmony_ci scope->bitset = bitset; 257bf215546Sopenharmony_ci scope->parent = state->scope; 258bf215546Sopenharmony_ci scope->state = state; 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci state->scope = scope; 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci return scope; 263bf215546Sopenharmony_ci} 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_cistatic void 266bf215546Sopenharmony_cipop_scope(struct decode_scope *scope) 267bf215546Sopenharmony_ci{ 268bf215546Sopenharmony_ci assert(scope->state->scope == scope); /* must be top of stack */ 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci scope->state->scope = scope->parent; 271bf215546Sopenharmony_ci ralloc_free(scope); 272bf215546Sopenharmony_ci} 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci/** 275bf215546Sopenharmony_ci * Evaluate an expression, returning it's resulting value 276bf215546Sopenharmony_ci */ 277bf215546Sopenharmony_cistatic uint64_t 278bf215546Sopenharmony_cievaluate_expr(struct decode_scope *scope, isa_expr_t expr) 279bf215546Sopenharmony_ci{ 280bf215546Sopenharmony_ci if (scope->cache) { 281bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search(scope->cache, expr); 282bf215546Sopenharmony_ci if (entry) { 283bf215546Sopenharmony_ci return *(uint64_t *)entry->data; 284bf215546Sopenharmony_ci } 285bf215546Sopenharmony_ci } else { 286bf215546Sopenharmony_ci scope->cache = _mesa_pointer_hash_table_create(scope); 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci if (!push_expr(scope->state, expr)) 290bf215546Sopenharmony_ci return 0; 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci uint64_t ret = expr(scope); 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci pop_expr(scope->state); 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci uint64_t *retp = ralloc_size(scope->cache, sizeof(*retp)); 297bf215546Sopenharmony_ci *retp = ret; 298bf215546Sopenharmony_ci _mesa_hash_table_insert(scope->cache, expr, retp); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci return ret; 301bf215546Sopenharmony_ci} 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci/** 304bf215546Sopenharmony_ci * Find the bitset in NULL terminated bitset hiearchy root table which 305bf215546Sopenharmony_ci * matches against 'val' 306bf215546Sopenharmony_ci */ 307bf215546Sopenharmony_cistatic const struct isa_bitset * 308bf215546Sopenharmony_cifind_bitset(struct decode_state *state, const struct isa_bitset **bitsets, 309bf215546Sopenharmony_ci bitmask_t val) 310bf215546Sopenharmony_ci{ 311bf215546Sopenharmony_ci const struct isa_bitset *match = NULL; 312bf215546Sopenharmony_ci for (int n = 0; bitsets[n]; n++) { 313bf215546Sopenharmony_ci if (state->options->gpu_id > bitsets[n]->gen.max) 314bf215546Sopenharmony_ci continue; 315bf215546Sopenharmony_ci if (state->options->gpu_id < bitsets[n]->gen.min) 316bf215546Sopenharmony_ci continue; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci // m = (val & bitsets[n]->mask) & ~bitsets[n]->dontcare; 319bf215546Sopenharmony_ci bitmask_t m = { 0 }; 320bf215546Sopenharmony_ci bitmask_t not_dontcare; 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci BITSET_AND(m.bitset, val.bitset, bitsets[n]->mask.bitset); 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci BITSET_COPY(not_dontcare.bitset, bitsets[n]->dontcare.bitset); 325bf215546Sopenharmony_ci BITSET_NOT(not_dontcare.bitset); 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci BITSET_AND(m.bitset, m.bitset, not_dontcare.bitset); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci if (!BITSET_EQUAL(m.bitset, bitsets[n]->match.bitset)) { 330bf215546Sopenharmony_ci continue; 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci /* We should only have exactly one match 334bf215546Sopenharmony_ci * 335bf215546Sopenharmony_ci * TODO more complete/formal way to validate that any given 336bf215546Sopenharmony_ci * bit pattern will only have a single match? 337bf215546Sopenharmony_ci */ 338bf215546Sopenharmony_ci if (match) { 339bf215546Sopenharmony_ci decode_error(state, "bitset conflict: %s vs %s", match->name, 340bf215546Sopenharmony_ci bitsets[n]->name); 341bf215546Sopenharmony_ci return NULL; 342bf215546Sopenharmony_ci } 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci match = bitsets[n]; 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci if (match) { 348bf215546Sopenharmony_ci bitmask_t m = { 0 }; 349bf215546Sopenharmony_ci BITSET_AND(m.bitset, match->dontcare.bitset, val.bitset); 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci if (BITSET_COUNT(m.bitset)) { 352bf215546Sopenharmony_ci decode_error(state, "dontcare bits in %s: %"BITSET_FORMAT, 353bf215546Sopenharmony_ci match->name, BITSET_VALUE(m.bitset)); 354bf215546Sopenharmony_ci } 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci return match; 358bf215546Sopenharmony_ci} 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_cistatic const struct isa_field * 361bf215546Sopenharmony_cifind_field(struct decode_scope *scope, const struct isa_bitset *bitset, 362bf215546Sopenharmony_ci const char *name, size_t name_len) 363bf215546Sopenharmony_ci{ 364bf215546Sopenharmony_ci for (unsigned i = 0; i < bitset->num_cases; i++) { 365bf215546Sopenharmony_ci const struct isa_case *c = bitset->cases[i]; 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci if (c->expr) { 368bf215546Sopenharmony_ci struct decode_state *state = scope->state; 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci /* When resolving a field for evaluating an expression, 371bf215546Sopenharmony_ci * temporarily assume the expression evaluates to true. 372bf215546Sopenharmony_ci * This allows <override/>'s to speculatively refer to 373bf215546Sopenharmony_ci * fields defined within the override: 374bf215546Sopenharmony_ci */ 375bf215546Sopenharmony_ci isa_expr_t cur_expr = NULL; 376bf215546Sopenharmony_ci if (state->expr_sp > 0) 377bf215546Sopenharmony_ci cur_expr = state->expr_stack[state->expr_sp - 1]; 378bf215546Sopenharmony_ci if ((cur_expr != c->expr) && !evaluate_expr(scope, c->expr)) 379bf215546Sopenharmony_ci continue; 380bf215546Sopenharmony_ci } 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci for (unsigned i = 0; i < c->num_fields; i++) { 383bf215546Sopenharmony_ci if (!strncmp(name, c->fields[i].name, name_len) && 384bf215546Sopenharmony_ci (c->fields[i].name[name_len] == '\0')) { 385bf215546Sopenharmony_ci return &c->fields[i]; 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci } 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci if (bitset->parent) { 391bf215546Sopenharmony_ci const struct isa_field *f = find_field(scope, bitset->parent, name, name_len); 392bf215546Sopenharmony_ci if (f) { 393bf215546Sopenharmony_ci return f; 394bf215546Sopenharmony_ci } 395bf215546Sopenharmony_ci } 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci return NULL; 398bf215546Sopenharmony_ci} 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_cistatic bitmask_t 401bf215546Sopenharmony_ciextract_field(struct decode_scope *scope, const struct isa_field *field) 402bf215546Sopenharmony_ci{ 403bf215546Sopenharmony_ci bitmask_t val, mask; 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci BITSET_COPY(val.bitset, scope->val.bitset); 406bf215546Sopenharmony_ci BITSET_ZERO(mask.bitset); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci BITSET_SET_RANGE(mask.bitset, field->low, field->high); 409bf215546Sopenharmony_ci BITSET_AND(val.bitset, val.bitset, mask.bitset); 410bf215546Sopenharmony_ci BITSET_SHR(val.bitset, field->low); 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci return val; 413bf215546Sopenharmony_ci} 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci/** 416bf215546Sopenharmony_ci * Find the display template for a given bitset, recursively searching 417bf215546Sopenharmony_ci * parents in the bitset hierarchy. 418bf215546Sopenharmony_ci */ 419bf215546Sopenharmony_cistatic const char * 420bf215546Sopenharmony_cifind_display(struct decode_scope *scope, const struct isa_bitset *bitset) 421bf215546Sopenharmony_ci{ 422bf215546Sopenharmony_ci for (unsigned i = 0; i < bitset->num_cases; i++) { 423bf215546Sopenharmony_ci const struct isa_case *c = bitset->cases[i]; 424bf215546Sopenharmony_ci if (c->expr && !evaluate_expr(scope, c->expr)) 425bf215546Sopenharmony_ci continue; 426bf215546Sopenharmony_ci /* since this is the chosen case, it seems like a good place 427bf215546Sopenharmony_ci * to check asserted bits: 428bf215546Sopenharmony_ci */ 429bf215546Sopenharmony_ci for (unsigned j = 0; j < c->num_fields; j++) { 430bf215546Sopenharmony_ci if (c->fields[j].type == TYPE_ASSERT) { 431bf215546Sopenharmony_ci const struct isa_field *f = &c->fields[j]; 432bf215546Sopenharmony_ci bitmask_t val; 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci val = extract_field(scope, f); 435bf215546Sopenharmony_ci if (!BITSET_EQUAL(val.bitset, f->val.bitset)) { 436bf215546Sopenharmony_ci decode_error(scope->state, "WARNING: unexpected " 437bf215546Sopenharmony_ci "bits[%u:%u] in %s: %"BITSET_FORMAT" vs %"BITSET_FORMAT, 438bf215546Sopenharmony_ci f->low, f->high, bitset->name, 439bf215546Sopenharmony_ci BITSET_VALUE(val.bitset), BITSET_VALUE(f->val.bitset)); 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci } 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci if (!c->display) 444bf215546Sopenharmony_ci continue; 445bf215546Sopenharmony_ci return c->display; 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci /** 449bf215546Sopenharmony_ci * If we didn't find something check up the bitset hierarchy. 450bf215546Sopenharmony_ci */ 451bf215546Sopenharmony_ci if (bitset->parent) { 452bf215546Sopenharmony_ci return find_display(scope, bitset->parent); 453bf215546Sopenharmony_ci } 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci return NULL; 456bf215546Sopenharmony_ci} 457bf215546Sopenharmony_ci 458bf215546Sopenharmony_ci/** 459bf215546Sopenharmony_ci * Decode a field that is itself another bitset type 460bf215546Sopenharmony_ci */ 461bf215546Sopenharmony_cistatic void 462bf215546Sopenharmony_cidisplay_bitset_field(struct decode_scope *scope, const struct isa_field *field, bitmask_t val) 463bf215546Sopenharmony_ci{ 464bf215546Sopenharmony_ci const struct isa_bitset *b = find_bitset(scope->state, field->bitsets, val); 465bf215546Sopenharmony_ci if (!b) { 466bf215546Sopenharmony_ci decode_error(scope->state, "no match: FIELD: '%s.%s': %"BITSET_FORMAT, 467bf215546Sopenharmony_ci scope->bitset->name, field->name, BITSET_VALUE(val.bitset)); 468bf215546Sopenharmony_ci return; 469bf215546Sopenharmony_ci } 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci struct decode_scope *nested_scope = 472bf215546Sopenharmony_ci push_scope(scope->state, b, val); 473bf215546Sopenharmony_ci nested_scope->params = field->params; 474bf215546Sopenharmony_ci display(nested_scope); 475bf215546Sopenharmony_ci pop_scope(nested_scope); 476bf215546Sopenharmony_ci} 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_cistatic void 479bf215546Sopenharmony_cidisplay_enum_field(struct decode_scope *scope, const struct isa_field *field, bitmask_t val) 480bf215546Sopenharmony_ci{ 481bf215546Sopenharmony_ci const struct isa_enum *e = field->enums; 482bf215546Sopenharmony_ci const uint64_t ui = bitmask_to_uint64_t(val); 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci for (unsigned i = 0; i < e->num_values; i++) { 485bf215546Sopenharmony_ci if (e->values[i].val == ui) { 486bf215546Sopenharmony_ci print(scope->state, "%s", e->values[i].display); 487bf215546Sopenharmony_ci return; 488bf215546Sopenharmony_ci } 489bf215546Sopenharmony_ci } 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci print(scope->state, "%u", (unsigned)ui); 492bf215546Sopenharmony_ci} 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_cistatic const struct isa_field * 495bf215546Sopenharmony_ciresolve_field(struct decode_scope *scope, const char *field_name, size_t field_name_len, bitmask_t *valp) 496bf215546Sopenharmony_ci{ 497bf215546Sopenharmony_ci if (!scope) { 498bf215546Sopenharmony_ci /* We've reached the bottom of the stack! */ 499bf215546Sopenharmony_ci return NULL; 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_ci const struct isa_field *field = 503bf215546Sopenharmony_ci find_field(scope, scope->bitset, field_name, field_name_len); 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci if (!field && scope->params) { 506bf215546Sopenharmony_ci for (unsigned i = 0; i < scope->params->num_params; i++) { 507bf215546Sopenharmony_ci if (!strncmp(field_name, scope->params->params[i].as, field_name_len) && 508bf215546Sopenharmony_ci (scope->params->params[i].as[field_name_len] == '\0')) { 509bf215546Sopenharmony_ci const char *param_name = scope->params->params[i].name; 510bf215546Sopenharmony_ci return resolve_field(scope->parent, param_name, strlen(param_name), valp); 511bf215546Sopenharmony_ci } 512bf215546Sopenharmony_ci } 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci if (!field) { 516bf215546Sopenharmony_ci return NULL; 517bf215546Sopenharmony_ci } 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_ci /* extract out raw field value: */ 520bf215546Sopenharmony_ci if (field->expr) { 521bf215546Sopenharmony_ci uint64_t val = evaluate_expr(scope, field->expr); 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci *valp = uint64_t_to_bitmask(val); 524bf215546Sopenharmony_ci } else { 525bf215546Sopenharmony_ci *valp = extract_field(scope, field); 526bf215546Sopenharmony_ci } 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci return field; 529bf215546Sopenharmony_ci} 530bf215546Sopenharmony_ci 531bf215546Sopenharmony_ci/* This is also used from generated expr functions */ 532bf215546Sopenharmony_ciuint64_t 533bf215546Sopenharmony_ciisa_decode_field(struct decode_scope *scope, const char *field_name) 534bf215546Sopenharmony_ci{ 535bf215546Sopenharmony_ci bitmask_t val; 536bf215546Sopenharmony_ci const struct isa_field *field = resolve_field(scope, field_name, strlen(field_name), &val); 537bf215546Sopenharmony_ci if (!field) { 538bf215546Sopenharmony_ci decode_error(scope->state, "no field '%s'", field_name); 539bf215546Sopenharmony_ci return 0; 540bf215546Sopenharmony_ci } 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci return bitmask_to_uint64_t(val); 543bf215546Sopenharmony_ci} 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_cistatic void 546bf215546Sopenharmony_cidisplay_field(struct decode_scope *scope, const char *field_name) 547bf215546Sopenharmony_ci{ 548bf215546Sopenharmony_ci const struct isa_decode_options *options = scope->state->options; 549bf215546Sopenharmony_ci struct decode_state *state = scope->state; 550bf215546Sopenharmony_ci size_t field_name_len = strlen(field_name); 551bf215546Sopenharmony_ci int num_align = 0; 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci /* alignment handling */ 554bf215546Sopenharmony_ci const char *align = strstr(field_name, ":align="); 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci if (align) { 557bf215546Sopenharmony_ci const char *value = strstr(align, "=") + 1; 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci field_name_len = align - field_name; 560bf215546Sopenharmony_ci num_align = atoi(value); 561bf215546Sopenharmony_ci } 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci /* Special case ':algin=' should only do alignment */ 564bf215546Sopenharmony_ci if (field_name == align) { 565bf215546Sopenharmony_ci while (scope->state->line_column < num_align) 566bf215546Sopenharmony_ci print(state, " "); 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci return; 569bf215546Sopenharmony_ci } 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci /* Special case 'NAME' maps to instruction/bitset name: */ 572bf215546Sopenharmony_ci if (!strncmp("NAME", field_name, field_name_len)) { 573bf215546Sopenharmony_ci if (options->field_cb) { 574bf215546Sopenharmony_ci options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){ 575bf215546Sopenharmony_ci .str = scope->bitset->name, 576bf215546Sopenharmony_ci }); 577bf215546Sopenharmony_ci } 578bf215546Sopenharmony_ci 579bf215546Sopenharmony_ci while (scope->state->line_column < num_align) 580bf215546Sopenharmony_ci print(state, " "); 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci print(scope->state, "%s", scope->bitset->name); 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci return; 585bf215546Sopenharmony_ci } 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci bitmask_t v; 588bf215546Sopenharmony_ci const struct isa_field *field = resolve_field(scope, field_name, field_name_len, &v); 589bf215546Sopenharmony_ci if (!field) { 590bf215546Sopenharmony_ci decode_error(scope->state, "no field '%.*s'", (int)field_name_len, field_name); 591bf215546Sopenharmony_ci return; 592bf215546Sopenharmony_ci } 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci uint64_t val = bitmask_to_uint64_t(v); 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_ci if (options->field_cb) { 597bf215546Sopenharmony_ci options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){ 598bf215546Sopenharmony_ci .num = val, 599bf215546Sopenharmony_ci }); 600bf215546Sopenharmony_ci } 601bf215546Sopenharmony_ci 602bf215546Sopenharmony_ci unsigned width = 1 + field->high - field->low; 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_ci while (scope->state->line_column < num_align) 605bf215546Sopenharmony_ci print(state, " "); 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci switch (field->type) { 608bf215546Sopenharmony_ci /* Basic types: */ 609bf215546Sopenharmony_ci case TYPE_BRANCH: 610bf215546Sopenharmony_ci if (scope->state->options->branch_labels) { 611bf215546Sopenharmony_ci int offset = util_sign_extend(val, width) + scope->state->n; 612bf215546Sopenharmony_ci if (offset < scope->state->num_instr) { 613bf215546Sopenharmony_ci print(scope->state, "l%d", offset); 614bf215546Sopenharmony_ci BITSET_SET(scope->state->branch_targets, offset); 615bf215546Sopenharmony_ci break; 616bf215546Sopenharmony_ci } 617bf215546Sopenharmony_ci } 618bf215546Sopenharmony_ci FALLTHROUGH; 619bf215546Sopenharmony_ci case TYPE_INT: 620bf215546Sopenharmony_ci print(scope->state, "%"PRId64, util_sign_extend(val, width)); 621bf215546Sopenharmony_ci break; 622bf215546Sopenharmony_ci case TYPE_UINT: 623bf215546Sopenharmony_ci print(scope->state, "%"PRIu64, val); 624bf215546Sopenharmony_ci break; 625bf215546Sopenharmony_ci case TYPE_HEX: 626bf215546Sopenharmony_ci // TODO format # of digits based on field width? 627bf215546Sopenharmony_ci print(scope->state, "%"PRIx64, val); 628bf215546Sopenharmony_ci break; 629bf215546Sopenharmony_ci case TYPE_OFFSET: 630bf215546Sopenharmony_ci if (val != 0) { 631bf215546Sopenharmony_ci print(scope->state, "%+"PRId64, util_sign_extend(val, width)); 632bf215546Sopenharmony_ci } 633bf215546Sopenharmony_ci break; 634bf215546Sopenharmony_ci case TYPE_UOFFSET: 635bf215546Sopenharmony_ci if (val != 0) { 636bf215546Sopenharmony_ci print(scope->state, "+%"PRIu64, val); 637bf215546Sopenharmony_ci } 638bf215546Sopenharmony_ci break; 639bf215546Sopenharmony_ci case TYPE_FLOAT: 640bf215546Sopenharmony_ci if (width == 16) { 641bf215546Sopenharmony_ci print(scope->state, "%f", _mesa_half_to_float(val)); 642bf215546Sopenharmony_ci } else { 643bf215546Sopenharmony_ci assert(width == 32); 644bf215546Sopenharmony_ci print(scope->state, "%f", uif(val)); 645bf215546Sopenharmony_ci } 646bf215546Sopenharmony_ci break; 647bf215546Sopenharmony_ci case TYPE_BOOL: 648bf215546Sopenharmony_ci if (field->display) { 649bf215546Sopenharmony_ci if (val) { 650bf215546Sopenharmony_ci print(scope->state, "%s", field->display); 651bf215546Sopenharmony_ci } 652bf215546Sopenharmony_ci } else { 653bf215546Sopenharmony_ci print(scope->state, "%u", (unsigned)val); 654bf215546Sopenharmony_ci } 655bf215546Sopenharmony_ci break; 656bf215546Sopenharmony_ci case TYPE_ENUM: 657bf215546Sopenharmony_ci display_enum_field(scope, field, v); 658bf215546Sopenharmony_ci break; 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci case TYPE_ASSERT: 661bf215546Sopenharmony_ci /* assert fields are not for display */ 662bf215546Sopenharmony_ci assert(0); 663bf215546Sopenharmony_ci break; 664bf215546Sopenharmony_ci 665bf215546Sopenharmony_ci /* For fields that are decoded with another bitset hierarchy: */ 666bf215546Sopenharmony_ci case TYPE_BITSET: 667bf215546Sopenharmony_ci display_bitset_field(scope, field, v); 668bf215546Sopenharmony_ci break; 669bf215546Sopenharmony_ci default: 670bf215546Sopenharmony_ci decode_error(scope->state, "Bad field type: %d (%s)", 671bf215546Sopenharmony_ci field->type, field->name); 672bf215546Sopenharmony_ci } 673bf215546Sopenharmony_ci} 674bf215546Sopenharmony_ci 675bf215546Sopenharmony_cistatic void 676bf215546Sopenharmony_cidisplay(struct decode_scope *scope) 677bf215546Sopenharmony_ci{ 678bf215546Sopenharmony_ci const struct isa_bitset *bitset = scope->bitset; 679bf215546Sopenharmony_ci const char *display = find_display(scope, bitset); 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci if (!display) { 682bf215546Sopenharmony_ci decode_error(scope->state, "%s: no display template", bitset->name); 683bf215546Sopenharmony_ci return; 684bf215546Sopenharmony_ci } 685bf215546Sopenharmony_ci 686bf215546Sopenharmony_ci const char *p = display; 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci while (*p != '\0') { 689bf215546Sopenharmony_ci if (*p == '{') { 690bf215546Sopenharmony_ci const char *e = ++p; 691bf215546Sopenharmony_ci while (*e != '}') { 692bf215546Sopenharmony_ci e++; 693bf215546Sopenharmony_ci } 694bf215546Sopenharmony_ci 695bf215546Sopenharmony_ci char *field_name = strndup(p, e-p); 696bf215546Sopenharmony_ci display_field(scope, field_name); 697bf215546Sopenharmony_ci free(field_name); 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci p = e; 700bf215546Sopenharmony_ci } else { 701bf215546Sopenharmony_ci fputc(*p, scope->state->out); 702bf215546Sopenharmony_ci scope->state->line_column++; 703bf215546Sopenharmony_ci } 704bf215546Sopenharmony_ci p++; 705bf215546Sopenharmony_ci } 706bf215546Sopenharmony_ci} 707bf215546Sopenharmony_ci 708bf215546Sopenharmony_cistatic void 709bf215546Sopenharmony_cidecode(struct decode_state *state, void *bin, int sz) 710bf215546Sopenharmony_ci{ 711bf215546Sopenharmony_ci BITSET_WORD *instrs = bin; 712bf215546Sopenharmony_ci unsigned errors = 0; /* number of consecutive unmatched instructions */ 713bf215546Sopenharmony_ci 714bf215546Sopenharmony_ci assert(sz % BITMASK_WORDS == 0); 715bf215546Sopenharmony_ci 716bf215546Sopenharmony_ci for (state->n = 0; state->n < state->num_instr; state->n++) { 717bf215546Sopenharmony_ci bitmask_t instr = { 0 }; 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci next_instruction(&instr, &instrs[state->n * BITMASK_WORDS]); 720bf215546Sopenharmony_ci state->line_column = 0; 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci if (state->options->max_errors && (errors > state->options->max_errors)) { 723bf215546Sopenharmony_ci break; 724bf215546Sopenharmony_ci } 725bf215546Sopenharmony_ci 726bf215546Sopenharmony_ci if (state->options->branch_labels && 727bf215546Sopenharmony_ci BITSET_TEST(state->branch_targets, state->n)) { 728bf215546Sopenharmony_ci if (state->options->instr_cb) { 729bf215546Sopenharmony_ci state->options->instr_cb(state->options->cbdata, 730bf215546Sopenharmony_ci state->n, instr.bitset); 731bf215546Sopenharmony_ci } 732bf215546Sopenharmony_ci print(state, "l%d:\n", state->n); 733bf215546Sopenharmony_ci } 734bf215546Sopenharmony_ci 735bf215546Sopenharmony_ci if (state->options->instr_cb) { 736bf215546Sopenharmony_ci state->options->instr_cb(state->options->cbdata, state->n, instr.bitset); 737bf215546Sopenharmony_ci } 738bf215546Sopenharmony_ci 739bf215546Sopenharmony_ci const struct isa_bitset *b = find_bitset(state, __instruction, instr); 740bf215546Sopenharmony_ci if (!b) { 741bf215546Sopenharmony_ci print(state, "no match: %"BITSET_FORMAT"\n", BITSET_VALUE(instr.bitset)); 742bf215546Sopenharmony_ci errors++; 743bf215546Sopenharmony_ci continue; 744bf215546Sopenharmony_ci } 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci struct decode_scope *scope = push_scope(state, b, instr); 747bf215546Sopenharmony_ci 748bf215546Sopenharmony_ci display(scope); 749bf215546Sopenharmony_ci if (flush_errors(state)) { 750bf215546Sopenharmony_ci errors++; 751bf215546Sopenharmony_ci } else { 752bf215546Sopenharmony_ci errors = 0; 753bf215546Sopenharmony_ci } 754bf215546Sopenharmony_ci print(state, "\n"); 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci pop_scope(scope); 757bf215546Sopenharmony_ci 758bf215546Sopenharmony_ci if (state->options->stop) { 759bf215546Sopenharmony_ci break; 760bf215546Sopenharmony_ci } 761bf215546Sopenharmony_ci } 762bf215546Sopenharmony_ci} 763bf215546Sopenharmony_ci 764bf215546Sopenharmony_civoid 765bf215546Sopenharmony_ciisa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *options) 766bf215546Sopenharmony_ci{ 767bf215546Sopenharmony_ci const struct isa_decode_options default_options = { 768bf215546Sopenharmony_ci .gpu_id = options ? options->gpu_id : 0, 769bf215546Sopenharmony_ci .branch_labels = options ? options->branch_labels : false 770bf215546Sopenharmony_ci }; 771bf215546Sopenharmony_ci struct decode_state *state; 772bf215546Sopenharmony_ci 773bf215546Sopenharmony_ci if (!options) 774bf215546Sopenharmony_ci options = &default_options; 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_ci state = rzalloc_size(NULL, sizeof(*state)); 777bf215546Sopenharmony_ci state->options = options; 778bf215546Sopenharmony_ci state->num_instr = sz / (BITMASK_WORDS * sizeof(BITSET_WORD)); 779bf215546Sopenharmony_ci 780bf215546Sopenharmony_ci if (state->options->branch_labels) { 781bf215546Sopenharmony_ci state->branch_targets = rzalloc_size(state, 782bf215546Sopenharmony_ci sizeof(BITSET_WORD) * BITSET_WORDS(state->num_instr)); 783bf215546Sopenharmony_ci 784bf215546Sopenharmony_ci /* Do a pre-pass to find all the branch targets: */ 785bf215546Sopenharmony_ci state->out = fopen("/dev/null", "w"); 786bf215546Sopenharmony_ci state->options = &default_options; /* skip hooks for prepass */ 787bf215546Sopenharmony_ci decode(state, bin, sz); 788bf215546Sopenharmony_ci fclose(state->out); 789bf215546Sopenharmony_ci if (options) { 790bf215546Sopenharmony_ci state->options = options; 791bf215546Sopenharmony_ci } 792bf215546Sopenharmony_ci } 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci state->out = out; 795bf215546Sopenharmony_ci 796bf215546Sopenharmony_ci decode(state, bin, sz); 797bf215546Sopenharmony_ci 798bf215546Sopenharmony_ci ralloc_free(state); 799bf215546Sopenharmony_ci} 800