aboutsummaryrefslogtreecommitdiff
path: root/gcc/ira-int.h
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2022-01-10 14:47:08 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2022-01-10 14:47:08 +0000
commit01f3e6a40e7202310abbeb41c345d325bd69554f (patch)
tree6d8f6b63a55b2760ea02c3cb0eccc5cf6fc86d58 /gcc/ira-int.h
parent8e7a23728f66d2da88b47e34224410457fdefbf5 (diff)
downloadgcc-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.h39
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 */