http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02186.html

Richard Henderson wrote:
> On 07/25/2011 10:30 AM, Georg-Johann Lay wrote:
>>      PR target/29560
>>      * config/avr/avr.md: Add peephole2 to map ashlhi3 to ashlqi3 if
>>      high part of shift target is unused.
> 
> Ok.
> 
> r~

Here is a more complete version that transforms earlier
and increases the number of cases covered.

Moreover, the original peep2 is not fully correct because it
maps a 16-bit shift to a 8-bit one.  The correct mapping is

(set (match_dup 2)
     (subreg:QI (ashift:HI (zero_extend:HI (match_dup 2))
                           (match_dup 1))
                0))

instead of

(set (match_dup 2)
     (ashift:QI (match_dup 2)
                (match_dup 1)))


I don't think it makes a difference that late in the
compilation process, yet I prefer correct semantics.

The new iterators are already seen in the widening
multiply patch.

Ok?

Johann

        PR target/29560
        * config/avr/avr.md (any_extend): New code interator.
        (extend_prefix): New code attribute.
        (*ashl<extend_prefix>qihiqi3): New insns.
        (*ashl<extend_prefix>qihiqi3.mem): New insn-and-splits.
        (*ashlhiqi3): New insn-and-split.
        Add peephole2 to map ashlhi3 to ashlqi3 if high part of
        shift target is unused.

Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 176624)
+++ config/avr/avr.md	(working copy)
@@ -132,6 +132,15 @@ (define_mode_iterator QIDI [(QI "") (HI
 (define_mode_iterator HIDI [(HI "") (SI "") (DI "")])
 (define_mode_iterator HISI [(HI "") (SI "")])
 
+;; Define code iterators
+(define_code_iterator any_extend  [sign_extend zero_extend])
+
+;; Define code attributes
+(define_code_attr extend_prefix
+  [(sign_extend "s")
+   (zero_extend "u")])
+
+
 ;;========================================================================
 ;; The following is used by nonlocal_goto and setjmp.
 ;; The receiver pattern will create no instructions since internally
@@ -1993,6 +2002,89 @@ (define_insn "ashlhi3"
   [(set_attr "length" "6,0,2,2,4,10,10")
    (set_attr "cc" "clobber,none,set_n,clobber,set_n,clobber,clobber")])
 
+
+;; Insn like the following are generated when (implicitly) extending 8-bit shifts
+;; like char1 = char2 << char3.  Only the low-byte is needed in that situation.
+;; The output is the same as of *ashlqi3.  Don't, however, map this to *ashlqi3
+;; to preserve the semantics of ashift:HI which is different to ashift:QI.
+
+;; "*ashluqihiqi3"
+;; "*ashlsqihiqi3"
+(define_insn "*ashl<extend_prefix>qihiqi3"
+  [(set (match_operand:QI 0 "register_operand"                                     "=r")
+        (subreg:QI (ashift:HI (any_extend:HI (match_operand:QI 1 "register_operand" "0"))
+                              (match_operand:QI 2 "register_operand"                "r"))
+                   0))]
+  ""
+  {
+    return ashlqi3_out (insn, operands, NULL);
+  }
+  [(set_attr "length" "5")
+   (set_attr "cc" "clobber")])
+
+;; Map to above.
+
+;; "*ashluqihiqi3.mem"
+;; "*ashlsqihiqi3.mem"
+(define_insn_and_split "*ashl<extend_prefix>qihiqi3.mem"
+  [(set (match_operand:QI 0 "memory_operand" "=m")
+        (subreg:QI (ashift:HI (any_extend:HI (match_operand:QI 1 "register_operand" "r"))
+                              (match_operand:QI 2 "register_operand" "r"))
+                   0))]
+  "!reload_completed"
+  { gcc_unreachable(); }
+  "&& 1"
+  [(set (match_dup 3)
+        (subreg:QI (ashift:HI (any_extend:HI (match_dup 1))
+                              (match_dup 2)) 0))
+   (set (match_dup 0)
+        (match_dup 3))]
+  {
+    operands[3] = force_reg (QImode, operands[0]);
+  })
+
+;; Ditto.
+
+(define_insn_and_split "*ashlhiqi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=r")
+        (subreg:QI (ashift:HI (match_operand:HI 1 "register_operand" "0")
+                              (match_operand:QI 2 "register_operand" "r")) 0))]
+  "!reload_completed"
+  { gcc_unreachable(); }
+  "&& 1"
+  [(set (match_dup 4)
+        (subreg:QI (ashift:HI (zero_extend:HI (match_dup 3))
+                              (match_dup 2)) 0))
+   (set (match_dup 0)
+        (match_dup 4))]
+  {
+    operands[3] = simplify_gen_subreg (QImode, operands[1], HImode, 0);
+    operands[4] = force_reg (QImode, operands[0]);
+  })
+
+;; High part of 16-bit shift is unused after the instruction:
+;; No need to compute it, map to 8-bit shift.
+
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand" "")
+        (ashift:HI (match_dup 0)
+                   (match_operand:QI 1 "register_operand" "")))]
+  ""
+  [(set (match_dup 2)
+        (subreg:QI (ashift:HI (zero_extend:HI (match_dup 2))
+                              (match_dup 1))
+                   0))
+   (clobber (match_dup 3))]
+  {
+    operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
+
+    if (!peep2_reg_dead_p (1, operands[3]))
+      FAIL;
+
+    operands[2] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+  })
+
+
 (define_insn "ashlsi3"
   [(set (match_operand:SI 0 "register_operand"           "=r,r,r,r,r,r,r")
 	(ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")

Reply via email to