Re: RFA: fix avr gcc.dg/fixed-point/convert-accum-neg.c execution failure

2013-08-26 Thread Denis Chertykov
2013/8/26 Joern Rennecke :
> The gcc.dg/fixed-point/convert-accum-neg.c execution test fails for avr
> because for fractional integer to accumulator / integer conversions,
> the avr target rounds towards -infinity, whereas we are supposed to round
> towards 0.
>
> The attached patch implements rounding towards 0, and adds an option
> -mfract-convert-truncate to revert to the previous behaviour (for
> situations where smaller code is more important than proper rounding).
>
> Tested for atmega128-sim.
>
> OK to apply?
>
> 2013-06-25  Joern Rennecke  
>
> * config/avr/avr.opt (mfract-convert-truncate): New option.
> * config/avr/avr.c (avr_out_fract): Unless TARGET_FRACT_CONV_TRUNC
> is set, round negative fractional integers according to n1169
> when converting to integer types.
>

Approved.

Denis.


RFA: fix avr gcc.dg/fixed-point/convert-accum-neg.c execution failure

2013-08-26 Thread Joern Rennecke

The gcc.dg/fixed-point/convert-accum-neg.c execution test fails for avr
because for fractional integer to accumulator / integer conversions,
the avr target rounds towards -infinity, whereas we are supposed to round
towards 0.

The attached patch implements rounding towards 0, and adds an option
-mfract-convert-truncate to revert to the previous behaviour (for
situations where smaller code is more important than proper rounding).

Tested for atmega128-sim.

OK to apply?
2013-06-25  Joern Rennecke  

* config/avr/avr.opt (mfract-convert-truncate): New option.
* config/avr/avr.c (avr_out_fract): Unless TARGET_FRACT_CONV_TRUNC
is set, round negative fractional integers according to n1169
when converting to integer types.

Index: config/avr/avr.c
===
--- config/avr/avr.c(revision 201989)
+++ config/avr/avr.c(working copy)
@@ -7030,7 +7030,9 @@ avr_out_fract (rtx insn, rtx operands[],
   RTX_CODE shift = UNKNOWN;
   bool sign_in_carry = false;
   bool msb_in_carry = false;
+  bool lsb_in_tmp_reg = false;
   bool lsb_in_carry = false;
+  bool frac_rounded = false;
   const char *code_ashift = "lsl %0";
 
 
@@ -7038,6 +7040,7 @@ #define MAY_CLOBBER(RR)
   /* Shorthand used below.  */  \
   ((sign_bytes  \
 && IN_RANGE (RR, dest.regno_msb - sign_bytes + 1, dest.regno_msb))  \
+   || (offset && IN_RANGE (RR, dest.regno, dest.regno_msb))\
|| (reg_unused_after (insn, all_regs_rtx[RR])\
&& !IN_RANGE (RR, dest.regno, dest.regno_msb)))
 
@@ -7112,13 +7115,119 @@ #define MAY_CLOBBER(RR)
   else
 gcc_unreachable();
 
+  /* If we need to round the fraction part, we might need to save/round it
+ before clobbering any of it in Step 1.  Also, we might to want to do
+ the rounding now to make use of LD_REGS.  */
+  if (SCALAR_INT_MODE_P (GET_MODE (xop[0]))
+  && SCALAR_ACCUM_MODE_P (GET_MODE (xop[1]))
+  && !TARGET_FRACT_CONV_TRUNC)
+{
+  bool overlap
+   = (src.regno <=
+  (offset ? dest.regno_msb - sign_bytes : dest.regno + zero_bytes - 1)
+  && dest.regno - offset -1 >= dest.regno);
+  unsigned s0 = dest.regno - offset -1;
+  bool use_src = true;
+  unsigned sn;
+  unsigned copied_msb = src.regno_msb;
+  bool have_carry = false;
+
+  if (src.ibyte > dest.ibyte)
+   copied_msb -= src.ibyte - dest.ibyte;
+
+  for (sn = s0; sn <= copied_msb; sn++)
+   if (!IN_RANGE (sn, dest.regno, dest.regno_msb)
+   && !reg_unused_after (insn, all_regs_rtx[sn]))
+ use_src = false;
+  if (use_src && TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0))
+   {
+ avr_asm_len ("tst %0" CR_TAB "brpl 0f",
+  &all_regs_rtx[src.regno_msb], plen, 2);
+ sn = src.regno;
+ if (sn < s0)
+   {
+ if (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], sn))
+   avr_asm_len ("cpi %0,1", &all_regs_rtx[sn], plen, 1);
+ else
+   avr_asm_len ("sec" CR_TAB "cpc %0,__zero_reg__",
+&all_regs_rtx[sn], plen, 2);
+ have_carry = true;
+   }
+ while (++sn < s0)
+   avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1);
+ avr_asm_len (have_carry ? "sbci %0,128" : "subi %0,129",
+  &all_regs_rtx[s0], plen, 1);
+ for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++)
+   avr_asm_len ("sbci %0,255", &all_regs_rtx[sn], plen, 1);
+ avr_asm_len ("\n0:", NULL, plen, 0);
+ frac_rounded = true;
+   }
+  else if (use_src && overlap)
+   {
+ avr_asm_len ("clr __tmp_reg__" CR_TAB
+  "sbrc %1,0" CR_TAB "dec __tmp_reg__", xop, plen, 1);
+ sn = src.regno;
+ if (sn < s0)
+   {
+ avr_asm_len ("add %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1);
+ have_carry = true;
+   }
+ while (++sn < s0)
+   avr_asm_len ("adc %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1);
+ if (have_carry)
+   avr_asm_len ("clt" CR_TAB "bld __tmp_reg__,7" CR_TAB
+"adc %0,__tmp_reg__",
+&all_regs_rtx[s0], plen, 1);
+ else
+   avr_asm_len ("lsr __tmp_reg" CR_TAB "add %0,__tmp_reg__",
+&all_regs_rtx[s0], plen, 2);
+ for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++)
+   avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1);
+ frac_rounded = true;
+   }
+  else if (overlap)
+   {
+ bool use_src
+   = (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0)
+  && (IN_RANGE (s0, dest.regno, dest.regno_msb)
+  || reg_unused_after (insn, all_regs_r