re PR target/54222 ([avr] Implement fixed-point support)

gcc/
	PR target/54222
	* config/avr/avr-fixed.md (ALL2S, ALL4S, ALL24S, ALL124S,
	ALL124U): New mode iterators.
	(<code_stdname><mode>3): New insns for SS_PLUS, SS_MINUS.
	(<code_stdname><mode>3): New insns for US_PLUS, US_MINUS.
	(usneg<mode>2): New insns.
	(<code_stdname><mode>2): New expanders for SS_NEG, SS_ABS.
	(*<code_stdname><mode>2): New insns for SS_NEG, SS_ABS.
	* config/avr/avr-dimode.md (ALL8U, ALL8S): New mode iterators.
	(avr_out_plus64, avr_out_minus64): Use avr_out_plus instead.
	(<code_stdname><mode>3): New expanders for SS_PLUS, SS_MINUS.
	(<code_stdname><mode>3): New expanders for US_PLUS, US_MINUS.
	(<code_stdname><mode>3_insn): New insns.
	(<code_stdname><mode>3_const_insn): New insns.
	* config/avr/avr.md (cc): Add: plus. Remove: out_plus,
	out_plus_noclobber, minus.
	(length): Add: plus.  Remove: out_plus, out_plus_noclobber,
	plus64, minus, minus64.
	(abelian): New code_attr.
	(code_stdname): Handle: ss_plus, ss_minus, ss_neg, ss_abs,
	us_plus, us_minus, us_neg.
	(*add<mode>3, add<mode>3_clobber, add<mode>3, addpsi3, sub<mode>3):
	Use avr_out_plus to output.
	* config/avr/avr-protos.h (avr_out_plus): Change prototype.
	(avr_out_plus_noclobber, avr_out_minus): Remove.
	(avr_out_plus64, avr_out_minus64): Remove.
	* config/avr/avr.c (avr_out_plus_1): Add new default arguments
	code_sat, sign.  Saturate after operation if code_sat != UNKNOWN.
	(avr_out_plus_symbol): New static function.
	(avr_out_plus): Rewrite.
	(adjust_insn_length): Handle: ADJUST_LEN_PLUS.  Remove handling
	of: ADJUST_LEN_OUT_PLUS, ADJUST_LEN_PLUS64, ADJUST_LEN_MINUS, 
	ADJUST_LEN_MINUS64, ADJUST_LEN_OUT_PLUS_NOCLOBBER.
	(notice_update_cc): Handle: CC_PLUS.  Remove handling of: CC_MINUS,
	CC_OUT_PLUS, CC_OUT_PLUS_NOCLOBBER
	(avr_out_plus_noclobber, avr_out_minus): Remove.
	(avr_out_plus64, avr_out_minus64): Remove.
	(avr_print_operand): Print raw REGNO if 'r' is used with REG.

libgcc/
	PR target/54222
	* config/avr/lib1funcs-fixed.S (__ssneg_2, __ssabs_2, __ssneg_4,
	__ssabs_4, __clr_8, __ssneg_8, __ssabs_8,
	__usadd_8, __ussub_8, __ssadd_8, __sssub_8): New functions.
	(__divsa3): Use __negsi2 to negate r_quoL.
	* config/avr/lib1funcs.S (FALIAS): New macro.
	(__divmodsi4): Break out and use __divmodsi4_neg1 as...
	(__negsi2): ...this new function.
	* config/avr/t-avr (LIB1ASMFUNCS): Add _negsi2, _clr_8,
	_ssneg_2, _ssneg_4, _ssneg_8, _ssabs_2, _ssabs_4,
	_ssabs_8, _ssadd_8, _sssub_8, _usadd_8, _ussub_8.
	(LIB2FUNCS_EXCLUDE): Fix typo for _add _sub.
	Add: _ssadd*, _sssub*, _ssneg*, _ssabs* for signed fixed modes.
	Add: _usadd*, _ussub*, _usneg* for unsigned fixed modes.

gcc/testsuite/
	PR target/54222
	* gcc.target/avr/torture/fix-types.h: New.
	* gcc.target/avr/torture/vals-hr.def: New.
	* gcc.target/avr/torture/vals-r.def: New.
	* gcc.target/avr/torture/vals-k.def: New.
	* gcc.target/avr/torture/vals-ur.def: New.
	* gcc.target/avr/torture/vals-uk.def: New.
	* gcc.target/avr/torture/vals-uhr.def: New.
	* gcc.target/avr/torture/vals-llk.def: New.
	* gcc.target/avr/torture/vals-ullk.def: New.
	* gcc.target/avr/torture/sat-hr-plus-minus.c: New.
	* gcc.target/avr/torture/sat-r-plus-minus.c: New.
	* gcc.target/avr/torture/sat-k-plus-minus.c: New.
	* gcc.target/avr/torture/sat-ur-plus-minus.c: New.
	* gcc.target/avr/torture/sat-uk-plus-minus.c: New.
	* gcc.target/avr/torture/sat-uhr-plus-minus.c: New.
	* gcc.target/avr/torture/sat-llk-plus-minus.c: New.
	* gcc.target/avr/torture/sat-ullk-plus-minus.c: New.

From-SVN: r191345
This commit is contained in:
Georg-Johann Lay 2012-09-15 15:52:28 +00:00 committed by Georg-Johann Lay
parent fc2655fb30
commit 51526856a1
28 changed files with 2105 additions and 224 deletions

View File

@ -1,3 +1,44 @@
2012-09-15 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* config/avr/avr-fixed.md (ALL2S, ALL4S, ALL24S, ALL124S,
ALL124U): New mode iterators.
(<code_stdname><mode>3): New insns for SS_PLUS, SS_MINUS.
(<code_stdname><mode>3): New insns for US_PLUS, US_MINUS.
(usneg<mode>2): New insns.
(<code_stdname><mode>2): New expanders for SS_NEG, SS_ABS.
(*<code_stdname><mode>2): New insns for SS_NEG, SS_ABS.
* config/avr/avr-dimode.md (ALL8U, ALL8S): New mode iterators.
(avr_out_plus64, avr_out_minus64): Use avr_out_plus instead.
(<code_stdname><mode>3): New expanders for SS_PLUS, SS_MINUS.
(<code_stdname><mode>3): New expanders for US_PLUS, US_MINUS.
(<code_stdname><mode>3_insn): New insns.
(<code_stdname><mode>3_const_insn): New insns.
* config/avr/avr.md (cc): Add: plus. Remove: out_plus,
out_plus_noclobber, minus.
(length): Add: plus. Remove: out_plus, out_plus_noclobber,
plus64, minus, minus64.
(abelian): New code_attr.
(code_stdname): Handle: ss_plus, ss_minus, ss_neg, ss_abs,
us_plus, us_minus, us_neg.
(*add<mode>3, add<mode>3_clobber, add<mode>3, addpsi3, sub<mode>3):
Use avr_out_plus to output.
* config/avr/avr-protos.h (avr_out_plus): Change prototype.
(avr_out_plus_noclobber, avr_out_minus): Remove.
(avr_out_plus64, avr_out_minus64): Remove.
* config/avr/avr.c (avr_out_plus_1): Add new default arguments
code_sat, sign. Saturate after operation if code_sat != UNKNOWN.
(avr_out_plus_symbol): New static function.
(avr_out_plus): Rewrite.
(adjust_insn_length): Handle: ADJUST_LEN_PLUS. Remove handling
of: ADJUST_LEN_OUT_PLUS, ADJUST_LEN_PLUS64, ADJUST_LEN_MINUS,
ADJUST_LEN_MINUS64, ADJUST_LEN_OUT_PLUS_NOCLOBBER.
(notice_update_cc): Handle: CC_PLUS. Remove handling of: CC_MINUS,
CC_OUT_PLUS, CC_OUT_PLUS_NOCLOBBER
(avr_out_plus_noclobber, avr_out_minus): Remove.
(avr_out_plus64, avr_out_minus64): Remove.
(avr_print_operand): Print raw REGNO if 'r' is used with REG.
2012-09-15 Oleg Endo <olegendo@gcc.gnu.org>
* config/sh/sh.c (sh_rtx_costs): Add handling of MEM, SIGN_EXTEND,

View File

@ -48,10 +48,10 @@
(ACC_B 10)])
;; Supported modes that are 8 bytes wide
(define_mode_iterator ALL8 [(DI "")
(DQ "") (UDQ "")
(DA "") (UDA "")
(TA "") (UTA "")])
(define_mode_iterator ALL8 [DI DQ UDQ DA UDA TA UTA])
(define_mode_iterator ALL8U [UDQ UDA UTA])
(define_mode_iterator ALL8S [ DQ DA TA])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Addition
@ -124,9 +124,9 @@
"avr_have_dimode
&& !s8_operand (operands[0], VOIDmode)"
{
return avr_out_plus64 (operands[0], NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "adjust_len" "plus64")
[(set_attr "adjust_len" "plus")
(set_attr "cc" "clobber")])
@ -185,11 +185,106 @@
(match_operand:ALL8 0 "const_operand" "n Ynn")))]
"avr_have_dimode"
{
return avr_out_minus64 (operands[0], NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "adjust_len" "minus64")
[(set_attr "adjust_len" "plus")
(set_attr "cc" "clobber")])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Signed Saturating Addition and Subtraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define_expand "<code_stdname><mode>3"
[(set (match_operand:ALL8S 0 "general_operand" "")
(ss_addsub:ALL8S (match_operand:ALL8S 1 "general_operand" "")
(match_operand:ALL8S 2 "general_operand" "")))]
"avr_have_dimode"
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
if (const_operand (operands[2], GET_MODE (operands[2])))
{
emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2]));
}
else
{
emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
emit_insn (gen_<code_stdname><mode>3_insn ());
}
emit_move_insn (operands[0], acc_a);
DONE;
})
(define_insn "<code_stdname><mode>3_insn"
[(set (reg:ALL8S ACC_A)
(ss_addsub:ALL8S (reg:ALL8S ACC_A)
(reg:ALL8S ACC_B)))]
"avr_have_dimode"
"%~call __<code_stdname><mode>3"
[(set_attr "adjust_len" "call")
(set_attr "cc" "clobber")])
(define_insn "<code_stdname><mode>3_const_insn"
[(set (reg:ALL8S ACC_A)
(ss_addsub:ALL8S (reg:ALL8S ACC_A)
(match_operand:ALL8S 0 "const_operand" "n Ynn")))]
"avr_have_dimode"
{
return avr_out_plus (insn, operands);
}
[(set_attr "adjust_len" "plus")
(set_attr "cc" "clobber")])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Unsigned Saturating Addition and Subtraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define_expand "<code_stdname><mode>3"
[(set (match_operand:ALL8U 0 "general_operand" "")
(us_addsub:ALL8U (match_operand:ALL8U 1 "general_operand" "")
(match_operand:ALL8U 2 "general_operand" "")))]
"avr_have_dimode"
{
rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
if (const_operand (operands[2], GET_MODE (operands[2])))
{
emit_insn (gen_<code_stdname><mode>3_const_insn (operands[2]));
}
else
{
emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
emit_insn (gen_<code_stdname><mode>3_insn ());
}
emit_move_insn (operands[0], acc_a);
DONE;
})
(define_insn "<code_stdname><mode>3_insn"
[(set (reg:ALL8U ACC_A)
(us_addsub:ALL8U (reg:ALL8U ACC_A)
(reg:ALL8U ACC_B)))]
"avr_have_dimode"
"%~call __<code_stdname><mode>3"
[(set_attr "adjust_len" "call")
(set_attr "cc" "clobber")])
(define_insn "<code_stdname><mode>3_const_insn"
[(set (reg:ALL8U ACC_A)
(us_addsub:ALL8U (reg:ALL8U ACC_A)
(match_operand:ALL8U 0 "const_operand" "n Ynn")))]
"avr_have_dimode"
{
return avr_out_plus (insn, operands);
}
[(set_attr "adjust_len" "plus")
(set_attr "cc" "clobber")])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Negation

View File

@ -29,6 +29,12 @@
(HA "") (UHA "")])
(define_mode_iterator ALL4A [(SA "") (USA "")])
(define_mode_iterator ALL2S [HQ HA])
(define_mode_iterator ALL4S [SA SQ])
(define_mode_iterator ALL24S [ HQ HA SA SQ])
(define_mode_iterator ALL124S [ QQ HQ HA SA SQ])
(define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ])
;;; Conversions
(define_mode_iterator FIXED_A
@ -71,6 +77,112 @@
[(set_attr "cc" "clobber")
(set_attr "adjust_len" "ufract")])
;******************************************************************************
;** Saturated Addition and Subtraction
;******************************************************************************
;; Fixme: It would be nice if we could expand the 32-bit versions to a
;; transparent libgcc call if $2 is a REG. Problem is that it is
;; not possible to describe that addition is commutative.
;; And defining register classes/constraintrs for the involved hard
;; registers and let IRA do the work, yields inacceptable bloated code.
;; Thus, we have to live with the up to 11 instructions that are output
;; for these 32-bit saturated operations.
;; "ssaddqq3" "ssaddhq3" "ssaddha3" "ssaddsq3" "ssaddsa3"
;; "sssubqq3" "sssubhq3" "sssubha3" "sssubsq3" "sssubsa3"
(define_insn "<code_stdname><mode>3"
[(set (match_operand:ALL124S 0 "register_operand" "=??d,d")
(ss_addsub:ALL124S (match_operand:ALL124S 1 "register_operand" "<abelian>0,0")
(match_operand:ALL124S 2 "nonmemory_operand" "r,Ynn")))]
""
{
return avr_out_plus (insn, operands);
}
[(set_attr "cc" "clobber")
(set_attr "adjust_len" "plus")])
;; "usadduqq3" "usadduhq3" "usadduha3" "usaddusq3" "usaddusa3"
;; "ussubuqq3" "ussubuhq3" "ussubuha3" "ussubusq3" "ussubusa3"
(define_insn "<code_stdname><mode>3"
[(set (match_operand:ALL124U 0 "register_operand" "=??r,d")
(us_addsub:ALL124U (match_operand:ALL124U 1 "register_operand" "<abelian>0,0")
(match_operand:ALL124U 2 "nonmemory_operand" "r,Ynn")))]
""
{
return avr_out_plus (insn, operands);
}
[(set_attr "cc" "clobber")
(set_attr "adjust_len" "plus")])
;******************************************************************************
;** Saturated Negation and Absolute Value
;******************************************************************************
;; Fixme: This will always result in 0. Dunno why simplify-rtx.c says
;; "unknown" on how to optimize this. libgcc call would be in order,
;; but the performance is *PLAIN* *HORROR* because the optimizers don't
;; manage to optimize out MEMCPY that's sprincled all over fixed-bit.c */
(define_expand "usneg<mode>2"
[(parallel [(match_operand:ALL124U 0 "register_operand" "")
(match_operand:ALL124U 1 "nonmemory_operand" "")])]
""
{
emit_move_insn (operands[0], CONST0_RTX (<MODE>mode));
DONE;
})
(define_insn "ssnegqq2"
[(set (match_operand:QQ 0 "register_operand" "=r")
(ss_neg:QQ (match_operand:QQ 1 "register_operand" "0")))]
""
"neg %0\;brvc 0f\;dec %0\;0:"
[(set_attr "cc" "clobber")
(set_attr "length" "3")])
(define_insn "ssabsqq2"
[(set (match_operand:QQ 0 "register_operand" "=r")
(ss_abs:QQ (match_operand:QQ 1 "register_operand" "0")))]
""
"sbrc %0,7\;neg %0\;sbrc %0,7\;dec %0"
[(set_attr "cc" "clobber")
(set_attr "length" "4")])
;; "ssneghq2" "ssnegha2" "ssnegsq2" "ssnegsa2"
;; "ssabshq2" "ssabsha2" "ssabssq2" "ssabssa2"
(define_expand "<code_stdname><mode>2"
[(set (match_dup 2)
(match_operand:ALL24S 1 "register_operand" ""))
(set (match_dup 2)
(ss_abs_neg:ALL24S (match_dup 2)))
(set (match_operand:ALL24S 0 "register_operand" "")
(match_dup 2))]
""
{
operands[2] = gen_rtx_REG (<MODE>mode, 26 - GET_MODE_SIZE (<MODE>mode));
})
;; "*ssneghq2" "*ssnegha2"
;; "*ssabshq2" "*ssabsha2"
(define_insn "*<code_stdname><mode>2"
[(set (reg:ALL2S 24)
(ss_abs_neg:ALL2S (reg:ALL2S 24)))]
""
"%~call __<code_stdname>_2"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; "*ssnegsq2" "*ssnegsa2"
;; "*ssabssq2" "*ssabssa2"
(define_insn "*<code_stdname><mode>2"
[(set (reg:ALL4S 22)
(ss_abs_neg:ALL4S (reg:ALL4S 22)))]
""
"%~call __<code_stdname>_4"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;******************************************************************************
; mul

View File

@ -91,12 +91,8 @@ extern int avr_starting_frame_offset (void);
extern void avr_output_addr_vec_elt (FILE *stream, int value);
extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
extern const char* avr_out_bitop (rtx, rtx*, int*);
extern const char* avr_out_plus (rtx*, int*, int*);
extern const char* avr_out_plus_noclobber (rtx*, int*, int*);
extern const char* avr_out_plus64 (rtx, int*);
extern const char* avr_out_plus (rtx, rtx*, int* =NULL, int* =NULL);
extern const char* avr_out_addto_sp (rtx*, int*);
extern const char* avr_out_minus (rtx*, int*, int*);
extern const char* avr_out_minus64 (rtx, int*);
extern const char* avr_out_xload (rtx, rtx*, int*);
extern const char* avr_out_movmem (rtx, rtx*, int*);
extern const char* avr_out_insert_bits (rtx*, int*);

View File

@ -2069,9 +2069,11 @@ avr_print_operand (FILE *file, rtx x, int code)
else if (REG_P (x))
{
if (x == zero_reg_rtx)
fprintf (file, "__zero_reg__");
fprintf (file, "__zero_reg__");
else if (code == 'r' && REGNO (x) < 32)
fprintf (file, "%d", (int) REGNO (x));
else
fprintf (file, reg_names[true_regnum (x) + abcd]);
fprintf (file, reg_names[REGNO (x) + abcd]);
}
else if (CONST_INT_P (x))
{
@ -2172,7 +2174,7 @@ avr_print_operand (FILE *file, rtx x, int code)
/* Use normal symbol for direct address no linker trampoline needed */
output_addr_const (file, x);
}
else if (GET_CODE (x) == CONST_FIXED)
else if (CONST_FIXED_P (x))
{
HOST_WIDE_INT ival = INTVAL (avr_to_int_mode (x));
if (code != 0)
@ -2213,9 +2215,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
default:
break;
case CC_OUT_PLUS:
case CC_OUT_PLUS_NOCLOBBER:
case CC_MINUS:
case CC_PLUS:
case CC_LDI:
{
rtx *op = recog_data.operand;
@ -2229,18 +2229,8 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
default:
gcc_unreachable();
case CC_OUT_PLUS:
avr_out_plus (op, &len_dummy, &icc);
cc = (enum attr_cc) icc;
break;
case CC_OUT_PLUS_NOCLOBBER:
avr_out_plus_noclobber (op, &len_dummy, &icc);
cc = (enum attr_cc) icc;
break;
case CC_MINUS:
avr_out_minus (op, &len_dummy, &icc);
case CC_PLUS:
avr_out_plus (insn, op, &len_dummy, &icc);
cc = (enum attr_cc) icc;
break;
@ -4246,7 +4236,7 @@ avr_out_compare (rtx insn, rtx *xop, int *plen)
/* Map fixed mode operands to integer operands with the same binary
representation. They are easier to handle in the remainder. */
if (CONST_FIXED == GET_CODE (xval))
if (CONST_FIXED_P (xval))
{
xreg = avr_to_int_mode (xop[0]);
xval = avr_to_int_mode (xop[1]);
@ -5987,19 +5977,32 @@ lshrsi3_out (rtx insn, rtx operands[], int *len)
}
/* Output addition of register XOP[0] and compile time constant XOP[2]:
/* Output addition of register XOP[0] and compile time constant XOP[2].
CODE == PLUS: perform addition by using ADD instructions or
CODE == MINUS: perform addition by using SUB instructions:
XOP[0] = XOP[0] + XOP[2]
Or perform addition/subtraction with register XOP[2] depending on CODE:
XOP[0] = XOP[0] +/- XOP[2]
and return "". If PLEN == NULL, print assembler instructions to perform the
addition; otherwise, set *PLEN to the length of the instruction sequence (in
words) printed with PLEN == NULL. XOP[3] is an 8-bit scratch register.
CODE == PLUS: perform addition by using ADD instructions.
CODE == MINUS: perform addition by using SUB instructions.
Set *PCC to effect on cc0 according to respective CC_* insn attribute. */
If PLEN == NULL, print assembler instructions to perform the operation;
otherwise, set *PLEN to the length of the instruction sequence (in words)
printed with PLEN == NULL. XOP[3] is an 8-bit scratch register or NULL_RTX.
Set *PCC to effect on cc0 according to respective CC_* insn attribute.
CODE_SAT == UNKNOWN: Perform ordinary, non-saturating operation.
CODE_SAT != UNKNOWN: Perform operation and saturate according to CODE_SAT.
If CODE_SAT != UNKNOWN then SIGN contains the sign of the summand resp.
the subtrahend in the original insn, provided it is a compile time constant.
In all other cases, SIGN is 0.
Return "". */
static void
avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc,
enum rtx_code code_sat = UNKNOWN, int sign = 0)
{
/* MODE of the operation. */
enum machine_mode mode = GET_MODE (xop[0]);
@ -6026,6 +6029,41 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
/* Value to add. There are two ways to add VAL: R += VAL and R -= -VAL. */
rtx xval = xop[2];
/* Output a BRVC instruction. Only needed with saturation. */
bool out_brvc = true;
if (plen)
*plen = 0;
if (REG_P (xop[2]))
{
*pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_SET_N;
for (i = 0; i < n_bytes; i++)
{
/* We operate byte-wise on the destination. */
op[0] = simplify_gen_subreg (QImode, xop[0], mode, i);
op[1] = simplify_gen_subreg (QImode, xop[2], mode, i);
if (i == 0)
avr_asm_len (code == PLUS ? "add %0,%1" : "sub %0,%1",
op, plen, 1);
else
avr_asm_len (code == PLUS ? "adc %0,%1" : "sbc %0,%1",
op, plen, 1);
}
if (reg_overlap_mentioned_p (xop[0], xop[2]))
{
gcc_assert (REGNO (xop[0]) == REGNO (xop[2]));
if (MINUS == code)
return;
}
goto saturate;
}
/* Except in the case of ADIW with 16-bit register (see below)
addition does not set cc0 in a usable way. */
@ -6034,13 +6072,39 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
if (CONST_FIXED_P (xval))
xval = avr_to_int_mode (xval);
/* Adding/Subtracting zero is a no-op. */
if (xval == const0_rtx)
{
*pcc = CC_NONE;
return;
}
if (MINUS == code)
xval = simplify_unary_operation (NEG, imode, xval, imode);
op[2] = xop[3];
if (plen)
*plen = 0;
if (SS_PLUS == code_sat && MINUS == code
&& sign < 0
&& 0x80 == (INTVAL (simplify_gen_subreg (QImode, xval, imode, n_bytes-1))
& GET_MODE_MASK (QImode)))
{
/* We compute x + 0x80 by means of SUB instructions. We negated the
constant subtrahend above and are left with x - (-128) so that we
need something like SUBI r,128 which does not exist because SUBI sets
V according to the sign of the subtrahend. Notice the only case
where this must be done is when NEG overflowed in case [2s] because
the V computation needs the right sign of the subtrahend. */
rtx msb = simplify_gen_subreg (QImode, xop[0], mode, n_bytes-1);
avr_asm_len ("subi %0,128" CR_TAB
"brmi 0f", &msb, plen, 2);
out_brvc = false;
goto saturate;
}
for (i = 0; i < n_bytes; i++)
{
@ -6082,7 +6146,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
op, plen, 1);
if (n_bytes == 2 && PLUS == code)
*pcc = CC_SET_ZN;
*pcc = CC_SET_ZN;
}
i++;
@ -6099,6 +6163,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
continue;
}
else if ((val8 == 1 || val8 == 0xff)
&& UNKNOWN == code_sat
&& !started
&& i == n_bytes - 1)
{
@ -6111,7 +6176,17 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
{
case PLUS:
gcc_assert (plen != NULL || REG_P (op[2]));
gcc_assert (plen != NULL || (op[2] && REG_P (op[2])));
if (plen != NULL && UNKNOWN != code_sat)
{
/* This belongs to the x + 0x80 corner case. The code with
ADD instruction is not smaller, thus make this case
expensive so that the caller won't pick it. */
*plen += 10;
break;
}
if (clobber_val != (int) val8)
avr_asm_len ("ldi %2,%1", op, plen, 1);
@ -6147,136 +6222,372 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
} /* for all sub-bytes */
/* No output doesn't change cc0. */
saturate:
if (UNKNOWN == code_sat)
return;
*pcc = (int) CC_CLOBBER;
/* Vanilla addition/subtraction is done. We are left with saturation.
We have to compute A = A <op> B where A is a register and
B is a register or a non-zero compile time constant CONST.
A is register class "r" if unsigned && B is REG. Otherwise, A is in "d".
B stands for the original operand $2 in INSN. In the case of B = CONST
SIGN in { -1, 1 } is the sign of B. Otherwise, SIGN is 0.
CODE is the instruction flavor we use in the asm sequence to perform <op>.
unsigned
operation | code | sat if | b is | sat value | case
-----------------+-------+----------+--------------+-----------+-------
+ as a + b | add | C == 1 | const, reg | u+ = 0xff | [1u]
+ as a - (-b) | sub | C == 0 | const | u+ = 0xff | [2u]
- as a - b | sub | C == 1 | const, reg | u- = 0 | [3u]
- as a + (-b) | add | C == 0 | const | u- = 0 | [4u]
signed
operation | code | sat if | b is | sat value | case
-----------------+-------+----------+--------------+-----------+-------
+ as a + b | add | V == 1 | const, reg | s+ | [1s]
+ as a - (-b) | sub | V == 1 | const | s+ | [2s]
- as a - b | sub | V == 1 | const, reg | s- | [3s]
- as a + (-b) | add | V == 1 | const | s- | [4s]
s+ = b < 0 ? -0x80 : 0x7f
s- = b < 0 ? 0x7f : -0x80
The cases a - b actually perform a - (-(-b)) if B is CONST.
*/
op[0] = simplify_gen_subreg (QImode, xop[0], mode, n_bytes-1);
op[1] = n_bytes > 1
? simplify_gen_subreg (QImode, xop[0], mode, n_bytes-2)
: NULL_RTX;
if (!plen && flag_print_asm_name)
avr_fdump (asm_out_file, ";; %C (%C)\n", code_sat, code);
bool need_copy = true;
int len_call = 1 + AVR_HAVE_JMP_CALL;
if (plen && *plen == 0)
*pcc = CC_NONE;
switch (code_sat)
{
default:
gcc_unreachable();
case SS_PLUS:
case SS_MINUS:
if (!plen && flag_print_asm_name)
avr_fdump (asm_out_file, ";; %s = %r\n", sign < 0 ? "neg" : "pos",
xop[2]);
if (out_brvc)
avr_asm_len ("brvc 0f", op, plen, 1);
if (reg_overlap_mentioned_p (xop[0], xop[2]))
{
/* [1s,reg] */
if (n_bytes == 1)
avr_asm_len ("ldi %0,0x7f" CR_TAB
"adc %0,__zero_reg__", op, plen, 2);
else
avr_asm_len ("ldi %0,0x7f" CR_TAB
"ldi %1,0xff" CR_TAB
"adc %1,__zero_reg__" CR_TAB
"adc %0,__zero_reg__", op, plen, 4);
}
else if (sign == 0 && PLUS == code)
{
/* [1s,reg] */
op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1);
if (n_bytes == 1)
avr_asm_len ("ldi %0,0x80" CR_TAB
"sbrs %2,7" CR_TAB
"dec %0", op, plen, 3);
else
avr_asm_len ("ldi %0,0x80" CR_TAB
"cp %2,%0" CR_TAB
"sbc %1,%1" CR_TAB
"sbci %0,0", op, plen, 4);
}
else if (sign == 0 && MINUS == code)
{
/* [3s,reg] */
op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1);
if (n_bytes == 1)
avr_asm_len ("ldi %0,0x7f" CR_TAB
"sbrs %2,7" CR_TAB
"inc %0", op, plen, 3);
else
avr_asm_len ("ldi %0,0x7f" CR_TAB
"cp %0,%2" CR_TAB
"sbc %1,%1" CR_TAB
"sbci %0,-1", op, plen, 4);
}
else if ((sign < 0) ^ (SS_MINUS == code_sat))
{
/* [1s,const,B < 0] [2s,B < 0] */
/* [3s,const,B > 0] [4s,B > 0] */
if (n_bytes == 8)
{
avr_asm_len ("%~call __clr_8", op, plen, len_call);
need_copy = false;
}
avr_asm_len ("ldi %0,0x80", op, plen, 1);
if (n_bytes > 1 && need_copy)
avr_asm_len ("clr %1", op, plen, 1);
}
else if ((sign > 0) ^ (SS_MINUS == code_sat))
{
/* [1s,const,B > 0] [2s,B > 0] */
/* [3s,const,B < 0] [4s,B < 0] */
if (n_bytes == 8)
{
avr_asm_len ("sec" CR_TAB
"%~call __sbc_8", op, plen, 1 + len_call);
need_copy = false;
}
avr_asm_len ("ldi %0,0x7f", op, plen, 1);
if (n_bytes > 1 && need_copy)
avr_asm_len ("ldi %1,0xff", op, plen, 1);
}
else
gcc_unreachable();
break;
case US_PLUS:
/* [1u] : [2u] */
avr_asm_len (PLUS == code ? "brcc 0f" : "brcs 0f", op, plen, 1);
if (n_bytes == 8)
{
if (MINUS == code)
avr_asm_len ("sec", op, plen, 1);
avr_asm_len ("%~call __sbc_8", op, plen, len_call);
need_copy = false;
}
else
{
if (MINUS == code && !test_hard_reg_class (LD_REGS, op[0]))
avr_asm_len ("sec" CR_TAB "sbc %0,%0", op, plen, 2);
else
avr_asm_len (PLUS == code ? "sbc %0,%0" : "ldi %0,0xff",
op, plen, 1);
}
break; /* US_PLUS */
case US_MINUS:
/* [4u] : [3u] */
avr_asm_len (PLUS == code ? "brcs 0f" : "brcc 0f", op, plen, 1);
if (n_bytes == 8)
{
avr_asm_len ("%~call __clr_8", op, plen, len_call);
need_copy = false;
}
else
avr_asm_len ("clr %0", op, plen, 1);
break;
}
/* We set the MSB in the unsigned case and the 2 MSBs in the signed case.
Now copy the right value to the LSBs. */
if (need_copy && n_bytes > 1)
{
if (US_MINUS == code_sat || US_PLUS == code_sat)
{
avr_asm_len ("mov %1,%0", op, plen, 1);
if (n_bytes > 2)
{
op[0] = xop[0];
if (AVR_HAVE_MOVW)
avr_asm_len ("movw %0,%1", op, plen, 1);
else
avr_asm_len ("mov %A0,%1" CR_TAB
"mov %B0,%1", op, plen, 2);
}
}
else if (n_bytes > 2)
{
op[0] = xop[0];
avr_asm_len ("mov %A0,%1" CR_TAB
"mov %B0,%1", op, plen, 2);
}
}
if (need_copy && n_bytes == 8)
{
if (AVR_HAVE_MOVW)
avr_asm_len ("movw %r0+2,%0" CR_TAB
"movw %r0+4,%0", xop, plen, 2);
else
avr_asm_len ("mov %r0+2,%0" CR_TAB
"mov %r0+3,%0" CR_TAB
"mov %r0+4,%0" CR_TAB
"mov %r0+5,%0", xop, plen, 4);
}
avr_asm_len ("0:", op, plen, 0);
}
/* Output addition of register XOP[0] and compile time constant XOP[2]:
/* Output addition/subtraction of register XOP[0] and a constant XOP[2] that
is ont a compile-time constant:
XOP[0] = XOP[0] + XOP[2]
XOP[0] = XOP[0] +/- XOP[2]
and return "". If PLEN == NULL, print assembler instructions to perform the
addition; otherwise, set *PLEN to the length of the instruction sequence (in
words) printed with PLEN == NULL.
If PCC != 0 then set *PCC to the the instruction sequence's effect on the
condition code (with respect to XOP[0]). */
This is a helper for the function below. The only insns that need this
are additions/subtraction for pointer modes, i.e. HImode and PSImode. */
static const char*
avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc)
{
enum machine_mode mode = GET_MODE (xop[0]);
int n_bytes = GET_MODE_SIZE (mode);
/* Only pointer modes want to add symbols. */
gcc_assert (mode == HImode || mode == PSImode);
*pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_SET_N;
avr_asm_len (PLUS == code
? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))"
: "subi %A0,lo8(%2)" CR_TAB "sbci %B0,hi8(%2)",
xop, plen, -2);
if (3 == n_bytes)
avr_asm_len (PLUS == code
? "sbci %C0,hlo8((-%2))"
: "sbci %C0,hlo8(%2)", xop, plen, 1);
return "";
}
/* Prepare operands of addition/subtraction to be used with avr_out_plus_1.
INSN is a single_set insn with a binary operation as SET_SRC that is
one of: PLUS, SS_PLUS, US_PLUS, MINUS, SS_MINUS, US_MINUS.
XOP are the operands of INSN. In the case of 64-bit operations with
constant XOP[] has just one element: The summand/subtrahend in XOP[0].
The non-saturating insns up to 32 bits may or may not supply a "d" class
scratch as XOP[3].
If PLEN == NULL output the instructions.
If PLEN != NULL set *PLEN to the length of the sequence in words.
PCC is a pointer to store the instructions' effect on cc0.
PCC may be NULL.
PLEN and PCC default to NULL.
Return "" */
const char*
avr_out_plus (rtx *xop, int *plen, int *pcc)
avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc)
{
int len_plus, len_minus;
int cc_plus, cc_minus, cc_dummy;
int len_plus, len_minus;
rtx op[4];
rtx xdest = SET_DEST (single_set (insn));
enum machine_mode mode = GET_MODE (xdest);
enum machine_mode imode = int_mode_for_mode (mode);
int n_bytes = GET_MODE_SIZE (mode);
enum rtx_code code_sat = GET_CODE (SET_SRC (single_set (insn)));
enum rtx_code code
= (PLUS == code_sat || SS_PLUS == code_sat || US_PLUS == code_sat
? PLUS : MINUS);
if (!pcc)
pcc = &cc_dummy;
/* Work out if XOP[0] += XOP[2] is better or XOP[0] -= -XOP[2]. */
avr_out_plus_1 (xop, &len_plus, PLUS, &cc_plus);
avr_out_plus_1 (xop, &len_minus, MINUS, &cc_minus);
/* Prefer MINUS over PLUS if size is equal because it sets cc0. */
/* PLUS and MINUS don't saturate: Use modular wrap-around. */
if (PLUS == code_sat || MINUS == code_sat)
code_sat = UNKNOWN;
if (n_bytes <= 4 && REG_P (xop[2]))
{
avr_out_plus_1 (xop, plen, code, pcc, code_sat);
return "";
}
if (8 == n_bytes)
{
op[0] = gen_rtx_REG (DImode, ACC_A);
op[1] = gen_rtx_REG (DImode, ACC_A);
op[2] = avr_to_int_mode (xop[0]);
}
else
{
if (!REG_P (xop[2])
&& !CONST_INT_P (xop[2])
&& !CONST_FIXED_P (xop[2]))
{
return avr_out_plus_symbol (xop, code, plen, pcc);
}
op[0] = avr_to_int_mode (xop[0]);
op[1] = avr_to_int_mode (xop[1]);
op[2] = avr_to_int_mode (xop[2]);
}
/* Saturations and 64-bit operations don't have a clobber operand.
For the other cases, the caller will provide a proper XOP[3]. */
op[3] = PARALLEL == GET_CODE (PATTERN (insn)) ? xop[3] : NULL_RTX;
/* Saturation will need the sign of the original operand. */
rtx xmsb = simplify_gen_subreg (QImode, op[2], imode, n_bytes-1);
int sign = INTVAL (xmsb) < 0 ? -1 : 1;
/* If we subtract and the subtrahend is a constant, then negate it
so that avr_out_plus_1 can be used. */
if (MINUS == code)
op[2] = simplify_unary_operation (NEG, imode, op[2], imode);
/* Work out the shortest sequence. */
avr_out_plus_1 (op, &len_minus, MINUS, &cc_plus, code_sat, sign);
avr_out_plus_1 (op, &len_plus, PLUS, &cc_minus, code_sat, sign);
if (plen)
{
*plen = (len_minus <= len_plus) ? len_minus : len_plus;
*pcc = (len_minus <= len_plus) ? cc_minus : cc_plus;
}
else if (len_minus <= len_plus)
avr_out_plus_1 (xop, NULL, MINUS, pcc);
avr_out_plus_1 (op, NULL, MINUS, pcc, code_sat, sign);
else
avr_out_plus_1 (xop, NULL, PLUS, pcc);
avr_out_plus_1 (op, NULL, PLUS, pcc, code_sat, sign);
return "";
}
/* Same as above but XOP has just 3 entries.
Supply a dummy 4th operand. */
const char*
avr_out_plus_noclobber (rtx *xop, int *plen, int *pcc)
{
rtx op[4];
op[0] = xop[0];
op[1] = xop[1];
op[2] = xop[2];
op[3] = NULL_RTX;
return avr_out_plus (op, plen, pcc);
}
/* Output subtraction of register XOP[0] and compile time constant XOP[2]:
XOP[0] = XOP[0] - XOP[2]
This is basically the same as `avr_out_plus' except that we subtract.
It's needed because (minus x const) is not mapped to (plus x -const)
for the fixed point modes. */
const char*
avr_out_minus (rtx *xop, int *plen, int *pcc)
{
rtx op[4];
if (pcc)
*pcc = (int) CC_SET_CZN;
if (REG_P (xop[2]))
return avr_asm_len ("sub %A0,%A2" CR_TAB
"sbc %B0,%B2", xop, plen, -2);
if (!CONST_INT_P (xop[2])
&& !CONST_FIXED_P (xop[2]))
return avr_asm_len ("subi %A0,lo8(%2)" CR_TAB
"sbci %B0,hi8(%2)", xop, plen, -2);
op[0] = avr_to_int_mode (xop[0]);
op[1] = avr_to_int_mode (xop[1]);
op[2] = gen_int_mode (-INTVAL (avr_to_int_mode (xop[2])),
GET_MODE (op[0]));
op[3] = xop[3];
return avr_out_plus (op, plen, pcc);
}
/* Prepare operands of adddi3_const_insn to be used with avr_out_plus_1. */
const char*
avr_out_plus64 (rtx addend, int *plen)
{
int cc_dummy;
rtx op[4];
op[0] = gen_rtx_REG (DImode, 18);
op[1] = op[0];
op[2] = addend;
op[3] = NULL_RTX;
avr_out_plus_1 (op, plen, MINUS, &cc_dummy);
return "";
}
/* Prepare operands of subdi3_const_insn to be used with avr_out_plus64. */
const char*
avr_out_minus64 (rtx subtrahend, int *plen)
{
rtx xneg = avr_to_int_mode (subtrahend);
xneg = simplify_unary_operation (NEG, DImode, xneg, DImode);
return avr_out_plus64 (xneg, plen);
}
/* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile
time constant XOP[2]:
@ -7004,13 +7315,7 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break;
case ADJUST_LEN_PLUS64: avr_out_plus64 (op[0], &len); break;
case ADJUST_LEN_MINUS: avr_out_minus (op, &len, NULL); break;
case ADJUST_LEN_MINUS64: avr_out_minus64 (op[0], &len); break;
case ADJUST_LEN_OUT_PLUS_NOCLOBBER:
avr_out_plus_noclobber (op, &len, NULL); break;
case ADJUST_LEN_PLUS: avr_out_plus (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;
@ -8897,8 +9202,8 @@ avr_rtx_costs (rtx x, int codearg, int outer_code,
static int
avr_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
addr_space_t as ATTRIBUTE_UNUSED,
bool speed ATTRIBUTE_UNUSED)
addr_space_t as ATTRIBUTE_UNUSED,
bool speed ATTRIBUTE_UNUSED)
{
int cost = 4;

View File

@ -91,7 +91,7 @@
;; Condition code settings.
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,
out_plus, out_plus_noclobber,ldi,minus"
plus,ldi"
(const_string "none"))
(define_attr "type" "branch,branch1,arith,xcall"
@ -138,8 +138,7 @@
;; Otherwise do special processing depending on the attribute.
(define_attr "adjust_len"
"out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp,
minus, minus64,
"out_bitop, plus, addto_sp,
tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
ufract, sfract,
@ -250,6 +249,10 @@
(define_code_iterator xior [xor ior])
(define_code_iterator eqne [eq ne])
(define_code_iterator ss_addsub [ss_plus ss_minus])
(define_code_iterator us_addsub [us_plus us_minus])
(define_code_iterator ss_abs_neg [ss_abs ss_neg])
;; Define code attributes
(define_code_attr extend_su
[(sign_extend "s")
@ -268,6 +271,10 @@
[(zero_extend "r")
(sign_extend "d")])
(define_code_attr abelian
[(ss_minus "") (us_minus "")
(ss_plus "%") (us_plus "%")])
;; Map RTX code to its standard insn name
(define_code_attr code_stdname
[(ashift "ashl")
@ -275,7 +282,10 @@
(lshiftrt "lshr")
(ior "ior")
(xor "xor")
(rotate "rotl")])
(rotate "rotl")
(ss_plus "ssadd") (ss_minus "sssub") (ss_neg "ssneg") (ss_abs "ssabs")
(us_plus "usadd") (us_minus "ussub") (us_neg "usneg")
])
;;========================================================================
;; The following is used by nonlocal_goto and setjmp.
@ -1181,17 +1191,11 @@
(match_operand:ALL2 2 "nonmemory_or_const_operand" "r,s,IJ YIJ,n Ynn")))]
""
{
if (REG_P (operands[2]))
return "add %A0,%A2\;adc %B0,%B2";
else if (CONST_INT_P (operands[2])
|| CONST_FIXED == GET_CODE (operands[2]))
return avr_out_plus_noclobber (operands, NULL, NULL);
else
return "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))";
return avr_out_plus (insn, operands);
}
[(set_attr "length" "2,2,2,2")
(set_attr "adjust_len" "*,*,out_plus_noclobber,out_plus_noclobber")
(set_attr "cc" "set_n,set_czn,out_plus_noclobber,out_plus_noclobber")])
[(set_attr "length" "2")
(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
;; Adding a constant to NO_LD_REGS might have lead to a reload of
;; that constant to LD_REGS. We don't add a scratch to *addhi3
@ -1238,13 +1242,11 @@
(clobber (match_scratch:QI 3 "=X ,X ,&d"))]
""
{
gcc_assert (REGNO (operands[0]) == REGNO (operands[1]));
return avr_out_plus (operands, NULL, NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "length" "4")
(set_attr "adjust_len" "out_plus")
(set_attr "cc" "out_plus")])
(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
;; "addsi3"
@ -1257,14 +1259,11 @@
(clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
{
if (REG_P (operands[2]))
return "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2";
return avr_out_plus (operands, NULL, NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "length" "4,4,8")
(set_attr "adjust_len" "*,out_plus,out_plus")
(set_attr "cc" "set_n,out_plus,out_plus")])
[(set_attr "length" "4")
(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
(define_insn "*addpsi3_zero_extend.qi"
[(set (match_operand:PSI 0 "register_operand" "=r")
@ -1318,22 +1317,11 @@
(clobber (match_scratch:QI 3 "=X,X ,X,&d"))]
""
{
static const char * const asm_code[] =
{
"add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2",
"subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))",
"",
""
};
if (*asm_code[which_alternative])
return asm_code[which_alternative];
return avr_out_plus (operands, NULL, NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "length" "3,3,3,6")
(set_attr "adjust_len" "*,*,out_plus,out_plus")
(set_attr "cc" "set_n,set_czn,out_plus,out_plus")])
[(set_attr "length" "3")
(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
(define_insn "subpsi3"
[(set (match_operand:PSI 0 "register_operand" "=r")
@ -1401,10 +1389,10 @@
(clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
{
return avr_out_minus (operands, NULL, NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "adjust_len" "minus")
(set_attr "cc" "minus")])
[(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
(define_insn "*subhi3_zero_extend1"
[(set (match_operand:HI 0 "register_operand" "=r")
@ -1438,14 +1426,10 @@
(clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
{
if (REG_P (operands[2]))
return "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2";
return avr_out_minus (operands, NULL, NULL);
return avr_out_plus (insn, operands);
}
[(set_attr "length" "4")
(set_attr "adjust_len" "*,minus,minus")
(set_attr "cc" "set_czn")])
[(set_attr "adjust_len" "plus")
(set_attr "cc" "plus")])
(define_insn "*subsi3_zero_extend"
[(set (match_operand:SI 0 "register_operand" "=r")

View File

@ -1,3 +1,24 @@
2012-09-15 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* gcc.target/avr/torture/fix-types.h: New.
* gcc.target/avr/torture/vals-hr.def: New.
* gcc.target/avr/torture/vals-r.def: New.
* gcc.target/avr/torture/vals-k.def: New.
* gcc.target/avr/torture/vals-ur.def: New.
* gcc.target/avr/torture/vals-uk.def: New.
* gcc.target/avr/torture/vals-uhr.def: New.
* gcc.target/avr/torture/vals-llk.def: New.
* gcc.target/avr/torture/vals-ullk.def: New.
* gcc.target/avr/torture/sat-hr-plus-minus.c: New.
* gcc.target/avr/torture/sat-r-plus-minus.c: New.
* gcc.target/avr/torture/sat-k-plus-minus.c: New.
* gcc.target/avr/torture/sat-ur-plus-minus.c: New.
* gcc.target/avr/torture/sat-uk-plus-minus.c: New.
* gcc.target/avr/torture/sat-uhr-plus-minus.c: New.
* gcc.target/avr/torture/sat-llk-plus-minus.c: New.
* gcc.target/avr/torture/sat-ullk-plus-minus.c: New.
2012-09-14 Dehao Chen <dehao@google.com>
* g++.dg/debug/dwarf2/deallocator.C: New test.

View File

@ -0,0 +1,134 @@
typedef __INT8_TYPE__ int_hr_t;
typedef __UINT8_TYPE__ int_uhr_t;
typedef __INT16_TYPE__ int_hk_t;
typedef __UINT16_TYPE__ int_uhk_t;
typedef __INT16_TYPE__ int_r_t;
typedef __UINT16_TYPE__ int_ur_t;
typedef __INT32_TYPE__ int_k_t;
typedef __UINT32_TYPE__ int_uk_t;
typedef __INT32_TYPE__ int_lr_t;
typedef __UINT32_TYPE__ int_ulr_t;
typedef __INT64_TYPE__ int_lk_t;
typedef __UINT64_TYPE__ int_ulk_t;
typedef __INT64_TYPE__ int_llr_t;
typedef __UINT64_TYPE__ int_ullr_t;
typedef __INT64_TYPE__ int_llk_t;
typedef __UINT64_TYPE__ int_ullk_t;
typedef __INT16_TYPE__ xint_hr_t;
typedef __UINT16_TYPE__ xint_uhr_t;
typedef __INT32_TYPE__ xint_hk_t;
typedef __UINT32_TYPE__ xint_uhk_t;
typedef __INT32_TYPE__ xint_r_t;
typedef __UINT32_TYPE__ xint_ur_t;
typedef __INT64_TYPE__ xint_k_t;
typedef __UINT64_TYPE__ xint_uk_t;
typedef __INT64_TYPE__ xint_lr_t;
typedef __UINT64_TYPE__ xint_ulr_t;
#define INThr_MAX __INT8_MAX__
#define INThr_MIN (-__INT8_MAX__-1)
#define INTuhr_MAX __UINT8_MAX__
#define INTr_MAX __INT16_MAX__
#define INTr_MIN (-__INT16_MAX__-1)
#define INTur_MAX __UINT16_MAX__
#define INThk_MAX __INT16_MAX__
#define INThk_MIN (-__INT16_MAX__-1)
#define INTuhk_MAX __UINT16_MAX__
#define INTlr_MAX __INT32_MAX__
#define INTlr_MIN (-__INT32_MAX__-1)
#define INTulr_MAX __UINT32_MAX__
#define INTk_MAX __INT32_MAX__
#define INTk_MIN (-__INT32_MAX__-1)
#define INTuk_MAX __UINT32_MAX__
#define INTlk_MAX __INT64_MAX__
#define INTlk_MIN (-__INT64_MAX__-1)
#define INTulk_MAX __UINT64_MAX__
#define INTllk_MAX __INT64_MAX__
#define INTllk_MIN (-__INT64_MAX__-1)
#define INTullk_MAX __UINT64_MAX__
#define SS_FUN(NAME, OP, T, FX) \
T __attribute__((noinline,noclone)) \
NAME##_##FX (T fa, T fb) \
{ \
int_##FX##_t ia; \
int_##FX##_t ib; \
xint_##FX##_t ic; \
__builtin_memcpy (&ia, &fa, sizeof (ia)); \
__builtin_memcpy (&ib, &fb, sizeof (ib)); \
ic = (xint_##FX##_t) ia OP ib; \
if (ic > INT##FX##_MAX) \
ic = INT##FX##_MAX; \
else if (ic < INT##FX##_MIN) \
ic = INT##FX##_MIN; \
ia = (int_##FX##_t) ic; \
__builtin_memcpy (&fa, &ia, sizeof (ia)); \
return fa; \
}
#define US_FUN(NAME, OP, T, FX) \
T __attribute__((noinline,noclone)) \
NAME##_##FX (T fa, T fb) \
{ \
int_##FX##_t ia; \
int_##FX##_t ib; \
xint_##FX##_t ic; \
__builtin_memcpy (&ia, &fa, sizeof (ia)); \
__builtin_memcpy (&ib, &fb, sizeof (ib)); \
ic = (xint_##FX##_t) ia OP ib; \
if (ic > INT##FX##_MAX) \
ic = INT##FX##_MAX; \
else if (ic < 0) \
ic = 0; \
ia = (int_##FX##_t) ic; \
__builtin_memcpy (&fa, &ia, sizeof (ia)); \
return fa; \
}
#define SS_LFUN(NAME, OP, T, FX, CMP) \
T __attribute__((noinline,noclone)) \
NAME##_##FX (T fa, T fb) \
{ \
int_##FX##_t ia; \
int_##FX##_t ib; \
int_##FX##_t ic; \
__builtin_memcpy (&ia, &fa, sizeof (ia)); \
__builtin_memcpy (&ib, &fb, sizeof (ib)); \
ic = (int_##FX##_t) ia OP ib; \
if (ic < ia && ib CMP 0) \
ic = INT##FX##_MAX; \
else if (ic > ia && 0 CMP ib) \
ic = INT##FX##_MIN; \
__builtin_memcpy (&fa, &ic, sizeof (ic)); \
return fa; \
}
#define US_LFUN(NAME, OP, T, FX, CMP) \
T __attribute__((noinline,noclone)) \
NAME##_##FX (T fa, T fb) \
{ \
int_##FX##_t ia; \
int_##FX##_t ib; \
int_##FX##_t ic; \
__builtin_memcpy (&ia, &fa, sizeof (ia)); \
__builtin_memcpy (&ib, &fb, sizeof (ib)); \
ic = (int_##FX##_t) ia OP ib; \
if (ia CMP ic && 1 CMP 0) \
ic = INT##FX##_MAX; \
if (ia CMP ic && 0 CMP 1) \
ic = 0; \
__builtin_memcpy (&fa, &ic, sizeof (ic)); \
return fa; \
}

View File

@ -0,0 +1,98 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef short _Fract fx_t;
typedef short _Sat _Fract satfx_t;
typedef char intfx_t;
SS_FUN (ss_add, +, fx_t, hr)
SS_FUN (ss_sub, -, fx_t, hr)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t ss_add2_##N (satfx_t a) \
{ \
return ss_add_hr (a, X##P##-##7hr); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_add_##N (satfx_t a) \
{ \
return a + X##P##-##7hr; \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub2_##N (satfx_t a) \
{ \
return ss_sub_hr (a, X##P##-##7hr); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub_##N (satfx_t a) \
{ \
return a - X##P##-##7hr; \
}
#include "vals-hr.def"
#undef VAL
__attribute__((noinline,noclone))
satfx_t ss_add2_99 (satfx_t a)
{
return ss_add_hr (a, __FRACT_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_add_99 (satfx_t a)
{
return a + __FRACT_MIN__;
}
__attribute__((noinline,noclone))
satfx_t ss_sub2_99 (satfx_t a)
{
return ss_sub_hr (a, __FRACT_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_sub_99 (satfx_t a)
{
return a - __FRACT_MIN__;
}
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
ss_add_##N, ss_add2_##N, \
ss_sub_##N, ss_sub2_##N,
#include "vals-hr.def"
VAL (99,)
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, 1, 2, 0x7f, 0x80, 0x81, 0xff,
0x40, 0x3e, 0x3f, 0xbf, 0xc0, 0xc1
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,108 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef _Accum fx_t;
typedef _Sat _Accum satfx_t;
typedef long intfx_t;
SS_FUN (ss_add, +, fx_t, k)
SS_FUN (ss_sub, -, fx_t, k)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t ss_add2_##N (satfx_t a) \
{ \
return ss_add_k (a, X##P##-##16k); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_add_##N (satfx_t a) \
{ \
return a + X##P##-##16k; \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub2_##N (satfx_t a) \
{ \
return ss_sub_k (a, X##P##-##16k); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub_##N (satfx_t a) \
{ \
return a - X##P##-##16k; \
}
#include "vals-k.def"
#undef VAL
__attribute__((noinline,noclone))
satfx_t ss_add2_99 (satfx_t a)
{
return ss_add_k (a, __ACCUM_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_add_99 (satfx_t a)
{
return a + __ACCUM_MIN__;
}
__attribute__((noinline,noclone))
satfx_t ss_sub2_99 (satfx_t a)
{
return ss_sub_k (a, __ACCUM_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_sub_99 (satfx_t a)
{
return a - __ACCUM_MIN__;
}
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
ss_add_##N, ss_add2_##N, \
ss_sub_##N, ss_sub2_##N,
#include "vals-k.def"
VAL (99,)
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x40000000, 0x3e800000, 0x3f800000,
0x7ffffffe, 0x7fffffff, 0x7f800000,
0x7f7f7f7f, 0x7f810080, 0x7f008000,
0x7f000001,
0x80000000, 0x80000001, 0x80808080,
0x80810000, 0x80ffffff, 0x80fffffe,
0x81000000, 0x81800000, 0x81800000,
0xff000000, 0xffffff01, 0xffffff80,
0xffffff7f, 0xff80ff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,108 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef long long _Accum fx_t;
typedef long long _Sat _Accum satfx_t;
typedef long long intfx_t;
SS_LFUN (ss_add, +, fx_t, llk, >)
SS_LFUN (ss_sub, -, fx_t, llk, <)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t ss_add2_##N (satfx_t a) \
{ \
return ss_add_llk (a, X##P##-##48llk); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_add_##N (satfx_t a) \
{ \
return a + X##P##-##48llk; \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub2_##N (satfx_t a) \
{ \
return ss_sub_llk (a, X##P##-##48llk); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub_##N (satfx_t a) \
{ \
return a - X##P##-##48llk; \
}
#include "vals-llk.def"
#undef VAL
__attribute__((noinline,noclone))
satfx_t ss_add2_99 (satfx_t a)
{
return ss_add_llk (a, __LLACCUM_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_add_99 (satfx_t a)
{
return a + __LLACCUM_MIN__;
}
__attribute__((noinline,noclone))
satfx_t ss_sub2_99 (satfx_t a)
{
return ss_sub_llk (a, __LLACCUM_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_sub_99 (satfx_t a)
{
return a - __LLACCUM_MIN__;
}
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
ss_add_##N, ss_add2_##N, \
ss_sub_##N, ss_sub2_##N,
#include "vals-llk.def"
VAL (99,)
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x4000000000000000, 0x3e80000000000000, 0x3f80000000000000,
0x7ffffffffffffffe, 0x7fffffffffffffff, 0x7f80000000000000,
0x7f7f7f7f7f7f7f7f, 0x7f81000000000080, 0x7f00000080000000,
0x7f00000000000001,
0x8000000000000000, 0x8000000000000001, 0x8080808080808080,
0x8081000000000000, 0x80ffffffffffffff, 0x80fffffffffffffe,
0x8100000000000000, 0x8180000000000000, 0x818000000000000,
0xff00000000000000, 0xffffffffffffff01, 0xffffffffffffff80,
0xffffffffffffff7f, 0xff80ff80ff80ff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,107 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef _Fract fx_t;
typedef _Sat _Fract satfx_t;
typedef int intfx_t;
SS_FUN (ss_add, +, fx_t, r)
SS_FUN (ss_sub, -, fx_t, r)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t ss_add2_##N (satfx_t a) \
{ \
return ss_add_r (a, X##P##-##15r); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_add_##N (satfx_t a) \
{ \
return a + X##P##-##15r; \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub2_##N (satfx_t a) \
{ \
return ss_sub_r (a, X##P##-##15r); \
} \
__attribute__((noinline,noclone)) \
satfx_t ss_sub_##N (satfx_t a) \
{ \
return a - X##P##-##15r; \
}
#include "vals-r.def"
#undef VAL
__attribute__((noinline,noclone))
satfx_t ss_add2_99 (satfx_t a)
{
return ss_add_r (a, __FRACT_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_add_99 (satfx_t a)
{
return a + __FRACT_MIN__;
}
__attribute__((noinline,noclone))
satfx_t ss_sub2_99 (satfx_t a)
{
return ss_sub_r (a, __FRACT_MIN__);
}
__attribute__((noinline,noclone))
satfx_t ss_sub_99 (satfx_t a)
{
return a - __FRACT_MIN__;
}
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
ss_add_##N, ss_add2_##N, \
ss_sub_##N, ss_sub2_##N,
#include "vals-r.def"
VAL (99,)
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x4000, 0x3e80, 0x3f80,
0x7ffe, 0x7fff,
0x7f7f, 0x7f81, 0x7f80,
0x7f01,
0x8000, 0x8001, 0x8080,
0x8081, 0x80ff, 0x80fe,
0x8100, 0x8180, 0x817f,
0xff00, 0xff01, 0xff01,
0xff7f, 0xff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,73 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef unsigned short _Fract fx_t;
typedef unsigned short _Sat _Fract satfx_t;
typedef unsigned char intfx_t;
US_LFUN (us_add, +, fx_t, uhr, >)
US_LFUN (us_sub, -, fx_t, uhr, <)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t us_add2_##N (satfx_t a) \
{ \
return us_add_uhr (a, X##P##-##8uhr); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_add_##N (satfx_t a) \
{ \
return a + X##P##-##8uhr; \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub2_##N (satfx_t a) \
{ \
return us_sub_uhr (a, X##P##-##8uhr); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub_##N (satfx_t a) \
{ \
return a - X##P##-##8uhr; \
}
#include "vals-uhr.def"
#undef VAL
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
us_add_##N, us_add2_##N, \
us_sub_##N, us_sub2_##N,
#include "vals-uhr.def"
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, 1, 2, 0x7f, 0x80, 0x81, 0xff,
0x40, 0x3e, 0x3f, 0xbf, 0xc0, 0xc1
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,82 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef unsigned _Accum fx_t;
typedef unsigned _Sat _Accum satfx_t;
typedef unsigned long intfx_t;
US_LFUN (us_add, +, fx_t, uk, >)
US_LFUN (us_sub, -, fx_t, uk, <)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t us_add2_##N (satfx_t a) \
{ \
return us_add_uk (a, X##P##-##16uk); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_add_##N (satfx_t a) \
{ \
return a + X##P##-##16uk; \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub2_##N (satfx_t a) \
{ \
return us_sub_uk (a, X##P##-##16uk); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub_##N (satfx_t a) \
{ \
return a - X##P##-##16uk; \
}
#include "vals-uk.def"
#undef VAL
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
us_add_##N, us_add2_##N, \
us_sub_##N, us_sub2_##N,
#include "vals-uk.def"
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x40000000, 0x3e800000, 0x3f800000,
0x7ffffffe, 0x7fffffff, 0x7f800000,
0x7f7f7f7f, 0x7f810080, 0x7f008000,
0x7f000001,
0x80000000, 0x80000001, 0x80808080,
0x80810000, 0x80ffffff, 0x80fffffe,
0x81000000, 0x81800000, 0x81800000,
0xff000000, 0xffffff01, 0xffffff80,
0xffffff7f, 0xff80ff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,82 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef unsigned long long _Accum fx_t;
typedef unsigned long long _Sat _Accum satfx_t;
typedef unsigned long long intfx_t;
US_LFUN (us_add, +, fx_t, ullk, >)
US_LFUN (us_sub, -, fx_t, ullk, <)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t us_add2_##N (satfx_t a) \
{ \
return us_add_ullk (a, X##P##-##48ullk); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_add_##N (satfx_t a) \
{ \
return a + X##P##-##48ullk; \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub2_##N (satfx_t a) \
{ \
return us_sub_ullk (a, X##P##-##48ullk); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub_##N (satfx_t a) \
{ \
return a - X##P##-##48ullk; \
}
#include "vals-ullk.def"
#undef VAL
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
us_add_##N, us_add2_##N, \
us_sub_##N, us_sub2_##N,
#include "vals-ullk.def"
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x4000000000000000, 0x3e80000000000000, 0x3f80000000000000,
0x7ffffffffffffffe, 0x7fffffffffffffff, 0x7f80000000000000,
0x7f7f7f7f7f7f7f7f, 0x7f81000000000080, 0x7f00000080000000,
0x7f00000000000001,
0x8000000000000000, 0x8000000000000001, 0x8080808080808080,
0x8081000000000000, 0x80ffffffffffffff, 0x80fffffffffffffe,
0x8100000000000000, 0x8180000000000000, 0x818000000000000,
0xff00000000000000, 0xffffffffffffff01, 0xffffffffffffff80,
0xffffffffffffff7f, 0xff80ff80ff80ff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,82 @@
/* { dg-do run } */
/* { dg-options "-std=gnu99 -fwrapv" } */
#include "fix-types.h"
extern void abort (void);
extern void exit (int);
typedef unsigned _Fract fx_t;
typedef unsigned _Sat _Fract satfx_t;
typedef unsigned int intfx_t;
US_LFUN (us_add, +, fx_t, ur, >)
US_LFUN (us_sub, -, fx_t, ur, <)
#define VAL(N, X) \
__attribute__((noinline,noclone)) \
satfx_t us_add2_##N (satfx_t a) \
{ \
return us_add_ur (a, X##P##-##16ur); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_add_##N (satfx_t a) \
{ \
return a + X##P##-##16ur; \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub2_##N (satfx_t a) \
{ \
return us_sub_ur (a, X##P##-##16ur); \
} \
__attribute__((noinline,noclone)) \
satfx_t us_sub_##N (satfx_t a) \
{ \
return a - X##P##-##16ur; \
}
#include "vals-ur.def"
#undef VAL
satfx_t (* __flash const fun[])(satfx_t) =
{
#define VAL(N, X) \
us_add_##N, us_add2_##N, \
us_sub_##N, us_sub2_##N,
#include "vals-ur.def"
#undef VAL
};
const volatile __flash intfx_t vals[] =
{
0, -1, 1, -2, 2, -127, -128, -129,
0x7f, 0x80, 0x81, 0x100,
0x4000, 0x3e80, 0x3f80,
0x7ffe, 0x7fff,
0x7f7f, 0x7f81, 0x7f80,
0x7f01,
0x8000, 0x8001, 0x8080,
0x8081, 0x80ff, 0x80fe,
0x8100, 0x8180, 0x817f,
0xff00, 0xff01, 0xff01,
0xff7f, 0xff80
};
int main (void)
{
for (unsigned int i = 0; i < sizeof (vals) / sizeof (*vals); i++)
{
satfx_t a, f1, f2;
intfx_t val = vals[i];
__builtin_memcpy (&a, &val, sizeof (satfx_t));
for (unsigned int f = 0; f < sizeof (fun) / sizeof (*fun); f += 2)
{
if (fun[f](a) != fun[f+1](a))
abort();
}
}
exit (0);
return 0;
}

View File

@ -0,0 +1,12 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04,-0x3f)
VAL (07, 0x40)
VAL (08,-0x40)
VAL (10,-0x1)
VAL (12, 0x3f)
VAL (13,-0x3f)
VAL (14, 0x7f)
VAL (15,-0x7f)

View File

@ -0,0 +1,32 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (05, -0x1)
VAL (06, -0x3f)
VAL (07, 0x40000000)
VAL (08,-0x40000000)
VAL (10,-0x7fffffff)
VAL (11, 0x7fffffff)
VAL (12, 0x7f800000)
VAL (13,-0x7f800000)
VAL (14, 0x7f800001)
VAL (15,-0x7f800001)
VAL (16, 0x7f7f7f7f)
VAL (17,-0x7f7f7f7f)
VAL (18, 0x7f808080)
VAL (19,-0x7f808080)
VAL (20, 0x3e800000)
VAL (21,-0x3e800000)
VAL (22, 0x3f800000)
VAL (23,-0x3f800000)
VAL (24, 0x400000)
VAL (25,-0x400000)
VAL (26, 0x3f000000)
VAL (27,-0x3f000000)
VAL (28, 0xffff00)
VAL (29,-0xffff00)
VAL (30, 0x00ff00ff)
VAL (31,-0x00ff00ff)

View File

@ -0,0 +1,32 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (05, -0x1)
VAL (06, -0x3f)
VAL (07, 0x4000000000000000)
VAL (08,-0x4000000000000000)
VAL (10,-0x7fffffffffffffff)
VAL (11, 0x7fffffffffffffff)
VAL (12, 0x7f80000000000000)
VAL (13,-0x7f80000000000000)
VAL (14, 0x7f80000000000001)
VAL (15,-0x7f80000000000001)
VAL (16, 0x7f7f7f7f7f7f7f7f)
VAL (17,-0x7f7f7f7f7f7f7f7f)
VAL (18, 0x7f80808080808000)
VAL (19,-0x7f80808080808000)
VAL (20, 0x3e80000000000000)
VAL (21,-0x3e80000000000000)
VAL (22, 0x3f80000000000000)
VAL (23,-0x3f80000000000000)
VAL (24, 0x40000000000000)
VAL (25,-0x40000000000000)
VAL (26, 0x3f000000000000)
VAL (27,-0x3f000000000000)
VAL (28, 0xffffff00)
VAL (29,-0xffffff00)
VAL (30, 0x00ff00ff00ff00ff)
VAL (31,-0x00ff00ff00ff00ff)

View File

@ -0,0 +1,30 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (05, -0x1)
VAL (06, -0x3f)
VAL (07, 0x4000)
VAL (08,-0x4000)
VAL (10,-0x7fff)
VAL (11, 0x7fff)
VAL (12, 0x7f80)
VAL (13,-0x7f80)
VAL (14, 0x7f81)
VAL (15,-0x7f81)
VAL (16, 0x7f7f)
VAL (17,-0x7f7f)
VAL (18, 0x7f80)
VAL (19,-0x7f80)
VAL (20, 0x3e80)
VAL (21,-0x3e80)
VAL (22, 0x3f80)
VAL (23,-0x3f80)
VAL (24, 0x40)
VAL (25,-0x40)
VAL (26, 0x3f00)
VAL (27,-0x3f00)
VAL (30, 0x00ff)
VAL (31,-0x00ff)

View File

@ -0,0 +1,13 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (07, 0x40)
VAL (08, 0xc0)
VAL (10, 0xc1)
VAL (12, 0xff)
VAL (14, 0x7f)
VAL (16, 0x81)
VAL (20, 0xbf)
VAL (99, 0x80)

View File

@ -0,0 +1,23 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (07, 0x40000000)
VAL (08, 0xc0000000)
VAL (10, 0x7fffffff)
VAL (12, 0x7f800000)
VAL (14, 0x7f800001)
VAL (16, 0x7f7f7f7f)
VAL (18, 0x7f808000)
VAL (20, 0x3e800000)
VAL (22, 0x3f800000)
VAL (24, 0x40000000)
VAL (26, 0x3f000000)
VAL (28, 0xffff00)
VAL (30, 0x00ff00ff)
VAL (31, 0xff00ff00)
VAL (32, 0x10000000)
VAL (33, 0xff000000)
VAL (99, 0x80000000)

View File

@ -0,0 +1,20 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (07, 0x4000000000000000)
VAL (08, 0x4000000000000000)
VAL (10, 0x7fffffffffffffff)
VAL (12, 0x7f80000000000000)
VAL (14, 0x7f80000000000001)
VAL (16, 0x7f7f7f7f7f7f7f7f)
VAL (18, 0x7f80808080808000)
VAL (20, 0x3e80000000000000)
VAL (22, 0x3f80000000000000)
VAL (24, 0x40000000000000)
VAL (26, 0x3f000000000000)
VAL (28, 0xffffff00)
VAL (30, 0x00ff00ff00ff00ff)
VAL (99, 0x8000000000000000)

View File

@ -0,0 +1,17 @@
VAL (01, 0x0)
VAL (02, 0x1)
VAL (03, 0x3f)
VAL (04, 0x80)
VAL (07, 0x4000)
VAL (08, 0xc000)
VAL (10, 0x7fff)
VAL (12, 0x7f80)
VAL (14, 0x7f81)
VAL (16, 0x7f7f)
VAL (20, 0x3e80)
VAL (22, 0x3f80)
VAL (26, 0x3f00)
VAL (32, 0x100)
VAL (99, 0x8000)

View File

@ -1,3 +1,20 @@
2012-09-15 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* config/avr/lib1funcs-fixed.S (__ssneg_2, __ssabs_2, __ssneg_4,
__ssabs_4, __clr_8, __ssneg_8, __ssabs_8,
__usadd_8, __ussub_8, __ssadd_8, __sssub_8): New functions.
(__divsa3): Use __negsi2 to negate r_quoL.
* config/avr/lib1funcs.S (FALIAS): New macro.
(__divmodsi4): Break out and use __divmodsi4_neg1 as...
(__negsi2): ...this new function.
* config/avr/t-avr (LIB1ASMFUNCS): Add _negsi2, _clr_8,
_ssneg_2, _ssneg_4, _ssneg_8, _ssabs_2, _ssabs_4,
_ssabs_8, _ssadd_8, _sssub_8, _usadd_8, _ussub_8.
(LIB2FUNCS_EXCLUDE): Fix typo for _add _sub.
Add: _ssadd*, _sssub*, _ssneg*, _ssabs* for signed fixed modes.
Add: _usadd*, _ussub*, _usneg* for unsigned fixed modes.
2012-09-10 Oleg Endo <olegendo@gcc.gnu.org>
PR target/54089

View File

@ -808,8 +808,8 @@ DEFUN __divsa3
XCALL __udivusa3
sbrs r0, 7 ; negate result if needed
ret
NEG4 r_quoL
ret
;; negate r_quoL
XJMP __negsi2
ENDF __divsa3
#endif /* defined (L_divsa3) */
@ -872,3 +872,223 @@ ENDF __udivusa3
#undef r_divHL
#undef r_divHH
#undef r_cnt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 2 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; First Argument and Return Register
#define A0 24
#define A1 A0+1
#if defined (L_ssneg_2)
DEFUN __ssneg_2
NEG2 A0
brvc 0f
sbiw A0, 1
0: ret
ENDF __ssneg_2
#endif /* L_ssneg_2 */
#if defined (L_ssabs_2)
DEFUN __ssabs_2
sbrs A1, 7
ret
XJMP __ssneg_2
ENDF __ssabs_2
#endif /* L_ssabs_2 */
#undef A0
#undef A1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 4 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; First Argument and Return Register
#define A0 22
#define A1 A0+1
#define A2 A0+2
#define A3 A0+3
#if defined (L_ssneg_4)
DEFUN __ssneg_4
XCALL __negsi2
brvc 0f
ldi A3, 0x7f
ldi A2, 0xff
ldi A1, 0xff
ldi A0, 0xff
0: ret
ENDF __ssneg_4
#endif /* L_ssneg_4 */
#if defined (L_ssabs_4)
DEFUN __ssabs_4
sbrs A3, 7
ret
XJMP __ssneg_4
ENDF __ssabs_4
#endif /* L_ssabs_4 */
#undef A0
#undef A1
#undef A2
#undef A3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 8 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; First Argument and Return Register
#define A0 18
#define A1 A0+1
#define A2 A0+2
#define A3 A0+3
#define A4 A0+4
#define A5 A0+5
#define A6 A0+6
#define A7 A0+7
#if defined (L_clr_8)
FALIAS __usneguta2
FALIAS __usneguda2
FALIAS __usnegudq2
;; Clear Carry and all Bytes
DEFUN __clr_8
;; Clear Carry and set Z
sub A7, A7
;; FALLTHRU
ENDF __clr_8
;; Propagate Carry to all Bytes, Carry unaltered
DEFUN __sbc_8
sbc A7, A7
sbc A6, A6
wmov A4, A6
wmov A2, A6
wmov A0, A6
ret
ENDF __sbc_8
#endif /* L_clr_8 */
#if defined (L_ssneg_8)
FALIAS __ssnegta2
FALIAS __ssnegda2
FALIAS __ssnegdq2
DEFUN __ssneg_8
XCALL __negdi2
brvc 0f
;; A[] = 0x7fffffff
sec
XCALL __sbc_8
ldi A7, 0x7f
0: ret
ENDF __ssneg_8
#endif /* L_ssneg_8 */
#if defined (L_ssabs_8)
FALIAS __ssabsta2
FALIAS __ssabsda2
FALIAS __ssabsdq2
DEFUN __ssabs_8
sbrs A7, 7
ret
XJMP __ssneg_8
ENDF __ssabs_8
#endif /* L_ssabs_8 */
;; Second Argument
#define B0 10
#define B1 B0+1
#define B2 B0+2
#define B3 B0+3
#define B4 B0+4
#define B5 B0+5
#define B6 B0+6
#define B7 B0+7
#if defined (L_usadd_8)
FALIAS __usadduta3
FALIAS __usadduda3
FALIAS __usaddudq3
DEFUN __usadd_8
XCALL __adddi3
brcs 0f
ret
;; A[] = 0xffffffff
0: XJMP __sbc_8
ENDF __usadd_8
#endif /* L_usadd_8 */
#if defined (L_ussub_8)
FALIAS __ussubuta3
FALIAS __ussubuda3
FALIAS __ussubudq3
DEFUN __ussub_8
XCALL __subdi3
brcs 0f
ret
;; A[] = 0
0: XJMP __clr_8
ENDF __ussub_8
#endif /* L_ussub_8 */
#if defined (L_ssadd_8)
FALIAS __ssaddta3
FALIAS __ssaddda3
FALIAS __ssadddq3
DEFUN __ssadd_8
;; A = (B >= 0) ? INT64_MAX : INT64_MIN
XCALL __adddi3
brvc 0f
cpi B7, 0x80
XCALL __sbc_8
subi A7, 0x80
0: ret
ENDF __ssadd_8
#endif /* L_ssadd_8 */
#if defined (L_sssub_8)
FALIAS __sssubta3
FALIAS __sssubda3
FALIAS __sssubdq3
DEFUN __sssub_8
XCALL __subdi3
brvc 0f
;; A = (B < 0) ? INT64_MAX : INT64_MIN
ldi A7, 0x7f
cp A7, B7
XCALL __sbc_8
subi A7, 0x80
0: ret
ENDF __sssub_8
#endif /* L_sssub_8 */
#undef A0
#undef A1
#undef A2
#undef A3
#undef A4
#undef A5
#undef A6
#undef A7
#undef B0
#undef B1
#undef B2
#undef B3
#undef B4
#undef B5
#undef B6
#undef B7

View File

@ -91,6 +91,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
.endfunc
.endm
.macro FALIAS name
.global \name
.func \name
\name:
.size \name, .-\name
.endfunc
.endm
;; Negate a 2-byte value held in consecutive registers
.macro NEG2 reg
com \reg+1
@ -99,6 +107,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
.endm
;; Negate a 4-byte value held in consecutive registers
;; Sets the V flag for signed overflow tests if REG >= 16
.macro NEG4 reg
com \reg+3
com \reg+2
@ -1325,7 +1334,7 @@ DEFUN __divmodsi4
bst r_arg1HH,7 ; store sign of dividend
brtc 0f
com __tmp_reg__ ; r0.7 is sign of result
rcall __divmodsi4_neg1 ; dividend negative: negate
XCALL __negsi2 ; dividend negative: negate
0:
sbrc r_arg2HH,7
rcall __divmodsi4_neg2 ; divisor negative: negate
@ -1333,16 +1342,7 @@ DEFUN __divmodsi4
sbrc __tmp_reg__, 7 ; correct quotient sign
rcall __divmodsi4_neg2
brtc __divmodsi4_exit ; correct remainder sign
__divmodsi4_neg1:
;; correct dividend/remainder sign
com r_arg1HH
com r_arg1HL
com r_arg1H
neg r_arg1L
sbci r_arg1H, 0xff
sbci r_arg1HL,0xff
sbci r_arg1HH,0xff
ret
XJMP __negsi2
__divmodsi4_neg2:
;; correct divisor/quotient sign
com r_arg2HH
@ -1357,6 +1357,16 @@ __divmodsi4_exit:
ENDF __divmodsi4
#endif /* defined (L_divmodsi4) */
#if defined (L_negsi2)
;; (set (reg:SI 22)
;; (neg:SI (reg:SI 22)))
;; Sets the V flag for signed overflow tests
DEFUN __negsi2
NEG4 22
ret
ENDF __negsi2
#endif /* L_negsi2 */
#undef r_remHH
#undef r_remHL
#undef r_remH
@ -1689,6 +1699,8 @@ ENDF __divdi3_moddi3
;; (set (reg:DI 18)
;; (plus:DI (reg:DI 18)
;; (reg:DI 10)))
;; Sets the V flag for signed overflow tests
;; Sets the C flag for unsigned overflow tests
DEFUN __adddi3
ADD A0,B0 $ adc A1,B1 $ adc A2,B2 $ adc A3,B3
adc A4,B4 $ adc A5,B5 $ adc A6,B6 $ adc A7,B7
@ -1700,6 +1712,8 @@ ENDF __adddi3
;; (set (reg:DI 18)
;; (plus:DI (reg:DI 18)
;; (sign_extend:SI (reg:QI 26))))
;; Sets the V flag for signed overflow tests
;; Sets the C flag for unsigned overflow tests provided 0 <= R26 < 128
DEFUN __adddi3_s8
clr TT
sbrc r26, 7
@ -1714,6 +1728,8 @@ ENDF __adddi3_s8
;; (set (reg:DI 18)
;; (minus:DI (reg:DI 18)
;; (reg:DI 10)))
;; Sets the V flag for signed overflow tests
;; Sets the C flag for unsigned overflow tests
DEFUN __subdi3
SUB A0,B0 $ sbc A1,B1 $ sbc A2,B2 $ sbc A3,B3
sbc A4,B4 $ sbc A5,B5 $ sbc A6,B6 $ sbc A7,B7
@ -1747,6 +1763,9 @@ ENDF __cmpdi2_s8
#endif /* L_cmpdi2_s8 */
#if defined (L_negdi2)
;; (set (reg:DI 18)
;; (neg:DI (reg:DI 18)))
;; Sets the V flag for signed overflow tests
DEFUN __negdi2
com A4 $ com A5 $ com A6 $ com A7

View File

@ -20,7 +20,7 @@ LIB1ASMFUNCS = \
_divdi3 _udivdi3 \
_muldi3 \
_udivmod64 \
_negdi2 \
_negsi2 _negdi2 \
_prologue \
_epilogue \
_exit \
@ -72,7 +72,12 @@ LIB1ASMFUNCS += \
_divqq3 _udivuqq3 \
_divhq3 _udivuhq3 \
_divha3 _udivuha3 \
_divsa3 _udivusa3
_divsa3 _udivusa3 \
_clr_8 \
_ssneg_2 _ssneg_4 _ssneg_8 \
_ssabs_2 _ssabs_4 _ssabs_8 \
_ssadd_8 _sssub_8 \
_usadd_8 _ussub_8
LIB2FUNCS_EXCLUDE = \
_moddi3 _umoddi3 \
@ -103,6 +108,7 @@ endif
# Filter out supported conversions from fixed-bit.c
# Also filter out TQ and UTQ.
conv_XY=$(conv)$(mode1)$(mode2)
func_X=$(func)$(mode)
@ -141,8 +147,20 @@ allfix_modes = QQ UQQ HQ UHQ HA UHA SQ USQ SA USA DA UDA DQ UDQ TQ UTQ TA UTA
LIB2FUNCS_EXCLUDE += \
$(foreach func,_add _sub,\
$(foreach mode,$(allfix_modes),$(func_X)3))
$(foreach mode,$(allfix_modes),$(func_X)))
LIB2FUNCS_EXCLUDE += \
$(foreach func,_lshr _ashl _ashr _cmp,\
$(foreach mode,$(allfix_modes),$(func_X)))
usat_modes = UQQ UHQ UHA USQ USA UDQ UDA UTQ UTA
ssat_modes = QQ HQ HA SQ SA DQ DA TQ TA
LIB2FUNCS_EXCLUDE += \
$(foreach func,_ssadd _sssub _ssneg _ssabs,\
$(foreach mode,$(ssat_modes),$(func_X)))
LIB2FUNCS_EXCLUDE += \
$(foreach func,_usadd _ussub _usneg,\
$(foreach mode,$(usat_modes),$(func_X)))