avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] new patch for loop and jump optimisation


From: Andy Hutchinson
Subject: [avr-gcc-list] new patch for loop and jump optimisation
Date: Wed, 16 Feb 2005 22:20:23 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)

Here is a new avr gcc patch to try out.

If I did everything correctly it should change avr.c and avr.h on HEAD.


This includes fixes for the following missed/broken optimisation:

1) SBxx and CPSE will now be used to skip 2 and 3 word instructions
2) SBxx Rx,7 (..15..31) will not be used at end of doloop in preference to more efficient BRPL/BRMI. This was caused by the SBxx optimisation being applied to all sign tests - even when we knew what sign was.
3) Removal of some redundant TST instructions related to above.

I am unaware of any speed/size optimisation regressions. There shouldn't be any.

It will still miss a few situations where a skip can be used - I already know how to make it perfect but I want this version checked first.

At present this patch folds sign test of SF (float) into a test of bit 31. This will not work if we are using signed zeros. However it is easily fixed (see below)

This change also replaces the current asm peephole sign tests with a single RTL peephole2. This helps avr move away from use of the deprecated asm peephole usage.

I have chosen to use the new mode macros for 4.0. This allows a single instruction pattern to be used for several mode. In this case QI,HI,SI,SF (- and thats where the float sign test is!)

There are now two jump_over_one_insn... functions. One is used by peephole and the other by peephole2. Both use the same logic. peephole (ie asm peepholes) can get at address of instructions. But you cant do that when the peephole2 (RTL) is used. Instead I use instruction length and a forward search.

The function jump_over_one_insn_p2 can totally replace the other one. This would remove nearly all the asm peephole patterns. (I beleive the only ones left would be CPSE). I have not done this yet as it would involve changing a lot of things at once! It would not affect generated code.

Can you try this?



*** avr.c   9 Feb 2005 14:43:28 -0000   1.129
--- avr.c   17 Feb 2005 01:48:23 -0000
***************
*** 5519,5525 ****
            }
        }
        }
!     else if (true_regnum (SET_SRC (pattern)) >= 0)
        {
          /* This is a tst insn */
          rtx next = next_real_insn (insn);
--- 5519,5525 ----
            }

        }

        }

!     else if (0&&true_regnum (SET_SRC (pattern)) >= 0)//awh disable TST 
REVERSAL
        {

          /* This is a tst insn */

          rtx next = next_real_insn (insn);

***************
*** 5624,5639 ****
    return 0;
  }
  
  
  int
  jump_over_one_insn_p (rtx insn, rtx dest)
  {
    int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
              ? XEXP (dest, 0)
              : dest);
!   int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
    int dest_addr = INSN_ADDRESSES (uid);
!   return dest_addr - jump_addr == get_attr_length (insn) + 1;
  }
  
  /* Returns 1 if a value of mode MODE can be stored starting with hard
--- 5624,5784 ----
    return 0;

  }

  

+ /* Check if dest label is ok for skip instruction destination in this 
instruction insn
+    SBxx is only valid over one asm (not RTL) instruction. One asm insn can be 
1,2 or 3 words.
+    return number of asm words skipped as true, 0= false if we can't work it 
out
+    or jump is too far 

+    Ideally we need addresses to find displacement - we can only do this with 
+    a code peephole not a peephole2 (as addresses are not yet calculated). To 
get around this
+    we get the length of following instructions from  length attribute. If 
length is 1
+    it is skippable. We also look for specific patterns we know are one 
instruction long 
+    this includes (call, r<=[mem], [mem]<=r and jump). Finally we look for the 
label.
+    This wont catch all of the possibilities
+    TODO use adjust_Ins_length for more accurate length?????
+ */
+ 
+ int jump_over_one_insn_p2(rtx insn, rtx operands[], rtx dest )
+ 
+  {
+  /* This is wrapper to get around problem where get_attr_length clobbers 
operand list! */
+   rtx ops[2];
+   ops[0]=operands[0];
+   ops[1]=operands[1];
+   ops[2]=operands[2];
+   int ret =jump_over_one_insn_pxx(insn,dest);
+   operands[0]=ops[0];
+   operands[1]=ops[1];
+   operands[2]=ops[2];
+ return ret;  
+ }
  
  int
+ jump_over_one_insn_pxx (rtx insn, rtx dest)
+ {
+   /* get dest instruction uid */
+   int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
+               ? XEXP (dest, 0)
+               : dest);
+               
+   /* skip next real instruction  - should be the jump*/
+   rtx nexti=next_real_insn(insn);
+ 
+   /*return false if there isn't one (bad md file)*/    
+   if (!nexti) return 0;
+ 
+   /* next real instruction is perhaps one we can skip*/
+   nexti=next_real_insn(nexti);
+ 
+   /*return false if there isn't one */    
+   if (!nexti) return 0;
+ 
+   /* length in words of skippable instruction */
+   int len =0;
+   
+   rtx next=    PATTERN(nexti);
+ 
+       
+   /* ok skipping byte stores of zero or register into direct memory STS */
+   if (GET_CODE(next)==SET)
+     if (GET_MODE(XEXP(next,0))==QImode)
+       if (GET_CODE(XEXP(next,0))==MEM)
+         if (CONSTANT_P(XEXP(XEXP(next,0),0)))
+           if ((GET_CODE(XEXP(next,1))==REG)||(XEXP(next,1)==const0_rtx))
+             len=2;
+ 
+           
+   /* ok skipping byte loads of register from direct mem LDS */
+   if (GET_CODE(next)==SET)
+     if (GET_MODE(XEXP(next,1))==QImode)
+       if (GET_CODE(XEXP(next,1))==MEM)
+         if (CONSTANT_P(XEXP(XEXP(next,1),0)))      
+           if ((GET_CODE(XEXP(next,0))==REG))
+             len= 2;
+     
+   /*ok skipping over any non conditional jump - JUMP */
+   if (GET_CODE(next)==SET)
+     if (GET_CODE(XEXP(next,0))==PC)
+       if (GET_CODE(XEXP(next,1))==LABEL_REF)
+         len=2;
+  
+   /* ok skipping calls which are always ONE instruction but sometimes 2 
words*/
+   if (GET_CODE(nexti)==CALL_INSN) len=2;
+ 
+ 
+   /*finally single word RTL instructions are one asm instruction */
+   int l=get_attr_length(nexti);
+   if (l==1) len=1;
+ 
+ 

+   /* exit if instruction is not skippable */
+   if (!len) return 0;
+   
+   /* jump target must be next non-note instruction */
+   while ((nexti=NEXT_INSN(nexti)))
+   {
+     if (uid==INSN_UID(nexti))
+         return  len;
+     else if INSN_P (nexti)
+         return 0;
+   }
+   
+   /* lable target was not found  */
+   return 0;
+ }
+ /* This is the same function but uses instruction addresses */
+ int

  jump_over_one_insn_p (rtx insn, rtx dest)

  {

    int uid = INSN_UID (GET_CODE (dest) == LABEL_REF

              ? XEXP (dest, 0)

              : dest);

!         
!   /* skip notes and look at next real instruction */
!   rtx nexti=next_real_insn(insn);
!   
!   /*return false if there isn't one */    
!   if (!nexti) return 0;
!   
!   /* Use this as baseline for displacment calculation */        
!   int jump_addr = INSN_ADDRESSES (INSN_UID (nexti));
    int dest_addr = INSN_ADDRESSES (uid);

!   int disp = dest_addr - jump_addr;
!   
!   /* valid displacments are 1,2 or 3 words */
!   if ((disp <= 0)||(disp>3)) return 0;
!   
!   /* one word displacment always means only one asm instruction */
!   if (disp == 1) return 1;
! 
!   /* ok skipping calls which are always ONE instruction but sometimes 2 
words*/
!   if (GET_CODE(nexti)==CALL_INSN) 
!     if (disp == 2) return 2;
!   
!   rtx next=   PATTERN(next_real_insn(insn));    
!   /* ok skipping byte stores of zero or register into direct memory STS */
!   if (GET_CODE(next)==SET)
!     if (GET_MODE(XEXP(next,0))==QImode)
!     if (GET_CODE(XEXP(next,0))==MEM)
!       if (CONSTANT_P(XEXP(XEXP(next,0),0)))
!         if ((GET_CODE(XEXP(next,1))==REG)||(XEXP(next,1)==const0_rtx))
!             if (disp == 2) return 2;
!         
!   /* ok skipping byte loads of register from direct mem LDS */
!   if (GET_CODE(next)==SET)
!     if (GET_MODE(XEXP(next,1))==QImode)
!     if (GET_CODE(XEXP(next,1))==MEM)
!       if (CONSTANT_P(XEXP(XEXP(next,1),0)))     
!         if ((GET_CODE(XEXP(next,0))==REG))
!             if (disp == 2) return 2;
!           
!   /*ok skipping over any non conditional jump to label - JUMP */
!   /*ok skipping over any non conditional jump - JUMP */
!   if (GET_CODE(next)==SET)
!     if (GET_CODE(XEXP(next,0))==PC)
!       if (GET_CODE(XEXP(next,1))==LABEL_REF)
!         if (disp == 2) return 2;
!     
!   return 0;
  }

  

  /* Returns 1 if a value of mode MODE can be stored starting with hard


*** avr.md  27 Jan 2005 18:22:25 -0000  1.49
--- avr.md  17 Feb 2005 02:18:27 -0000
***************
*** 1903,1985 ****
                    (const_int 4))))
     (set_attr "cc" "clobber")])
  
- ;; Convert sign tests to bit 7/15/31 tests that match the above insns.
- (define_peephole2
-   [(set (cc0) (match_operand:QI 0 "register_operand" ""))
-    (set (pc) (if_then_else (ge (cc0) (const_int 0))
-              (label_ref (match_operand 1 "" ""))
-              (pc)))]
-   ""
-   [(set (pc) (if_then_else (eq (zero_extract (match_dup 0)
-                        (const_int 1)
-                        (const_int 7))
-                  (const_int 0))
-              (label_ref (match_dup 1))
-              (pc)))]
-   "")
  
- (define_peephole2
-   [(set (cc0) (match_operand:QI 0 "register_operand" ""))
-    (set (pc) (if_then_else (lt (cc0) (const_int 0))
-              (label_ref (match_operand 1 "" ""))
-              (pc)))]
-   ""
-   [(set (pc) (if_then_else (ne (zero_extract (match_dup 0)
-                        (const_int 1)
-                        (const_int 7))
-                  (const_int 0))
-              (label_ref (match_dup 1))
-              (pc)))]
-   "")
  
! (define_peephole2
!   [(set (cc0) (match_operand:HI 0 "register_operand" ""))
!    (set (pc) (if_then_else (ge (cc0) (const_int 0))
!              (label_ref (match_operand 1 "" ""))
!              (pc)))]
!   ""
!   [(set (pc) (if_then_else (eq (and:HI (match_dup 0) (const_int -32768))
!                  (const_int 0))
!              (label_ref (match_dup 1))
!              (pc)))]
!   "")
  
  (define_peephole2
!   [(set (cc0) (match_operand:HI 0 "register_operand" ""))
!    (set (pc) (if_then_else (lt (cc0) (const_int 0))
               (label_ref (match_operand 1 "" ""))
               (pc)))]
    ""
!   [(set (pc) (if_then_else (ne (and:HI (match_dup 0) (const_int -32768))
!                  (const_int 0))
               (label_ref (match_dup 1))
!              (pc)))]
!   "")
  
! (define_peephole2
!   [(set (cc0) (match_operand:SI 0 "register_operand" ""))
!    (set (pc) (if_then_else (ge (cc0) (const_int 0))
!              (label_ref (match_operand 1 "" ""))
!              (pc)))]
!   ""
!   [(set (pc) (if_then_else (eq (and:SI (match_dup 0) (match_dup 2))
!                  (const_int 0))
!              (label_ref (match_dup 1))
!              (pc)))]
!   "operands[2] = GEN_INT (-2147483647 - 1);")
  
- (define_peephole2
-   [(set (cc0) (match_operand:SI 0 "register_operand" ""))
-    (set (pc) (if_then_else (lt (cc0) (const_int 0))
-              (label_ref (match_operand 1 "" ""))
-              (pc)))]
-   ""
-   [(set (pc) (if_then_else (ne (and:SI (match_dup 0) (match_dup 2))
-                  (const_int 0))
-              (label_ref (match_dup 1))
-              (pc)))]
-   "operands[2] = GEN_INT (-2147483647 - 1);")
  
  ;; ************************************************************************
  ;; Implementation of conditional jumps here.
  ;;  Compare with 0 (test) jumps
--- 1903,1955 ----
                    (const_int 4))))
     (set_attr "cc" "clobber")])
  
  
  
! ;; Convert sign tests to bit 7/15/31 tests that match the above insns.
! ;; but only if we have a forward jump within skip range
! ;; TODO - I think this pattern could handle i/o tests
! ;;
! (define_mode_macro BMODES [ QI HI SI SF])
  
  (define_peephole2
!   [(set (cc0) (match_operand:BMODES 0 "register_operand" ""))
!    (set (pc) (if_then_else (match_operator 2 "comparison_operator" [(cc0) 
(const_int 0)])
                 (label_ref (match_operand 1 "" ""))
                 (pc)))]
    ""
!   [(set (pc) (if_then_else (match_dup 0)
                 (label_ref (match_dup 1))
!                (pc)
!                ))]
!   "{
!     enum rtx_code cond =GET_CODE(operands[2]);
!     rtx hibyte=operands[0];    
!     rtx dest=operands[1];
!     enum machine_mode mode=GET_MODE(operands[0]);
!     
!     int ret =jump_over_one_insn_p2(curr_insn,operands,operands[1]);
!     if (!ret) FAIL;
!     
!     if (mode!=QImode)
!       hibyte=gen_rtx_SUBREG(QImode,hibyte, GET_MODE_SIZE(mode)-1);
! 
!     rtx bit=gen_rtx_ZERO_EXTRACT(QImode,hibyte,GEN_INT(1),GEN_INT(7));
! 
!     if (cond==GE)
!         operands[0]=gen_rtx_EQ(QImode,bit,const0_rtx);
!     else if (cond==LT)
!         operands[0]=gen_rtx_NE(QImode,bit,const0_rtx);
!     else
!         FAIL;
!     operands[1]=dest;
  
!   }
!    "
! )
  
  
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

+ ;;
  ;; ************************************************************************
  ;; Implementation of conditional jumps here.
  ;;  Compare with 0 (test) jumps


reply via email to

[Prev in Thread] Current Thread [Next in Thread]