Understanding peephole2

Georg-Johann Lay avr@gjlay.de
Wed Nov 20 10:27:02 GMT 2024


Consider the following RTL peephole from avr.md:

(define_peephole2               ; avr.md:5387
   [(match_scratch:QI 3 "d")
    (parallel [(set (match_operand:ALL4 0 "register_operand" "")
                    (ashift:ALL4 (match_operand:ALL4 1 
"register_operand" "")
                                 (match_operand:QI 2 "const_int_operand" 
"")))
               (clobber (reg:CC REG_CC))])]
   ""
   [(parallel [(set (match_dup 0)
                    (ashift:ALL4 (match_dup 1)
                                 (match_dup 2)))
               (clobber (match_dup 3))
               (clobber (reg:CC REG_CC))])])

As far as I understand, its purpose is to provide a QImode
scratch register provided such a scratch is available.

However, in the .peephole2 RTL dump with -da I see the following:

Splitting with gen_peephole2_100 (avr.md:5387)
...
(insn 24 8 15 2 (parallel [
             (set (reg:SI 22 r22 [orig:47 _3 ] [47])
                  (ashift:SI (reg:SI 20 r20 [orig:48 x ] [48])
                             (const_int 7 [0x7])))
             (clobber (reg:QI 24 r24))
             (clobber (reg:CC 36 cc))
         ])
      (nil))

That is, the scratch r24:QI is overlapping the output in
r22:SI.  All hard registers are 8-bit regs and hence r22:SI
extends from r22...r25.

A scratch that overlaps the operands is pretty much useless
or even plain wrong.  recog.cc::peep2_find_free_register()
has this comment:  /* Don't use registers set or clobbered by the insn.  */

   from = peep2_buf_position (peep2_current + from);
   to = peep2_buf_position (peep2_current + to);

   gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
   REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);

   while (from != to)
     {
       gcc_assert (peep2_insn_data[from].insn != NULL_RTX);

       /* Don't use registers set or clobbered by the insn.  */
       FOR_EACH_INSN_DEF (def, peep2_insn_data[from].insn)
	SET_HARD_REG_BIT (live, DF_REF_REGNO (def));

       from = peep2_buf_position (from + 1);
     }

So it this bogus in that it assumes all registers extend only
over one hard reg?

FYI, the purpose is to provide a scratch without increasing the register
pressure (which "match_scratch" would do).  Therefore, the RTL peephole
is used instead of forcing reload to come up with a scratch.

More specifically, I see this with

$ avr-gcc bogus-peep2.c -S -Os -da

long ashl32_7 (int i, long x)
{
     return x << 7;
}

with the attached WIP patch atop trunk b222ee10045d.

Johann

Target: avr
Configured with: ../../source/gcc-master/configure --target=avr 
--disable-nls --with-dwarf2 --with-gnu-as --with-gnu-ld --disable-shared 
  --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 15.0.0 20241119 (experimental) (GCC)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bogus-peep2.diff
Type: text/x-patch
Size: 9428 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20241120/fb5ab0a1/attachment-0001.bin>
-------------- next part --------------

;; Function ashl32_7 (ashl32_7, funcdef_no=0, decl_uid=1900, cgraph_uid=1, symbol_order=0)

starting the processing of deferred insns
ending the processing of deferred insns
df_analyze called


ashl32_7

Dataflow summary:
def_info->table_size = 0, use_info->table_size = 0
;;  fully invalidated by EH 	 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] 36 [cc]
;;  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 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;;  regs ever live 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 36 [cc]
;;  ref usage 	r8={1d} r9={1d} r10={1d} r11={1d} r12={1d} r13={1d} r14={1d} r15={1d} r16={1d} r17={1d} r18={1d} r19={1d} r20={1d,1u} r21={1d,1u} r22={2d,3u} r23={2d,3u} r24={2d,2u} r25={2d,2u} r32={1d,2u} r36={1d} 
;;    total ref usage 38{24d,14u,0e} in 3{3 regular + 0 call} insns.

( )->[0]->( 2 )
;; bb 0 artificial_defs: { d-1(8){ }d-1(9){ }d-1(10){ }d-1(11){ }d-1(12){ }d-1(13){ }d-1(14){ }d-1(15){ }d-1(16){ }d-1(17){ }d-1(18){ }d-1(19){ }d-1(20){ }d-1(21){ }d-1(22){ }d-1(23){ }d-1(24){ }d-1(25){ }d-1(32){ }}
;; bb 0 artificial_uses: { }
;; lr  in  	
;; lr  use 	
;; lr  def 	 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__]
;; live  in  	
;; live  gen 	 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__]
;; live  kill	
;; lr  out 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; live  out 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]

( 0 )->[2]->( 1 )
;; bb 2 artificial_defs: { }
;; bb 2 artificial_uses: { u-1(32){ }}
;; lr  in  	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; lr  use 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; lr  def 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 36 [cc]
;; live  in  	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; live  gen 	 22 [r22] 23 [r23] 24 [r24] 25 [r25]
;; live  kill	 36 [cc]
;; lr  out 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;; live  out 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]

( 2 )->[1]->( )
;; bb 1 artificial_defs: { }
;; bb 1 artificial_uses: { u-1(22){ }u-1(23){ }u-1(24){ }u-1(25){ }u-1(32){ }}
;; lr  in  	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;; lr  use 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;; lr  def 	
;; live  in  	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;; live  gen 	
;; live  kill	
;; lr  out 	
;; live  out 	

Finding needed instructions:
  Adding insn 20 to worklist
  Adding insn 13 to worklist
Finished finding needed instructions:
processing block 2 lr out =  22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
  Adding insn 17 to worklist
Splitting with gen_peephole2_100 (avr.md:5388)
scanning new insn with uid = 22.
deleting insn with uid = 17.
verify found no changes in insn with uid = 22.
starting the processing of deferred insns
ending the processing of deferred insns


ashl32_7

Dataflow summary:
;;  fully invalidated by EH 	 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] 36 [cc]
;;  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 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;;  regs ever live 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 24 [r24] 25 [r25] 36 [cc]
;;  ref usage 	r8={1d} r9={1d} r10={1d} r11={1d} r12={1d} r13={1d} r14={1d} r15={1d} r16={1d} r17={1d} r18={1d} r19={1d} r20={1d,1u} r21={1d,1u} r22={2d,3u} r23={2d,3u} r24={3d,2u} r25={2d,2u} r32={1d,2u} r36={1d} 
;;    total ref usage 39{25d,14u,0e} in 3{3 regular + 0 call} insns.
(note 1 0 5 NOTE_INSN_DELETED)
;; basic block 2, loop depth 0, count 1073741824 (estimated locally, freq 1.0000), maybe hot
;;  prev block 0, next block 1, flags: (REACHABLE, RTL, MODIFIED)
;;  pred:       ENTRY [always]  count:1073741824 (estimated locally, freq 1.0000) (FALLTHRU)
;; bb 2 artificial_defs: { }
;; bb 2 artificial_uses: { u-1(32){ }}
;; lr  in  	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; lr  use 	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; lr  def 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 36 [cc]
;; live  in  	 20 [r20] 21 [r21] 22 [r22] 23 [r23] 32 [__SP_L__]
;; live  gen 	 22 [r22] 23 [r23] 24 [r24] 25 [r25]
;; live  kill	 36 [cc]
(note 5 1 18 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(note 18 5 3 2 NOTE_INSN_PROLOGUE_END)
(note 3 18 4 2 NOTE_INSN_DELETED)
(note 4 3 22 2 NOTE_INSN_FUNCTION_BEG)
(insn 22 4 13 2 (parallel [
            (set (reg:SI 22 r22 [orig:46 _2 ] [46])
                (ashift:SI (reg:SI 20 r20 [orig:47 x ] [47])
                    (const_int 7 [0x7])))
            (clobber (reg:QI 24 r24))
            (clobber (reg:CC 36 cc))
        ]) "bogus-peep2.c":3:14 -1
     (nil))
(insn 13 22 19 2 (use (reg/i:SI 22 r22)) "bogus-peep2.c":4:1 -1
     (nil))
(note 19 13 20 2 NOTE_INSN_EPILOGUE_BEG)
(jump_insn 20 19 21 2 (return) "bogus-peep2.c":4:1 -1
     (nil)
 -> return)
;;  succ:       EXIT [always]  count:1073741824 (estimated locally, freq 1.0000)
;; lr  out 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]
;; live  out 	 22 [r22] 23 [r23] 24 [r24] 25 [r25] 32 [__SP_L__]

(barrier 21 20 16)
(note 16 21 0 NOTE_INSN_DELETED)


More information about the Gcc mailing list