https://gcc.gnu.org/g:9ae9db54631f38d66666a2080a2a26c5c5d98fa9
commit r15-5935-g9ae9db54631f38d66666a2080a2a26c5c5d98fa9 Author: Georg-Johann Lay <a...@gjlay.de> Date: Tue Dec 3 21:49:32 2024 +0100 AVR: Rework patterns that add / subtract an (inverted) MSB. gcc/ * config/avr/avr-protos.h (avr_out_add_msb): New proto. * config/avr/avr.cc (avr_out_add_msb): New function. (avr_adjust_insn_length) [ADJUST_LEN_ADD_GE0, ADJUST_LEN_ADD_LT0]: Handle cases. * config/avr/avr.md (adjust_len) <add_lt0, add_ge0>: New attr values. (QISI2): New mode iterator. (C_MSB): New mode_attr. (*add<mode>3...msb_split, *add<mode>3.ge0, *add<mode>3.lt0) (*sub<mode>3...msb_split, *sub<mode>3.ge0, *sub<mode>3.lt0): New patterns replacing old ones, but with iterators and using avr_out_add_msb() for asm out. Diff: --- gcc/config/avr/avr-protos.h | 1 + gcc/config/avr/avr.cc | 91 ++++++++++++++++ gcc/config/avr/avr.md | 249 ++++++++++++++++++++++++-------------------- 3 files changed, 227 insertions(+), 114 deletions(-) diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 4aa8554000b8..5b42f04fb313 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -109,6 +109,7 @@ extern const char *avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]); extern const char* avr_out_bitop (rtx, rtx*, int*); extern const char* avr_out_plus (rtx, rtx*, int* =NULL, bool =true); extern const char* avr_out_plus_ext (rtx_insn*, rtx*, int*); +extern const char* avr_out_add_msb (rtx_insn*, rtx*, rtx_code, int*); extern const char* avr_out_round (rtx_insn *, rtx*, int* =NULL); extern const char* avr_out_addto_sp (rtx*, int*); extern const char* avr_out_xload (rtx_insn *, rtx*, int*); diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 9bebd67cd9c4..3544571d3dfa 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -8274,6 +8274,94 @@ avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen) } +/* Output code for addition of a sign-bit + + YOP[0] += YOP[1] <CMP> 0 + + or such a subtraction: + + YOP[0] -= YOP[2] <CMP> 0 + + where CMP is in { GE, LT }. + If PLEN == NULL output the instructions. + If PLEN != NULL set *PLEN to the length of the sequence in words. */ + +const char * +avr_out_add_msb (rtx_insn *insn, rtx *yop, rtx_code cmp, int *plen) +{ + const rtx_code add = GET_CODE (SET_SRC (single_set (insn))); + const machine_mode mode = GET_MODE (yop[0]); + const int n_bytes = GET_MODE_SIZE (mode); + rtx sigop = yop[add == PLUS ? 1 : 2]; + rtx msb = avr_byte (sigop, GET_MODE_SIZE (GET_MODE (sigop)) - 1); + rtx op[3] = { yop[0], msb, nullptr }; + + if (plen) + *plen = 0; + + if (n_bytes == 1 + || (n_bytes == 2 && avr_adiw_reg_p (op[0]))) + { + avr_asm_len (cmp == LT + ? "sbrc %1,7" + : "sbrs %1,7", op, plen, 1); + const char *s_add = add == PLUS + ? n_bytes == 1 ? "inc %0" : "adiw %0,1" + : n_bytes == 1 ? "dec %0" : "sbiw %0,1"; + return avr_asm_len (s_add, op, plen, 1); + } + + bool labl_p = false; + const char *s_code0 = nullptr; + + // Default code provided SREG.C = MSBit. + const char *s_code = add == PLUS + ? "adc %2,__zero_reg__" + : "sbc %2,__zero_reg__"; + + if (cmp == LT) + { + if (reg_unused_after (insn, sigop) + && ! reg_overlap_mentioned_p (msb, op[0])) + avr_asm_len ("lsl %1", op, plen, 1); + else + avr_asm_len ("mov __tmp_reg__,%1" CR_TAB + "lsl __tmp_reg__", op, plen, 2); + } + else if (test_hard_reg_class (LD_REGS, msb)) + { + avr_asm_len ("cpi %1,0x80", op, plen, 1); + } + else if (test_hard_reg_class (LD_REGS, op[0])) + { + labl_p = true; + avr_asm_len ("tst %1" CR_TAB + "brmi 0f", op, plen, 2); + s_code0 = add == PLUS ? "subi %2,-1" : "subi %2,1"; + s_code = add == PLUS ? "sbci %2,-1" : "sbci %2,0"; + } + else + { + labl_p = true; + avr_asm_len ("tst %1" CR_TAB + "brmi 0f" CR_TAB + "sec", op, plen, 3); + } + + for (int i = 0; i < n_bytes; ++i) + { + op[2] = avr_byte (op[0], i); + avr_asm_len (i == 0 && s_code0 + ? s_code0 + : s_code, op, plen, 1); + } + + return labl_p + ? avr_asm_len ("0:", op, plen, 0) + : ""; +} + + /* Output addition of register XOP[0] and compile time constant XOP[2]. INSN is a single_set insn or an insn pattern. CODE == PLUS: perform addition by using ADD instructions or @@ -10669,6 +10757,9 @@ avr_adjust_insn_length (rtx_insn *insn, int len) case ADJUST_LEN_ADD_SET_ZN: avr_out_plus_set_ZN (op, &len); break; case ADJUST_LEN_ADD_SET_N: avr_out_plus_set_N (op, &len); break; + case ADJUST_LEN_ADD_GE0: avr_out_add_msb (insn, op, GE, &len); break; + case ADJUST_LEN_ADD_LT0: avr_out_add_msb (insn, op, LT, &len); break; + case ADJUST_LEN_INSV_NOTBIT: avr_out_insert_notbit (insn, op, &len); break; default: diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 0c98318c03dc..a68b38c272de 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -169,6 +169,7 @@ ashlhi, ashrhi, lshrhi, ashlsi, ashrsi, lshrsi, ashlpsi, ashrpsi, lshrpsi, + add_lt0, add_ge0, insert_bits, insv_notbit, insv, set_some, add_set_ZN, add_set_N, cmp_uext, cmp_sext, cmp_lsr, no" @@ -256,6 +257,7 @@ (define_mode_iterator QIHI [QI HI]) (define_mode_iterator QIHI2 [QI HI]) (define_mode_iterator QISI [QI HI PSI SI]) +(define_mode_iterator QISI2 [QI HI PSI SI]) (define_mode_iterator QIDI [QI HI PSI SI DI]) (define_mode_iterator QIPSI [QI HI PSI]) (define_mode_iterator HISI [HI PSI SI]) @@ -301,7 +303,15 @@ (define_mode_attr MSB [(QI "7") (QQ "7") (UQQ "7") (HI "15") (HQ "15") (UHQ "15") (HA "15") (UHA "15") (PSI "23") - (SI "31") (SQ "31") (USQ "31") (SA "31") (USA "31") (SF "31")]) + (SI "31") (SQ "31") (USQ "31") (SA "31") (USA "31") + (SF "31")]) + +;; Where the most significant bit is located, as a constraint. +(define_mode_attr C_MSB [(QI "C07") (QQ "C07") (UQQ "C07") + (HI "C15") (HQ "C15") (UHQ "C15") (HA "C15") (UHA "C15") + (PSI "C23") + (SI "C31") (SQ "C31") (USQ "C31") (SA "C31") (USA "C31") + (SF "C31")]) ;; Size in bytes of the mode. (define_mode_attr SIZE [(QI "1") (QQ "1") (UQQ "1") @@ -1867,11 +1877,11 @@ ;; "*addhi3.sign_extend.qi_split" -;; "*addpsi3.sign_extend.qi_split" "*addpsi3.sign_extend.qi_split" -;; "*addpsi3.sign_extend.hi_split" "*addpsi3.sign_extend.hi_split" -;; "*addsi3.sign_extend.qi_split" "*addsi3.sign_extend.qi_split" -;; "*addsi3.sign_extend.hi_split" "*addsi3.sign_extend.hi_split" -;; "*addsi3.sign_extend.psi_split" "*addsi3.sign_extend.psi_split" +;; "*addpsi3.zero_extend.qi_split" "*addpsi3.sign_extend.qi_split" +;; "*addpsi3.zero_extend.hi_split" "*addpsi3.sign_extend.hi_split" +;; "*addsi3.zero_extend.qi_split" "*addsi3.sign_extend.qi_split" +;; "*addsi3.zero_extend.hi_split" "*addsi3.sign_extend.hi_split" +;; "*addsi3.zero_extend.psi_split" "*addsi3.sign_extend.psi_split" ;; The zero_extend:HI(QI) case is treated in an own insn as it can ;; more than just "r,r,0". (define_insn_and_split "*add<HISI:mode>3.<code>.<QIPSI:mode>_split" @@ -1888,11 +1898,11 @@ (clobber (reg:CC REG_CC))])]) ;; "*addhi3.sign_extend.qi" -;; "*addpsi3.sign_extend.qi" "*addpsi3.sign_extend.qi" -;; "*addpsi3.sign_extend.hi" "*addpsi3.sign_extend.hi" -;; "*addsi3.sign_extend.qi" "*addsi3.sign_extend.qi" -;; "*addsi3.sign_extend.hi" "*addsi3.sign_extend.hi" -;; "*addsi3.sign_extend.psi" "*addsi3.sign_extend.psi" +;; "*addpsi3.zero_extend.qi" "*addpsi3.sign_extend.qi" +;; "*addpsi3.zero_extend.hi" "*addpsi3.sign_extend.hi" +;; "*addsi3.zero_extend.qi" "*addsi3.sign_extend.qi" +;; "*addsi3.zero_extend.hi" "*addsi3.sign_extend.hi" +;; "*addsi3.zero_extend.psi" "*addsi3.sign_extend.psi" (define_insn "*add<HISI:mode>3.<code>.<QIPSI:mode>" [(set (match_operand:HISI 0 "register_operand" "=r") (plus:HISI (any_extend:HISI (match_operand:QIPSI 1 "register_operand" "r")) @@ -2194,135 +2204,146 @@ ;; Used when expanding div or mod inline for some special values -(define_insn_and_split "*subqi3.ashiftrt7_split" - [(set (match_operand:QI 0 "register_operand" "=r") - (minus:QI (match_operand:QI 1 "register_operand" "0") - (ashiftrt:QI (match_operand:QI 2 "register_operand" "r") - (const_int 7))))] +;; *subqi3.msbit_split *subhi3.msbit_split +;; *subpsi3.msbit_split *subsi3.msbit_split +(define_insn_and_split "*sub<mode>3.msbit_split" + [(set (match_operand:QISI 0 "register_operand" "=r") + (minus:QISI (match_operand:QISI 1 "register_operand" "0") + (any_shiftrt:QISI (match_operand:QISI 2 "register_operand" "r") + (match_operand:QI 3 "const<MSB>_operand" "<C_MSB>"))))] "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:QI (match_dup 1) - (ashiftrt:QI (match_dup 2) - (const_int 7)))) + [; *sub<QISI:mode>3.lt0 + (parallel [(set (match_dup 0) + (minus:QISI (match_dup 1) + (lt:QISI (match_dup 2) + (const_int 0)))) (clobber (reg:CC REG_CC))])]) -(define_insn "*subqi3.ashiftrt7" - [(set (match_operand:QI 0 "register_operand" "=r") - (minus:QI (match_operand:QI 1 "register_operand" "0") - (ashiftrt:QI (match_operand:QI 2 "register_operand" "r") - (const_int 7)))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "sbrc %2,7\;inc %0" - [(set_attr "length" "2")]) - -(define_insn_and_split "*addqi3.lt0_split" - [(set (match_operand:QI 0 "register_operand" "=r") - (plus:QI (lt:QI (match_operand:QI 1 "register_operand" "r") - (const_int 0)) - (match_operand:QI 2 "register_operand" "0")))] +;; *addqi3.msbit_split *addhi3.msbit_split +;; *addpsi3.msbit_split *addsi3.msbit_split +(define_insn_and_split "*add<mode>3.msbit_split" + [(set (match_operand:QISI 0 "register_operand" "=r") + (plus:QISI (any_shiftrt:QISI (match_operand:QISI 1 "register_operand" "r") + (match_operand:QI 2 "const<MSB>_operand" "<C_MSB>")) + (match_operand:QISI 3 "register_operand" "0")))] "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:QI (lt:QI (match_dup 1) - (const_int 0)) - (match_dup 2))) + [; *add<QISI:mode>3.lt0 + (parallel [(set (match_dup 0) + (plus:QISI (lt:QISI (match_dup 1) + (const_int 0)) + (match_dup 3))) + (clobber (reg:CC REG_CC))])]) + +;; *addhi3.sex.msbit_split +;; *addpsi3.sex.msbit_split *addsi3.sex.msbit_split +(define_insn_and_split "*add<HISI:mode>3.sex.msbit_split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (plus:HISI (any_shiftrt:HISI + (sign_extend:HISI (match_operand:QIPSI 1 "register_operand" "r")) + (match_operand:QI 2 "const<HISI:MSB>_operand" "<HISI:C_MSB>")) + (match_operand:HISI 3 "register_operand" "0")))] + "<HISI:SIZE> > <QIPSI:SIZE>" + "#" + "&& reload_completed" + [; *add<QISI:mode>3.lt0 + (parallel [(set (match_dup 0) + (plus:HISI (lt:HISI (match_dup 1) + (const_int 0)) + (match_dup 3))) + (clobber (reg:CC REG_CC))])]) + +;; *subhi3.sex.msbit_split +;; *subpsi3.sex.msbit_split *subsi3.sex.msbit_split +(define_insn_and_split "*sub<HISI:mode>3.sex.msbit_split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (minus:HISI (match_operand:HISI 1 "register_operand" "0") + (any_shiftrt:HISI + (sign_extend:HISI (match_operand:QIPSI 2 "register_operand" "r")) + (match_operand:QI 3 "const<HISI:MSB>_operand" "<HISI:C_MSB>"))))] + "<HISI:SIZE> > <QIPSI:SIZE>" + "#" + "&& reload_completed" + [; *sub<QISI:mode>3.lt0 + (parallel [(set (match_dup 0) + (minus:HISI (match_dup 1) + (lt:HISI (match_dup 2) + (const_int 0)))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addqi3.lt0" - [(set (match_operand:QI 0 "register_operand" "=r") - (plus:QI (lt:QI (match_operand:QI 1 "register_operand" "r") - (const_int 0)) - (match_operand:QI 2 "register_operand" "0"))) +;; *subqi3.lt0 *subqi3.ge0 +;; *subhi3.lt0 *subhi3.ge0 +;; *subpsi3.lt0 *subpsi3.ge0 +;; *subsi3.lt0 *subsi3.ge0 +(define_insn "*sub<QISI:mode>3.<code>0" + [(set (match_operand:QISI 0 "register_operand" "=r") + (minus:QISI (match_operand:QISI 1 "register_operand" "0") + (gelt:QISI (match_operand:QISI2 2 "register_operand" "r") + (const_int 0)))) (clobber (reg:CC REG_CC))] "reload_completed" - "sbrc %1,7\;inc %0" - [(set_attr "length" "2")]) - -(define_insn_and_split "*addhi3.lt0_split" - [(set (match_operand:HI 0 "register_operand" "=w,r") - (plus:HI (lt:HI (match_operand:QI 1 "register_operand" "r,r") - (const_int 0)) - (match_operand:HI 2 "register_operand" "0,0"))) - (clobber (match_scratch:QI 3 "=X,&1"))] - "" - "#" - "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (lt:HI (match_dup 1) - (const_int 0)) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])] - "" - [(set_attr "isa" "adiw,*")]) + { + return avr_out_add_msb (insn, operands, <CODE>, nullptr); + } + [(set_attr "adjust_len" "add_<code>0")]) -(define_insn "*addhi3.lt0" - [(set (match_operand:HI 0 "register_operand" "=w,r") - (plus:HI (lt:HI (match_operand:QI 1 "register_operand" "r,r") - (const_int 0)) - (match_operand:HI 2 "register_operand" "0,0"))) - (clobber (match_scratch:QI 3 "=X,&1")) +;; *addqi3.lt0 *addqi3.ge0 +;; *addhi3.lt0 *addhi3.ge0 +;; *addpsi3.lt0 *addpsi3.ge0 +;; *addsi3.lt0 *addsi3.ge0 +(define_insn "*add<QISI:mode>3.<code>0" + [(set (match_operand:QISI 0 "register_operand" "=r") + (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r") + (const_int 0)) + (match_operand:QISI 2 "register_operand" "0"))) (clobber (reg:CC REG_CC))] "reload_completed" - "@ - sbrc %1,7\;adiw %0,1 - lsl %1\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__" - [(set_attr "length" "2,3") - (set_attr "isa" "adiw,*")]) + { + return avr_out_add_msb (insn, operands, <CODE>, nullptr); + } + [(set_attr "adjust_len" "add_<code>0")]) -(define_insn_and_split "*addpsi3.lt0_split" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "r") - (const_int 23)) - (match_operand:PSI 2 "register_operand" "0")))] +;; *addqi3.lt0_split *addqi3.ge0_split +;; *addhi3.lt0_split *addhi3.ge0_split +;; *addpsi3.lt0_split *addpsi3.ge0_split +;; *addsi3.lt0_split *addsi3.ge0_split +(define_insn_and_split "*add<QISI:mode>3.<code>0_split" + [(set (match_operand:QISI 0 "register_operand" "=r") + (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r") + (const_int 0)) + (match_operand:QISI 2 "register_operand" "0")))] "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:PSI (lshiftrt:PSI (match_dup 1) - (const_int 23)) - (match_dup 2))) + [; *add<QISI:mode>3.<code>0 + (parallel [(set (match_dup 0) + (plus:QISI (gelt:QISI (match_dup 1) + (const_int 0)) + (match_dup 2))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addpsi3.lt0" - [(set (match_operand:PSI 0 "register_operand" "=r") - (plus:PSI (lshiftrt:PSI (match_operand:PSI 1 "register_operand" "r") - (const_int 23)) - (match_operand:PSI 2 "register_operand" "0"))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "mov __tmp_reg__,%C1\;lsl __tmp_reg__ - adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__" - [(set_attr "length" "5")]) - -(define_insn_and_split "*addsi3.lt0_split" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") - (const_int 31)) - (match_operand:SI 2 "register_operand" "0")))] +;; *subqi3.lt0_split *subqi3.ge0_split +;; *subhi3.lt0_split *subhi3.ge0_split +;; *subpsi3.lt0_split *subpsi3.ge0_split +;; *subsi3.lt0_split *subsi3.ge0_split +(define_insn_and_split "*sub<QISI:mode>3.<code>0_split" + [(set (match_operand:QISI 0 "register_operand" "=r") + (minus:QISI (match_operand:QISI 1 "register_operand" "0") + (gelt:QISI (match_operand:QISI2 2 "register_operand" "r") + (const_int 0))))] "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:SI (lshiftrt:SI (match_dup 1) - (const_int 31)) - (match_dup 2))) + [; *sub<QISI:mode>3.<code>0 + (parallel [(set (match_dup 0) + (minus:QISI (match_dup 1) + (gelt:QISI (match_dup 2) + (const_int 0)))) (clobber (reg:CC REG_CC))])]) -(define_insn "*addsi3.lt0" - [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") - (const_int 31)) - (match_operand:SI 2 "register_operand" "0"))) - (clobber (reg:CC REG_CC))] - "reload_completed" - "mov __tmp_reg__,%D1\;lsl __tmp_reg__ - adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__" - [(set_attr "length" "6")]) (define_insn_and_split "*umulqihi3.call_split" [(set (reg:HI 24)