AVR: Overhaul add and sub insns that extend one operand.

These are insns of the forms

  (set (regA:M)
       (plus:M (extend:M (regB:L))
               (regA:M)))
and

  (set (regA:M)
       (minus:M (regA:M)
                (extend:M (regB:L))))

where "extend" may be a sign-extend or zero-extend,
and the integer modes are  SImode >= M > L >= QImode.

The existing patterns are now represented in terms of insns
with mode iterators and a code iterator over any_extend,
and these new insn support all valid combinations of M and L
(which previously was not the case).

gcc/
	* config/avr/avr.cc (avr_out_minus): Assimilate into...
	(avr_out_plus_ext): ...this new function.
	(avr_adjust_insn_length) [ADJUST_LEN_PLUS_EXT]: Handle case.
	(avr_rtx_costs_1) [PLUS, MINUS]: Adjust RTX costs.
	* config/avr/avr.md (adjust_len) <plus_ext>: Add new attribute value.
	(*addpsi3_zero_extend.hi_split): Assimilate...
	(*addpsi3_zero_extend.qi_split): Assimilate...
	(*addsi3_zero_extend_split): Assimilate...
	(*addsi3_zero_extend.hi_split): Assimilate...
	(*addpsi3_sign_extend.hi_split): Assimilate...
	(*addhi3.sign_extend1_split): Assimilate...
	(*add<PSISI:mode>3.<code>.<QIPSI:mode>_split): ...into this
	new insn-and-split.
	(*addpsi3_zero_extend.hi): Assimilate...
	(*addpsi3_zero_extend.qi): Assimilate...
	(*addsi3_zero_extend): Assimilate...
	(*addsi3_zero_extend.hi): Assimilate...
	(*addpsi3_sign_extend.hi): Assimilate...
	(*addhi3.sign_extend1): Assimilate...
	(*add<PSISI:mode>3.<code>.<QIPSI:mode>): ...into this new insn.
	(*subpsi3_sign_extend.hi_split): Assimilate...
	(*subhi3.sign_extend2_split): Assimilate...
	(*sub<HISI:mode>3.zero_extend.<QIPSI:mode>_split): Assimilate...
	(*sub<HISI:mode>3.<code><QIPSI:mode>_split): ...into this new
	insn-and-split.
	(*subpsi3_sign_extend.hi): Assimilate...
	(*subhi3.sign_extend2): Assimilate...
	(*sub<HISI:mode>3.zero_extend.<QIPSI:mode>): Assimilate...
	(*sub<HISI:mode>3.<code>.<QIPSI:mode>): ...into this new insn.
	(*sub<HISI:mode>3.zero_extend.<QIPSI:mode>): Use avr_out_plus_ext
	for asm out.
	* config/avr/avr-protos.h (avr_out_minus): Remove.
	(avr_out_plus_ext): New proto.
gcc/testsuite/
	* gcc.target/avr/torture/add-extend.c: New test.
	* gcc.target/avr/torture/sub-extend.c: New test.
This commit is contained in:
Georg-Johann Lay 2024-07-12 13:02:55 +02:00
parent d9709fafb2
commit a074780fce
5 changed files with 379 additions and 216 deletions

View File

@ -96,7 +96,7 @@ extern void avr_output_addr_vec (rtx_insn*, rtx);
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_minus (rtx*);
extern const char* avr_out_plus_ext (rtx_insn*, rtx*, 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*);

View File

@ -8843,30 +8843,90 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
}
/* Output subtraction of integer registers XOP[0] and XOP[2] and return ""
/* Output addition of registers YOP[0] and YOP[1]
XOP[0] = XOP[0] - XOP[2]
YOP[0] += extend (YOP[1])
where the mode of XOP[0] is in { HI, PSI, SI }, and the mode of
XOP[2] is in { QI, HI, PSI }. When the mode of XOP[0] is larger
than the mode of XOP[2], then the latter is zero-extended on the fly.
The number of instructions will be the mode size of XOP[0]. */
or subtraction of registers YOP[0] and YOP[2]
YOP[0] -= extend (YOP[2])
where the integer modes satisfy SI >= YOP[0].mode > YOP[1/2].mode >= QI,
and the extension may be sign- or zero-extend. Returns "".
If PLEN == NULL output the instructions.
If PLEN != NULL set *PLEN to the length of the sequence in words. */
const char *
avr_out_minus (rtx *xop)
avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
{
int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
int n_bytes2 = GET_MODE_SIZE (GET_MODE (xop[2]));
rtx regs[2];
output_asm_insn ("sub %0,%2", xop);
const rtx src = SET_SRC (single_set (insn));
const RTX_CODE add = GET_CODE (src);
gcc_assert (GET_CODE (src) == PLUS || GET_CODE (src) == MINUS);
// Use XOP[] in the remainder with XOP[0] = YOP[0] and XOP[1] = YOP[1/2].
rtx xop[2] = { yop[0], yop[add == PLUS ? 1 : 2] };
const rtx xreg = XEXP (src, add == PLUS ? 1 : 0);
const rtx xext = XEXP (src, add == PLUS ? 0 : 1);
const RTX_CODE ext = GET_CODE (xext);
gcc_assert (REG_P (xreg)
&& (ext == ZERO_EXTEND || ext == SIGN_EXTEND));
const int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
const int n_bytes1 = GET_MODE_SIZE (GET_MODE (xop[1]));
rtx msb1 = all_regs_rtx[n_bytes1 - 1 + REGNO (xop[1])];
const char *const s_ADD = add == PLUS ? "add %0,%1" : "sub %0,%1";
const char *const s_ADC = add == PLUS ? "adc %0,%1" : "sbc %0,%1";
const char *const s_DEC = add == PLUS
? "adc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "dec %0"
: "sbc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "inc %0";
// A register that containts 8 copies of $1.msb.
rtx ext_reg = ext == ZERO_EXTEND ? zero_reg_rtx : NULL_RTX;
if (plen)
*plen = 0;
if (ext == SIGN_EXTEND
&& (n_bytes0 > 1 + n_bytes1
|| reg_overlap_mentioned_p (msb1, xop[0])))
{
// Sign-extending more than one byte: Set tmp_reg to 0 or -1
// depending on $1.msb. Same for the pathological case where
// $0 and $1 overlap.
regs[0] = ext_reg = tmp_reg_rtx;
regs[1] = msb1;
avr_asm_len ("mov %0,%1" CR_TAB
"lsl %0" CR_TAB
"sbc %0,%0", regs, plen, 3);
}
// Adding the bytes of $1 is just plain additions / subtractions.
// Same for the extended bytes when we have ext_reg.
avr_asm_len (s_ADD, xop, plen, 1);
for (int i = 1; i < n_bytes0; ++i)
{
rtx op[2];
op[0] = all_regs_rtx[i + REGNO (xop[0])];
op[1] = (i < n_bytes2) ? all_regs_rtx[i + REGNO (xop[2])] : zero_reg_rtx;
regs[0] = all_regs_rtx[i + REGNO (xop[0])];
regs[1] = i < n_bytes1 ? all_regs_rtx[i + REGNO (xop[1])] : ext_reg;
output_asm_insn ("sbc %0,%1", op);
if (! regs[1])
{
// Extending just 1 byte: This is one instruction shorter
// than sign-extending $1.msb to tmp_reg.
regs[1] = msb1;
avr_asm_len (s_DEC, regs, plen, 3);
}
else
avr_asm_len (s_ADC, regs, plen, 1);
}
return "";
@ -11062,6 +11122,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len)
case ADJUST_LEN_INSV: avr_out_insv (insn, op, &len); break;
case ADJUST_LEN_PLUS: avr_out_plus (insn, op, &len); break;
case ADJUST_LEN_PLUS_EXT: avr_out_plus_ext (insn, op, &len); break;
case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break;
case ADJUST_LEN_MOV8: output_movqi (insn, op, &len); break;
@ -12699,6 +12760,8 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
return true;
}
// *add<PSISI:mode>3.zero_extend.<QIPSI:mode>
// *addhi3_zero_extend
if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
&& REG_P (XEXP (x, 1)))
{
@ -12712,6 +12775,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
return true;
}
// *add<HISI:mode>3.sign_extend.<QIPSI:mode>
if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
&& REG_P (XEXP (x, 1)))
{
int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0), 0)));
*total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode)
+ (GET_MODE_SIZE (mode) > 1 + size2));
return true;
}
switch (mode)
{
case E_QImode:
@ -12806,11 +12879,13 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
*total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
return true;
}
// *sub<mode>3.sign_extend2
// *sub<HISI:mode>3.sign_extend.<QIPSI:mode>
if (REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
{
*total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode));
int size2 = GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 1), 0)));
*total = COSTS_N_INSNS (2 + GET_MODE_SIZE (mode)
+ (GET_MODE_SIZE (mode) > 1 + size2));
return true;
}

View File

@ -161,7 +161,7 @@
;; Otherwise do special processing depending on the attribute.
(define_attr "adjust_len"
"out_bitop, plus, addto_sp, sext, extr, extr_not,
"out_bitop, plus, addto_sp, sext, extr, extr_not, plus_ext,
tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
ufract, sfract, round,
@ -1596,33 +1596,6 @@
"add %A0,%2\;adc %B0,__zero_reg__"
[(set_attr "length" "2")])
(define_insn_and_split "*addhi3.sign_extend1_split"
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "register_operand" "0")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:HI (sign_extend:HI (match_dup 1))
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
(define_insn "*addhi3.sign_extend1"
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))
(match_operand:HI 2 "register_operand" "0")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return reg_overlap_mentioned_p (operands[0], operands[1])
? "mov __tmp_reg__,%1\;add %A0,%1\;adc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;dec %B0"
: "add %A0,%1\;adc %B0,__zero_reg__\;sbrc %1,7\;dec %B0";
}
[(set (attr "length")
(symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[1])")))])
(define_insn_and_split "*addhi3_zero_extend.const_split"
[(set (match_operand:HI 0 "register_operand" "=d")
(plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0"))
@ -1878,110 +1851,88 @@
[(set_attr "length" "4")
(set_attr "adjust_len" "plus")])
(define_insn_and_split "*addpsi3_zero_extend.qi_split"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))]
""
;; "*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"
;; 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"
[(set (match_operand:HISI 0 "register_operand" "=r")
(plus:HISI (any_extend:HISI (match_operand:QIPSI 1 "register_operand" "r"))
(match_operand:HISI 2 "register_operand" "0")))]
"<HISI:SIZE> > <QIPSI:SIZE>
&& (<HISI:SIZE> > 2 || <CODE> == SIGN_EXTEND)"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:PSI (zero_extend:PSI (match_dup 1))
(match_dup 2)))
(plus:HISI (any_extend:HISI (match_dup 1))
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
(define_insn "*addpsi3_zero_extend.qi"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))
;; "*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"
(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"))
(match_operand:HISI 2 "register_operand" "0")))
(clobber (reg:CC REG_CC))]
"reload_completed"
"add %A0,%A1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__"
[(set_attr "length" "3")])
"reload_completed
&& <HISI:SIZE> > <QIPSI:SIZE>
&& (<HISI:SIZE> > 2 || <CODE> == SIGN_EXTEND)"
{
return avr_out_plus_ext (insn, operands, nullptr);
}
[(set (attr "length")
(symbol_ref "<HISI:SIZE> + 3 * (<CODE> == SIGN_EXTEND)"))
(set_attr "adjust_len" "plus_ext")])
(define_insn_and_split "*addpsi3_zero_extend.hi_split"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))]
""
;; "*subhi3.zero_extend.qi_split" "*subhi3.sign_extend.qi_split"
;; "*subpsi3.zero_extend.qi_split" "*subpsi3.sign_extend.qi_split"
;; "*subpsi3.zero_extend.hi_split" "*subpsi3.sign_extend.hi_split"
;; "*subsi3.zero_extend.qi_split" "*subsi3.sign_extend.qi_split"
;; "*subsi3.zero_extend.hi_split" "*subsi3.sign_extend.hi_split"
;; "*subsi3.zero_extend.psi_split" "*subsi3.sign_extend.psi_split"
(define_insn_and_split "*sub<HISI:mode>3.<code>.<QIPSI:mode>_split"
[(set (match_operand:HISI 0 "register_operand" "=r")
(minus:HISI (match_operand:HISI 1 "register_operand" "0")
(any_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))]
"<HISI:SIZE> > <QIPSI:SIZE>"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:PSI (zero_extend:PSI (match_dup 1))
(match_dup 2)))
(minus:HISI (match_dup 1)
(any_extend:HISI (match_dup 2))))
(clobber (reg:CC REG_CC))])])
(define_insn "*addpsi3_zero_extend.hi"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))
;; "*subhi3.zero_extend.qi" "*subhi3.sign_extend.qi"
;; "*subpsi3.zero_extend.qi" "*subpsi3.sign_extend.qi"
;; "*subpsi3.zero_extend.hi" "*subpsi3.sign_extend.hi"
;; "*subsi3.zero_extend.qi" "*subsi3.sign_extend.qi"
;; "*subsi3.zero_extend.hi" "*subsi3.sign_extend.hi"
;; "*subsi3.zero_extend.psi" "*subsi3.sign_extend.psi"
(define_insn "*sub<HISI:mode>3.<code>.<QIPSI:mode>"
[(set (match_operand:HISI 0 "register_operand" "=r")
(minus:HISI (match_operand:HISI 1 "register_operand" "0")
(any_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))
(clobber (reg:CC REG_CC))]
"reload_completed"
"add %A0,%A1\;adc %B0,%B1\;adc %C0,__zero_reg__"
[(set_attr "length" "3")])
"reload_completed
&& <HISI:SIZE> > <QIPSI:SIZE>"
{
return avr_out_plus_ext (insn, operands, nullptr);
}
[(set (attr "length")
(symbol_ref "<HISI:SIZE> + 3 * (<CODE> == SIGN_EXTEND)"))
(set_attr "adjust_len" "plus_ext")])
(define_insn_and_split "*addpsi3_sign_extend.hi_split"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:PSI (sign_extend:PSI (match_dup 1))
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
(define_insn "*addpsi3_sign_extend.hi"
[(set (match_operand:PSI 0 "register_operand" "=r")
(plus:PSI (sign_extend:PSI (match_operand:HI 1 "register_operand" "r"))
(match_operand:PSI 2 "register_operand" "0")))
(clobber (reg:CC REG_CC))]
"reload_completed"
"add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;sbrc %B1,7\;dec %C0"
[(set_attr "length" "5")])
(define_insn_and_split "*addsi3_zero_extend_split"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "0")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:SI (zero_extend:SI (match_dup 1))
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
(define_insn "*addsi3_zero_extend"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "0")))
(clobber (reg:CC REG_CC))]
"reload_completed"
"add %A0,%1\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
[(set_attr "length" "4")])
(define_insn_and_split "*addsi3_zero_extend.hi_split"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "0")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:SI (zero_extend:SI (match_dup 1))
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
(define_insn "*addsi3_zero_extend.hi"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "0")))
(clobber (reg:CC REG_CC))]
"reload_completed"
"add %A0,%1\;adc %B0,%B1\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
[(set_attr "length" "4")])
(define_insn_and_split "addpsi3"
[(set (match_operand:PSI 0 "register_operand" "=??r,d ,d,r")
@ -2032,27 +1983,6 @@
[(set_attr "length" "3")])
(define_insn_and_split "*subpsi3_sign_extend.hi_split"
[(set (match_operand:PSI 0 "register_operand" "=r")
(minus:PSI (match_operand:PSI 1 "register_operand" "0")
(sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(minus:PSI (match_dup 1)
(sign_extend:PSI (match_dup 2))))
(clobber (reg:CC REG_CC))])])
(define_insn "*subpsi3_sign_extend.hi"
[(set (match_operand:PSI 0 "register_operand" "=r")
(minus:PSI (match_operand:PSI 1 "register_operand" "0")
(sign_extend:PSI (match_operand:HI 2 "register_operand" "r"))))
(clobber (reg:CC REG_CC))]
"reload_completed"
"sub %A0,%A2\;sbc %B0,%B2\;sbc %C0,__zero_reg__\;sbrc %B2,7\;inc %C0"
[(set_attr "length" "5")])
;-----------------------------------------------------------------------------
; sub bytes
@ -2115,33 +2045,6 @@
[(set_attr "adjust_len" "plus")])
(define_insn_and_split "*subhi3.sign_extend2_split"
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (match_operand:HI 1 "register_operand" "0")
(sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(minus:HI (match_dup 1)
(sign_extend:HI (match_dup 2))))
(clobber (reg:CC REG_CC))])])
(define_insn "*subhi3.sign_extend2"
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (match_operand:HI 1 "register_operand" "0")
(sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return reg_overlap_mentioned_p (operands[0], operands[2])
? "mov __tmp_reg__,%2\;sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;inc %B0"
: "sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc %2,7\;inc %B0";
}
[(set (attr "length")
(symbol_ref ("4 + reg_overlap_mentioned_p (operands[0], operands[2])")))])
;; "subsi3"
;; "subsq3" "subusq3"
;; "subsa3" "subusa3"
@ -2172,39 +2075,6 @@
[(set_attr "adjust_len" "plus")])
;; "*subhi3.zero_extend.qi_split"
;; "*subpsi3.zero_extend.qi_split" "*subpsi3.zero_extend.hi_split"
;; "*subsi3.zero_extend.qi_split" "*subsi3.zero_extend.hi_split"
;; "*subsi3.zero_extend.psi_split"
(define_insn_and_split "*sub<HISI:mode>3.zero_extend.<QIPSI:mode>_split"
[(set (match_operand:HISI 0 "register_operand" "=r")
(minus:HISI (match_operand:HISI 1 "register_operand" "0")
(zero_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))]
"GET_MODE_SIZE (<HISI:MODE>mode) > GET_MODE_SIZE (<QIPSI:MODE>mode)"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(minus:HISI (match_dup 1)
(zero_extend:HISI (match_dup 2))))
(clobber (reg:CC REG_CC))])])
;; "*subhi3.zero_extend.qi"
;; "*subpsi3.zero_extend.qi" "*subpsi3.zero_extend.hi"
;; "*subsi3.zero_extend.qi" "*subsi3.zero_extend.hi"
;; "*subsi3.zero_extend.psi"
(define_insn "*sub<HISI:mode>3.zero_extend.<QIPSI:mode>"
[(set (match_operand:HISI 0 "register_operand" "=r")
(minus:HISI (match_operand:HISI 1 "register_operand" "0")
(zero_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))))
(clobber (reg:CC REG_CC))]
"reload_completed
&& GET_MODE_SIZE (<HISI:MODE>mode) > GET_MODE_SIZE (<QIPSI:MODE>mode)"
{
return avr_out_minus (operands);
}
[(set_attr "length" "<HISI:SIZE>")])
;******************************************************************************
; mul

View File

@ -0,0 +1,109 @@
/* { dg-do run } */
typedef __UINT8_TYPE__ u8;
typedef __UINT16_TYPE__ u16;
typedef __uint24 u24;
typedef __UINT32_TYPE__ u32;
typedef __INT8_TYPE__ s8;
typedef __INT16_TYPE__ s16;
typedef __int24 s24;
typedef __INT32_TYPE__ s32;
#define NI __attribute__((noinline,noclone,noipa))
NI u32 addu_32_8 (u32 a, u8 b) { return a + b; }
NI u32 addu_32_16 (u32 a, u16 b) { return a + b; }
NI u32 addu_32_24 (u32 a, u24 b) { return a + b; }
NI u24 addu_24_8 (u24 a, u8 b) { return a + b; }
NI u24 addu_24_16 (u24 a, u16 b) { return a + b; }
NI u16 addu_16_8 (u16 a, u8 b) { return a + b; }
/************************/
NI s32 adds_32_8 (s32 a, s8 b) { return a + b; }
NI s32 adds_32_16 (s32 a, s16 b) { return a + b; }
NI s32 adds_32_24 (s32 a, s24 b) { return a + b; }
NI s24 adds_24_8 (s24 a, s8 b) { return a + b; }
NI s24 adds_24_16 (s24 a, s16 b) { return a + b; }
NI s16 adds_16_8 (s16 a, s8 b) { return a + b; }
/************************/
NI u32 addu_32 (u32 a, u32 b) { return a + b; }
NI u24 addu_24 (u24 a, u24 b) { return a + b; }
NI u16 addu_16 (u16 a, u16 b) { return a + b; }
NI s32 adds_32 (s32 a, s32 b) { return a + b; }
NI s24 adds_24 (s24 a, s24 b) { return a + b; }
NI s16 adds_16 (s16 a, s16 b) { return a + b; }
/************************/
NI u8 next (void *p0, u8 n_bytes)
{
u8 *p = (u8*) p0;
u8 n;
for (n = 0; n < n_bytes; ++n)
{
u8 val = *p;
/* Cycle over 0 -> 1 -> -1 -> 0 */
if (++val == 2)
val = -1;
*p++ = val;
if (val)
return 1;
}
return 0;
}
#define MK_TEST(A, B) \
NI void test_##A##_##B (void) \
{ \
u##A a = 0; \
do \
{ \
u##B b = 0; \
do \
{ \
if (addu_##A##_##B (a, b) != addu_##A (a, b)) \
__builtin_exit (11); \
\
if (adds_##A##_##B (a, b) != adds_##A ((s##A) a, (s##B) b)) \
__builtin_exit (13); \
\
} while (next (&b, sizeof (b))); \
} while (next (&a, sizeof (a))); \
}
MK_TEST (16, 8)
MK_TEST (24, 8)
MK_TEST (24, 16)
MK_TEST (32, 8)
MK_TEST (32, 16)
MK_TEST (32, 24)
int main (void)
{
test_16_8 ();
test_24_8 ();
test_24_16 ();
test_32_8 ();
test_32_16 ();
test_32_24 ();
return 0;
}

View File

@ -0,0 +1,109 @@
/* { dg-do run } */
typedef __UINT8_TYPE__ u8;
typedef __UINT16_TYPE__ u16;
typedef __uint24 u24;
typedef __UINT32_TYPE__ u32;
typedef __INT8_TYPE__ s8;
typedef __INT16_TYPE__ s16;
typedef __int24 s24;
typedef __INT32_TYPE__ s32;
#define NI __attribute__((noinline,noclone,noipa))
NI u32 subu_32_8 (u32 a, u8 b) { return a - b; }
NI u32 subu_32_16 (u32 a, u16 b) { return a - b; }
NI u32 subu_32_24 (u32 a, u24 b) { return a - b; }
NI u24 subu_24_8 (u24 a, u8 b) { return a - b; }
NI u24 subu_24_16 (u24 a, u16 b) { return a - b; }
NI u16 subu_16_8 (u16 a, u8 b) { return a - b; }
/************************/
NI s32 subs_32_8 (s32 a, s8 b) { return a - b; }
NI s32 subs_32_16 (s32 a, s16 b) { return a - b; }
NI s32 subs_32_24 (s32 a, s24 b) { return a - b; }
NI s24 subs_24_8 (s24 a, s8 b) { return a - b; }
NI s24 subs_24_16 (s24 a, s16 b) { return a - b; }
NI s16 subs_16_8 (s16 a, s8 b) { return a - b; }
/************************/
NI u32 subu_32 (u32 a, u32 b) { return a - b; }
NI u24 subu_24 (u24 a, u24 b) { return a - b; }
NI u16 subu_16 (u16 a, u16 b) { return a - b; }
NI s32 subs_32 (s32 a, s32 b) { return a - b; }
NI s24 subs_24 (s24 a, s24 b) { return a - b; }
NI s16 subs_16 (s16 a, s16 b) { return a - b; }
/************************/
NI u8 next (void *p0, u8 n_bytes)
{
u8 *p = (u8*) p0;
u8 n;
for (n = 0; n < n_bytes; ++n)
{
u8 val = *p;
/* Cycle over 0 -> 1 -> -1 -> 0 */
if (++val == 2)
val = -1;
*p++ = val;
if (val)
return 1;
}
return 0;
}
#define MK_TEST(A, B) \
NI void test_##A##_##B (void) \
{ \
u##A a = 0; \
do \
{ \
u##B b = 0; \
do \
{ \
if (subu_##A##_##B (a, b) != subu_##A (a, b)) \
__builtin_exit (11); \
\
if (subs_##A##_##B (a, b) != subs_##A ((s##A) a, (s##B) b)) \
__builtin_exit (13); \
\
} while (next (&b, sizeof (b))); \
} while (next (&a, sizeof (a))); \
}
MK_TEST (16, 8)
MK_TEST (24, 8)
MK_TEST (24, 16)
MK_TEST (32, 8)
MK_TEST (32, 16)
MK_TEST (32, 24)
int main (void)
{
test_16_8 ();
test_24_8 ();
test_24_16 ();
test_32_8 ();
test_32_16 ();
test_32_24 ();
return 0;
}