This PR skips saving of any registers in main.
Attribute OS_main can do this as well, however we can just drop
any saves / restores in all optimized compilation -- not even
the test suite needs these saves.
The feature can still be switched off by new -mno-OS_main
Ok for trunk?
gcc/
Don't save registers in main().
PR target/83737
* doc/invoke.texi (AVR Options) [-mOS_main]: Document it.
* config/avr/avr.opt (-mOS_main): New target option.
* config/avr/avr.c (avr_in_main_p): New static function.
(avr_regs_to_save) [avr_in_main_p]: Return 0.
(avr_prologue_setup_frame): Don't save any regs if avr_in_main_p.
(avr_expand_epilogue): Same.
* common/config/avr/avr-common.c (avr_option_optimization_table):
Switch on -mOS_main for optimizing compilations.
Index: common/config/avr/avr-common.c
===================================================================
--- common/config/avr/avr-common.c (revision 256338)
+++ common/config/avr/avr-common.c (working copy)
@@ -31,6 +31,7 @@ static const struct default_options avr_
// a frame without need when it tries to be smart around calls.
{ OPT_LEVELS_ALL, OPT_fcaller_saves, NULL, 0 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_mgas_isr_prologues, NULL, 1 },
+ { OPT_LEVELS_1_PLUS, OPT_mOS_main, NULL, 1 },
{ OPT_LEVELS_NONE, 0, NULL, 0 }
};
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c (revision 256338)
+++ config/avr/avr.c (working copy)
@@ -1167,6 +1167,23 @@ avr_starting_frame_offset (void)
}
+/* Return true if we are supposed to be in main(). This is only used
+ to determine if the callee-saved registers don't need to be saved
+ because the caller of main (crt*.o) doesn't use any of them. */
+
+static bool
+avr_in_main_p ()
+{
+ return (TARGET_OS_MAIN
+ && MAIN_NAME_P (DECL_NAME (current_function_decl))
+ // FIXME: We'd like to also test `flag_hosted' which is only
+ // available in the C-ish fronts, so no such test for now.
+ // Instead, we test the return type of "main" which is not exactly
+ // the same but good enough.
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
+}
+
+
/* Return the number of hard registers to push/pop in the prologue/epilogue
of the current function, and optionally store these registers in SET. */
@@ -1180,10 +1197,11 @@ avr_regs_to_save (HARD_REG_SET *set)
CLEAR_HARD_REG_SET (*set);
count = 0;
- /* No need to save any registers if the function never returns or
- has the "OS_task" or "OS_main" attribute. */
+ /* No need to save any registers if the function never returns or has the
+ "OS_task" or "OS_main" attribute. Dito if we are in "main". */
if (TREE_THIS_VOLATILE (current_function_decl)
+ || avr_in_main_p()
|| cfun->machine->is_OS_task
|| cfun->machine->is_OS_main)
return 0;
@@ -1651,6 +1669,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT
&& size < size_max
&& live_seq
&& !isr_p
+ && !avr_in_main_p()
&& !cfun->machine->is_OS_task
&& !cfun->machine->is_OS_main
&& !AVR_TINY);
@@ -1713,7 +1732,9 @@ avr_prologue_setup_frame (HOST_WIDE_INT
emit_push_byte (reg, true);
if (frame_pointer_needed
- && (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main)))
+ && (!(avr_in_main_p()
+ || cfun->machine->is_OS_task
+ || cfun->machine->is_OS_main)))
{
/* Push frame pointer. Always be consistent about the
ordering of pushes -- epilogue_restores expects the
@@ -1834,6 +1855,9 @@ avr_prologue_setup_frame (HOST_WIDE_INT
if (cfun->machine->is_interrupt)
irq_state = 1;
+ /* IRQs might be on when entering "main", hence avr_in_main_p
+ is *not* included in the following test. */
+
if (TARGET_NO_INTERRUPTS
|| cfun->machine->is_signal
|| cfun->machine->is_OS_main)
@@ -2122,6 +2146,7 @@ avr_expand_epilogue (bool sibcall_p)
&& !isr_p
&& !cfun->machine->is_OS_task
&& !cfun->machine->is_OS_main
+ && !avr_in_main_p()
&& !AVR_TINY);
if (minimize
@@ -2227,7 +2252,9 @@ avr_expand_epilogue (bool sibcall_p)
} /* size != 0 */
if (frame_pointer_needed
- && !(cfun->machine->is_OS_task || cfun->machine->is_OS_main))
+ && !(avr_in_main_p()
+ || cfun->machine->is_OS_task
+ || cfun->machine->is_OS_main))
{
/* Restore previous frame_pointer. See avr_expand_prologue for
rationale for not using pophi. */
Index: config/avr/avr.opt
===================================================================
--- config/avr/avr.opt (revision 256338)
+++ config/avr/avr.opt (working copy)
@@ -70,6 +70,10 @@ Target Report Undocumented Mask(ORDER_1)
morder2
Target Report Undocumented Mask(ORDER_2)
+mOS_main
+Target Report Mask(OS_MAIN)
+Treat main as if it had attribute OS_main.
+
mtiny-stack
Target Report Mask(TINY_STACK)
Change only the low 8 bits of the stack pointer.
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi (revision 256338)
+++ doc/invoke.texi (working copy)
@@ -669,7 +669,8 @@ -imacros @var{file} -imultilib @var{dir
-mbranch-cost=@var{cost} @gol
-mcall-prologues -mgas-isr-prologues -mint8 @gol
-mn_flash=@var{size} -mno-interrupts @gol
--mrelax -mrmw -mstrict-X -mtiny-stack -mfract-convert-truncate @gol
+-mOS_main -mrelax -mrmw -mstrict-X -mtiny-stack @gol
+-mfract-convert-truncate @gol
-mshort-calls -nodevicelib @gol
-Waddr-space-convert -Wmisspelled-isr}
@@ -16472,6 +16473,12 @@ Assume that the flash memory has a size
Generated code is not compatible with hardware interrupts.
Code size is smaller.
+@item -mOS_main
+@opindex mOS_main
+Do not save registers in @code{main}. The effect is similar to
+attaching attribute @ref{AVR Function Attributes,,@code{OS_main}}
+to @code{main}. It is activated per default if optimization is on.
+
@item -mrelax
@opindex mrelax
Try to replace @code{CALL} resp.@: @code{JMP} instruction by the shorter