In current trunk (r170704), 4.4-branch and 4.5-branch I observe the following optimization issue in IRA: It saves regs in the frame instead of in callee-saved registers which would be much smarter.
In the following C source, foo2 is compiled as desired (push/pop r17 to save r24). In foo1 and foo3 r24 is saved in the frame. The old lreg/greg allocator of 4.3-branch generates fine code for all functions. Saving a reg in the frame should only be done if running out of hard registers because setting up frame(pointer) and accessing frame is very expensive on avr. Maybe someone can give me a hint what's going wrong. gcc configured /gnu/source/gcc.gnu.org/trunk/configure --target=avr --prefix=... --enable-languages=c,c++ --disable-libssp --disable-libada --disable-nls --disable-shared and sources compiled with -Os -mmcu=atmega8 -c -dp -da -fira-verbose=100 /*****************************************************/ void bar0 (void); void bar1 (char); void foo1 (char x) { bar0(); bar1(x); } char foo2 (char x) { bar1(x); return x; } char foo3 (char x) { bar0(); return x; } /*****************************************************/ FYI, I attached IRA dumps and asm output As far I can see target avr gives appropriate costs for memory and register moves. IRA printout is as follows: Thanks for any hints on that! Johann =========================================================== Building IRA IR Pass 0 for finding pseudo/allocno costs a0 (r42,l0) best GENERAL_REGS, cover GENERAL_REGS a0(r42,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:4000 Pass 1 for finding pseudo/allocno costs r42: preferred GENERAL_REGS, alternative NO_REGS, cover GENERAL_REGS a0(r42,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:4000 Insn 10(l0): point = 0 Insn 9(l0): point = 2 Insn 7(l0): point = 4 Insn 2(l0): point = 6 a0(r42): [3..6] Compressing live ranges: from 9 to 2 - 22% Ranges after the compression: a0(r42): [0..1] +++Allocating 0 bytes for conflict table (uncompressed size 4) ;; a0(r42,l0) conflicts: regions=1, blocks=3, points=2 allocnos=1 (big 0), copies=0, conflicts=0, ranges=1 **** Allocnos coloring: Loop 0 (parent -1, header bb0, depth 0) bbs: 2 all: 0r42 modified regnos: 42 border: Pressure: GENERAL_REGS=1 Reg 42 of GENERAL_REGS has 6 regs less Pushing a0(r42,l0) Popping a0(r42,l0) -- assign reg 24 Disposition: 0:r42 l0 24 New iteration of spill/restore move +++Costs: overall -4000, reg -4000, mem 0, ld 0, st 0, move 0 +++ move loops 0, new jumps 0 =========================================================== Building IRA IR Pass 0 for finding pseudo/allocno costs a0 (r43,l0) best GENERAL_REGS, cover GENERAL_REGS a0(r43,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:6000 Pass 1 for finding pseudo/allocno costs r43: preferred GENERAL_REGS, alternative NO_REGS, cover GENERAL_REGS a0(r43,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:6000 Insn 16(l0): point = 0 Insn 13(l0): point = 2 Insn 8(l0): point = 4 Insn 7(l0): point = 6 Insn 2(l0): point = 8 a0(r43): [3..8] Compressing live ranges: from 11 to 2 - 18% Ranges after the compression: a0(r43): [0..1] +++Allocating 0 bytes for conflict table (uncompressed size 4) ;; a0(r43,l0) conflicts: regions=1, blocks=3, points=2 allocnos=1 (big 0), copies=0, conflicts=0, ranges=1 **** Allocnos coloring: Loop 0 (parent -1, header bb0, depth 0) bbs: 2 all: 0r43 modified regnos: 43 border: Pressure: GENERAL_REGS=2 Reg 43 of GENERAL_REGS has 7 regs less Pushing a0(r43,l0) Popping a0(r43,l0) -- assign reg 17 Disposition: 0:r43 l0 17 New iteration of spill/restore move +++Costs: overall 0, reg 0, mem 0, ld 0, st 0, move 0 +++ move loops 0, new jumps 0 =========================================================== Building IRA IR Pass 0 for finding pseudo/allocno costs a0 (r43,l0) best GENERAL_REGS, cover GENERAL_REGS a0(r43,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:4000 Pass 1 for finding pseudo/allocno costs r43: preferred GENERAL_REGS, alternative NO_REGS, cover GENERAL_REGS a0(r43,l0) costs: POINTER_X_REGS:0,0 POINTER_Z_REGS:0,0 BASE_POINTER_REGS:0,0 POINTER_REGS:0,0 ADDW_REGS:0,0 SIMPLE_LD_REGS:0,0 LD_REGS:0,0 NO_LD_REGS:0,0 GENERAL_REGS:0,0 MEM:4000 Insn 15(l0): point = 0 Insn 12(l0): point = 2 Insn 7(l0): point = 4 Insn 2(l0): point = 6 a0(r43): [3..6] Compressing live ranges: from 9 to 2 - 22% Ranges after the compression: a0(r43): [0..1] +++Allocating 0 bytes for conflict table (uncompressed size 4) ;; a0(r43,l0) conflicts: regions=1, blocks=3, points=2 allocnos=1 (big 0), copies=0, conflicts=0, ranges=1 **** Allocnos coloring: Loop 0 (parent -1, header bb0, depth 0) bbs: 2 all: 0r43 modified regnos: 43 border: Pressure: GENERAL_REGS=1 Reg 43 of GENERAL_REGS has 6 regs less Pushing a0(r43,l0) Popping a0(r43,l0) -- assign reg 24 Disposition: 0:r43 l0 24 New iteration of spill/restore move +++Costs: overall -4000, reg -4000, mem 0, ld 0, st 0, move 0 +++ move loops 0, new jumps 0
;; Function foo1 (foo1) starting the processing of deferred insns ending the processing of deferred insns df_analyze called starting the processing of deferred insns ending the processing of deferred insns df_analyze called insn=2, live_throughout: 32, dead_or_set: 24, 42 insn=7, live_throughout: 32, 42, dead_or_set: insn=9, live_throughout: 32, dead_or_set: 24, 42 insn=10, live_throughout: 32, dead_or_set: 24 changing reg in insn 2 changing reg in insn 9 24 uses a new slot 24 uses a slot from prev iteration Spilling for insn 16. Using reg 30 for reload 0 Spilling for insn 17. Using reg 30 for reload 0 deleting insn with uid = 16. deleting insn with uid = 17. 24 uses a slot from prev iteration Spilling for insn 18. deleting insn with uid = 18. deleting insn with uid = 19. 24 uses a slot from prev iteration Spilling for insn 20. Reloads for insn # 20 Reload 0: reload_out (QI) = (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) NO_REGS, RELOAD_FOR_OUTPUT (opnum = 0), optional reload_out_reg: (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) deleting insn with uid = 2. deleting insn with uid = 9. try_optimize_cfg iteration 1 starting the processing of deferred insns ending the processing of deferred insns verify found no changes in insn with uid = 7. verify found no changes in insn with uid = 10. starting the processing of deferred insns ending the processing of deferred insns df_analyze called df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) foo1 Dataflow summary: ;; invalidated by call 0 [r0] 1 [r1] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; hardware regs used 32 [__SP_L__] ;; regular block artificial uses 28 [r28] 32 [__SP_L__] ;; eh block artificial uses 28 [r28] 32 [__SP_L__] 34 [argL] ;; entry block defs 8 [r8] 9 [r9] 10 [r10] 11 [r11] 12 [r12] 13 [r13] 14 [r14] 15 [r15] 16 [r16] 17 [r17] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 28 [r28] 32 [__SP_L__] ;; exit block uses 28 [r28] 32 [__SP_L__] ;; regs ever live 24[r24] 28[r28] 29[r29] 30[r30] 31[r31] 32[__SP_L__] ;; ref usage r0={2d} r1={2d} r8={1d} r9={1d} r10={1d} r11={1d} r12={1d} r13={1d} r14={1d} r15={1d} r16={1d} r17={1d} r18={3d} r19={3d} r20={3d} r21={3d} r22={3d} r23={3d} r24={4d,2u} r25={3d} r26={2d} r27={2d} r28={1d,4u} r29={2u} r30={2d} r31={2d} r32={1d,4u} r33={2d} r35={2d} ;; total ref usage 65{53d,12u,0e} in 4{2 regular + 2 call} insns. (note 1 0 4 NOTE_INSN_DELETED) ;; Start of basic block ( 0) -> 2 ;; bb 2 artificial_defs: { } ;; bb 2 artificial_uses: { u-1(28){ }u-1(32){ }} ;; lr in 24 [r24] 28 [r28] 29 [r29] 32 [__SP_L__] ;; lr use 24 [r24] 28 [r28] 29 [r29] 32 [__SP_L__] ;; lr def 0 [r0] 1 [r1] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; live in 24 [r24] 28 [r28] 32 [__SP_L__] ;; live gen 24 [r24] ;; live kill ;; Pred edge ENTRY [100.0%] (fallthru) (note 4 1 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (note 3 4 20 2 NOTE_INSN_FUNCTION_BEG) (insn 20 3 7 2 (set (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) (reg:QI 24 r24)) sib.c:6 4 {*movqi} (nil)) (call_insn 7 20 21 2 (call (mem:HI (symbol_ref:HI ("bar0") [flags 0x41] <function_decl 0xb753e680 bar0>) [0 S2 A8]) (const_int 0 [0])) sib.c:6 122 {call_insn} (nil) (nil)) (insn 21 7 10 2 (set (reg:QI 24 r24) (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8])) sib.c:7 4 {*movqi} (nil)) (call_insn 10 21 15 2 (call (mem:HI (symbol_ref:HI ("bar1") [flags 0x41] <function_decl 0xb753e700 bar1>) [0 S2 A8]) (const_int 0 [0])) sib.c:7 122 {call_insn} (nil) (expr_list:REG_DEP_TRUE (use (reg:QI 24 r24)) (nil))) ;; End of basic block 2 -> ( 1) ;; lr out 28 [r28] 32 [__SP_L__] ;; live out 28 [r28] 32 [__SP_L__] ;; Succ edge EXIT [100.0%] (fallthru) (note 15 10 0 NOTE_INSN_DELETED) ;; Function foo2 (foo2) starting the processing of deferred insns ending the processing of deferred insns df_analyze called starting the processing of deferred insns ending the processing of deferred insns df_analyze called insn=2, live_throughout: 32, dead_or_set: 24, 43 insn=7, live_throughout: 32, 43, dead_or_set: 24 insn=8, live_throughout: 32, 43, dead_or_set: 24 insn=13, live_throughout: 32, dead_or_set: 24, 43 insn=16, live_throughout: 24, 32, dead_or_set: changing reg in insn 2 changing reg in insn 13 changing reg in insn 7 try_optimize_cfg iteration 1 starting the processing of deferred insns ending the processing of deferred insns verify found no changes in insn with uid = 8. starting the processing of deferred insns ending the processing of deferred insns df_analyze called df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) foo2 Dataflow summary: ;; invalidated by call 0 [r0] 1 [r1] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; hardware regs used 32 [__SP_L__] ;; regular block artificial uses 32 [__SP_L__] ;; eh block artificial uses 32 [__SP_L__] 34 [argL] ;; entry block defs 8 [r8] 9 [r9] 10 [r10] 11 [r11] 12 [r12] 13 [r13] 14 [r14] 15 [r15] 16 [r16] 17 [r17] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__] ;; exit block uses 24 [r24] 32 [__SP_L__] ;; regs ever live 17[r17] 24[r24] 32[__SP_L__] ;; ref usage r0={1d} r1={1d} r8={1d} r9={1d} r10={1d} r11={1d} r12={1d} r13={1d} r14={1d} r15={1d} r16={1d} r17={2d,2u} r18={2d} r19={2d} r20={2d} r21={2d} r22={2d} r23={2d} r24={4d,4u} r25={2d} r26={1d} r27={1d} r30={1d} r31={1d} r32={1d,3u} r33={1d} r35={1d} ;; total ref usage 47{38d,9u,0e} in 5{4 regular + 1 call} insns. (note 1 0 4 NOTE_INSN_DELETED) ;; Start of basic block ( 0) -> 2 ;; bb 2 artificial_defs: { } ;; bb 2 artificial_uses: { u-1(32){ }} ;; lr in 24 [r24] 32 [__SP_L__] ;; lr use 24 [r24] 32 [__SP_L__] ;; lr def 0 [r0] 1 [r1] 17 [r17] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; live in 24 [r24] 32 [__SP_L__] ;; live gen 17 [r17] 24 [r24] ;; live kill ;; Pred edge ENTRY [100.0%] (fallthru) (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (insn 2 4 3 2 (set (reg/v:QI 17 r17 [orig:43 x ] [43]) (reg:QI 24 r24 [ x ])) sib.c:12 4 {*movqi} (nil)) (note 3 2 7 2 NOTE_INSN_FUNCTION_BEG) (insn 7 3 8 2 (set (reg:QI 24 r24) (reg/v:QI 17 r17 [orig:43 x ] [43])) sib.c:13 4 {*movqi} (nil)) (call_insn 8 7 13 2 (call (mem:HI (symbol_ref:HI ("bar1") [flags 0x41] <function_decl 0xb753e700 bar1>) [0 S2 A8]) (const_int 0 [0])) sib.c:13 122 {call_insn} (nil) (expr_list:REG_DEP_TRUE (use (reg:QI 24 r24)) (nil))) (insn 13 8 16 2 (set (reg/i:QI 24 r24) (reg/v:QI 17 r17 [orig:43 x ] [43])) sib.c:16 4 {*movqi} (nil)) (insn 16 13 20 2 (use (reg/i:QI 24 r24)) sib.c:16 -1 (nil)) ;; End of basic block 2 -> ( 1) ;; lr out 24 [r24] 32 [__SP_L__] ;; live out 24 [r24] 32 [__SP_L__] ;; Succ edge EXIT [100.0%] (fallthru) (note 20 16 0 NOTE_INSN_DELETED) ;; Function foo3 (foo3) starting the processing of deferred insns ending the processing of deferred insns df_analyze called starting the processing of deferred insns ending the processing of deferred insns df_analyze called insn=2, live_throughout: 32, dead_or_set: 24, 43 insn=7, live_throughout: 32, 43, dead_or_set: insn=12, live_throughout: 32, dead_or_set: 24, 43 insn=15, live_throughout: 24, 32, dead_or_set: changing reg in insn 2 changing reg in insn 12 24 uses a new slot 24 uses a slot from prev iteration Spilling for insn 20. Using reg 30 for reload 0 Spilling for insn 21. Using reg 30 for reload 0 deleting insn with uid = 20. deleting insn with uid = 21. 24 uses a slot from prev iteration Spilling for insn 22. deleting insn with uid = 22. deleting insn with uid = 23. 24 uses a slot from prev iteration Spilling for insn 24. Reloads for insn # 24 Reload 0: reload_out (QI) = (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) NO_REGS, RELOAD_FOR_OUTPUT (opnum = 0), optional reload_out_reg: (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) deleting insn with uid = 2. deleting insn with uid = 12. try_optimize_cfg iteration 1 starting the processing of deferred insns ending the processing of deferred insns verify found no changes in insn with uid = 7. starting the processing of deferred insns ending the processing of deferred insns df_analyze called df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) df_worklist_dataflow_doublequeue:n_basic_blocks 3 n_edges 2 count 3 ( 1) foo3 Dataflow summary: ;; invalidated by call 0 [r0] 1 [r1] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; hardware regs used 32 [__SP_L__] ;; regular block artificial uses 28 [r28] 32 [__SP_L__] ;; eh block artificial uses 28 [r28] 32 [__SP_L__] 34 [argL] ;; entry block defs 8 [r8] 9 [r9] 10 [r10] 11 [r11] 12 [r12] 13 [r13] 14 [r14] 15 [r15] 16 [r16] 17 [r17] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 28 [r28] 32 [__SP_L__] ;; exit block uses 24 [r24] 28 [r28] 32 [__SP_L__] ;; regs ever live 24[r24] 28[r28] 29[r29] 30[r30] 31[r31] 32[__SP_L__] ;; ref usage r0={1d} r1={1d} r8={1d} r9={1d} r10={1d} r11={1d} r12={1d} r13={1d} r14={1d} r15={1d} r16={1d} r17={1d} r18={2d} r19={2d} r20={2d} r21={2d} r22={2d} r23={2d} r24={3d,3u} r25={2d} r26={1d} r27={1d} r28={1d,4u} r29={2u} r30={1d} r31={1d} r32={1d,3u} r33={1d} r35={1d} ;; total ref usage 49{37d,12u,0e} in 4{3 regular + 1 call} insns. (note 1 0 4 NOTE_INSN_DELETED) ;; Start of basic block ( 0) -> 2 ;; bb 2 artificial_defs: { } ;; bb 2 artificial_uses: { u-1(28){ }u-1(32){ }} ;; lr in 24 [r24] 28 [r28] 29 [r29] 32 [__SP_L__] ;; lr use 24 [r24] 28 [r28] 29 [r29] 32 [__SP_L__] ;; lr def 0 [r0] 1 [r1] 18 [r18] 19 [r19] 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 26 [r26] 27 [r27] 30 [r30] 31 [r31] 33 [__SP_H__] 35 [argH] ;; live in 24 [r24] 28 [r28] 32 [__SP_L__] ;; live gen 24 [r24] ;; live kill ;; Pred edge ENTRY [100.0%] (fallthru) (note 4 1 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (note 3 4 24 2 NOTE_INSN_FUNCTION_BEG) (insn 24 3 7 2 (set (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8]) (reg:QI 24 r24)) sib.c:20 4 {*movqi} (nil)) (call_insn 7 24 25 2 (call (mem:HI (symbol_ref:HI ("bar0") [flags 0x41] <function_decl 0xb753e680 bar0>) [0 S2 A8]) (const_int 0 [0])) sib.c:20 122 {call_insn} (nil) (nil)) (insn 25 7 15 2 (set (reg:QI 24 r24) (mem/c:QI (plus:HI (reg/f:HI 28 r28) (const_int 1 [0x1])) [2 S1 A8])) sib.c:23 4 {*movqi} (nil)) (insn 15 25 19 2 (use (reg/i:QI 24 r24)) sib.c:23 -1 (nil)) ;; End of basic block 2 -> ( 1) ;; lr out 24 [r24] 28 [r28] 32 [__SP_L__] ;; live out 24 [r24] 28 [r28] 32 [__SP_L__] ;; Succ edge EXIT [100.0%] (fallthru) (note 19 15 0 NOTE_INSN_DELETED)
.file "sib.c" __SREG__ = 0x3f __SP_H__ = 0x3e __SP_L__ = 0x3d __tmp_reg__ = 0 __zero_reg__ = 1 .global __do_copy_data .global __do_clear_bss .text .global foo1 .type foo1, @function foo1: push r29 ; 22 *pushhi/1 [length = 2] push r28 push __tmp_reg__ ; 26 *addhi3_sp_R_pc2 [length = 1] in r28,__SP_L__ ; 27 *movhi_sp/2 [length = 2] in r29,__SP_H__ /* prologue: function */ /* frame size = 1 */ /* stack size = 3 */ .L__stack_usage = 3 std Y+1,r24 ; 20 *movqi/3 [length = 1] rcall bar0 ; 7 call_insn/3 [length = 1] ldd r24,Y+1 ; 21 *movqi/4 [length = 1] rcall bar1 ; 10 call_insn/3 [length = 1] /* epilogue start */ pop __tmp_reg__ ; 32 *addhi3_sp_R_pc2 [length = 1] pop r28 ; 33 pophi [length = 2] pop r29 ret ; 34 return_from_epilogue [length = 1] .size foo1, .-foo1 .global foo2 .type foo2, @function foo2: push r17 ; 21 *pushqi/1 [length = 1] /* prologue: function */ /* frame size = 0 */ /* stack size = 1 */ .L__stack_usage = 1 mov r17,r24 ; 2 *movqi/1 [length = 1] rcall bar1 ; 8 call_insn/3 [length = 1] mov r24,r17 ; 13 *movqi/1 [length = 1] /* epilogue start */ pop r17 ; 24 popqi [length = 1] ret ; 25 return_from_epilogue [length = 1] .size foo2, .-foo2 .global foo3 .type foo3, @function foo3: push r29 ; 26 *pushhi/1 [length = 2] push r28 push __tmp_reg__ ; 30 *addhi3_sp_R_pc2 [length = 1] in r28,__SP_L__ ; 31 *movhi_sp/2 [length = 2] in r29,__SP_H__ /* prologue: function */ /* frame size = 1 */ /* stack size = 3 */ .L__stack_usage = 3 std Y+1,r24 ; 24 *movqi/3 [length = 1] rcall bar0 ; 7 call_insn/3 [length = 1] ldd r24,Y+1 ; 25 *movqi/4 [length = 1] /* epilogue start */ pop __tmp_reg__ ; 36 *addhi3_sp_R_pc2 [length = 1] pop r28 ; 37 pophi [length = 2] pop r29 ret ; 38 return_from_epilogue [length = 1] .size foo3, .-foo3