aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Michalkiewicz <marekm@amelek.gda.pl>2002-05-26 22:19:32 +0200
committerMarek Michalkiewicz <marekm@gcc.gnu.org>2002-05-26 20:19:32 +0000
commit331ca3501dda7ce9a91996117c5127d52ac1e02c (patch)
treeea23f56fa9169a28bf2f05e88970c86fa1a79396 /gcc
parent9059e33cbbb601ed3a7f36d62a4dc7600b72bc60 (diff)
downloadgcc-331ca3501dda7ce9a91996117c5127d52ac1e02c.zip
gcc-331ca3501dda7ce9a91996117c5127d52ac1e02c.tar.gz
gcc-331ca3501dda7ce9a91996117c5127d52ac1e02c.tar.bz2
avr-protos.h (avr_out_sbxx_branch): Declare.
* config/avr/avr-protos.h (avr_out_sbxx_branch): Declare. * config/avr/avr.c (jump_over_one_insn_p): Take length of the branch insn into account, do not assume 1. (avr_out_sbxx_branch): New function. Optimize cases of skipping over single word insn. Handle upper half of I/O space too. * config/avr/avr.md (*sbrx_branch): Use it. (*sbrx_and_branchhi, *sbrx_and_branchsi): Likewise. (*sbix_branch, *sbix_branch_bit7): Likewise. (*sbix_branch_tmp, *sbix_branch_tmp_bit7): New. Use RTL peepholes to optimize register operand sign tests. From-SVN: r53906
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/avr/avr-protos.h1
-rw-r--r--gcc/config/avr/avr.c75
-rw-r--r--gcc/config/avr/avr.md285
4 files changed, 234 insertions, 140 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 800233d..7b8ba2d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -27,6 +27,19 @@
2002-05-26 Marek Michalkiewicz <marekm@amelek.gda.pl>
+ * config/avr/avr-protos.h (avr_out_sbxx_branch): Declare.
+ * config/avr/avr.c (jump_over_one_insn_p): Take length of the
+ branch insn into account, do not assume 1.
+ (avr_out_sbxx_branch): New function. Optimize cases of skipping
+ over single word insn. Handle upper half of I/O space too.
+ * config/avr/avr.md (*sbrx_branch): Use it.
+ (*sbrx_and_branchhi, *sbrx_and_branchsi): Likewise.
+ (*sbix_branch, *sbix_branch_bit7): Likewise.
+ (*sbix_branch_tmp, *sbix_branch_tmp_bit7): New.
+ Use RTL peepholes to optimize register operand sign tests.
+
+2002-05-26 Marek Michalkiewicz <marekm@amelek.gda.pl>
+
* config/avr/avr.c (avr_asm_only_p): New variable.
(avr_override_options): Set it here if AVR1.
(asm_file_start): Test it here, report an error if set.
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index f6dd880..3d0be48 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -98,6 +98,7 @@ extern const char * lshrsi3_out PARAMS ((rtx insn, rtx operands[], int *len));
extern void avr_output_bld PARAMS ((rtx operands[], int bit_nr));
extern void avr_output_addr_vec_elt PARAMS ((FILE *stream, int value));
+extern const char *avr_out_sbxx_branch PARAMS ((rtx insn, rtx operands[]));
extern enum reg_class preferred_reload_class PARAMS ((rtx x,
enum reg_class class));
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 5167ee65..67e6d52 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -5233,7 +5233,7 @@ jump_over_one_insn_p (insn, dest)
: dest);
int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
int dest_addr = INSN_ADDRESSES (uid);
- return dest_addr - jump_addr == 2;
+ return dest_addr - jump_addr == get_attr_length (insn) + 1;
}
/* Returns 1 if a value of mode MODE can be stored starting with hard
@@ -5451,3 +5451,76 @@ avr_peep2_scratch_safe (scratch)
}
return 1;
}
+
+/* Output a branch that tests a single bit of a register (QI, HI or SImode)
+ or memory location in the I/O space (QImode only).
+
+ Operand 0: comparison operator (must be EQ or NE, compare bit to zero).
+ Operand 1: register operand to test, or CONST_INT memory address.
+ Operand 2: bit number (for QImode operand) or mask (HImode, SImode).
+ Operand 3: label to jump to if the test is true. */
+
+const char *
+avr_out_sbxx_branch (insn, operands)
+ rtx insn;
+ rtx operands[];
+{
+ enum rtx_code comp = GET_CODE (operands[0]);
+ int long_jump = (get_attr_length (insn) >= 4);
+ int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
+
+ if (comp == GE)
+ comp = EQ;
+ else if (comp == LT)
+ comp = NE;
+
+ if (reverse)
+ comp = reverse_condition (comp);
+
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ if (INTVAL (operands[1]) < 0x40)
+ {
+ if (comp == EQ)
+ output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+ else
+ output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+ }
+ else
+ {
+ output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
+ if (comp == EQ)
+ output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
+ else
+ output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
+ }
+ }
+ else /* GET_CODE (operands[1]) == REG */
+ {
+ if (GET_MODE (operands[1]) == QImode)
+ {
+ if (comp == EQ)
+ output_asm_insn (AS2 (sbrs,%1,%2), operands);
+ else
+ output_asm_insn (AS2 (sbrc,%1,%2), operands);
+ }
+ else /* HImode or SImode */
+ {
+ static char buf[] = "sbrc %A1,0";
+ int bit_nr = exact_log2 (INTVAL (operands[2])
+ & GET_MODE_MASK (GET_MODE (operands[1])));
+
+ buf[3] = (comp == EQ) ? 's' : 'c';
+ buf[6] = 'A' + (bit_nr >> 3);
+ buf[9] = '0' + (bit_nr & 7);
+ output_asm_insn (buf, operands);
+ }
+ }
+
+ if (long_jump)
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%3));
+ if (!reverse)
+ return AS1 (rjmp,%3);
+ return "";
+}
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index da4c571..08a468a 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -1850,6 +1850,7 @@
""
"")
+;; Test a single bit in a QI/HI/SImode register.
(define_insn "*sbrx_branch"
[(set (pc)
(if_then_else
@@ -1857,24 +1858,12 @@
[(zero_extract
(match_operand:QI 1 "register_operand" "r")
(const_int 1)
- (match_operand 2 "immediate_operand" "n"))
+ (match_operand 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
- "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)"
- "* {
- int comp = ((get_attr_length (insn) == 4)
- ? reverse_condition (GET_CODE (operands[0]))
- : GET_CODE (operands[0]));
- if (comp == EQ)
- output_asm_insn (AS2 (sbrs,%1,%2), operands);
- else
- output_asm_insn (AS2 (sbrc,%1,%2), operands);
- if (get_attr_length (insn) != 4)
- return AS1 (rjmp,%3);
- return (AS1 (rjmp,_PC_+4) CR_TAB
- AS1 (jmp,%3));
- }"
+ "GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE"
+ "* return avr_out_sbxx_branch (insn, operands);"
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2046)))
@@ -1884,34 +1873,19 @@
(const_int 4))))
(set_attr "cc" "clobber")])
-(define_insn "*sbrx_and_branchsi"
+(define_insn "*sbrx_and_branchhi"
[(set (pc)
(if_then_else
(match_operator 0 "comparison_operator"
- [(and:SI
- (match_operand:SI 1 "register_operand" "r")
- (match_operand:SI 2 "immediate_operand" "n"))
+ [(and:HI
+ (match_operand:HI 1 "register_operand" "r")
+ (match_operand:HI 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
- && mask_one_bit_p(INTVAL (operands[2]))"
- "* {
- int comp = ((get_attr_length (insn) == 4)
- ? reverse_condition (GET_CODE (operands[0]))
- : GET_CODE (operands[0]));
- int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
- static char buf[] = \"sbrc %A1,0\";
- buf[3] = (comp == EQ ? 's' : 'c');
- buf[6] = bit / 8 + 'A';
- buf[9] = bit % 8 + '0';
- output_asm_insn (buf, operands);
-
- if (get_attr_length (insn) != 4)
- return AS1 (rjmp,%3);
- return (AS1 (rjmp,_PC_+4) CR_TAB
- AS1 (jmp,%3));
- }"
+ && exact_log2 (INTVAL (operands[2]) & 0xffff) >= 0"
+ "* return avr_out_sbxx_branch (insn, operands);"
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2046)))
@@ -1921,34 +1895,19 @@
(const_int 4))))
(set_attr "cc" "clobber")])
-(define_insn "*sbrx_and_branchhi"
+(define_insn "*sbrx_and_branchsi"
[(set (pc)
(if_then_else
(match_operator 0 "comparison_operator"
- [(and:HI
- (match_operand:HI 1 "register_operand" "r")
- (match_operand:HI 2 "immediate_operand" "n"))
+ [(and:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
"(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
- && mask_one_bit_p(INTVAL (operands[2]))"
- "* {
- int comp = ((get_attr_length (insn) == 4)
- ? reverse_condition (GET_CODE (operands[0]))
- : GET_CODE (operands[0]));
- int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
- static char buf[] = \"sbrc %A1,0\";
- buf[3] = (comp == EQ ? 's' : 'c');
- buf[6] = bit / 8 + 'A';
- buf[9] = bit % 8 + '0';
- output_asm_insn (buf, operands);
-
- if (get_attr_length (insn) != 4)
- return AS1 (rjmp,%3);
- return (AS1 (rjmp,_PC_+4) CR_TAB
- AS1 (jmp,%3));
- }"
+ && exact_log2 (INTVAL (operands[2]) & 0xffffffff) >= 0"
+ "* return avr_out_sbxx_branch (insn, operands);"
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2046)))
@@ -1958,6 +1917,83 @@
(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 (0x80000000);")
+
+(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 (0x80000000);")
+
;; ************************************************************************
;; Implementation of conditional jumps here.
;; Compare with 0 (test) jumps
@@ -2258,6 +2294,7 @@
[(set_attr "length" "1")
(set_attr "cc" "none")])
+;; Lower half of the I/O space - use sbic/sbis directly.
(define_insn "*sbix_branch"
[(set (pc)
(if_then_else
@@ -2271,21 +2308,7 @@
(pc)))]
"(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
&& avr_io_address_p (operands[1], 1 + 0x20)"
-{
- enum rtx_code comp = GET_CODE (operands[0]);
- int reverse = (get_attr_length (insn) == 4);
-
- if (reverse)
- comp = reverse_condition (comp);
- if (comp == EQ)
- output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
- else
- output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
- if (!reverse)
- return AS1 (rjmp,%3);
- return (AS1 (rjmp,_PC_+4) CR_TAB
- AS1 (jmp,%3));
-}
+ "* return avr_out_sbxx_branch (insn, operands);"
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2046)))
@@ -2307,19 +2330,9 @@
"(GET_CODE (operands[0]) == GE || GET_CODE (operands[0]) == LT)
&& avr_io_address_p (operands[1], 1 + 0x20)"
{
- enum rtx_code comp = GET_CODE (operands[0]);
- int reverse = (get_attr_length (insn) == 4);
-
- if (reverse)
- comp = reverse_condition (comp);
- if (comp == GE)
- output_asm_insn (AS2 (sbis,%1-0x20,7), operands);
- else
- output_asm_insn (AS2 (sbic,%1-0x20,7), operands);
- if (!reverse)
- return AS1 (rjmp,%2);
- return (AS1 (rjmp,_PC_+4) CR_TAB
- AS1 (jmp,%2));
+ operands[3] = operands[2];
+ operands[2] = GEN_INT (7);
+ return avr_out_sbxx_branch (insn, operands);
}
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
@@ -2330,6 +2343,54 @@
(const_int 4))))
(set_attr "cc" "clobber")])
+;; Upper half of the I/O space - read port to __tmp_reg__ and use sbrc/sbrs.
+(define_insn "*sbix_branch_tmp"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(zero_extract
+ (mem:QI (match_operand 1 "const_int_operand" "n"))
+ (const_int 1)
+ (match_operand 2 "const_int_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+ && avr_io_address_p (operands[1], 1) && INTVAL (operands[1]) >= 0x40"
+ "* return avr_out_sbxx_branch (insn, operands);"
+ [(set (attr "length")
+ (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
+ (le (minus (pc) (match_dup 3)) (const_int 2045)))
+ (const_int 3)
+ (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 3)
+ (const_int 5))))
+ (set_attr "cc" "clobber")])
+
+(define_insn "*sbix_branch_tmp_bit7"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(mem:QI (match_operand 1 "const_int_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == GE || GET_CODE (operands[0]) == LT)
+ && avr_io_address_p (operands[1], 1) && INTVAL (operands[1]) >= 0x40"
+{
+ operands[3] = operands[2];
+ operands[2] = GEN_INT (7);
+ return avr_out_sbxx_branch (insn, operands);
+}
+ [(set (attr "length")
+ (if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
+ (le (minus (pc) (match_dup 2)) (const_int 2045)))
+ (const_int 3)
+ (if_then_else (eq_attr "mcu_mega" "no")
+ (const_int 3)
+ (const_int 5))))
+ (set_attr "cc" "clobber")])
+
;; ************************* Peepholes ********************************
(define_peephole
@@ -2430,60 +2491,6 @@
return (AS1 (brcs,_PC_+4) CR_TAB
AS1 (jmp,%1));
}")
-
-(define_peephole
- [(set (cc0) (match_operand:QI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (lt (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrs %0,7")
-
-(define_peephole
- [(set (cc0) (match_operand:QI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (ge (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrc %0,7")
-
-(define_peephole
- [(set (cc0) (match_operand:HI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (lt (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrs %B0,7")
-
-(define_peephole
- [(set (cc0) (match_operand:HI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (ge (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrc %B0,7")
-
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (lt (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrs %D0,7")
-
-(define_peephole
- [(set (cc0) (match_operand:SI 0 "register_operand" ""))
- (set (pc)
- (if_then_else (ge (cc0) (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))]
- "jump_over_one_insn_p (insn, operands[1])"
- "sbrc %D0,7")
(define_peephole
[(set (cc0) (match_operand:QI 0 "register_operand" ""))