1193 |
1193 |
}
|
1194 |
1194 |
}
|
1195 |
1195 |
|
1196 |
|
/* Liveness analysis : update the opc_dead_iargs array to tell if a
|
|
1196 |
/* Liveness analysis : update the opc_dead_args array to tell if a
|
1197 |
1197 |
given input arguments is dead. Instructions updating dead
|
1198 |
1198 |
temporaries are removed. */
|
1199 |
1199 |
static void tcg_liveness_analysis(TCGContext *s)
|
... | ... | |
1203 |
1203 |
TCGArg *args;
|
1204 |
1204 |
const TCGOpDef *def;
|
1205 |
1205 |
uint8_t *dead_temps;
|
1206 |
|
unsigned int dead_iargs;
|
|
1206 |
unsigned int dead_args;
|
1207 |
1207 |
|
1208 |
1208 |
gen_opc_ptr++; /* skip end */
|
1209 |
1209 |
|
1210 |
1210 |
nb_ops = gen_opc_ptr - gen_opc_buf;
|
1211 |
1211 |
|
1212 |
|
s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
|
|
1212 |
s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
|
1213 |
1213 |
|
1214 |
1214 |
dead_temps = tcg_malloc(s->nb_temps);
|
1215 |
1215 |
memset(dead_temps, 1, s->nb_temps);
|
... | ... | |
1256 |
1256 |
}
|
1257 |
1257 |
|
1258 |
1258 |
/* input args are live */
|
1259 |
|
dead_iargs = 0;
|
1260 |
|
for(i = 0; i < nb_iargs; i++) {
|
1261 |
|
arg = args[i + nb_oargs];
|
|
1259 |
dead_args = 0;
|
|
1260 |
for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
|
|
1261 |
arg = args[i];
|
1262 |
1262 |
if (arg != TCG_CALL_DUMMY_ARG) {
|
1263 |
1263 |
if (dead_temps[arg]) {
|
1264 |
|
dead_iargs |= (1 << i);
|
|
1264 |
dead_args |= (1 << i);
|
1265 |
1265 |
}
|
1266 |
1266 |
dead_temps[arg] = 0;
|
1267 |
1267 |
}
|
1268 |
1268 |
}
|
1269 |
|
s->op_dead_iargs[op_index] = dead_iargs;
|
|
1269 |
s->op_dead_args[op_index] = dead_args;
|
1270 |
1270 |
}
|
1271 |
1271 |
args--;
|
1272 |
1272 |
}
|
... | ... | |
1327 |
1327 |
}
|
1328 |
1328 |
|
1329 |
1329 |
/* input args are live */
|
1330 |
|
dead_iargs = 0;
|
1331 |
|
for(i = 0; i < nb_iargs; i++) {
|
1332 |
|
arg = args[i + nb_oargs];
|
|
1330 |
dead_args = 0;
|
|
1331 |
for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
|
|
1332 |
arg = args[i];
|
1333 |
1333 |
if (dead_temps[arg]) {
|
1334 |
|
dead_iargs |= (1 << i);
|
|
1334 |
dead_args |= (1 << i);
|
1335 |
1335 |
}
|
1336 |
1336 |
dead_temps[arg] = 0;
|
1337 |
1337 |
}
|
1338 |
|
s->op_dead_iargs[op_index] = dead_iargs;
|
|
1338 |
s->op_dead_args[op_index] = dead_args;
|
1339 |
1339 |
}
|
1340 |
1340 |
break;
|
1341 |
1341 |
}
|
... | ... | |
1352 |
1352 |
int nb_ops;
|
1353 |
1353 |
nb_ops = gen_opc_ptr - gen_opc_buf;
|
1354 |
1354 |
|
1355 |
|
s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
|
1356 |
|
memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
|
|
1355 |
s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
|
|
1356 |
memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t));
|
1357 |
1357 |
}
|
1358 |
1358 |
#endif
|
1359 |
1359 |
|
... | ... | |
1557 |
1557 |
save_globals(s, allocated_regs);
|
1558 |
1558 |
}
|
1559 |
1559 |
|
1560 |
|
#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
|
|
1560 |
#define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
|
1561 |
1561 |
|
1562 |
1562 |
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
|
1563 |
1563 |
{
|
... | ... | |
1582 |
1582 |
|
1583 |
1583 |
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
1584 |
1584 |
const TCGArg *args,
|
1585 |
|
unsigned int dead_iargs)
|
|
1585 |
unsigned int dead_args)
|
1586 |
1586 |
{
|
1587 |
1587 |
TCGTemp *ts, *ots;
|
1588 |
1588 |
int reg;
|
... | ... | |
1592 |
1592 |
ts = &s->temps[args[1]];
|
1593 |
1593 |
arg_ct = &def->args_ct[0];
|
1594 |
1594 |
|
1595 |
|
/* XXX: always mark arg dead if IS_DEAD_IARG(0) */
|
|
1595 |
/* XXX: always mark arg dead if IS_DEAD_ARG(1) */
|
1596 |
1596 |
if (ts->val_type == TEMP_VAL_REG) {
|
1597 |
|
if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
|
|
1597 |
if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
|
1598 |
1598 |
/* the mov can be suppressed */
|
1599 |
1599 |
if (ots->val_type == TEMP_VAL_REG)
|
1600 |
1600 |
s->reg_to_temp[ots->reg] = -1;
|
... | ... | |
1642 |
1642 |
static void tcg_reg_alloc_op(TCGContext *s,
|
1643 |
1643 |
const TCGOpDef *def, TCGOpcode opc,
|
1644 |
1644 |
const TCGArg *args,
|
1645 |
|
unsigned int dead_iargs)
|
|
1645 |
unsigned int dead_args)
|
1646 |
1646 |
{
|
1647 |
1647 |
TCGRegSet allocated_regs;
|
1648 |
1648 |
int i, k, nb_iargs, nb_oargs, reg;
|
... | ... | |
1701 |
1701 |
/* if the input is aliased to an output and if it is
|
1702 |
1702 |
not dead after the instruction, we must allocate
|
1703 |
1703 |
a new register and move it */
|
1704 |
|
if (!IS_DEAD_IARG(i - nb_oargs))
|
|
1704 |
if (!IS_DEAD_ARG(i)) {
|
1705 |
1705 |
goto allocate_in_reg;
|
|
1706 |
}
|
1706 |
1707 |
}
|
1707 |
1708 |
}
|
1708 |
1709 |
reg = ts->reg;
|
... | ... | |
1725 |
1726 |
tcg_reg_alloc_bb_end(s, allocated_regs);
|
1726 |
1727 |
} else {
|
1727 |
1728 |
/* mark dead temporaries and free the associated registers */
|
1728 |
|
for(i = 0; i < nb_iargs; i++) {
|
1729 |
|
arg = args[nb_oargs + i];
|
1730 |
|
if (IS_DEAD_IARG(i)) {
|
|
1729 |
for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
|
|
1730 |
arg = args[i];
|
|
1731 |
if (IS_DEAD_ARG(i)) {
|
1731 |
1732 |
ts = &s->temps[arg];
|
1732 |
1733 |
if (!ts->fixed_reg) {
|
1733 |
1734 |
if (ts->val_type == TEMP_VAL_REG)
|
... | ... | |
1808 |
1809 |
|
1809 |
1810 |
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
1810 |
1811 |
TCGOpcode opc, const TCGArg *args,
|
1811 |
|
unsigned int dead_iargs)
|
|
1812 |
unsigned int dead_args)
|
1812 |
1813 |
{
|
1813 |
1814 |
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
|
1814 |
1815 |
TCGArg arg, func_arg;
|
... | ... | |
1930 |
1931 |
|
1931 |
1932 |
|
1932 |
1933 |
/* mark dead temporaries and free the associated registers */
|
1933 |
|
for(i = 0; i < nb_iargs; i++) {
|
1934 |
|
arg = args[nb_oargs + i];
|
1935 |
|
if (IS_DEAD_IARG(i)) {
|
|
1934 |
for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
|
|
1935 |
arg = args[i];
|
|
1936 |
if (IS_DEAD_ARG(i)) {
|
1936 |
1937 |
ts = &s->temps[arg];
|
1937 |
1938 |
if (!ts->fixed_reg) {
|
1938 |
1939 |
if (ts->val_type == TEMP_VAL_REG)
|
... | ... | |
2007 |
2008 |
TCGOpcode opc;
|
2008 |
2009 |
int op_index;
|
2009 |
2010 |
const TCGOpDef *def;
|
2010 |
|
unsigned int dead_iargs;
|
|
2011 |
unsigned int dead_args;
|
2011 |
2012 |
const TCGArg *args;
|
2012 |
2013 |
|
2013 |
2014 |
#ifdef DEBUG_DISAS
|
... | ... | |
2058 |
2059 |
#if TCG_TARGET_REG_BITS == 64
|
2059 |
2060 |
case INDEX_op_mov_i64:
|
2060 |
2061 |
#endif
|
2061 |
|
dead_iargs = s->op_dead_iargs[op_index];
|
2062 |
|
tcg_reg_alloc_mov(s, def, args, dead_iargs);
|
|
2062 |
dead_args = s->op_dead_args[op_index];
|
|
2063 |
tcg_reg_alloc_mov(s, def, args, dead_args);
|
2063 |
2064 |
break;
|
2064 |
2065 |
case INDEX_op_movi_i32:
|
2065 |
2066 |
#if TCG_TARGET_REG_BITS == 64
|
... | ... | |
2095 |
2096 |
tcg_out_label(s, args[0], (long)s->code_ptr);
|
2096 |
2097 |
break;
|
2097 |
2098 |
case INDEX_op_call:
|
2098 |
|
dead_iargs = s->op_dead_iargs[op_index];
|
2099 |
|
args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
|
|
2099 |
dead_args = s->op_dead_args[op_index];
|
|
2100 |
args += tcg_reg_alloc_call(s, def, opc, args, dead_args);
|
2100 |
2101 |
goto next;
|
2101 |
2102 |
case INDEX_op_end:
|
2102 |
2103 |
goto the_end;
|
... | ... | |
2104 |
2105 |
/* Note: in order to speed up the code, it would be much
|
2105 |
2106 |
faster to have specialized register allocator functions for
|
2106 |
2107 |
some common argument patterns */
|
2107 |
|
dead_iargs = s->op_dead_iargs[op_index];
|
2108 |
|
tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
|
|
2108 |
dead_args = s->op_dead_args[op_index];
|
|
2109 |
tcg_reg_alloc_op(s, def, opc, args, dead_args);
|
2109 |
2110 |
break;
|
2110 |
2111 |
}
|
2111 |
2112 |
args += def->nb_args;
|