aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2024-12-03 21:49:32 +0100
committerGeorg-Johann Lay <avr@gjlay.de>2024-12-05 11:42:57 +0100
commit9ae9db54631f38d66666a2080a2a26c5c5d98fa9 (patch)
tree54bac999d4e0108c7d5126ec21eb121c5caa240b /gcc
parent9755f5973473aa547063d1a97d47a409d237eb5b (diff)
downloadgcc-9ae9db54631f38d66666a2080a2a26c5c5d98fa9.zip
gcc-9ae9db54631f38d66666a2080a2a26c5c5d98fa9.tar.gz
gcc-9ae9db54631f38d66666a2080a2a26c5c5d98fa9.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/avr/avr-protos.h1
-rw-r--r--gcc/config/avr/avr.cc91
-rw-r--r--gcc/config/avr/avr.md249
3 files changed, 227 insertions, 114 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 4aa8554..5b42f04 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 9bebd67..3544571 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 0c98318..a68b38c 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)