This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [rfc] multi-word subreg lowering pass
- From: Björn Haase <bjoern dot m dot haase at web dot de>
- To: Paul Schlie <schlie at comcast dot net>
- Cc: Richard Henderson <rth at redhat dot com>,gcc-patches at gcc dot gnu dot org
- Date: Sun, 8 May 2005 12:14:31 +0200
- Subject: Re: [rfc] multi-word subreg lowering pass
- References: <BEA33C83.A155%schlie@comcast.net>
Am Sonntag, 8. Mai 2005 09:48 schrieb Paul Schlie:
> > From: Richard Henderson <rth@redhat.com>
> > ...
> > The Object is to present the register allocator with something that
> > it has more freedom to work with. This doesn't achieve that goal.
>
> Thanks, after building HEAD with your patches applied, I think I better
> understand. However there seem to be a few odd things going on. Which the
> following code attempts to show: (including signed char casts for lowered
> operands even though compiled with unsigned chars, and oddly better code
> for in-lined calls than for identical expressions, and finally if the below
> function zed is defined first, the compile will terminate with a bus
> error):
... I think that it is not very useful to test Richard's patch with the
present back-end. I think also that at this stage we should not start
complaining about a a couple of ICEs but rather be grateful that Richard's
work exists :-).
You'll find enclosed an attachment where I have replaced the present patterns
for sign- and zero- extension by define_expands and where the shifting
instructions are largely replaced by expanders as well.
IMO, one could try to use the infrastructure Richard's patch provides as a
base for a complete re-work of the avr back end. Main remaining
complications, IMO will be
1.) Re-using the condition codes for branching
2.) Teaching the mid-end algebra on "add-with-carry" "sub-with-carry"
"compare-with-carry" operations.
3.) Identifying single-bit-test branches.
4.) Finding a way to continue to use movw as frequently as possible.
5.) Make sure that one could continue to use the addiw operations for the
pointers.
Most of these issues are somewhat related to condition code use and the
cc0->CCmode issue.
For 5.) one might consider to distinguish pointers from usual numbers by
defining Pmode to be PHI instead of HI.
I'd also like to suggest to change the convention for __tmp_reg__ and
__zero_reg__ so that these refer to r2:r3 instead of r0:r1 . This way, one
could prevent unnecessary moves within the register file for the results of
multiplications, avoid all of the permanent clr __zero_reg__ and shorten IRQ
function prologues.
Yours,
Björn
Btw.: As example code showing the potential you might look at the following
function. It used to generate a function size of 43 with 3.4.3 and now ends
up with a length of 16!
#include <inttypes.h>
uint32_t a;
int16_t b;
uint16_t
dummy (uint8_t x, uint32_t y)
{ a = x;
b = ((uint16_t) (y >> 24)) | (x << 8);
return x | (y << 8);
}
Index: avr.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr.md,v
retrieving revision 1.51
diff -u -r1.51 avr.md
--- avr.md 13 Mar 2005 10:09:53 -0000 1.51
+++ avr.md 8 May 2005 09:47:33 -0000
@@ -35,8 +35,15 @@
;; ~ Output 'r' if not AVR_MEGA.
;; UNSPEC usage:
-;; 0 Length of a string, see "strlenhi".
-;; 1 Read from a word address in program memory, see "casesi".
+;; 0 Length of a string, see "strlenhi".
+;; 1 Read from a word address in program memory, see "casesi".
+;; 30 Generate sign byte sequence "clr %0 \; sbrs %1,7 \; com %0"
+;; for the sign_extend splitter
+
+(define_constants
+ [(UNSP_STRLENHI 0)
+ (UNSP_READ_PMEM 1)
+ (UNSP_GEN_SIGN 30)])
;; Condition code settings.
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
@@ -478,7 +485,8 @@
[(set (match_dup 4)
(unspec:HI [(match_operand:BLK 1 "memory_operand" "")
(match_operand:QI 2 "const_int_operand" "")
- (match_operand:HI 3 "immediate_operand" "")] 0))
+ (match_operand:HI 3 "immediate_operand" "")]
+ UNSP_STRLENHI))
(set (match_dup 4) (plus:HI (match_dup 4)
(const_int -1)))
(set (match_operand:HI 0 "register_operand" "")
@@ -499,7 +507,8 @@
[(set (match_operand:HI 0 "register_operand" "=e")
(unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
(const_int 0)
- (match_operand:HI 2 "immediate_operand" "i")] 0))]
+ (match_operand:HI 2 "immediate_operand" "i")]
+ UNSP_STRLENHI))]
""
"ld __tmp_reg__,%a0+
tst __tmp_reg__
@@ -964,73 +973,6 @@
[(set_attr "length" "1,1")
(set_attr "cc" "set_zn,set_zn")])
-(define_insn "andhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d,r")
- (and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
- (match_operand:HI 2 "nonmemory_operand" "r,i,M")))
- (clobber (match_scratch:QI 3 "=X,X,&d"))]
- ""
- "*{
- if (which_alternative==0)
- return (AS2 (and,%A0,%A2) CR_TAB
- AS2 (and,%B0,%B2));
- else if (which_alternative==1)
- {
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- int mask = INTVAL (operands[2]);
- if ((mask & 0xff) != 0xff)
- output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
- if ((mask & 0xff00) != 0xff00)
- output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
- return \"\";
- }
- return (AS2 (andi,%A0,lo8(%2)) CR_TAB
- AS2 (andi,%B0,hi8(%2)));
- }
- return (AS2 (ldi,%3,lo8(%2)) CR_TAB
- AS2 (and,%A0,%3) CR_TAB
- AS1 (clr,%B0));
-}"
- [(set_attr "length" "2,2,3")
- (set_attr "cc" "set_n,clobber,set_n")])
-
-(define_insn "andsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,i")))]
- ""
- "*{
- if (which_alternative==0)
- return (AS2 (and, %0,%2) CR_TAB
- AS2 (and, %B0,%B2) CR_TAB
- AS2 (and, %C0,%C2) CR_TAB
- AS2 (and, %D0,%D2));
- else if (which_alternative==1)
- {
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (operands[2]);
- if ((mask & 0xff) != 0xff)
- output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
- if ((mask & 0xff00) != 0xff00)
- output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
- if ((mask & 0xff0000L) != 0xff0000L)
- output_asm_insn (AS2 (andi,%C0,hlo8(%2)), operands);
- if ((mask & 0xff000000L) != 0xff000000L)
- output_asm_insn (AS2 (andi,%D0,hhi8(%2)), operands);
- return \"\";
- }
- return (AS2 (andi, %A0,lo8(%2)) CR_TAB
- AS2 (andi, %B0,hi8(%2)) CR_TAB
- AS2 (andi, %C0,hlo8(%2)) CR_TAB
- AS2 (andi, %D0,hhi8(%2)));
- }
- return \"bug\";
-}"
- [(set_attr "length" "4,4")
- (set_attr "cc" "set_n,set_n")])
-
;;|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
;; ior
@@ -1045,86 +987,6 @@
[(set_attr "length" "1,1")
(set_attr "cc" "set_zn,set_zn")])
-(define_insn "iorhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d")
- (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "nonmemory_operand" "r,i")))]
- ""
- "*{
- if (which_alternative==0)
- return (AS2 (or,%A0,%A2) CR_TAB
- AS2 (or,%B0,%B2));
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- int mask = INTVAL (operands[2]);
- if (mask & 0xff)
- output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
- if (mask & 0xff00)
- output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
- return \"\";
- }
- return (AS2 (ori,%0,lo8(%2)) CR_TAB
- AS2 (ori,%B0,hi8(%2)));
-}"
- [(set_attr "length" "2,2")
- (set_attr "cc" "set_n,clobber")])
-
-(define_insn "*iorhi3_clobber"
- [(set (match_operand:HI 0 "register_operand" "=r,r")
- (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "immediate_operand" "M,i")))
- (clobber (match_scratch:QI 3 "=&d,&d"))]
- ""
- "@
- ldi %3,lo8(%2)\;or %A0,%3
- ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3"
- [(set_attr "length" "2,4")
- (set_attr "cc" "clobber,set_n")])
-
-(define_insn "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,i")))]
- ""
- "*{
- if (which_alternative==0)
- return (AS2 (or, %0,%2) CR_TAB
- AS2 (or, %B0,%B2) CR_TAB
- AS2 (or, %C0,%C2) CR_TAB
- AS2 (or, %D0,%D2));
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- HOST_WIDE_INT mask = INTVAL (operands[2]);
- if (mask & 0xff)
- output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
- if (mask & 0xff00)
- output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
- if (mask & 0xff0000L)
- output_asm_insn (AS2 (ori,%C0,hlo8(%2)), operands);
- if (mask & 0xff000000L)
- output_asm_insn (AS2 (ori,%D0,hhi8(%2)), operands);
- return \"\";
- }
- return (AS2 (ori, %A0,lo8(%2)) CR_TAB
- AS2 (ori, %B0,hi8(%2)) CR_TAB
- AS2 (ori, %C0,hlo8(%2)) CR_TAB
- AS2 (ori, %D0,hhi8(%2)));
-}"
- [(set_attr "length" "4,4")
- (set_attr "cc" "set_n,clobber")])
-
-(define_insn "*iorsi3_clobber"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "immediate_operand" "M,i")))
- (clobber (match_scratch:QI 3 "=&d,&d"))]
- ""
- "@
- ldi %3,lo8(%2)\;or %A0,%3
- ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3\;ldi %3,hlo8(%2)\;or %C0,%3\;ldi %3,hhi8(%2)\;or %D0,%3"
- [(set_attr "length" "2,8")
- (set_attr "cc" "clobber,set_n")])
-
;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; xor
@@ -1137,28 +999,32 @@
[(set_attr "length" "1")
(set_attr "cc" "set_zn")])
-(define_insn "xorhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (xor:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "register_operand" "r")))]
+(define_expand "xorhi3"
+ [(set (subreg:QI (match_operand:HI 0 "register_operand" "=r") 0)
+ (xor:QI (subreg:QI (match_operand:HI 1 "register_operand" "%0") 0)
+ (subreg:QI (match_operand:HI 2 "register_operand" "r") 0)))
+ (set (subreg:QI (match_dup 0) 1)
+ (xor:QI (subreg:QI (match_dup 1) 1)
+ (subreg:QI (match_dup 2) 1))) ]
""
- "eor %0,%2
- eor %B0,%B2"
- [(set_attr "length" "2")
- (set_attr "cc" "set_n")])
+ "")
-(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (xor:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "r")))]
+(define_expand "xorsi3"
+ [(set (subreg:QI (match_operand:SI 0 "register_operand" "=r") 0)
+ (xor:QI (subreg:QI (match_operand:SI 1 "register_operand" "%0") 0)
+ (subreg:QI (match_operand:SI 2 "register_operand" "r") 0)))
+ (set (subreg:QI (match_dup 0) 1)
+ (xor:QI (subreg:QI (match_dup 1) 1)
+ (subreg:QI (match_dup 2) 1)))
+ (set (subreg:QI (match_dup 0) 2)
+ (xor:QI (subreg:QI (match_dup 1) 2)
+ (subreg:QI (match_dup 2) 2)))
+ (set (subreg:QI (match_dup 0) 3)
+ (xor:QI (subreg:QI (match_dup 1) 3)
+ (subreg:QI (match_dup 2) 3)))]
""
- "eor %0,%2
- eor %B0,%B2
- eor %C0,%C2
- eor %D0,%D2"
- [(set_attr "length" "4")
- (set_attr "cc" "set_n")])
-
+ "")
+
;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
;; arithmetic shift left
@@ -1171,7 +1037,44 @@
[(set_attr "length" "5,0,1,2,4,6,9")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
-(define_insn "ashlhi3"
+(define_expand "ashlhi3"
+ [(set (match_operand:HI 0 "register_operand" "r")
+ (ashift:HI (match_operand:HI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_msb_target,rtx_lsb_source));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value > 15)
+ {
+ emit_insn (gen_movhi (operands[0],GEN_INT (0) ));
+ DONE;
+ }
+ if (value > 8)
+ {
+ emit_insn (gen_ashlqi3 (rtx_msb_target,
+ rtx_lsb_source, GEN_INT (value - 8)));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "*ashlhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashift:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1180,7 +1083,70 @@
[(set_attr "length" "6,0,2,2,4,10,10")
(set_attr "cc" "clobber,none,set_n,clobber,set_n,clobber,clobber")])
-(define_insn "ashlsi3"
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_mid1sb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_mid2sb_source = gen_rtx_SUBREG (QImode,operands[1],2);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],3);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_mid1sb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+ rtx rtx_mid2sb_target = gen_rtx_SUBREG (QImode,operands[0],2);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],3);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_lsb_source));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_mid1sb_source));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_mid2sb_source));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value == 16)
+ {
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_lsb_source));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_mid1sb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,GEN_INT(0)));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+
+ DONE;
+ }
+ if (value == 24)
+ {
+ emit_insn (gen_movqi (rtx_msb_target,rtx_lsb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,GEN_INT(0)));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value > 31)
+ {
+ emit_insn (gen_movsi (operands[0],GEN_INT (0) ));
+ DONE;
+ }
+
+ if (value > 24)
+ {
+ emit_insn (gen_ashlqi3 (rtx_msb_target,
+ rtx_lsb_source, GEN_INT (value - 24)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid1sb_target,GEN_INT(0)));
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "*ashlsi3_insn"
[(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")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1245,7 +1211,45 @@
[(set_attr "length" "5,0,1,2,5,9")
(set_attr "cc" "clobber,none,clobber,clobber,clobber,clobber")])
-(define_insn "ashrhi3"
+(define_expand "ashrhi3"
+ [(set (match_operand:HI 0 "register_operand" "r")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_generate_extension_byte(rtx_msb_target,rtx_lsb_target));
+ DONE;
+ }
+ if (value > 15)
+ {
+ emit_insn (gen_generate_extension_byte(rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_lsb_target));
+ DONE;
+ }
+ if (value > 8)
+ {
+ emit_insn (gen_ashrqi3 (rtx_lsb_target,
+ rtx_msb_source, GEN_INT (value - 8)));
+ emit_insn (gen_generate_extension_byte(rtx_msb_target,rtx_lsb_target));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "*ashrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1254,7 +1258,73 @@
[(set_attr "length" "6,0,2,4,4,10,10")
(set_attr "cc" "clobber,none,clobber,set_n,clobber,clobber,clobber")])
-(define_insn "ashrsi3"
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_mid1sb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_mid2sb_source = gen_rtx_SUBREG (QImode,operands[1],2);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],3);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_mid1sb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+ rtx rtx_mid2sb_target = gen_rtx_SUBREG (QImode,operands[0],2);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],3);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_mid1sb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_mid2sb_source));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_msb_source));
+ emit_insn (gen_generate_extension_byte(rtx_msb_target,rtx_mid2sb_target));
+ DONE;
+ }
+ if (value == 16)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_mid2sb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_msb_source));
+ emit_insn (gen_generate_extension_byte(rtx_msb_target,rtx_mid1sb_target));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_msb_target));
+ DONE;
+ }
+ if (value == 24)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_generate_extension_byte(rtx_msb_target,rtx_lsb_target));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_msb_target));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_msb_target));
+ DONE;
+ }
+ if (value > 31)
+ {
+ emit_insn (gen_generate_extension_byte(rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_lsb_target));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_lsb_target));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_lsb_target));
+ DONE;
+ }
+
+ if (value > 24)
+ {
+ emit_insn (gen_generate_extension_byte(rtx_mid1sb_target,rtx_msb_source));
+ emit_insn (gen_ashrqi3 (rtx_lsb_target,
+ rtx_msb_source, GEN_INT (value - 24)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_mid1sb_target));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_mid1sb_target));
+ DONE;
+ }
+ }"
+)
+
+
+(define_insn "*ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1319,7 +1389,45 @@
[(set_attr "length" "5,0,1,2,4,6,9")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
-(define_insn "lshrhi3"
+(define_expand "lshrhi3"
+ [(set (match_operand:HI 0 "register_operand" "r")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value > 15)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_msb_target,rtx_lsb_target));
+ DONE;
+ }
+ if (value > 8)
+ {
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ emit_insn (gen_lshrqi3 (rtx_lsb_target,
+ rtx_msb_source, GEN_INT (value - 8)));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "*lshrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1328,7 +1436,70 @@
[(set_attr "length" "6,0,2,2,4,10,10")
(set_attr "cc" "clobber,none,clobber,clobber,clobber,clobber,clobber")])
-(define_insn "lshrsi3"
+
+(define_expand "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:QI 2 "nonmemory_operand" "rI")))]
+ ""
+ "if (GET_CODE (operands[2]) == CONST_INT
+ && REG_P (operands[0]) && REG_P (operands[1]))
+ { int value = INTVAL (operands[2]);
+ if (value <= 0)
+ DONE;
+
+ rtx rtx_lsb_source = gen_rtx_SUBREG (QImode,operands[1],0);
+ rtx rtx_mid1sb_source = gen_rtx_SUBREG (QImode,operands[1],1);
+ rtx rtx_mid2sb_source = gen_rtx_SUBREG (QImode,operands[1],2);
+ rtx rtx_msb_source = gen_rtx_SUBREG (QImode,operands[1],3);
+ rtx rtx_lsb_target = gen_rtx_SUBREG (QImode,operands[0],0);
+ rtx rtx_mid1sb_target = gen_rtx_SUBREG (QImode,operands[0],1);
+ rtx rtx_mid2sb_target = gen_rtx_SUBREG (QImode,operands[0],2);
+ rtx rtx_msb_target = gen_rtx_SUBREG (QImode,operands[0],3);
+
+ if (value == 8)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_mid1sb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_mid2sb_source));
+ emit_insn (gen_movqi (rtx_mid2sb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value == 16)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_mid2sb_source));
+ emit_insn (gen_movqi (rtx_mid1sb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value == 24)
+ {
+ emit_insn (gen_movqi (rtx_lsb_target,rtx_msb_source));
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid1sb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,GEN_INT (0)));
+ DONE;
+ }
+ if (value > 31)
+ {
+ emit_insn (gen_movsi (operands[0],GEN_INT (0)));
+ DONE;
+ }
+
+ if (value > 24)
+ {
+ emit_insn (gen_lshrqi3 (rtx_lsb_target,
+ rtx_msb_source, GEN_INT (value - 24)));
+ emit_insn (gen_movqi (rtx_mid1sb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_mid2sb_target,GEN_INT (0)));
+ emit_insn (gen_movqi (rtx_msb_target,GEN_INT (0)));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "*lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
(match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
@@ -1486,77 +1657,90 @@
;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
;; sign extend
-(define_insn "extendqihi2"
- [(set (match_operand:HI 0 "register_operand" "=r,r")
- (sign_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
- ""
- "@
- clr %B0\;sbrc %0,7\;com %B0
- mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0"
- [(set_attr "length" "3,4")
- (set_attr "cc" "set_n,set_n")])
-
-(define_insn "extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (sign_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
- ""
- "@
- clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0
- mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0"
- [(set_attr "length" "5,6")
- (set_attr "cc" "set_n,set_n")])
-
-(define_insn "extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "=r,&r")
- (sign_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
- ""
- "@
- clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0
- {mov %A0,%A1\;mov %B0,%B1|movw %A0,%A1}\;clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0"
- [(set_attr_alternative "length"
- [(const_int 4)
- (if_then_else (eq_attr "mcu_enhanced" "yes")
- (const_int 5)
- (const_int 6))])
- (set_attr "cc" "set_n,set_n")])
+(define_insn "generate_extension_byte"
+ [(set (match_operand:QI 0 "register_operand" "=&r,=r")
+ (unspec:QI [(match_operand:QI 1 "register_operand" "r,r")]
+ UNSP_GEN_SIGN ))]
+ ""
+ "@
+ clr %0\;sbrc %1,7\;com %0
+ mov __tmp_reg__,%1\;clr %0\;sbrc __tmp_reg__,7\;com %0"
+ [(set_attr "length" "3,4")
+ (set_attr "cc" "clobber,clobber")])
+
+(define_expand "extendqihi2"
+ [ (set (subreg:QI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:QI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 1)
+ (unspec:QI [(match_dup 1)] UNSP_GEN_SIGN))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
+(define_expand "extendqisi2"
+ [ (set (subreg:QI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:QI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 1)
+ (unspec:QI [(match_dup 1)] UNSP_GEN_SIGN))
+ (set (subreg:QI (match_dup 0) 2)
+ (subreg:QI (match_dup 0) 1))
+ (set (subreg:QI (match_dup 0) 3)
+ (subreg:QI (match_dup 0) 1))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
+
+(define_expand "extendhisi2"
+ [ (set (subreg:HI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:HI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 2)
+ (unspec:QI [(subreg:QI (match_dup 1) 1)] UNSP_GEN_SIGN))
+ (set (subreg:QI (match_dup 0) 3)
+ (subreg:QI (match_dup 0) 2))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
;; 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")))]
- ""
- "@
- clr %B0
- mov %A0,%A1\;clr %B0"
- [(set_attr "length" "1,2")
- (set_attr "cc" "set_n,set_n")])
-
-(define_insn "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (zero_extend:SI (match_operand:QI 1 "register_operand" "0,*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")])
-
-(define_insn "zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "=r,&r")
- (zero_extend:SI (match_operand:HI 1 "register_operand" "0,*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_enhanced" "yes")
- (const_int 3)
- (const_int 4))])
- (set_attr "cc" "set_n,set_n")])
-
+(define_expand "zero_extendqihi2"
+ [ (set (subreg:QI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:QI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 1)
+ (const_int 0))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
+
+(define_expand "zero_extendqisi2"
+ [ (set (subreg:QI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:QI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 1)
+ (const_int 0))
+ (set (subreg:QI (match_dup 0) 2)
+ (const_int 0))
+ (set (subreg:QI (match_dup 0) 3)
+ (const_int 0))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
+
+(define_expand "zero_extendhisi2"
+ [ (set (subreg:HI (match_operand:HI 0 "register_operand" "=r,r") 0)
+ (match_operand:HI 1 "register_operand" "0,*r"))
+ (set (subreg:QI (match_dup 0) 2)
+ (const_int 0))
+ (set (subreg:QI (match_dup 0) 3)
+ (const_int 0))]
+ ""
+ "if (!REG_P (operands[1]))
+ FAIL;"
+)
;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
;; compare
@@ -2176,7 +2360,8 @@
;; Table made from "rjmp" instructions for <=8K devices.
(define_insn "*tablejump_rjmp"
- [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")] 1))
+ [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")]
+ UNSP_READ_PMEM))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"!AVR_MEGA"
@@ -2197,7 +2382,8 @@
(set_attr "cc" "clobber")])
(define_insn "*tablejump_enh"
- [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] 1))
+ [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")]
+ UNSP_READ_PMEM))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"AVR_MEGA && AVR_ENHANCED"
@@ -2211,7 +2397,8 @@
(set_attr "cc" "clobber")])
(define_insn "*tablejump"
- [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] 1))
+ [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")]
+ UNSP_READ_PMEM))
(use (label_ref (match_operand 1 "" "")))
(clobber (match_dup 0))]
"AVR_MEGA"
@@ -2244,7 +2431,7 @@
(set (match_dup 6)
(plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
- (parallel [(set (pc) (unspec:HI [(match_dup 6)] 1))
+ (parallel [(set (pc) (unspec:HI [(match_dup 6)] UNSP_READ_PMEM))
(use (label_ref (match_dup 3)))
(clobber (match_dup 6))])]
""