From: Marek Michalkiewicz Date: Sun, 26 May 2002 20:19:32 +0000 (+0200) Subject: avr-protos.h (avr_out_sbxx_branch): Declare. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=331ca3501dda7ce9a91996117c5127d52ac1e02c;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 800233d43db..7b8ba2d8a75 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -25,6 +25,19 @@ (_cpp_parse_expr, reduce): Update to handle two-integers. * cpplib.c (_cpp_test_assertion): Back up on CPP_EOF. +2002-05-26 Marek Michalkiewicz + + * 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 * config/avr/avr.c (avr_asm_only_p): New variable. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index f6dd8802e98..3d0be48c807 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 5167ee65ada..67e6d52114e 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 da4c571742b..08a468aa40b 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" ""))