tcg: Reorg process_op_defs

Process each TCGConstraintSetIndex first.  Allocate TCGArgConstraint
arrays based on those.  Only afterward process the TCGOpcodes and
share those TCGArgConstraint arrays.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-12-27 11:40:42 -08:00
parent f44824cc4d
commit 3e80824e8b
2 changed files with 136 additions and 143 deletions

View file

@ -714,17 +714,12 @@ typedef struct TCGOpDef {
const char *name; const char *name;
uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args; uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
uint8_t flags; uint8_t flags;
TCGArgConstraint *args_ct; const TCGArgConstraint *args_ct;
} TCGOpDef; } TCGOpDef;
extern TCGOpDef tcg_op_defs[]; extern TCGOpDef tcg_op_defs[];
extern const size_t tcg_op_defs_max; extern const size_t tcg_op_defs_max;
typedef struct TCGTargetOpDef {
TCGOpcode op;
const char *args_ct_str[TCG_MAX_OP_ARGS];
} TCGTargetOpDef;
/* /*
* tcg_op_supported: * tcg_op_supported:
* Query if @op, for @type and @flags, is supported by the host * Query if @op, for @type and @flags, is supported by the host

272
tcg/tcg.c
View file

@ -887,31 +887,35 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
/* Put all of the constraint sets into an array, indexed by the enum. */ /* Put all of the constraint sets into an array, indexed by the enum. */
#define C_O0_I1(I1) { .args_ct_str = { #I1 } }, typedef struct TCGConstraintSet {
#define C_O0_I2(I1, I2) { .args_ct_str = { #I1, #I2 } }, uint8_t nb_oargs, nb_iargs;
#define C_O0_I3(I1, I2, I3) { .args_ct_str = { #I1, #I2, #I3 } }, const char *args_ct_str[TCG_MAX_OP_ARGS];
#define C_O0_I4(I1, I2, I3, I4) { .args_ct_str = { #I1, #I2, #I3, #I4 } }, } TCGConstraintSet;
#define C_O1_I1(O1, I1) { .args_ct_str = { #O1, #I1 } }, #define C_O0_I1(I1) { 0, 1, { #I1 } },
#define C_O1_I2(O1, I1, I2) { .args_ct_str = { #O1, #I1, #I2 } }, #define C_O0_I2(I1, I2) { 0, 2, { #I1, #I2 } },
#define C_O1_I3(O1, I1, I2, I3) { .args_ct_str = { #O1, #I1, #I2, #I3 } }, #define C_O0_I3(I1, I2, I3) { 0, 3, { #I1, #I2, #I3 } },
#define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, #define C_O0_I4(I1, I2, I3, I4) { 0, 4, { #I1, #I2, #I3, #I4 } },
#define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, #define C_O1_I1(O1, I1) { 1, 1, { #O1, #I1 } },
#define C_N1O1_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, #O2, #I1 } }, #define C_O1_I2(O1, I1, I2) { 1, 2, { #O1, #I1, #I2 } },
#define C_N2_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, "&" #O2, #I1 } }, #define C_O1_I3(O1, I1, I2, I3) { 1, 3, { #O1, #I1, #I2, #I3 } },
#define C_O1_I4(O1, I1, I2, I3, I4) { 1, 4, { #O1, #I1, #I2, #I3, #I4 } },
#define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, #define C_N1_I2(O1, I1, I2) { 1, 2, { "&" #O1, #I1, #I2 } },
#define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } }, #define C_N1O1_I1(O1, O2, I1) { 2, 1, { "&" #O1, #O2, #I1 } },
#define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } }, #define C_N2_I1(O1, O2, I1) { 2, 1, { "&" #O1, "&" #O2, #I1 } },
#define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
#define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
static const TCGTargetOpDef constraint_sets[] = { #define C_O2_I1(O1, O2, I1) { 2, 1, { #O1, #O2, #I1 } },
#define C_O2_I2(O1, O2, I1, I2) { 2, 2, { #O1, #O2, #I1, #I2 } },
#define C_O2_I3(O1, O2, I1, I2, I3) { 2, 3, { #O1, #O2, #I1, #I2, #I3 } },
#define C_O2_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { #O1, #O2, #I1, #I2, #I3, #I4 } },
#define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { 2, 4, { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
static const TCGConstraintSet constraint_sets[] = {
#include "tcg-target-con-set.h" #include "tcg-target-con-set.h"
}; };
#undef C_O0_I1 #undef C_O0_I1
#undef C_O0_I2 #undef C_O0_I2
#undef C_O0_I3 #undef C_O0_I3
@ -1499,32 +1503,12 @@ static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
static void tcg_context_init(unsigned max_cpus) static void tcg_context_init(unsigned max_cpus)
{ {
TCGContext *s = &tcg_init_ctx; TCGContext *s = &tcg_init_ctx;
int op, total_args, n, i; int n, i;
TCGOpDef *def;
TCGArgConstraint *args_ct;
TCGTemp *ts; TCGTemp *ts;
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
s->nb_globals = 0; s->nb_globals = 0;
/* Count total number of arguments and allocate the corresponding
space */
total_args = 0;
for(op = 0; op < NB_OPS; op++) {
def = &tcg_op_defs[op];
n = def->nb_iargs + def->nb_oargs;
total_args += n;
}
args_ct = g_new0(TCGArgConstraint, total_args);
for(op = 0; op < NB_OPS; op++) {
def = &tcg_op_defs[op];
def->args_ct = args_ct;
n = def->nb_iargs + def->nb_oargs;
args_ct += n;
}
init_call_layout(&info_helper_ld32_mmu); init_call_layout(&info_helper_ld32_mmu);
init_call_layout(&info_helper_ld64_mmu); init_call_layout(&info_helper_ld64_mmu);
init_call_layout(&info_helper_ld128_mmu); init_call_layout(&info_helper_ld128_mmu);
@ -3132,10 +3116,12 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
} }
/* we give more priority to constraints with less registers */ /* we give more priority to constraints with less registers */
static int get_constraint_priority(const TCGOpDef *def, int k) static int get_constraint_priority(const TCGArgConstraint *arg_ct, int k)
{ {
const TCGArgConstraint *arg_ct = &def->args_ct[k]; int n;
int n = ctpop64(arg_ct->regs);
arg_ct += k;
n = ctpop64(arg_ct->regs);
/* /*
* Sort constraints of a single register first, which includes output * Sort constraints of a single register first, which includes output
@ -3164,10 +3150,9 @@ static int get_constraint_priority(const TCGOpDef *def, int k)
} }
/* sort from highest priority to lowest */ /* sort from highest priority to lowest */
static void sort_constraints(TCGOpDef *def, int start, int n) static void sort_constraints(TCGArgConstraint *a, int start, int n)
{ {
int i, j; int i, j;
TCGArgConstraint *a = def->args_ct;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
a[start + i].sort_index = start + i; a[start + i].sort_index = start + i;
@ -3177,8 +3162,8 @@ static void sort_constraints(TCGOpDef *def, int start, int n)
} }
for (i = 0; i < n - 1; i++) { for (i = 0; i < n - 1; i++) {
for (j = i + 1; j < n; j++) { for (j = i + 1; j < n; j++) {
int p1 = get_constraint_priority(def, a[start + i].sort_index); int p1 = get_constraint_priority(a, a[start + i].sort_index);
int p2 = get_constraint_priority(def, a[start + j].sort_index); int p2 = get_constraint_priority(a, a[start + j].sort_index);
if (p1 < p2) { if (p1 < p2) {
int tmp = a[start + i].sort_index; int tmp = a[start + i].sort_index;
a[start + i].sort_index = a[start + j].sort_index; a[start + i].sort_index = a[start + j].sort_index;
@ -3188,57 +3173,39 @@ static void sort_constraints(TCGOpDef *def, int start, int n)
} }
} }
static const TCGArgConstraint empty_cts[TCG_MAX_OP_ARGS];
static TCGArgConstraint all_cts[ARRAY_SIZE(constraint_sets)][TCG_MAX_OP_ARGS];
static void process_op_defs(TCGContext *s) static void process_op_defs(TCGContext *s)
{ {
TCGOpcode op; for (size_t c = 0; c < ARRAY_SIZE(constraint_sets); ++c) {
const TCGConstraintSet *tdefs = &constraint_sets[c];
for (op = 0; op < NB_OPS; op++) { TCGArgConstraint *args_ct = all_cts[c];
TCGOpDef *def = &tcg_op_defs[op]; int nb_oargs = tdefs->nb_oargs;
const TCGTargetOpDef *tdefs; int nb_iargs = tdefs->nb_iargs;
int nb_args = nb_oargs + nb_iargs;
bool saw_alias_pair = false; bool saw_alias_pair = false;
int i, o, i2, o2, nb_args;
TCGConstraintSetIndex con_set;
if (def->flags & TCG_OPF_NOT_PRESENT) { for (int i = 0; i < nb_args; i++) {
continue;
}
nb_args = def->nb_iargs + def->nb_oargs;
if (nb_args == 0) {
continue;
}
/*
* Macro magic should make it impossible, but double-check that
* the array index is in range. At the same time, double-check
* that the opcode is implemented, i.e. not C_NotImplemented.
*/
con_set = tcg_target_op_def(op);
tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets));
tdefs = &constraint_sets[con_set];
for (i = 0; i < nb_args; i++) {
const char *ct_str = tdefs->args_ct_str[i]; const char *ct_str = tdefs->args_ct_str[i];
bool input_p = i >= def->nb_oargs; bool input_p = i >= nb_oargs;
int o;
/* Incomplete TCGTargetOpDef entry. */
tcg_debug_assert(ct_str != NULL);
switch (*ct_str) { switch (*ct_str) {
case '0' ... '9': case '0' ... '9':
o = *ct_str - '0'; o = *ct_str - '0';
tcg_debug_assert(input_p); tcg_debug_assert(input_p);
tcg_debug_assert(o < def->nb_oargs); tcg_debug_assert(o < nb_oargs);
tcg_debug_assert(def->args_ct[o].regs != 0); tcg_debug_assert(args_ct[o].regs != 0);
tcg_debug_assert(!def->args_ct[o].oalias); tcg_debug_assert(!args_ct[o].oalias);
def->args_ct[i] = def->args_ct[o]; args_ct[i] = args_ct[o];
/* The output sets oalias. */ /* The output sets oalias. */
def->args_ct[o].oalias = 1; args_ct[o].oalias = 1;
def->args_ct[o].alias_index = i; args_ct[o].alias_index = i;
/* The input sets ialias. */ /* The input sets ialias. */
def->args_ct[i].ialias = 1; args_ct[i].ialias = 1;
def->args_ct[i].alias_index = o; args_ct[i].alias_index = o;
if (def->args_ct[i].pair) { if (args_ct[i].pair) {
saw_alias_pair = true; saw_alias_pair = true;
} }
tcg_debug_assert(ct_str[1] == '\0'); tcg_debug_assert(ct_str[1] == '\0');
@ -3246,41 +3213,41 @@ static void process_op_defs(TCGContext *s)
case '&': case '&':
tcg_debug_assert(!input_p); tcg_debug_assert(!input_p);
def->args_ct[i].newreg = true; args_ct[i].newreg = true;
ct_str++; ct_str++;
break; break;
case 'p': /* plus */ case 'p': /* plus */
/* Allocate to the register after the previous. */ /* Allocate to the register after the previous. */
tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); tcg_debug_assert(i > (input_p ? nb_oargs : 0));
o = i - 1; o = i - 1;
tcg_debug_assert(!def->args_ct[o].pair); tcg_debug_assert(!args_ct[o].pair);
tcg_debug_assert(!def->args_ct[o].ct); tcg_debug_assert(!args_ct[o].ct);
def->args_ct[i] = (TCGArgConstraint){ args_ct[i] = (TCGArgConstraint){
.pair = 2, .pair = 2,
.pair_index = o, .pair_index = o,
.regs = def->args_ct[o].regs << 1, .regs = args_ct[o].regs << 1,
.newreg = def->args_ct[o].newreg, .newreg = args_ct[o].newreg,
}; };
def->args_ct[o].pair = 1; args_ct[o].pair = 1;
def->args_ct[o].pair_index = i; args_ct[o].pair_index = i;
tcg_debug_assert(ct_str[1] == '\0'); tcg_debug_assert(ct_str[1] == '\0');
continue; continue;
case 'm': /* minus */ case 'm': /* minus */
/* Allocate to the register before the previous. */ /* Allocate to the register before the previous. */
tcg_debug_assert(i > (input_p ? def->nb_oargs : 0)); tcg_debug_assert(i > (input_p ? nb_oargs : 0));
o = i - 1; o = i - 1;
tcg_debug_assert(!def->args_ct[o].pair); tcg_debug_assert(!args_ct[o].pair);
tcg_debug_assert(!def->args_ct[o].ct); tcg_debug_assert(!args_ct[o].ct);
def->args_ct[i] = (TCGArgConstraint){ args_ct[i] = (TCGArgConstraint){
.pair = 1, .pair = 1,
.pair_index = o, .pair_index = o,
.regs = def->args_ct[o].regs >> 1, .regs = args_ct[o].regs >> 1,
.newreg = def->args_ct[o].newreg, .newreg = args_ct[o].newreg,
}; };
def->args_ct[o].pair = 2; args_ct[o].pair = 2;
def->args_ct[o].pair_index = i; args_ct[o].pair_index = i;
tcg_debug_assert(ct_str[1] == '\0'); tcg_debug_assert(ct_str[1] == '\0');
continue; continue;
} }
@ -3288,16 +3255,16 @@ static void process_op_defs(TCGContext *s)
do { do {
switch (*ct_str) { switch (*ct_str) {
case 'i': case 'i':
def->args_ct[i].ct |= TCG_CT_CONST; args_ct[i].ct |= TCG_CT_CONST;
break; break;
/* Include all of the target-specific constraints. */ /* Include all of the target-specific constraints. */
#undef CONST #undef CONST
#define CONST(CASE, MASK) \ #define CONST(CASE, MASK) \
case CASE: def->args_ct[i].ct |= MASK; break; case CASE: args_ct[i].ct |= MASK; break;
#define REGS(CASE, MASK) \ #define REGS(CASE, MASK) \
case CASE: def->args_ct[i].regs |= MASK; break; case CASE: args_ct[i].regs |= MASK; break;
#include "tcg-target-con-str.h" #include "tcg-target-con-str.h"
@ -3308,15 +3275,12 @@ static void process_op_defs(TCGContext *s)
case '&': case '&':
case 'p': case 'p':
case 'm': case 'm':
/* Typo in TCGTargetOpDef constraint. */ /* Typo in TCGConstraintSet constraint. */
g_assert_not_reached(); g_assert_not_reached();
} }
} while (*++ct_str != '\0'); } while (*++ct_str != '\0');
} }
/* TCGTargetOpDef entry with too much information? */
tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
/* /*
* Fix up output pairs that are aliased with inputs. * Fix up output pairs that are aliased with inputs.
* When we created the alias, we copied pair from the output. * When we created the alias, we copied pair from the output.
@ -3337,51 +3301,53 @@ static void process_op_defs(TCGContext *s)
* first output to pair=3, and the pair_index'es to match. * first output to pair=3, and the pair_index'es to match.
*/ */
if (saw_alias_pair) { if (saw_alias_pair) {
for (i = def->nb_oargs; i < nb_args; i++) { for (int i = nb_oargs; i < nb_args; i++) {
int o, o2, i2;
/* /*
* Since [0-9pm] must be alone in the constraint string, * Since [0-9pm] must be alone in the constraint string,
* the only way they can both be set is if the pair comes * the only way they can both be set is if the pair comes
* from the output alias. * from the output alias.
*/ */
if (!def->args_ct[i].ialias) { if (!args_ct[i].ialias) {
continue; continue;
} }
switch (def->args_ct[i].pair) { switch (args_ct[i].pair) {
case 0: case 0:
break; break;
case 1: case 1:
o = def->args_ct[i].alias_index; o = args_ct[i].alias_index;
o2 = def->args_ct[o].pair_index; o2 = args_ct[o].pair_index;
tcg_debug_assert(def->args_ct[o].pair == 1); tcg_debug_assert(args_ct[o].pair == 1);
tcg_debug_assert(def->args_ct[o2].pair == 2); tcg_debug_assert(args_ct[o2].pair == 2);
if (def->args_ct[o2].oalias) { if (args_ct[o2].oalias) {
/* Case 1a */ /* Case 1a */
i2 = def->args_ct[o2].alias_index; i2 = args_ct[o2].alias_index;
tcg_debug_assert(def->args_ct[i2].pair == 2); tcg_debug_assert(args_ct[i2].pair == 2);
def->args_ct[i2].pair_index = i; args_ct[i2].pair_index = i;
def->args_ct[i].pair_index = i2; args_ct[i].pair_index = i2;
} else { } else {
/* Case 1b */ /* Case 1b */
def->args_ct[i].pair_index = i; args_ct[i].pair_index = i;
} }
break; break;
case 2: case 2:
o = def->args_ct[i].alias_index; o = args_ct[i].alias_index;
o2 = def->args_ct[o].pair_index; o2 = args_ct[o].pair_index;
tcg_debug_assert(def->args_ct[o].pair == 2); tcg_debug_assert(args_ct[o].pair == 2);
tcg_debug_assert(def->args_ct[o2].pair == 1); tcg_debug_assert(args_ct[o2].pair == 1);
if (def->args_ct[o2].oalias) { if (args_ct[o2].oalias) {
/* Case 1a */ /* Case 1a */
i2 = def->args_ct[o2].alias_index; i2 = args_ct[o2].alias_index;
tcg_debug_assert(def->args_ct[i2].pair == 1); tcg_debug_assert(args_ct[i2].pair == 1);
def->args_ct[i2].pair_index = i; args_ct[i2].pair_index = i;
def->args_ct[i].pair_index = i2; args_ct[i].pair_index = i2;
} else { } else {
/* Case 2 */ /* Case 2 */
def->args_ct[i].pair = 3; args_ct[i].pair = 3;
def->args_ct[o2].pair = 3; args_ct[o2].pair = 3;
def->args_ct[i].pair_index = o2; args_ct[i].pair_index = o2;
def->args_ct[o2].pair_index = i; args_ct[o2].pair_index = i;
} }
break; break;
default: default:
@ -3391,8 +3357,40 @@ static void process_op_defs(TCGContext *s)
} }
/* sort the constraints (XXX: this is just an heuristic) */ /* sort the constraints (XXX: this is just an heuristic) */
sort_constraints(def, 0, def->nb_oargs); sort_constraints(args_ct, 0, nb_oargs);
sort_constraints(def, def->nb_oargs, def->nb_iargs); sort_constraints(args_ct, nb_oargs, nb_iargs);
}
for (TCGOpcode op = 0; op < NB_OPS; op++) {
TCGOpDef *def = &tcg_op_defs[op];
const TCGConstraintSet *tdefs;
TCGConstraintSetIndex con_set;
int nb_args;
nb_args = def->nb_iargs + def->nb_oargs;
if (nb_args == 0) {
continue;
}
if (def->flags & TCG_OPF_NOT_PRESENT) {
def->args_ct = empty_cts;
continue;
}
/*
* Macro magic should make it impossible, but double-check that
* the array index is in range. At the same time, double-check
* that the opcode is implemented, i.e. not C_NotImplemented.
*/
con_set = tcg_target_op_def(op);
tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets));
/* The constraint arguments must match TCGOpcode arguments. */
tdefs = &constraint_sets[con_set];
tcg_debug_assert(tdefs->nb_oargs == def->nb_oargs);
tcg_debug_assert(tdefs->nb_iargs == def->nb_iargs);
def->args_ct = all_cts[con_set];
} }
} }