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,7 +269,7 @@ void tcg_func_start(TCGContext *s) | ||
269 | int i; | 269 | int i; |
270 | tcg_pool_reset(s); | 270 | tcg_pool_reset(s); |
271 | s->nb_temps = s->nb_globals; | 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 | s->first_free_temp[i] = -1; | 273 | s->first_free_temp[i] = -1; |
274 | s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); | 274 | s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); |
275 | s->nb_labels = 0; | 275 | s->nb_labels = 0; |
@@ -407,19 +407,23 @@ TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, | @@ -407,19 +407,23 @@ TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, | ||
407 | return MAKE_TCGV(idx); | 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 | TCGContext *s = &tcg_ctx; | 412 | TCGContext *s = &tcg_ctx; |
413 | TCGTemp *ts; | 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 | if (idx != -1) { | 420 | if (idx != -1) { |
418 | /* There is already an available temp with the | 421 | /* There is already an available temp with the |
419 | right type */ | 422 | right type */ |
420 | ts = &s->temps[idx]; | 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 | ts->temp_allocated = 1; | 425 | ts->temp_allocated = 1; |
426 | + assert(ts->temp_local == temp_local); | ||
423 | } else { | 427 | } else { |
424 | idx = s->nb_temps; | 428 | idx = s->nb_temps; |
425 | #if TCG_TARGET_REG_BITS == 32 | 429 | #if TCG_TARGET_REG_BITS == 32 |
@@ -429,11 +433,13 @@ TCGv tcg_temp_new(TCGType type) | @@ -429,11 +433,13 @@ TCGv tcg_temp_new(TCGType type) | ||
429 | ts->base_type = type; | 433 | ts->base_type = type; |
430 | ts->type = TCG_TYPE_I32; | 434 | ts->type = TCG_TYPE_I32; |
431 | ts->temp_allocated = 1; | 435 | ts->temp_allocated = 1; |
436 | + ts->temp_local = temp_local; | ||
432 | ts->name = NULL; | 437 | ts->name = NULL; |
433 | ts++; | 438 | ts++; |
434 | ts->base_type = TCG_TYPE_I32; | 439 | ts->base_type = TCG_TYPE_I32; |
435 | ts->type = TCG_TYPE_I32; | 440 | ts->type = TCG_TYPE_I32; |
436 | ts->temp_allocated = 1; | 441 | ts->temp_allocated = 1; |
442 | + ts->temp_local = temp_local; | ||
437 | ts->name = NULL; | 443 | ts->name = NULL; |
438 | s->nb_temps += 2; | 444 | s->nb_temps += 2; |
439 | } else | 445 | } else |
@@ -444,6 +450,7 @@ TCGv tcg_temp_new(TCGType type) | @@ -444,6 +450,7 @@ TCGv tcg_temp_new(TCGType type) | ||
444 | ts->base_type = type; | 450 | ts->base_type = type; |
445 | ts->type = type; | 451 | ts->type = type; |
446 | ts->temp_allocated = 1; | 452 | ts->temp_allocated = 1; |
453 | + ts->temp_local = temp_local; | ||
447 | ts->name = NULL; | 454 | ts->name = NULL; |
448 | s->nb_temps++; | 455 | s->nb_temps++; |
449 | } | 456 | } |
@@ -456,15 +463,17 @@ void tcg_temp_free(TCGv arg) | @@ -456,15 +463,17 @@ void tcg_temp_free(TCGv arg) | ||
456 | TCGContext *s = &tcg_ctx; | 463 | TCGContext *s = &tcg_ctx; |
457 | TCGTemp *ts; | 464 | TCGTemp *ts; |
458 | int idx = GET_TCGV(arg); | 465 | int idx = GET_TCGV(arg); |
459 | - TCGType type; | 466 | + int k; |
460 | 467 | ||
461 | assert(idx >= s->nb_globals && idx < s->nb_temps); | 468 | assert(idx >= s->nb_globals && idx < s->nb_temps); |
462 | ts = &s->temps[idx]; | 469 | ts = &s->temps[idx]; |
463 | assert(ts->temp_allocated != 0); | 470 | assert(ts->temp_allocated != 0); |
464 | ts->temp_allocated = 0; | 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,7 +692,10 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, | ||
683 | if (idx < s->nb_globals) { | 692 | if (idx < s->nb_globals) { |
684 | pstrcpy(buf, buf_size, ts->name); | 693 | pstrcpy(buf, buf_size, ts->name); |
685 | } else { | 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 | return buf; | 700 | return buf; |
689 | } | 701 | } |
@@ -987,13 +999,34 @@ static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, | @@ -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 | memset(dead_temps, 0, s->nb_globals); | 1008 | memset(dead_temps, 0, s->nb_globals); |
994 | memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); | 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 | /* Liveness analysis : update the opc_dead_iargs array to tell if a | 1030 | /* Liveness analysis : update the opc_dead_iargs array to tell if a |
998 | given input arguments is dead. Instructions updating dead | 1031 | given input arguments is dead. Instructions updating dead |
999 | temporaries are removed. */ | 1032 | temporaries are removed. */ |
@@ -1366,37 +1399,48 @@ static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) | @@ -1366,37 +1399,48 @@ static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) | ||
1366 | tcg_abort(); | 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 | /* save globals to their cannonical location and assume they can be | 1435 | /* save globals to their cannonical location and assume they can be |
1370 | modified be the following code. 'allocated_regs' is used in case a | 1436 | modified be the following code. 'allocated_regs' is used in case a |
1371 | temporary registers needs to be allocated to store a constant. */ | 1437 | temporary registers needs to be allocated to store a constant. */ |
1372 | static void save_globals(TCGContext *s, TCGRegSet allocated_regs) | 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 | for(i = 0; i < s->nb_globals; i++) { | 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,10 +1453,14 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) | ||
1409 | 1453 | ||
1410 | for(i = s->nb_globals; i < s->nb_temps; i++) { | 1454 | for(i = s->nb_globals; i < s->nb_temps; i++) { |
1411 | ts = &s->temps[i]; | 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 | save_globals(s, allocated_regs); | 1466 | save_globals(s, allocated_regs); |
tcg/tcg.h
@@ -189,6 +189,9 @@ typedef struct TCGTemp { | @@ -189,6 +189,9 @@ typedef struct TCGTemp { | ||
189 | unsigned int fixed_reg:1; | 189 | unsigned int fixed_reg:1; |
190 | unsigned int mem_coherent:1; | 190 | unsigned int mem_coherent:1; |
191 | unsigned int mem_allocated:1; | 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 | unsigned int temp_allocated:1; /* never used for code gen */ | 195 | unsigned int temp_allocated:1; /* never used for code gen */ |
193 | /* index of next free temp of same base type, -1 if end */ | 196 | /* index of next free temp of same base type, -1 if end */ |
194 | int next_free_temp; | 197 | int next_free_temp; |
@@ -212,11 +215,8 @@ struct TCGContext { | @@ -212,11 +215,8 @@ struct TCGContext { | ||
212 | TCGTemp *temps; /* globals first, temps after */ | 215 | TCGTemp *temps; /* globals first, temps after */ |
213 | int nb_globals; | 216 | int nb_globals; |
214 | int nb_temps; | 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 | /* goto_tb support */ | 221 | /* goto_tb support */ |
222 | uint8_t *code_buf; | 222 | uint8_t *code_buf; |
@@ -224,8 +224,10 @@ struct TCGContext { | @@ -224,8 +224,10 @@ struct TCGContext { | ||
224 | uint16_t *tb_next_offset; | 224 | uint16_t *tb_next_offset; |
225 | uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ | 225 | uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ |
226 | 226 | ||
227 | + /* liveness analysis */ | ||
227 | uint16_t *op_dead_iargs; /* for each operation, each bit tells if the | 228 | uint16_t *op_dead_iargs; /* for each operation, each bit tells if the |
228 | corresponding input argument is dead */ | 229 | corresponding input argument is dead */ |
230 | + | ||
229 | /* tells in which temporary a given register is. It does not take | 231 | /* tells in which temporary a given register is. It does not take |
230 | into account fixed registers */ | 232 | into account fixed registers */ |
231 | int reg_to_temp[TCG_TARGET_NB_REGS]; | 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,7 +307,15 @@ TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, | ||
305 | const char *name); | 307 | const char *name); |
306 | TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, | 308 | TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset, |
307 | const char *name); | 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 | void tcg_temp_free(TCGv arg); | 319 | void tcg_temp_free(TCGv arg); |
310 | char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg); | 320 | char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg); |
311 | void tcg_dump_info(FILE *f, | 321 | void tcg_dump_info(FILE *f, |