This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[AVR][4.4/4.5 Regression] Bug in *rotlsi3_8, *rotlsi3_16 and *rotlsi3_24 insns
- From: Anatoly Sokolov <aesok at post dot ru>
- To: gcc-patches at gcc dot gnu dot org
- Cc: avr at gjlay dot de, eweddington at cso dot atmel dot com, aesok at post dot ru
- Date: Fri, 17 Apr 2009 02:51:07 +0400
- Subject: [AVR][4.4/4.5 Regression] Bug in *rotlsi3_8, *rotlsi3_16 and *rotlsi3_24 insns
Hello.
The '*rotlsi3_8', '*rotlsi3_16' and '*rotlsi3_24' insns generate incorrect
code in cases when operands[0] and operands[1] is placed in overlapped hard
registers.
Testcase:
unsigned long rotl (int dummy, unsigned long x)
{
return (x << 8) | (x >> 24);
}
Compile with:
avr-gcc -mmcu=atmega8 -S -Os -fno-split-wide-types
rotl:
/* prologue: function */
/* frame size = 0 */
mov r22,r23
mov r23,r20
mov r24,r21
mov r25,r22
/* epilogue start */
ret
This will map 0x33221100 to 0x33110033 instead of to 0x22110033. The value of
r22 reg is corrupt and in r25 reg wrong value is written.
This patch fix this error.
2008-04-17 Anatoly Sokolov <aesok@post.ru>
* config/avr/avr.md (*rotlsi3_8, *rotlsi3_16, *rotlsi3_24 ): Check
whether operands 0 and 1 overlaps.
Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md (revision 146215)
+++ gcc/config/avr/avr.md (working copy)
@@ -1478,7 +1478,7 @@
(rotate:SI (match_operand:SI 1 "register_operand" "r")
(const_int 16)))]
""
- "{mov __tmp_reg__,%A0\;mov %A0,%D0\;mov %D0, __tmp_reg__\;mov __tmp_reg__,%B0\;mov %B0,%C0\;mov %C0, __tmp_reg__|movw __tmp_reg__,%A0\;movw %A0,%C0\;movw %C0, __tmp_reg__\;clr __zero_reg__}"
+ "{mov __tmp_reg__,%A1\;mov %A0,%C1\;mov %C0, __tmp_reg__\;mov __tmp_reg__,%B1\;mov %B0,%D1\;mov %D0, __tmp_reg__|movw __tmp_reg__,%A1\;movw %A0,%C1\;movw %C0, __tmp_reg__\;clr __zero_reg__}"
"reload_completed
&& REGNO (operands[0]) != REGNO (operands[1])"
[(set (match_dup 2) (match_dup 5))
@@ -1490,7 +1490,18 @@
operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, si_hi_off);
operands[4] = simplify_gen_subreg (HImode, operands[1], SImode, si_lo_off);
- operands[5] = simplify_gen_subreg (HImode, operands[1], SImode, si_hi_off);"
+ operands[5] = simplify_gen_subreg (HImode, operands[1], SImode, si_hi_off);
+
+ if (REGNO (operands[0]) == REGNO(operands[1]) + 2)
+ {
+ emit_move_insn (operands[3], operands[4]);
+ DONE;
+ }
+ else if (REGNO (operands[0]) == REGNO(operands[1]) - 2)
+ {
+ emit_move_insn (operands[2], operands[5]);
+ DONE;
+ }"
[(set (attr "length") (if_then_else (eq_attr "mcu_have_movw" "yes")
(const_int 4)
(const_int 6)))
@@ -1503,17 +1514,14 @@
(rotate:SI (match_operand:SI 1 "register_operand" "r")
(const_int 8)))]
""
- "mov __tmp_reg__,%D0
- mov %D0,%C0
- mov %C0,%B0
- mov %B0,%A0
+ "mov __tmp_reg__,%D1
+ mov %D0,%C1
+ mov %C0,%B1
+ mov %B0,%A1
mov %A0, __tmp_reg__"
"reload_completed
&& REGNO (operands[0]) != REGNO (operands[1])"
- [(set (match_dup 2) (match_dup 9))
- (set (match_dup 3) (match_dup 6))
- (set (match_dup 4) (match_dup 7))
- (set (match_dup 5) (match_dup 8))]
+ [(const_int 0)]
"unsigned int si_lo_off = subreg_lowpart_offset (HImode, SImode);
unsigned int si_hi_off = subreg_highpart_offset (HImode, SImode);
unsigned int hi_lo_off = subreg_lowpart_offset (QImode, HImode);
@@ -1531,7 +1539,23 @@
operands[7] = simplify_gen_subreg (QImode, operands[6], HImode, hi_hi_off);
operands[6] = simplify_gen_subreg (QImode, operands[6], HImode, hi_lo_off);
operands[9] = simplify_gen_subreg (QImode, operands[8], HImode, hi_hi_off);
- operands[8] = simplify_gen_subreg (QImode, operands[8], HImode, hi_lo_off);"
+ operands[8] = simplify_gen_subreg (QImode, operands[8], HImode, hi_lo_off);
+
+ if (REGNO (operands[0]) < REGNO(operands[1]))
+ {
+ emit_move_insn (operands[2], operands[9]);
+ emit_move_insn (operands[3], operands[6]);
+ emit_move_insn (operands[4], operands[7]);
+ emit_move_insn (operands[5], operands[8]);
+ }
+ else
+ {
+ emit_move_insn (operands[5], operands[8]);
+ emit_move_insn (operands[2], operands[9]);
+ emit_move_insn (operands[4], operands[7]);
+ emit_move_insn (operands[3], operands[6]);
+ }
+ DONE;"
[(set_attr "length" "5")
(set_attr "cc" "none")])
@@ -1540,17 +1564,14 @@
(rotate:SI (match_operand:SI 1 "register_operand" "r")
(const_int 24)))]
""
- "mov __tmp_reg__,%A0
- mov %A0,%B0
- mov %B0,%C0
- mov %C0,%D0
+ "mov __tmp_reg__,%A1
+ mov %A0,%B1
+ mov %B0,%C1
+ mov %C0,%D1
mov %D0, __tmp_reg__"
"reload_completed
&& REGNO (operands[0]) != REGNO (operands[1])"
- [(set (match_dup 2) (match_dup 7))
- (set (match_dup 3) (match_dup 8))
- (set (match_dup 4) (match_dup 9))
- (set (match_dup 5) (match_dup 6))]
+ [(const_int 0)]
"unsigned int si_lo_off = subreg_lowpart_offset (HImode, SImode);
unsigned int si_hi_off = subreg_highpart_offset (HImode, SImode);
unsigned int hi_lo_off = subreg_lowpart_offset (QImode, HImode);
@@ -1568,7 +1589,23 @@
operands[7] = simplify_gen_subreg (QImode, operands[6], HImode, hi_hi_off);
operands[6] = simplify_gen_subreg (QImode, operands[6], HImode, hi_lo_off);
operands[9] = simplify_gen_subreg (QImode, operands[8], HImode, hi_hi_off);
- operands[8] = simplify_gen_subreg (QImode, operands[8], HImode, hi_lo_off);"
+ operands[8] = simplify_gen_subreg (QImode, operands[8], HImode, hi_lo_off);
+
+ if (REGNO (operands[0]) < REGNO(operands[1]))
+ {
+ emit_move_insn (operands[2], operands[7]);
+ emit_move_insn (operands[5], operands[6]);
+ emit_move_insn (operands[3], operands[8]);
+ emit_move_insn (operands[4], operands[9]);
+ }
+ else
+ {
+ emit_move_insn (operands[5], operands[6]);
+ emit_move_insn (operands[4], operands[9]);
+ emit_move_insn (operands[3], operands[8]);
+ emit_move_insn (operands[2], operands[7]);
+ }
+ DONE;"
[(set_attr "length" "5")
(set_attr "cc" "none")])
Anatoly.