mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-03 15:31:06 +00:00
tcg: Allow an operand to be matching or a constant
This allows an output operand to match an input operand only when the input operand needs a register. Backports commit 17280ff4a5f264e01e55ae514ee6d3586f9577b2 from qemu
This commit is contained in:
parent
3f38611159
commit
b4b173615c
|
@ -533,24 +533,29 @@ version. Aliases are specified in the input operands as for GCC.
|
||||||
The same register may be used for both an input and an output, even when
|
The same register may be used for both an input and an output, even when
|
||||||
they are not explicitly aliased. If an op expands to multiple target
|
they are not explicitly aliased. If an op expands to multiple target
|
||||||
instructions then care must be taken to avoid clobbering input values.
|
instructions then care must be taken to avoid clobbering input values.
|
||||||
GCC style "early clobber" outputs are not currently supported.
|
GCC style "early clobber" outputs are supported, with '&'.
|
||||||
|
|
||||||
A target can define specific register or constant constraints. If an
|
A target can define specific register or constant constraints. If an
|
||||||
operation uses a constant input constraint which does not allow all
|
operation uses a constant input constraint which does not allow all
|
||||||
constants, it must also accept registers in order to have a fallback.
|
constants, it must also accept registers in order to have a fallback.
|
||||||
|
The constraint 'i' is defined generically to accept any constant.
|
||||||
|
The constraint 'r' is not defined generically, but is consistently
|
||||||
|
used by each backend to indicate all registers.
|
||||||
|
|
||||||
The movi_i32 and movi_i64 operations must accept any constants.
|
The movi_i32 and movi_i64 operations must accept any constants.
|
||||||
|
|
||||||
The mov_i32 and mov_i64 operations must accept any registers of the
|
The mov_i32 and mov_i64 operations must accept any registers of the
|
||||||
same type.
|
same type.
|
||||||
|
|
||||||
The ld/st instructions must accept signed 32 bit constant offsets. It
|
The ld/st/sti instructions must accept signed 32 bit constant offsets.
|
||||||
can be implemented by reserving a specific register to compute the
|
This can be implemented by reserving a specific register in which to
|
||||||
address if the offset is too big.
|
compute the address if the offset is too big.
|
||||||
|
|
||||||
The ld/st instructions must accept any destination (ld) or source (st)
|
The ld/st instructions must accept any destination (ld) or source (st)
|
||||||
register.
|
register.
|
||||||
|
|
||||||
|
The sti instruction may fail if it cannot store the given constant.
|
||||||
|
|
||||||
4.3) Function call assumptions
|
4.3) Function call assumptions
|
||||||
|
|
||||||
- The only supported types for parameters and return value are: 32 and
|
- The only supported types for parameters and return value are: 32 and
|
||||||
|
|
|
@ -1301,37 +1301,46 @@ static void process_op_defs(TCGContext *s)
|
||||||
|
|
||||||
tcg_regset_clear(def->args_ct[i].u.regs);
|
tcg_regset_clear(def->args_ct[i].u.regs);
|
||||||
def->args_ct[i].ct = 0;
|
def->args_ct[i].ct = 0;
|
||||||
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
|
while (*ct_str != '\0') {
|
||||||
int oarg;
|
switch(*ct_str) {
|
||||||
oarg = ct_str[0] - '0';
|
case '0':
|
||||||
tcg_debug_assert(oarg < def->nb_oargs);
|
case '1':
|
||||||
tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
|
case '2':
|
||||||
/* TCG_CT_ALIAS is for the output arguments. The input
|
case '3':
|
||||||
argument is tagged with TCG_CT_IALIAS. */
|
case '4':
|
||||||
def->args_ct[i] = def->args_ct[oarg];
|
case '5':
|
||||||
def->args_ct[oarg].ct = TCG_CT_ALIAS;
|
case '6':
|
||||||
def->args_ct[oarg].alias_index = i;
|
case '7':
|
||||||
def->args_ct[i].ct |= TCG_CT_IALIAS;
|
case '8':
|
||||||
def->args_ct[i].alias_index = oarg;
|
case '9':
|
||||||
} else {
|
{
|
||||||
for(;;) {
|
int oarg = *ct_str - '0';
|
||||||
if (*ct_str == '\0')
|
tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
|
||||||
break;
|
tcg_debug_assert(oarg < def->nb_oargs);
|
||||||
switch(*ct_str) {
|
tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
|
||||||
case '&':
|
/* TCG_CT_ALIAS is for the output arguments.
|
||||||
def->args_ct[i].ct |= TCG_CT_NEWREG;
|
The input is tagged with TCG_CT_IALIAS. */
|
||||||
ct_str++;
|
def->args_ct[i] = def->args_ct[oarg];
|
||||||
break;
|
def->args_ct[oarg].ct |= TCG_CT_ALIAS;
|
||||||
case 'i':
|
def->args_ct[oarg].alias_index = i;
|
||||||
def->args_ct[i].ct |= TCG_CT_CONST;
|
def->args_ct[i].ct |= TCG_CT_IALIAS;
|
||||||
ct_str++;
|
def->args_ct[i].alias_index = oarg;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ct_str = target_parse_constraint(&def->args_ct[i],
|
|
||||||
ct_str, type);
|
|
||||||
/* Typo in TCGTargetOpDef constraint. */
|
|
||||||
tcg_debug_assert(ct_str != NULL);
|
|
||||||
}
|
}
|
||||||
|
ct_str++;
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
def->args_ct[i].ct |= TCG_CT_NEWREG;
|
||||||
|
ct_str++;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
def->args_ct[i].ct |= TCG_CT_CONST;
|
||||||
|
ct_str++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ct_str = target_parse_constraint(&def->args_ct[i],
|
||||||
|
ct_str, type);
|
||||||
|
/* Typo in TCGTargetOpDef constraint. */
|
||||||
|
tcg_debug_assert(ct_str != NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2356,7 +2365,8 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
||||||
arg = args[i];
|
arg = args[i];
|
||||||
arg_ct = &def->args_ct[i];
|
arg_ct = &def->args_ct[i];
|
||||||
ts = &s->temps[arg];
|
ts = &s->temps[arg];
|
||||||
if (arg_ct->ct & TCG_CT_ALIAS) {
|
if ((arg_ct->ct & TCG_CT_ALIAS)
|
||||||
|
&& !const_args[arg_ct->alias_index]) {
|
||||||
reg = new_args[arg_ct->alias_index];
|
reg = new_args[arg_ct->alias_index];
|
||||||
} else if (arg_ct->ct & TCG_CT_NEWREG) {
|
} else if (arg_ct->ct & TCG_CT_NEWREG) {
|
||||||
reg = tcg_reg_alloc(s, arg_ct->u.regs,
|
reg = tcg_reg_alloc(s, arg_ct->u.regs,
|
||||||
|
|
Loading…
Reference in a new issue