diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2022-01-10 14:47:08 +0000 |
---|---|---|
committer | Richard Sandiford <richard.sandiford@arm.com> | 2022-01-10 14:47:08 +0000 |
commit | 01f3e6a40e7202310abbeb41c345d325bd69554f (patch) | |
tree | 6d8f6b63a55b2760ea02c3cb0eccc5cf6fc86d58 /gcc/ira-int.h | |
parent | 8e7a23728f66d2da88b47e34224410457fdefbf5 (diff) | |
download | gcc-01f3e6a40e7202310abbeb41c345d325bd69554f.zip gcc-01f3e6a40e7202310abbeb41c345d325bd69554f.tar.gz gcc-01f3e6a40e7202310abbeb41c345d325bd69554f.tar.bz2 |
ira: Consider modelling caller-save allocations as loop spills
If an allocno A in an inner loop L spans a call, a parent allocno AP
can choose to handle a call-clobbered/caller-saved hard register R
in one of two ways:
(1) save R before each call in L and restore R after each call
(2) spill R to memory throughout L
(2) can be cheaper than (1) in some cases, particularly if L does
not reference A.
Before the patch we always did (1). The patch adds support for
picking (2) instead, when it seems cheaper. It builds on the
earlier support for not propagating conflicts to parent allocnos.
gcc/
PR rtl-optimization/98782
* ira-int.h (ira_caller_save_cost): New function.
(ira_caller_save_loop_spill_p): Likewise.
* ira-build.c (ira_propagate_hard_reg_costs): Test whether it is
cheaper to spill a call-clobbered register throughout a loop rather
than spill it around each individual call. If so, treat all
call-clobbered registers as conflicts and...
(propagate_allocno_info): ...do not propagate call information
from the child to the parent.
* ira-color.c (move_spill_restore): Update accordingly.
* ira-costs.c (ira_tune_allocno_costs): Use ira_caller_save_cost.
gcc/testsuite/
* gcc.target/aarch64/reg-alloc-3.c: New test.
Diffstat (limited to 'gcc/ira-int.h')
-rw-r--r-- | gcc/ira-int.h | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/gcc/ira-int.h b/gcc/ira-int.h index 8b87498..a78811e 100644 --- a/gcc/ira-int.h +++ b/gcc/ira-int.h @@ -1660,4 +1660,43 @@ ira_total_conflict_hard_regs (ira_allocno_t a) return conflicts; } +/* Return the cost of saving a caller-saved register before each call + in A's live range and restoring the same register after each call. */ +inline int +ira_caller_save_cost (ira_allocno_t a) +{ + auto mode = ALLOCNO_MODE (a); + auto rclass = ALLOCNO_CLASS (a); + return (ALLOCNO_CALL_FREQ (a) + * (ira_memory_move_cost[mode][rclass][0] + + ira_memory_move_cost[mode][rclass][1])); +} + +/* A and SUBLOOP_A are allocnos for the same pseudo register, with A's + loop immediately enclosing SUBLOOP_A's loop. If we allocate to A a + hard register R that is clobbered by a call in SUBLOOP_A, decide + which of the following approaches should be used for handling the + conflict: + + (1) Spill R on entry to SUBLOOP_A's loop, assign memory to SUBLOOP_A, + and restore R on exit from SUBLOOP_A's loop. + + (2) Spill R before each necessary call in SUBLOOP_A's live range and + restore R after each such call. + + Return true if (1) is better than (2). SPILL_COST is the cost of + doing (1). */ +inline bool +ira_caller_save_loop_spill_p (ira_allocno_t a, ira_allocno_t subloop_a, + int spill_cost) +{ + if (!ira_subloop_allocnos_can_differ_p (a)) + return false; + + /* Calculate the cost of saving a call-clobbered register + before each call and restoring it afterwards. */ + int call_cost = ira_caller_save_cost (subloop_a); + return call_cost && call_cost >= spill_cost; +} + #endif /* GCC_IRA_INT_H */ |