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, | ... | ... |