$OpenBSD: patch-gcc_config_avr_avr_md,v 1.1 2008/10/01 04:52:19 ckuethe Exp $
--- gcc/config/avr/avr.md.orig	Sat Sep  1 08:28:30 2007
+++ gcc/config/avr/avr.md	Sat Sep 27 16:29:43 2008
@@ -32,6 +32,7 @@
 ;;  p  POST_INC or PRE_DEC address as a pointer (X, Y, Z)
 ;;  r  POST_INC or PRE_DEC address as a register (r26, r28, r30)
 ;;  ~  Output 'r' if not AVR_MEGA.
+;;  !  Output 'e' if AVR_HAVE_EIJMP_EICALL.
 
 ;; UNSPEC usage:
 ;;  0  Length of a string, see "strlenhi".
@@ -46,7 +47,8 @@
    (TMP_REGNO	0)	; temporary register r0
    (ZERO_REGNO	1)	; zero register r1
    (UNSPEC_STRLEN	0)
-   (UNSPEC_INDEX_JMP	1)])
+   (UNSPEC_INDEX_JMP	1)
+   (UNSPEC_SWAP		4)])
 
 (include "predicates.md")
 (include "constraints.md")
@@ -1051,6 +1053,19 @@
   [(set_attr "length" "4,4")
    (set_attr "cc" "set_n,set_n")])
 
+(define_peephole2 ; andi
+  [(set (match_operand:QI 0 "d_register_operand" "")
+        (and:QI (match_dup 0)
+	        (match_operand:QI 1 "const_int_operand" "")))
+   (set (match_dup 0)
+        (and:QI (match_dup 0)
+	        (match_operand:QI 2 "const_int_operand" "")))]
+  ""
+  [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
+  {
+    operands[1] = GEN_INT (INTVAL (operands[1]) & INTVAL (operands[2]));
+  })
+
 ;;|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ;; ior
 
@@ -1179,10 +1194,57 @@
   [(set_attr "length" "4")
    (set_attr "cc" "set_n")])
 
+;; swap
+
+(define_insn "*swap"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+	(unspec:QI [(match_operand:QI 1 "register_operand" "0")]
+		   UNSPEC_SWAP))]
+  ""
+  "swap %0"
+  [(set_attr "length" "1")
+   (set_attr "cc" "none")])
+
 ;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
 ;; arithmetic shift left
 
-(define_insn "ashlqi3"
+(define_expand "ashlqi3"
+  [(set (match_operand:QI 0 "register_operand"            "")
+	(ashift:QI (match_operand:QI 1 "register_operand" "")
+		   (match_operand:QI 2 "general_operand"  "")))]
+  ""
+  "")
+
+(define_split ; ashlqi3_const4
+  [(set (match_operand:QI 0 "d_register_operand"            "")
+	(ashift:QI (match_operand:QI 1 "d_register_operand" "")
+		   (const_int 4)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int -16)))]
+  "")
+
+(define_split ; ashlqi3_const5
+  [(set (match_operand:QI 0 "d_register_operand"            "")
+	(ashift:QI (match_operand:QI 1 "d_register_operand" "")
+		   (const_int 5)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int -32)))]
+  "")
+
+(define_split ; ashlqi3_const6
+  [(set (match_operand:QI 0 "d_register_operand"            "")
+	(ashift:QI (match_operand:QI 1 "d_register_operand" "")
+		   (const_int 6)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int -64)))]
+  "")
+
+(define_insn "*ashlqi3"
   [(set (match_operand:QI 0 "register_operand"           "=r,r,r,r,!d,r,r")
 	(ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
 		   (match_operand:QI 2 "general_operand"  "r,L,P,K,n,n,Qm")))]
@@ -1212,6 +1274,47 @@
 ;; Optimize if a scratch register from LD_REGS happens to be available.
 
 (define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(ashift:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 4)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 2) (const_int -16))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(ashift:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 5)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
+   (set (match_dup 2) (const_int -32))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(ashift:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 6)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
+   (set (match_dup 2) (const_int -64))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
   [(match_scratch:QI 3 "d")
    (set (match_operand:HI 0 "register_operand" "")
 	(ashift:HI (match_operand:HI 1 "register_operand" "")
@@ -1330,7 +1433,49 @@
 ;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
 ;; logical shift right
 
-(define_insn "lshrqi3"
+(define_expand "lshrqi3"
+  [(set (match_operand:QI 0 "register_operand"              "")
+	(lshiftrt:QI (match_operand:QI 1 "register_operand" "")
+		     (match_operand:QI 2 "general_operand"  "")))]
+  ""
+  "")
+
+(define_insn_and_split "*lshrqi3_const4"
+  [(set (match_operand:QI 0 "d_register_operand"             "=d")
+	(lshiftrt:QI (match_operand:QI 1 "d_register_operand" "0")
+		     (const_int 4)))]
+  ""
+  "#"
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int 15)))]
+  "")
+
+(define_insn_and_split "*lshrqi3_const5"
+  [(set (match_operand:QI 0 "d_register_operand"             "=d")
+	(lshiftrt:QI (match_operand:QI 1 "d_register_operand" "0")
+		     (const_int 5)))]
+  ""
+  "#"
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int 7)))]
+  "")
+
+(define_insn_and_split "*lshrqi3_const6"
+  [(set (match_operand:QI 0 "d_register_operand"             "=d")
+	(lshiftrt:QI (match_operand:QI 1 "d_register_operand" "0")
+		     (const_int 6)))]
+  ""
+  "#"
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
+   (set (match_dup 0) (and:QI (match_dup 0) (const_int 3)))]
+  "")
+
+(define_insn "*lshrqi3"
   [(set (match_operand:QI 0 "register_operand"             "=r,r,r,r,!d,r,r")
 	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
 		     (match_operand:QI 2 "general_operand"  "r,L,P,K,n,n,Qm")))]
@@ -1360,6 +1505,47 @@
 ;; Optimize if a scratch register from LD_REGS happens to be available.
 
 (define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(lshiftrt:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 4)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 2) (const_int 15))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(lshiftrt:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 5)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
+   (set (match_dup 2) (const_int 7))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
+  [(match_scratch:QI 2 "d")
+   (set (match_operand:QI 0 "l_register_operand" "")
+	(lshiftrt:QI (match_operand:QI 1 "l_register_operand" "")
+		     (const_int 6)))]
+  ""
+  [(set (match_dup 0) (unspec:QI [(match_dup 0)] UNSPEC_SWAP))
+   (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
+   (set (match_dup 2) (const_int 3))
+   (set (match_dup 0) (and:QI (match_dup 0) (match_dup 2)))
+   (clobber (match_dup 2))]
+  "if (!avr_peep2_scratch_safe (operands[2]))
+     FAIL;")
+
+(define_peephole2
   [(match_scratch:QI 3 "d")
    (set (match_operand:HI 0 "register_operand" "")
 	(lshiftrt:HI (match_operand:HI 1 "register_operand" "")
@@ -1543,40 +1729,96 @@
 ;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
 ;; zero extend
 
-(define_insn "zero_extendqihi2"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-        (zero_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
+(define_insn_and_split "zero_extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
   ""
-  "@
-	clr %B0
-	mov %A0,%A1\;clr %B0"
-  [(set_attr "length" "1,2")
-   (set_attr "cc" "set_n,set_n")])
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (QImode, HImode);
+   unsigned int high_off = subreg_highpart_offset (QImode, HImode);
+   
+   operands[2] = simplify_gen_subreg (QImode, operands[0], HImode, low_off);
+   operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, high_off);
+  ")
 
-(define_insn "zero_extendqisi2"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-        (zero_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
+(define_insn_and_split "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
   ""
-  "@
-	clr %B0\;clr %C0\;clr %D0
-	mov %A0,%A1\;clr %B0\;clr %C0\;clr %D0"
-  [(set_attr "length" "3,4")
-   (set_attr "cc" "set_n,set_n")])
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (zero_extend:HI (match_dup 1)))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (HImode, SImode);
+   unsigned int high_off = subreg_highpart_offset (HImode, SImode);
+   
+   operands[2] = simplify_gen_subreg (HImode, operands[0], SImode, low_off);
+   operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
+  ")
 
-(define_insn "zero_extendhisi2"
-  [(set (match_operand:SI 0 "register_operand" "=r,&r")
-        (zero_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
+(define_insn_and_split "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
   ""
-  "@
-	clr %C0\;clr %D0
-	{mov %A0,%A1\;mov %B0,%B1|movw %A0,%A1}\;clr %C0\;clr %D0"
-  [(set_attr_alternative "length"
-			 [(const_int 2)
-			  (if_then_else (eq_attr "mcu_have_movw" "yes")
-					(const_int 3)
-					(const_int 4))])
-   (set_attr "cc" "set_n,set_n")])
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (HImode, SImode);
+   unsigned int high_off = subreg_highpart_offset (HImode, SImode);
+   
+   operands[2] = simplify_gen_subreg (HImode, operands[0], SImode, low_off);
+   operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
+  ")
 
+(define_insn_and_split "zero_extendqidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
+   unsigned int high_off = subreg_highpart_offset (SImode, DImode);
+   
+   operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
+   operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
+  ")
+
+(define_insn_and_split "zero_extendhidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
+   unsigned int high_off = subreg_highpart_offset (SImode, DImode);
+   
+   operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
+   operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
+  ")
+
+(define_insn_and_split "zero_extendsidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 3) (const_int 0))]
+  "unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
+   unsigned int high_off = subreg_highpart_offset (SImode, DImode);
+   
+   operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
+   operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
+  ")
+
 ;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
 ;; compare
 
@@ -2099,22 +2341,22 @@
   "(register_operand (operands[0], HImode) || CONSTANT_P (operands[0]))"
   "*{
   if (which_alternative==0)
-     return \"icall\";
+     return \"%!icall\";
   else if (which_alternative==1)
     {
       if (AVR_HAVE_MOVW)
 	return (AS2 (movw, r30, %0) CR_TAB
-		\"icall\");
+               \"%!icall\");
       else
 	return (AS2 (mov, r30, %A0) CR_TAB
 		AS2 (mov, r31, %B0) CR_TAB
-		\"icall\");
+		\"%!icall\");
     }
   else if (which_alternative==2)
     return AS1(%~call,%c0);
   return (AS2 (ldi,r30,lo8(%0)) CR_TAB
           AS2 (ldi,r31,hi8(%0)) CR_TAB
-          \"icall\");
+          \"%!icall\");
 }"
   [(set_attr "cc" "clobber,clobber,clobber,clobber")
    (set_attr_alternative "length"
@@ -2136,22 +2378,22 @@
   "(register_operand (operands[0], VOIDmode) || CONSTANT_P (operands[0]))"
   "*{
   if (which_alternative==0)
-     return \"icall\";
+     return \"%!icall\";
   else if (which_alternative==1)
     {
       if (AVR_HAVE_MOVW)
 	return (AS2 (movw, r30, %1) CR_TAB
-		\"icall\");
+		\"%!icall\");
       else
 	return (AS2 (mov, r30, %A1) CR_TAB
 		AS2 (mov, r31, %B1) CR_TAB
-		\"icall\");
+		\"%!icall\");
     }
   else if (which_alternative==2)
     return AS1(%~call,%c1);
   return (AS2 (ldi, r30, lo8(%1)) CR_TAB
           AS2 (ldi, r31, hi8(%1)) CR_TAB
-          \"icall\");
+          \"%!icall\");
 }"
   [(set_attr "cc" "clobber,clobber,clobber,clobber")
    (set_attr_alternative "length"
@@ -2181,13 +2423,20 @@
 ; indirect jump
 (define_insn "indirect_jump"
   [(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))]
-  ""
+  "!AVR_HAVE_EIJMP_EICALL"
   "@
 	ijmp
 	push %A0\;push %B0\;ret"
   [(set_attr "length" "1,3")
    (set_attr "cc" "none,none")])
 
+(define_insn "*indirect_jump_avr6"
+  [(set (pc) (match_operand:HI 0 "register_operand" "z"))]
+  "AVR_HAVE_EIJMP_EICALL"
+  "eijmp"
+  [(set_attr "length" "1")
+   (set_attr "cc" "none")])
+
 ;; table jump
 
 ;; Table made from "rjmp" instructions for <=8K devices.
@@ -2196,7 +2445,7 @@
 			UNSPEC_INDEX_JMP))
    (use (label_ref (match_operand 1 "" "")))
    (clobber (match_dup 0))]
-  "!AVR_MEGA"
+  "(!AVR_MEGA) && (!AVR_HAVE_EIJMP_EICALL)"
   "@
 	ijmp
 	push %A0\;push %B0\;ret"
@@ -2225,7 +2474,7 @@
 	lpm __tmp_reg__,Z+
 	lpm r31,Z
 	mov r30,__tmp_reg__
-	ijmp"
+	%!ijmp"
   [(set_attr "length" "6")
    (set_attr "cc" "clobber")])
 
@@ -2234,7 +2483,7 @@
 			UNSPEC_INDEX_JMP))
    (use (label_ref (match_operand 1 "" "")))
    (clobber (match_dup 0))]
-  "AVR_MEGA"
+  "AVR_MEGA && !AVR_HAVE_EIJMP_EICALL"
   "lsl r30
 	rol r31
 	lpm
