mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-09 01:15:40 +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
|
||||
they are not explicitly aliased. If an op expands to multiple target
|
||||
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
|
||||
operation uses a constant input constraint which does not allow all
|
||||
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 mov_i32 and mov_i64 operations must accept any registers of the
|
||||
same type.
|
||||
|
||||
The ld/st instructions must accept signed 32 bit constant offsets. It
|
||||
can be implemented by reserving a specific register to compute the
|
||||
address if the offset is too big.
|
||||
The ld/st/sti instructions must accept signed 32 bit constant offsets.
|
||||
This can be implemented by reserving a specific register in which to
|
||||
compute the address if the offset is too big.
|
||||
|
||||
The ld/st instructions must accept any destination (ld) or source (st)
|
||||
register.
|
||||
|
||||
The sti instruction may fail if it cannot store the given constant.
|
||||
|
||||
4.3) Function call assumptions
|
||||
|
||||
- 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);
|
||||
def->args_ct[i].ct = 0;
|
||||
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
|
||||
int oarg;
|
||||
oarg = ct_str[0] - '0';
|
||||
tcg_debug_assert(oarg < def->nb_oargs);
|
||||
tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
|
||||
/* TCG_CT_ALIAS is for the output arguments. The input
|
||||
argument is tagged with TCG_CT_IALIAS. */
|
||||
def->args_ct[i] = def->args_ct[oarg];
|
||||
def->args_ct[oarg].ct = TCG_CT_ALIAS;
|
||||
def->args_ct[oarg].alias_index = i;
|
||||
def->args_ct[i].ct |= TCG_CT_IALIAS;
|
||||
def->args_ct[i].alias_index = oarg;
|
||||
} else {
|
||||
for(;;) {
|
||||
if (*ct_str == '\0')
|
||||
break;
|
||||
switch(*ct_str) {
|
||||
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);
|
||||
while (*ct_str != '\0') {
|
||||
switch(*ct_str) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
int oarg = *ct_str - '0';
|
||||
tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
|
||||
tcg_debug_assert(oarg < def->nb_oargs);
|
||||
tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
|
||||
/* TCG_CT_ALIAS is for the output arguments.
|
||||
The input is tagged with TCG_CT_IALIAS. */
|
||||
def->args_ct[i] = def->args_ct[oarg];
|
||||
def->args_ct[oarg].ct |= TCG_CT_ALIAS;
|
||||
def->args_ct[oarg].alias_index = i;
|
||||
def->args_ct[i].ct |= TCG_CT_IALIAS;
|
||||
def->args_ct[i].alias_index = oarg;
|
||||
}
|
||||
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_ct = &def->args_ct[i];
|
||||
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];
|
||||
} else if (arg_ct->ct & TCG_CT_NEWREG) {
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs,
|
||||
|
|
Loading…
Reference in a new issue