Commit 641d5fbe6bef1cbc34732665efa8d5f0b71acbc4
1 parent
98fc5614
added local temporaries
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4576 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
103 additions
and
45 deletions
tcg/tcg.c
| ... | ... | @@ -269,7 +269,7 @@ void tcg_func_start(TCGContext *s) |
| 269 | 269 | int i; |
| 270 | 270 | tcg_pool_reset(s); |
| 271 | 271 | s->nb_temps = s->nb_globals; |
| 272 | - for(i = 0; i < TCG_TYPE_COUNT; i++) | |
| 272 | + for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) | |
| 273 | 273 | s->first_free_temp[i] = -1; |
| 274 | 274 | s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); |
| 275 | 275 | s->nb_labels = 0; |
| ... | ... | @@ -407,19 +407,23 @@ TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, |
| 407 | 407 | return MAKE_TCGV(idx); |
| 408 | 408 | } |
| 409 | 409 | |
| 410 | -TCGv tcg_temp_new(TCGType type) | |
| 410 | +TCGv tcg_temp_new_internal(TCGType type, int temp_local) | |
| 411 | 411 | { |
| 412 | 412 | TCGContext *s = &tcg_ctx; |
| 413 | 413 | TCGTemp *ts; |
| 414 | - int idx; | |
| 414 | + int idx, k; | |
| 415 | 415 | |
| 416 | - idx = s->first_free_temp[type]; | |
| 416 | + k = type; | |
| 417 | + if (temp_local) | |
| 418 | + k += TCG_TYPE_COUNT; | |
| 419 | + idx = s->first_free_temp[k]; | |
| 417 | 420 | if (idx != -1) { |
| 418 | 421 | /* There is already an available temp with the |
| 419 | 422 | right type */ |
| 420 | 423 | ts = &s->temps[idx]; |
| 421 | - s->first_free_temp[type] = ts->next_free_temp; | |
| 424 | + s->first_free_temp[k] = ts->next_free_temp; | |
| 422 | 425 | ts->temp_allocated = 1; |
| 426 | + assert(ts->temp_local == temp_local); | |
| 423 | 427 | } else { |
| 424 | 428 | idx = s->nb_temps; |
| 425 | 429 | #if TCG_TARGET_REG_BITS == 32 |
| ... | ... | @@ -429,11 +433,13 @@ TCGv tcg_temp_new(TCGType type) |
| 429 | 433 | ts->base_type = type; |
| 430 | 434 | ts->type = TCG_TYPE_I32; |
| 431 | 435 | ts->temp_allocated = 1; |
| 436 | + ts->temp_local = temp_local; | |
| 432 | 437 | ts->name = NULL; |
| 433 | 438 | ts++; |
| 434 | 439 | ts->base_type = TCG_TYPE_I32; |
| 435 | 440 | ts->type = TCG_TYPE_I32; |
| 436 | 441 | ts->temp_allocated = 1; |
| 442 | + ts->temp_local = temp_local; | |
| 437 | 443 | ts->name = NULL; |
| 438 | 444 | s->nb_temps += 2; |
| 439 | 445 | } else |
| ... | ... | @@ -444,6 +450,7 @@ TCGv tcg_temp_new(TCGType type) |
| 444 | 450 | ts->base_type = type; |
| 445 | 451 | ts->type = type; |
| 446 | 452 | ts->temp_allocated = 1; |
| 453 | + ts->temp_local = temp_local; | |
| 447 | 454 | ts->name = NULL; |
| 448 | 455 | s->nb_temps++; |
| 449 | 456 | } |
| ... | ... | @@ -456,15 +463,17 @@ void tcg_temp_free(TCGv arg) |
| 456 | 463 | TCGContext *s = &tcg_ctx; |
| 457 | 464 | TCGTemp *ts; |
| 458 | 465 | int idx = GET_TCGV(arg); |
| 459 | - TCGType type; | |
| 466 | + int k; | |
| 460 | 467 | |
| 461 | 468 | assert(idx >= s->nb_globals && idx < s->nb_temps); |
| 462 | 469 | ts = &s->temps[idx]; |
| 463 | 470 | assert(ts->temp_allocated != 0); |
| 464 | 471 | 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; | |
| 472 | + k = ts->base_type; | |
| 473 | + if (ts->temp_local) | |
| 474 | + k += TCG_TYPE_COUNT; | |
| 475 | + ts->next_free_temp = s->first_free_temp[k]; | |
| 476 | + s->first_free_temp[k] = idx; | |
| 468 | 477 | } |
| 469 | 478 | |
| 470 | 479 | |
| ... | ... | @@ -683,7 +692,10 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, |
| 683 | 692 | if (idx < s->nb_globals) { |
| 684 | 693 | pstrcpy(buf, buf_size, ts->name); |
| 685 | 694 | } else { |
| 686 | - snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); | |
| 695 | + if (ts->temp_local) | |
| 696 | + snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); | |
| 697 | + else | |
| 698 | + snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); | |
| 687 | 699 | } |
| 688 | 700 | return buf; |
| 689 | 701 | } |
| ... | ... | @@ -987,13 +999,34 @@ static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, |
| 987 | 999 | } |
| 988 | 1000 | } |
| 989 | 1001 | |
| 990 | -/* liveness analysis: end of basic block: globals are live, temps are dead */ | |
| 991 | -static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) | |
| 1002 | +/* liveness analysis: end of function: globals are live, temps are | |
| 1003 | + dead. */ | |
| 1004 | +/* XXX: at this stage, not used as there would be little gains because | |
| 1005 | + most TBs end with a conditional jump. */ | |
| 1006 | +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) | |
| 992 | 1007 | { |
| 993 | 1008 | memset(dead_temps, 0, s->nb_globals); |
| 994 | 1009 | memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); |
| 995 | 1010 | } |
| 996 | 1011 | |
| 1012 | +/* liveness analysis: end of basic block: globals are live, temps are | |
| 1013 | + dead, local temps are live. */ | |
| 1014 | +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) | |
| 1015 | +{ | |
| 1016 | + int i; | |
| 1017 | + TCGTemp *ts; | |
| 1018 | + | |
| 1019 | + memset(dead_temps, 0, s->nb_globals); | |
| 1020 | + ts = &s->temps[s->nb_globals]; | |
| 1021 | + for(i = s->nb_globals; i < s->nb_temps; i++) { | |
| 1022 | + if (ts->temp_local) | |
| 1023 | + dead_temps[i] = 0; | |
| 1024 | + else | |
| 1025 | + dead_temps[i] = 1; | |
| 1026 | + ts++; | |
| 1027 | + } | |
| 1028 | +} | |
| 1029 | + | |
| 997 | 1030 | /* Liveness analysis : update the opc_dead_iargs array to tell if a |
| 998 | 1031 | given input arguments is dead. Instructions updating dead |
| 999 | 1032 | temporaries are removed. */ |
| ... | ... | @@ -1366,37 +1399,48 @@ static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) |
| 1366 | 1399 | tcg_abort(); |
| 1367 | 1400 | } |
| 1368 | 1401 | |
| 1402 | +/* save a temporary to memory. 'allocated_regs' is used in case a | |
| 1403 | + temporary registers needs to be allocated to store a constant. */ | |
| 1404 | +static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) | |
| 1405 | +{ | |
| 1406 | + TCGTemp *ts; | |
| 1407 | + int reg; | |
| 1408 | + | |
| 1409 | + ts = &s->temps[temp]; | |
| 1410 | + if (!ts->fixed_reg) { | |
| 1411 | + switch(ts->val_type) { | |
| 1412 | + case TEMP_VAL_REG: | |
| 1413 | + tcg_reg_free(s, ts->reg); | |
| 1414 | + break; | |
| 1415 | + case TEMP_VAL_DEAD: | |
| 1416 | + ts->val_type = TEMP_VAL_MEM; | |
| 1417 | + break; | |
| 1418 | + case TEMP_VAL_CONST: | |
| 1419 | + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], | |
| 1420 | + allocated_regs); | |
| 1421 | + if (!ts->mem_allocated) | |
| 1422 | + temp_allocate_frame(s, temp); | |
| 1423 | + tcg_out_movi(s, ts->type, reg, ts->val); | |
| 1424 | + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); | |
| 1425 | + ts->val_type = TEMP_VAL_MEM; | |
| 1426 | + break; | |
| 1427 | + case TEMP_VAL_MEM: | |
| 1428 | + break; | |
| 1429 | + default: | |
| 1430 | + tcg_abort(); | |
| 1431 | + } | |
| 1432 | + } | |
| 1433 | +} | |
| 1434 | + | |
| 1369 | 1435 | /* save globals to their cannonical location and assume they can be |
| 1370 | 1436 | modified be the following code. 'allocated_regs' is used in case a |
| 1371 | 1437 | temporary registers needs to be allocated to store a constant. */ |
| 1372 | 1438 | static void save_globals(TCGContext *s, TCGRegSet allocated_regs) |
| 1373 | 1439 | { |
| 1374 | - TCGTemp *ts; | |
| 1375 | - int i, reg; | |
| 1440 | + int i; | |
| 1376 | 1441 | |
| 1377 | 1442 | for(i = 0; i < s->nb_globals; i++) { |
| 1378 | - ts = &s->temps[i]; | |
| 1379 | - if (!ts->fixed_reg) { | |
| 1380 | - switch(ts->val_type) { | |
| 1381 | - case TEMP_VAL_REG: | |
| 1382 | - tcg_reg_free(s, ts->reg); | |
| 1383 | - break; | |
| 1384 | - case TEMP_VAL_DEAD: | |
| 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(); | |
| 1398 | - } | |
| 1399 | - } | |
| 1443 | + temp_save(s, i, allocated_regs); | |
| 1400 | 1444 | } |
| 1401 | 1445 | } |
| 1402 | 1446 | |
| ... | ... | @@ -1409,10 +1453,14 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) |
| 1409 | 1453 | |
| 1410 | 1454 | for(i = s->nb_globals; i < s->nb_temps; i++) { |
| 1411 | 1455 | ts = &s->temps[i]; |
| 1412 | - if (ts->val_type == TEMP_VAL_REG) { | |
| 1413 | - s->reg_to_temp[ts->reg] = -1; | |
| 1456 | + if (ts->temp_local) { | |
| 1457 | + temp_save(s, i, allocated_regs); | |
| 1458 | + } else { | |
| 1459 | + if (ts->val_type == TEMP_VAL_REG) { | |
| 1460 | + s->reg_to_temp[ts->reg] = -1; | |
| 1461 | + } | |
| 1462 | + ts->val_type = TEMP_VAL_DEAD; | |
| 1414 | 1463 | } |
| 1415 | - ts->val_type = TEMP_VAL_DEAD; | |
| 1416 | 1464 | } |
| 1417 | 1465 | |
| 1418 | 1466 | save_globals(s, allocated_regs); | ... | ... |
tcg/tcg.h
| ... | ... | @@ -189,6 +189,9 @@ typedef struct TCGTemp { |
| 189 | 189 | unsigned int fixed_reg:1; |
| 190 | 190 | unsigned int mem_coherent:1; |
| 191 | 191 | unsigned int mem_allocated:1; |
| 192 | + unsigned int temp_local:1; /* If true, the temp is saved accross | |
| 193 | + basic blocks. Otherwise, it is not | |
| 194 | + preserved accross basic blocks. */ | |
| 192 | 195 | unsigned int temp_allocated:1; /* never used for code gen */ |
| 193 | 196 | /* index of next free temp of same base type, -1 if end */ |
| 194 | 197 | int next_free_temp; |
| ... | ... | @@ -212,11 +215,8 @@ struct TCGContext { |
| 212 | 215 | TCGTemp *temps; /* globals first, temps after */ |
| 213 | 216 | int nb_globals; |
| 214 | 217 | int nb_temps; |
| 215 | - int first_free_temp[TCG_TYPE_COUNT]; /* index of free temps, -1 if none */ | |
| 216 | - | |
| 217 | - /* constant indexes (end of temp array) */ | |
| 218 | - int const_start; | |
| 219 | - int const_end; | |
| 218 | + /* index of free temps, -1 if none */ | |
| 219 | + int first_free_temp[TCG_TYPE_COUNT * 2]; | |
| 220 | 220 | |
| 221 | 221 | /* goto_tb support */ |
| 222 | 222 | uint8_t *code_buf; |
| ... | ... | @@ -224,8 +224,10 @@ struct TCGContext { |
| 224 | 224 | uint16_t *tb_next_offset; |
| 225 | 225 | uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ |
| 226 | 226 | |
| 227 | + /* liveness analysis */ | |
| 227 | 228 | uint16_t *op_dead_iargs; /* for each operation, each bit tells if the |
| 228 | 229 | corresponding input argument is dead */ |
| 230 | + | |
| 229 | 231 | /* tells in which temporary a given register is. It does not take |
| 230 | 232 | into account fixed registers */ |
| 231 | 233 | int reg_to_temp[TCG_TARGET_NB_REGS]; |
| ... | ... | @@ -305,7 +307,15 @@ TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, |
| 305 | 307 | const char *name); |
| 306 | 308 | TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, |
| 307 | 309 | const char *name); |
| 308 | -TCGv tcg_temp_new(TCGType type); | |
| 310 | +TCGv tcg_temp_new_internal(TCGType type, int temp_local); | |
| 311 | +static inline TCGv tcg_temp_new(TCGType type) | |
| 312 | +{ | |
| 313 | + return tcg_temp_new_internal(type, 0); | |
| 314 | +} | |
| 315 | +static inline TCGv tcg_temp_local_new(TCGType type) | |
| 316 | +{ | |
| 317 | + return tcg_temp_new_internal(type, 1); | |
| 318 | +} | |
| 309 | 319 | void tcg_temp_free(TCGv arg); |
| 310 | 320 | char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg); |
| 311 | 321 | void tcg_dump_info(FILE *f, | ... | ... |