Revision e8996ee0 tcg/tcg.c
b/tcg/tcg.c | ||
---|---|---|
266 | 266 |
|
267 | 267 |
void tcg_func_start(TCGContext *s) |
268 | 268 |
{ |
269 |
int i; |
|
269 | 270 |
tcg_pool_reset(s); |
270 | 271 |
s->nb_temps = s->nb_globals; |
272 |
for(i = 0; i < TCG_TYPE_COUNT; i++) |
|
273 |
s->first_free_temp[i] = -1; |
|
271 | 274 |
s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); |
272 | 275 |
s->nb_labels = 0; |
273 | 276 |
s->current_frame_offset = s->frame_start; |
... | ... | |
301 | 304 |
ts->type = type; |
302 | 305 |
ts->fixed_reg = 1; |
303 | 306 |
ts->reg = reg; |
304 |
ts->val_type = TEMP_VAL_REG; |
|
305 | 307 |
ts->name = name; |
306 | 308 |
s->nb_globals++; |
307 | 309 |
tcg_regset_set_reg(s->reserved_regs, reg); |
... | ... | |
327 | 329 |
ts->type = TCG_TYPE_I32; |
328 | 330 |
ts->fixed_reg = 1; |
329 | 331 |
ts->reg = reg1; |
330 |
ts->val_type = TEMP_VAL_REG; |
|
331 | 332 |
pstrcpy(buf, sizeof(buf), name); |
332 | 333 |
pstrcat(buf, sizeof(buf), "_0"); |
333 | 334 |
ts->name = strdup(buf); |
... | ... | |
337 | 338 |
ts->type = TCG_TYPE_I32; |
338 | 339 |
ts->fixed_reg = 1; |
339 | 340 |
ts->reg = reg2; |
340 |
ts->val_type = TEMP_VAL_REG; |
|
341 | 341 |
pstrcpy(buf, sizeof(buf), name); |
342 | 342 |
pstrcat(buf, sizeof(buf), "_1"); |
343 | 343 |
ts->name = strdup(buf); |
... | ... | |
370 | 370 |
#else |
371 | 371 |
ts->mem_offset = offset; |
372 | 372 |
#endif |
373 |
ts->val_type = TEMP_VAL_MEM; |
|
374 | 373 |
pstrcpy(buf, sizeof(buf), name); |
375 | 374 |
pstrcat(buf, sizeof(buf), "_0"); |
376 | 375 |
ts->name = strdup(buf); |
... | ... | |
386 | 385 |
#else |
387 | 386 |
ts->mem_offset = offset + 4; |
388 | 387 |
#endif |
389 |
ts->val_type = TEMP_VAL_MEM; |
|
390 | 388 |
pstrcpy(buf, sizeof(buf), name); |
391 | 389 |
pstrcat(buf, sizeof(buf), "_1"); |
392 | 390 |
ts->name = strdup(buf); |
... | ... | |
403 | 401 |
ts->mem_allocated = 1; |
404 | 402 |
ts->mem_reg = reg; |
405 | 403 |
ts->mem_offset = offset; |
406 |
ts->val_type = TEMP_VAL_MEM; |
|
407 | 404 |
ts->name = name; |
408 | 405 |
s->nb_globals++; |
409 | 406 |
} |
... | ... | |
416 | 413 |
TCGTemp *ts; |
417 | 414 |
int idx; |
418 | 415 |
|
419 |
idx = s->nb_temps; |
|
416 |
idx = s->first_free_temp[type]; |
|
417 |
if (idx != -1) { |
|
418 |
/* There is already an available temp with the |
|
419 |
right type */ |
|
420 |
ts = &s->temps[idx]; |
|
421 |
s->first_free_temp[type] = ts->next_free_temp; |
|
422 |
ts->temp_allocated = 1; |
|
423 |
} else { |
|
424 |
idx = s->nb_temps; |
|
420 | 425 |
#if TCG_TARGET_REG_BITS == 32 |
421 |
if (type == TCG_TYPE_I64) { |
|
422 |
tcg_temp_alloc(s, s->nb_temps + 1); |
|
423 |
ts = &s->temps[s->nb_temps]; |
|
424 |
ts->base_type = type; |
|
425 |
ts->type = TCG_TYPE_I32; |
|
426 |
ts->fixed_reg = 0; |
|
427 |
ts->val_type = TEMP_VAL_DEAD; |
|
428 |
ts->mem_allocated = 0; |
|
429 |
ts->name = NULL; |
|
430 |
ts++; |
|
431 |
ts->base_type = TCG_TYPE_I32; |
|
432 |
ts->type = TCG_TYPE_I32; |
|
433 |
ts->val_type = TEMP_VAL_DEAD; |
|
434 |
ts->fixed_reg = 0; |
|
435 |
ts->mem_allocated = 0; |
|
436 |
ts->name = NULL; |
|
437 |
s->nb_temps += 2; |
|
438 |
} else |
|
426 |
if (type == TCG_TYPE_I64) { |
|
427 |
tcg_temp_alloc(s, s->nb_temps + 1); |
|
428 |
ts = &s->temps[s->nb_temps]; |
|
429 |
ts->base_type = type; |
|
430 |
ts->type = TCG_TYPE_I32; |
|
431 |
ts->temp_allocated = 1; |
|
432 |
ts->name = NULL; |
|
433 |
ts++; |
|
434 |
ts->base_type = TCG_TYPE_I32; |
|
435 |
ts->type = TCG_TYPE_I32; |
|
436 |
ts->temp_allocated = 1; |
|
437 |
ts->name = NULL; |
|
438 |
s->nb_temps += 2; |
|
439 |
} else |
|
439 | 440 |
#endif |
440 |
{ |
|
441 |
tcg_temp_alloc(s, s->nb_temps + 1); |
|
442 |
ts = &s->temps[s->nb_temps]; |
|
443 |
ts->base_type = type; |
|
444 |
ts->type = type; |
|
445 |
ts->fixed_reg = 0; |
|
446 |
ts->val_type = TEMP_VAL_DEAD; |
|
447 |
ts->mem_allocated = 0; |
|
448 |
ts->name = NULL; |
|
449 |
s->nb_temps++; |
|
441 |
{ |
|
442 |
tcg_temp_alloc(s, s->nb_temps + 1); |
|
443 |
ts = &s->temps[s->nb_temps]; |
|
444 |
ts->base_type = type; |
|
445 |
ts->type = type; |
|
446 |
ts->temp_allocated = 1; |
|
447 |
ts->name = NULL; |
|
448 |
s->nb_temps++; |
|
449 |
} |
|
450 | 450 |
} |
451 | 451 |
return MAKE_TCGV(idx); |
452 | 452 |
} |
453 | 453 |
|
454 |
TCGv tcg_const_i32(int32_t val)
|
|
454 |
void tcg_temp_free(TCGv arg)
|
|
455 | 455 |
{ |
456 | 456 |
TCGContext *s = &tcg_ctx; |
457 | 457 |
TCGTemp *ts; |
458 |
int idx; |
|
458 |
int idx = GET_TCGV(arg); |
|
459 |
TCGType type; |
|
459 | 460 |
|
460 |
idx = s->nb_temps; |
|
461 |
tcg_temp_alloc(s, idx + 1); |
|
461 |
assert(idx >= s->nb_globals && idx < s->nb_temps); |
|
462 | 462 |
ts = &s->temps[idx]; |
463 |
ts->base_type = ts->type = TCG_TYPE_I32; |
|
464 |
ts->val_type = TEMP_VAL_CONST; |
|
465 |
ts->name = NULL; |
|
466 |
ts->val = val; |
|
467 |
s->nb_temps++; |
|
468 |
return MAKE_TCGV(idx); |
|
463 |
assert(ts->temp_allocated != 0); |
|
464 |
ts->temp_allocated = 0; |
|
465 |
type = ts->base_type; |
|
466 |
ts->next_free_temp = s->first_free_temp[type]; |
|
467 |
s->first_free_temp[type] = idx; |
|
469 | 468 |
} |
470 | 469 |
|
471 |
TCGv tcg_const_i64(int64_t val) |
|
470 |
|
|
471 |
TCGv tcg_const_i32(int32_t val) |
|
472 | 472 |
{ |
473 |
TCGContext *s = &tcg_ctx; |
|
474 |
TCGTemp *ts; |
|
475 |
int idx; |
|
473 |
TCGv t0; |
|
474 |
t0 = tcg_temp_new(TCG_TYPE_I32); |
|
475 |
tcg_gen_movi_i32(t0, val); |
|
476 |
return t0; |
|
477 |
} |
|
476 | 478 |
|
477 |
idx = s->nb_temps; |
|
478 |
#if TCG_TARGET_REG_BITS == 32 |
|
479 |
tcg_temp_alloc(s, idx + 2); |
|
480 |
ts = &s->temps[idx]; |
|
481 |
ts->base_type = TCG_TYPE_I64; |
|
482 |
ts->type = TCG_TYPE_I32; |
|
483 |
ts->val_type = TEMP_VAL_CONST; |
|
484 |
ts->name = NULL; |
|
485 |
ts->val = val; |
|
486 |
ts++; |
|
487 |
ts->base_type = TCG_TYPE_I32; |
|
488 |
ts->type = TCG_TYPE_I32; |
|
489 |
ts->val_type = TEMP_VAL_CONST; |
|
490 |
ts->name = NULL; |
|
491 |
ts->val = val >> 32; |
|
492 |
s->nb_temps += 2; |
|
493 |
#else |
|
494 |
tcg_temp_alloc(s, idx + 1); |
|
495 |
ts = &s->temps[idx]; |
|
496 |
ts->base_type = ts->type = TCG_TYPE_I64; |
|
497 |
ts->val_type = TEMP_VAL_CONST; |
|
498 |
ts->name = NULL; |
|
499 |
ts->val = val; |
|
500 |
s->nb_temps++; |
|
501 |
#endif |
|
502 |
return MAKE_TCGV(idx); |
|
479 |
TCGv tcg_const_i64(int64_t val) |
|
480 |
{ |
|
481 |
TCGv t0; |
|
482 |
t0 = tcg_temp_new(TCG_TYPE_I64); |
|
483 |
tcg_gen_movi_i64(t0, val); |
|
484 |
return t0; |
|
503 | 485 |
} |
504 | 486 |
|
505 | 487 |
void tcg_register_helper(void *func, const char *name) |
... | ... | |
663 | 645 |
tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); |
664 | 646 |
tcg_gen_mov_i32(ret, t1); |
665 | 647 |
} |
648 |
tcg_temp_free(t0); |
|
649 |
tcg_temp_free(t1); |
|
666 | 650 |
} |
667 | 651 |
} |
668 | 652 |
#endif |
... | ... | |
679 | 663 |
ts->val_type = TEMP_VAL_MEM; |
680 | 664 |
} |
681 | 665 |
} |
666 |
for(i = s->nb_globals; i < s->nb_temps; i++) { |
|
667 |
ts = &s->temps[i]; |
|
668 |
ts->val_type = TEMP_VAL_DEAD; |
|
669 |
ts->mem_allocated = 0; |
|
670 |
ts->fixed_reg = 0; |
|
671 |
} |
|
682 | 672 |
for(i = 0; i < TCG_TARGET_NB_REGS; i++) { |
683 | 673 |
s->reg_to_temp[i] = -1; |
684 | 674 |
} |
... | ... | |
693 | 683 |
if (idx < s->nb_globals) { |
694 | 684 |
pstrcpy(buf, buf_size, ts->name); |
695 | 685 |
} else { |
696 |
if (ts->val_type == TEMP_VAL_CONST) { |
|
697 |
snprintf(buf, buf_size, "$0x%" TCG_PRIlx , ts->val); |
|
698 |
} else { |
|
699 |
snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); |
|
700 |
} |
|
686 |
snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); |
|
701 | 687 |
} |
702 | 688 |
return buf; |
703 | 689 |
} |
... | ... | |
707 | 693 |
return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg)); |
708 | 694 |
} |
709 | 695 |
|
710 |
/* find helper definition (XXX: inefficient) */ |
|
711 |
static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) |
|
696 |
static int helper_cmp(const void *p1, const void *p2) |
|
712 | 697 |
{ |
713 |
int i; |
|
714 |
for(i = 0; i < s->nb_helpers; i++) { |
|
715 |
if (s->helpers[i].func == val) |
|
716 |
return &s->helpers[i]; |
|
717 |
} |
|
718 |
return NULL; |
|
698 |
const TCGHelperInfo *th1 = p1; |
|
699 |
const TCGHelperInfo *th2 = p2; |
|
700 |
if (th1->func < th2->func) |
|
701 |
return -1; |
|
702 |
else if (th1->func == th2->func) |
|
703 |
return 0; |
|
704 |
else |
|
705 |
return 1; |
|
719 | 706 |
} |
720 | 707 |
|
721 |
static const char *tcg_get_helper_str_idx(TCGContext *s, char *buf, int buf_size,
|
|
722 |
int idx)
|
|
708 |
/* find helper definition (Note: A hash table would be better) */
|
|
709 |
static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
|
|
723 | 710 |
{ |
724 |
TCGTemp *ts;
|
|
711 |
int m, m_min, m_max;
|
|
725 | 712 |
TCGHelperInfo *th; |
713 |
tcg_target_ulong v; |
|
726 | 714 |
|
727 |
ts = &s->temps[idx]; |
|
728 |
if (ts->val_type == TEMP_VAL_CONST) { |
|
729 |
/* find helper name (XXX: inefficient) */ |
|
730 |
th = tcg_find_helper(s, ts->val); |
|
731 |
if (th) { |
|
732 |
pstrcpy(buf, buf_size, "$"); |
|
733 |
pstrcat(buf, buf_size, th->name); |
|
734 |
return buf; |
|
715 |
if (unlikely(!s->helpers_sorted)) { |
|
716 |
qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), |
|
717 |
helper_cmp); |
|
718 |
s->helpers_sorted = 1; |
|
719 |
} |
|
720 |
|
|
721 |
/* binary search */ |
|
722 |
m_min = 0; |
|
723 |
m_max = s->nb_helpers - 1; |
|
724 |
while (m_min <= m_max) { |
|
725 |
m = (m_min + m_max) >> 1; |
|
726 |
th = &s->helpers[m]; |
|
727 |
v = th->func; |
|
728 |
if (v == val) |
|
729 |
return th; |
|
730 |
else if (val < v) { |
|
731 |
m_max = m - 1; |
|
732 |
} else { |
|
733 |
m_min = m + 1; |
|
735 | 734 |
} |
736 | 735 |
} |
737 |
return tcg_get_arg_str_idx(s, buf, buf_size, idx);
|
|
736 |
return NULL;
|
|
738 | 737 |
} |
739 | 738 |
|
740 |
|
|
741 | 739 |
void tcg_dump_ops(TCGContext *s, FILE *outfile) |
742 | 740 |
{ |
743 | 741 |
const uint16_t *opc_ptr; |
... | ... | |
780 | 778 |
|
781 | 779 |
/* function name */ |
782 | 780 |
fprintf(outfile, "%s", |
783 |
tcg_get_helper_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
|
|
781 |
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
|
|
784 | 782 |
/* flags */ |
785 | 783 |
fprintf(outfile, ",$0x%" TCG_PRIlx, |
786 | 784 |
args[nb_oargs + nb_iargs]); |
... | ... | |
800 | 798 |
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); |
801 | 799 |
} |
802 | 800 |
} |
801 |
} else if (c == INDEX_op_movi_i32 |
|
802 |
#if TCG_TARGET_REG_BITS == 64 |
|
803 |
|| c == INDEX_op_movi_i64 |
|
804 |
#endif |
|
805 |
) { |
|
806 |
tcg_target_ulong val; |
|
807 |
TCGHelperInfo *th; |
|
808 |
|
|
809 |
nb_oargs = def->nb_oargs; |
|
810 |
nb_iargs = def->nb_iargs; |
|
811 |
nb_cargs = def->nb_cargs; |
|
812 |
fprintf(outfile, " %s %s,$", def->name, |
|
813 |
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); |
|
814 |
val = args[1]; |
|
815 |
th = tcg_find_helper(s, val); |
|
816 |
if (th) { |
|
817 |
fprintf(outfile, th->name); |
|
818 |
} else { |
|
819 |
if (c == INDEX_op_movi_i32) |
|
820 |
fprintf(outfile, "0x%x", (uint32_t)val); |
|
821 |
else |
|
822 |
fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); |
|
823 |
} |
|
803 | 824 |
} else { |
804 | 825 |
fprintf(outfile, " %s ", def->name); |
805 | 826 |
if (c == INDEX_op_nopn) { |
... | ... | |
1281 | 1302 |
dump_regs(s); |
1282 | 1303 |
tcg_abort(); |
1283 | 1304 |
} |
1284 |
if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) { |
|
1285 |
printf("constant forbidden in global %s\n", |
|
1286 |
tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); |
|
1287 |
goto fail; |
|
1288 |
} |
|
1289 | 1305 |
} |
1290 | 1306 |
} |
1291 | 1307 |
#endif |
... | ... | |
1351 | 1367 |
} |
1352 | 1368 |
|
1353 | 1369 |
/* save globals to their cannonical location and assume they can be |
1354 |
modified be the following code. */ |
|
1355 |
static void save_globals(TCGContext *s) |
|
1370 |
modified be the following code. 'allocated_regs' is used in case a |
|
1371 |
temporary registers needs to be allocated to store a constant. */ |
|
1372 |
static void save_globals(TCGContext *s, TCGRegSet allocated_regs) |
|
1356 | 1373 |
{ |
1357 | 1374 |
TCGTemp *ts; |
1358 |
int i; |
|
1375 |
int i, reg;
|
|
1359 | 1376 |
|
1360 | 1377 |
for(i = 0; i < s->nb_globals; i++) { |
1361 | 1378 |
ts = &s->temps[i]; |
1362 | 1379 |
if (!ts->fixed_reg) { |
1363 |
if (ts->val_type == TEMP_VAL_REG) { |
|
1380 |
switch(ts->val_type) { |
|
1381 |
case TEMP_VAL_REG: |
|
1364 | 1382 |
tcg_reg_free(s, ts->reg); |
1365 |
} else if (ts->val_type == TEMP_VAL_DEAD) { |
|
1383 |
break; |
|
1384 |
case TEMP_VAL_DEAD: |
|
1366 | 1385 |
ts->val_type = TEMP_VAL_MEM; |
1386 |
break; |
|
1387 |
case TEMP_VAL_CONST: |
|
1388 |
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], |
|
1389 |
allocated_regs); |
|
1390 |
tcg_out_movi(s, ts->type, reg, ts->val); |
|
1391 |
tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); |
|
1392 |
ts->val_type = TEMP_VAL_MEM; |
|
1393 |
break; |
|
1394 |
case TEMP_VAL_MEM: |
|
1395 |
break; |
|
1396 |
default: |
|
1397 |
tcg_abort(); |
|
1367 | 1398 |
} |
1368 | 1399 |
} |
1369 | 1400 |
} |
1370 | 1401 |
} |
1371 | 1402 |
|
1372 | 1403 |
/* at the end of a basic block, we assume all temporaries are dead and |
1373 |
all globals are stored at their canonical location */ |
|
1374 |
/* XXX: optimize by handling constants in another array ? */ |
|
1375 |
void tcg_reg_alloc_bb_end(TCGContext *s) |
|
1404 |
all globals are stored at their canonical location. */ |
|
1405 |
static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) |
|
1376 | 1406 |
{ |
1377 | 1407 |
TCGTemp *ts; |
1378 | 1408 |
int i; |
1379 | 1409 |
|
1380 |
save_globals(s); |
|
1381 |
|
|
1382 | 1410 |
for(i = s->nb_globals; i < s->nb_temps; i++) { |
1383 | 1411 |
ts = &s->temps[i]; |
1384 |
if (ts->val_type != TEMP_VAL_CONST) { |
|
1385 |
if (ts->val_type == TEMP_VAL_REG) { |
|
1386 |
s->reg_to_temp[ts->reg] = -1; |
|
1387 |
} |
|
1388 |
ts->val_type = TEMP_VAL_DEAD; |
|
1412 |
if (ts->val_type == TEMP_VAL_REG) { |
|
1413 |
s->reg_to_temp[ts->reg] = -1; |
|
1389 | 1414 |
} |
1415 |
ts->val_type = TEMP_VAL_DEAD; |
|
1390 | 1416 |
} |
1417 |
|
|
1418 |
save_globals(s, allocated_regs); |
|
1391 | 1419 |
} |
1392 | 1420 |
|
1393 | 1421 |
#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) |
1394 | 1422 |
|
1423 |
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) |
|
1424 |
{ |
|
1425 |
TCGTemp *ots; |
|
1426 |
tcg_target_ulong val; |
|
1427 |
|
|
1428 |
ots = &s->temps[args[0]]; |
|
1429 |
val = args[1]; |
|
1430 |
|
|
1431 |
if (ots->fixed_reg) { |
|
1432 |
/* for fixed registers, we do not do any constant |
|
1433 |
propagation */ |
|
1434 |
tcg_out_movi(s, ots->type, ots->reg, val); |
|
1435 |
} else { |
|
1436 |
/* The movi is not explicitely generated here */ |
|
1437 |
if (ots->val_type == TEMP_VAL_REG) |
|
1438 |
s->reg_to_temp[ots->reg] = -1; |
|
1439 |
ots->val_type = TEMP_VAL_CONST; |
|
1440 |
ots->val = val; |
|
1441 |
} |
|
1442 |
} |
|
1443 |
|
|
1395 | 1444 |
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, |
1396 | 1445 |
const TCGArg *args, |
1397 | 1446 |
unsigned int dead_iargs) |
... | ... | |
1404 | 1453 |
ts = &s->temps[args[1]]; |
1405 | 1454 |
arg_ct = &def->args_ct[0]; |
1406 | 1455 |
|
1456 |
/* XXX: always mark arg dead if IS_DEAD_IARG(0) */ |
|
1407 | 1457 |
if (ts->val_type == TEMP_VAL_REG) { |
1408 | 1458 |
if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { |
1409 | 1459 |
/* the mov can be suppressed */ |
... | ... | |
1430 | 1480 |
} |
1431 | 1481 |
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); |
1432 | 1482 |
} else if (ts->val_type == TEMP_VAL_CONST) { |
1433 |
if (ots->val_type == TEMP_VAL_REG) {
|
|
1483 |
if (ots->fixed_reg) {
|
|
1434 | 1484 |
reg = ots->reg; |
1485 |
tcg_out_movi(s, ots->type, reg, ts->val); |
|
1435 | 1486 |
} else { |
1436 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); |
|
1487 |
/* propagate constant */ |
|
1488 |
if (ots->val_type == TEMP_VAL_REG) |
|
1489 |
s->reg_to_temp[ots->reg] = -1; |
|
1490 |
ots->val_type = TEMP_VAL_CONST; |
|
1491 |
ots->val = ts->val; |
|
1492 |
return; |
|
1437 | 1493 |
} |
1438 |
tcg_out_movi(s, ots->type, reg, ts->val); |
|
1439 | 1494 |
} else { |
1440 | 1495 |
tcg_abort(); |
1441 | 1496 |
} |
... | ... | |
1487 | 1542 |
new_args[i] = ts->val; |
1488 | 1543 |
goto iarg_end; |
1489 | 1544 |
} else { |
1490 |
/* need to move to a register*/ |
|
1545 |
/* need to move to a register */
|
|
1491 | 1546 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
1492 | 1547 |
tcg_out_movi(s, ts->type, reg, ts->val); |
1493 |
goto iarg_end1; |
|
1548 |
ts->val_type = TEMP_VAL_REG; |
|
1549 |
ts->reg = reg; |
|
1550 |
ts->mem_coherent = 0; |
|
1551 |
s->reg_to_temp[reg] = arg; |
|
1494 | 1552 |
} |
1495 | 1553 |
} |
1496 | 1554 |
assert(ts->val_type == TEMP_VAL_REG); |
... | ... | |
1518 | 1576 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
1519 | 1577 |
tcg_out_mov(s, reg, ts->reg); |
1520 | 1578 |
} |
1521 |
iarg_end1: |
|
1522 | 1579 |
new_args[i] = reg; |
1523 | 1580 |
const_args[i] = 0; |
1524 | 1581 |
tcg_regset_set_reg(allocated_regs, reg); |
1525 | 1582 |
iarg_end: ; |
1526 | 1583 |
} |
1527 | 1584 |
|
1528 |
/* mark dead temporaries and free the associated registers */ |
|
1529 |
for(i = 0; i < nb_iargs; i++) { |
|
1530 |
arg = args[nb_oargs + i]; |
|
1531 |
if (IS_DEAD_IARG(i)) { |
|
1532 |
ts = &s->temps[arg]; |
|
1533 |
if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) { |
|
1534 |
if (ts->val_type == TEMP_VAL_REG) |
|
1535 |
s->reg_to_temp[ts->reg] = -1; |
|
1536 |
ts->val_type = TEMP_VAL_DEAD; |
|
1585 |
if (def->flags & TCG_OPF_BB_END) { |
|
1586 |
tcg_reg_alloc_bb_end(s, allocated_regs); |
|
1587 |
} else { |
|
1588 |
/* mark dead temporaries and free the associated registers */ |
|
1589 |
for(i = 0; i < nb_iargs; i++) { |
|
1590 |
arg = args[nb_oargs + i]; |
|
1591 |
if (IS_DEAD_IARG(i)) { |
|
1592 |
ts = &s->temps[arg]; |
|
1593 |
if (!ts->fixed_reg) { |
|
1594 |
if (ts->val_type == TEMP_VAL_REG) |
|
1595 |
s->reg_to_temp[ts->reg] = -1; |
|
1596 |
ts->val_type = TEMP_VAL_DEAD; |
|
1597 |
} |
|
1537 | 1598 |
} |
1538 | 1599 |
} |
1539 |
} |
|
1540 |
|
|
1541 |
if (def->flags & TCG_OPF_CALL_CLOBBER) {
|
|
1542 |
/* XXX: permit generic clobber register list ? */
|
|
1543 |
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
|
|
1544 |
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
|
|
1545 |
tcg_reg_free(s, reg);
|
|
1600 |
|
|
1601 |
if (def->flags & TCG_OPF_CALL_CLOBBER) { |
|
1602 |
/* XXX: permit generic clobber register list ? */
|
|
1603 |
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
|
|
1604 |
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
|
|
1605 |
tcg_reg_free(s, reg);
|
|
1606 |
}
|
|
1546 | 1607 |
} |
1608 |
/* XXX: for load/store we could do that only for the slow path |
|
1609 |
(i.e. when a memory callback is called) */ |
|
1610 |
|
|
1611 |
/* store globals and free associated registers (we assume the insn |
|
1612 |
can modify any global. */ |
|
1613 |
save_globals(s, allocated_regs); |
|
1547 | 1614 |
} |
1548 |
/* XXX: for load/store we could do that only for the slow path |
|
1549 |
(i.e. when a memory callback is called) */ |
|
1550 |
|
|
1551 |
/* store globals and free associated registers (we assume the insn |
|
1552 |
can modify any global. */ |
|
1553 |
save_globals(s); |
|
1554 |
} |
|
1555 |
|
|
1556 |
/* satisfy the output constraints */ |
|
1557 |
tcg_regset_set(allocated_regs, s->reserved_regs); |
|
1558 |
for(k = 0; k < nb_oargs; k++) { |
|
1559 |
i = def->sorted_args[k]; |
|
1560 |
arg = args[i]; |
|
1561 |
arg_ct = &def->args_ct[i]; |
|
1562 |
ts = &s->temps[arg]; |
|
1563 |
if (arg_ct->ct & TCG_CT_ALIAS) { |
|
1564 |
reg = new_args[arg_ct->alias_index]; |
|
1565 |
} else { |
|
1566 |
/* if fixed register, we try to use it */ |
|
1567 |
reg = ts->reg; |
|
1568 |
if (ts->fixed_reg && |
|
1569 |
tcg_regset_test_reg(arg_ct->u.regs, reg)) { |
|
1570 |
goto oarg_end; |
|
1615 |
|
|
1616 |
/* satisfy the output constraints */ |
|
1617 |
tcg_regset_set(allocated_regs, s->reserved_regs); |
|
1618 |
for(k = 0; k < nb_oargs; k++) { |
|
1619 |
i = def->sorted_args[k]; |
|
1620 |
arg = args[i]; |
|
1621 |
arg_ct = &def->args_ct[i]; |
|
1622 |
ts = &s->temps[arg]; |
|
1623 |
if (arg_ct->ct & TCG_CT_ALIAS) { |
|
1624 |
reg = new_args[arg_ct->alias_index]; |
|
1625 |
} else { |
|
1626 |
/* if fixed register, we try to use it */ |
|
1627 |
reg = ts->reg; |
|
1628 |
if (ts->fixed_reg && |
|
1629 |
tcg_regset_test_reg(arg_ct->u.regs, reg)) { |
|
1630 |
goto oarg_end; |
|
1631 |
} |
|
1632 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
|
1571 | 1633 |
} |
1572 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
|
1573 |
} |
|
1574 |
tcg_regset_set_reg(allocated_regs, reg); |
|
1575 |
/* if a fixed register is used, then a move will be done afterwards */ |
|
1576 |
if (!ts->fixed_reg) { |
|
1577 |
if (ts->val_type == TEMP_VAL_REG) |
|
1578 |
s->reg_to_temp[ts->reg] = -1; |
|
1579 |
ts->val_type = TEMP_VAL_REG; |
|
1580 |
ts->reg = reg; |
|
1581 |
/* temp value is modified, so the value kept in memory is |
|
1582 |
potentially not the same */ |
|
1583 |
ts->mem_coherent = 0; |
|
1584 |
s->reg_to_temp[reg] = arg; |
|
1634 |
tcg_regset_set_reg(allocated_regs, reg); |
|
1635 |
/* if a fixed register is used, then a move will be done afterwards */ |
|
1636 |
if (!ts->fixed_reg) { |
|
1637 |
if (ts->val_type == TEMP_VAL_REG) |
|
1638 |
s->reg_to_temp[ts->reg] = -1; |
|
1639 |
ts->val_type = TEMP_VAL_REG; |
|
1640 |
ts->reg = reg; |
|
1641 |
/* temp value is modified, so the value kept in memory is |
|
1642 |
potentially not the same */ |
|
1643 |
ts->mem_coherent = 0; |
|
1644 |
s->reg_to_temp[reg] = arg; |
|
1645 |
} |
|
1646 |
oarg_end: |
|
1647 |
new_args[i] = reg; |
|
1585 | 1648 |
} |
1586 |
oarg_end: |
|
1587 |
new_args[i] = reg; |
|
1588 | 1649 |
} |
1589 | 1650 |
|
1590 |
if (def->flags & TCG_OPF_BB_END) |
|
1591 |
tcg_reg_alloc_bb_end(s); |
|
1592 |
|
|
1593 | 1651 |
/* emit instruction */ |
1594 | 1652 |
tcg_out_op(s, opc, new_args, const_args); |
1595 | 1653 |
|
... | ... | |
1708 | 1766 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
1709 | 1767 |
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); |
1710 | 1768 |
func_arg = reg; |
1769 |
tcg_regset_set_reg(allocated_regs, reg); |
|
1711 | 1770 |
} else if (ts->val_type == TEMP_VAL_REG) { |
1712 | 1771 |
reg = ts->reg; |
1713 | 1772 |
if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { |
... | ... | |
1715 | 1774 |
tcg_out_mov(s, reg, ts->reg); |
1716 | 1775 |
} |
1717 | 1776 |
func_arg = reg; |
1777 |
tcg_regset_set_reg(allocated_regs, reg); |
|
1718 | 1778 |
} else if (ts->val_type == TEMP_VAL_CONST) { |
1719 | 1779 |
if (tcg_target_const_match(func_addr, arg_ct)) { |
1720 | 1780 |
const_func_arg = 1; |
... | ... | |
1723 | 1783 |
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); |
1724 | 1784 |
tcg_out_movi(s, ts->type, reg, func_addr); |
1725 | 1785 |
func_arg = reg; |
1786 |
tcg_regset_set_reg(allocated_regs, reg); |
|
1726 | 1787 |
} |
1727 | 1788 |
} else { |
1728 | 1789 |
tcg_abort(); |
1729 | 1790 |
} |
1791 |
|
|
1730 | 1792 |
|
1731 | 1793 |
/* mark dead temporaries and free the associated registers */ |
1732 | 1794 |
for(i = 0; i < nb_iargs; i++) { |
1733 | 1795 |
arg = args[nb_oargs + i]; |
1734 | 1796 |
if (IS_DEAD_IARG(i)) { |
1735 | 1797 |
ts = &s->temps[arg]; |
1736 |
if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
|
|
1798 |
if (!ts->fixed_reg) { |
|
1737 | 1799 |
if (ts->val_type == TEMP_VAL_REG) |
1738 | 1800 |
s->reg_to_temp[ts->reg] = -1; |
1739 | 1801 |
ts->val_type = TEMP_VAL_DEAD; |
... | ... | |
1750 | 1812 |
|
1751 | 1813 |
/* store globals and free associated registers (we assume the call |
1752 | 1814 |
can modify any global. */ |
1753 |
save_globals(s); |
|
1815 |
save_globals(s, allocated_regs);
|
|
1754 | 1816 |
|
1755 | 1817 |
tcg_out_op(s, opc, &func_arg, &const_func_arg); |
1756 | 1818 |
|
... | ... | |
1763 | 1825 |
arg = args[i]; |
1764 | 1826 |
ts = &s->temps[arg]; |
1765 | 1827 |
reg = tcg_target_call_oarg_regs[i]; |
1766 |
tcg_reg_free(s, reg);
|
|
1828 |
assert(s->reg_to_temp[reg] == -1);
|
|
1767 | 1829 |
if (ts->fixed_reg) { |
1768 | 1830 |
if (ts->reg != reg) { |
1769 | 1831 |
tcg_out_mov(s, ts->reg, reg); |
... | ... | |
1863 | 1925 |
dead_iargs = s->op_dead_iargs[op_index]; |
1864 | 1926 |
tcg_reg_alloc_mov(s, def, args, dead_iargs); |
1865 | 1927 |
break; |
1928 |
case INDEX_op_movi_i32: |
|
1929 |
#if TCG_TARGET_REG_BITS == 64 |
|
1930 |
case INDEX_op_movi_i64: |
|
1931 |
#endif |
|
1932 |
tcg_reg_alloc_movi(s, args); |
|
1933 |
break; |
|
1866 | 1934 |
case INDEX_op_debug_insn_start: |
1867 | 1935 |
/* debug instruction */ |
1868 | 1936 |
break; |
... | ... | |
1879 | 1947 |
TCGTemp *ts; |
1880 | 1948 |
ts = &s->temps[args[0]]; |
1881 | 1949 |
/* mark the temporary as dead */ |
1882 |
if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
|
|
1950 |
if (!ts->fixed_reg) { |
|
1883 | 1951 |
if (ts->val_type == TEMP_VAL_REG) |
1884 | 1952 |
s->reg_to_temp[ts->reg] = -1; |
1885 | 1953 |
ts->val_type = TEMP_VAL_DEAD; |
... | ... | |
1900 | 1968 |
/* must never happen here */ |
1901 | 1969 |
tcg_abort(); |
1902 | 1970 |
case INDEX_op_set_label: |
1903 |
tcg_reg_alloc_bb_end(s); |
|
1971 |
tcg_reg_alloc_bb_end(s, s->reserved_regs);
|
|
1904 | 1972 |
tcg_out_label(s, args[0], (long)s->code_ptr); |
1905 | 1973 |
break; |
1906 | 1974 |
case INDEX_op_call: |
... | ... | |
1916 | 1984 |
#ifdef CONFIG_PROFILER |
1917 | 1985 |
s->old_op_count++; |
1918 | 1986 |
#endif |
1919 |
tcg_reg_alloc_bb_end(s); |
|
1987 |
tcg_reg_alloc_bb_end(s, s->reserved_regs);
|
|
1920 | 1988 |
if (search_pc >= 0) { |
1921 | 1989 |
s->code_ptr += def->copy_size; |
1922 | 1990 |
args += def->nb_args; |
Also available in: Unified diff