OSDN Git Service

* parse.y (check_static_final_variable_assignment_flag): Fix spelling.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 5dbbcaa..5ee436d 100644 (file)
@@ -218,7 +218,19 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   rtx real_t, imag_t;
   rtx temp1, temp2;
   rtx res;
+  optab this_add_optab = add_optab;
+  optab this_sub_optab = sub_optab;
+  optab this_neg_optab = neg_optab;
+  optab this_mul_optab = smul_optab;
              
+  if (binoptab == sdivv_optab)
+    {
+      this_add_optab = addv_optab;
+      this_sub_optab = subv_optab;
+      this_neg_optab = negv_optab;
+      this_mul_optab = smulv_optab;
+    }
+
   /* Don't fetch these from memory more than once.  */
   real0 = force_reg (submode, real0);
   real1 = force_reg (submode, real1);
@@ -229,16 +241,16 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   imag1 = force_reg (submode, imag1);
 
   /* Divisor: c*c + d*d.  */
-  temp1 = expand_binop (submode, smul_optab, real1, real1,
+  temp1 = expand_binop (submode, this_mul_optab, real1, real1,
                        NULL_RTX, unsignedp, methods);
 
-  temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+  temp2 = expand_binop (submode, this_mul_optab, imag1, imag1,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0 || temp2 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, temp2,
+  divisor = expand_binop (submode, this_add_optab, temp1, temp2,
                          NULL_RTX, unsignedp, methods);
   if (divisor == 0)
     return 0;
@@ -249,44 +261,44 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
 
       /* Calculate the dividend.  */
-      real_t = expand_binop (submode, smul_optab, real0, real1,
+      real_t = expand_binop (submode, this_mul_optab, real0, real1,
                             NULL_RTX, unsignedp, methods);
                  
-      imag_t = expand_binop (submode, smul_optab, real0, imag1,
+      imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
        return 0;
 
-      imag_t = expand_unop (submode, neg_optab, imag_t,
+      imag_t = expand_unop (submode, this_neg_optab, imag_t,
                            NULL_RTX, unsignedp);
     }
   else
     {
       /* Mathematically, ((a+ib)(c-id))/divider.  */
       /* Calculate the dividend.  */
-      temp1 = expand_binop (submode, smul_optab, real0, real1,
+      temp1 = expand_binop (submode, this_mul_optab, real0, real1,
                            NULL_RTX, unsignedp, methods);
 
-      temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+      temp2 = expand_binop (submode, this_mul_optab, imag0, imag1,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0 || temp2 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, temp2,
+      real_t = expand_binop (submode, this_add_optab, temp1, temp2,
                             NULL_RTX, unsignedp, methods);
                  
-      temp1 = expand_binop (submode, smul_optab, imag0, real1,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
                            NULL_RTX, unsignedp, methods);
 
-      temp2 = expand_binop (submode, smul_optab, real0, imag1,
+      temp2 = expand_binop (submode, this_mul_optab, real0, imag1,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0 || temp2 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+      imag_t = expand_binop (submode, this_sub_optab, temp1, temp2,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -340,6 +352,18 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
   enum machine_mode mode;
   int align;
   rtx res;
+  optab this_add_optab = add_optab;
+  optab this_sub_optab = sub_optab;
+  optab this_neg_optab = neg_optab;
+  optab this_mul_optab = smul_optab;
+
+  if (binoptab == sdivv_optab)
+    {
+      this_add_optab = addv_optab;
+      this_sub_optab = subv_optab;
+      this_neg_optab = negv_optab;
+      this_mul_optab = smulv_optab;
+    }
              
   /* Don't fetch these from memory more than once.  */
   real0 = force_reg (submode, real0);
@@ -358,8 +382,8 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
     }
   else
     {
-      temp1 = expand_abs (submode, real1, NULL_RTX, 1);
-      temp2 = expand_abs (submode, imag1, NULL_RTX, 1);
+      temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
+      temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
     }
 
   if (temp1 == 0 || temp2 == 0)
@@ -385,13 +409,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate divisor.  */
 
-  temp1 = expand_binop (submode, smul_optab, imag1, ratio,
+  temp1 = expand_binop (submode, this_mul_optab, imag1, ratio,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, real1,
+  divisor = expand_binop (submode, this_add_optab, temp1, real1,
                          NULL_RTX, unsignedp, methods);
 
   if (divisor == 0)
@@ -405,13 +429,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
       /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
 
-      imag_t = expand_binop (submode, smul_optab, real0, ratio,
+      imag_t = expand_binop (submode, this_mul_optab, real0, ratio,
                             NULL_RTX, unsignedp, methods);
 
       if (imag_t == 0)
        return 0;
 
-      imag_t = expand_unop (submode, neg_optab, imag_t,
+      imag_t = expand_unop (submode, this_neg_optab, imag_t,
                            NULL_RTX, unsignedp);
 
       if (real_t == 0 || imag_t == 0)
@@ -422,22 +446,22 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
       /* Compute (a+ib)/(c+id) as
         (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
 
-      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, real0,
+      real_t = expand_binop (submode, this_add_optab, temp1, real0,
                             NULL_RTX, unsignedp, methods);
 
-      temp1 = expand_binop (submode, smul_optab, real0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, imag0, temp1,
+      imag_t = expand_binop (submode, this_sub_optab, imag0, temp1,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -490,13 +514,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate divisor.  */
 
-  temp1 = expand_binop (submode, smul_optab, real1, ratio,
+  temp1 = expand_binop (submode, this_mul_optab, real1, ratio,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, imag1,
+  divisor = expand_binop (submode, this_add_optab, temp1, imag1,
                          NULL_RTX, unsignedp, methods);
 
   if (divisor == 0)
@@ -508,10 +532,10 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
     {
       /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
 
-      real_t = expand_binop (submode, smul_optab, real0, ratio,
+      real_t = expand_binop (submode, this_mul_optab, real0, ratio,
                             NULL_RTX, unsignedp, methods);
 
-      imag_t = expand_unop (submode, neg_optab, real0,
+      imag_t = expand_unop (submode, this_neg_optab, real0,
                            NULL_RTX, unsignedp);
 
       if (real_t == 0 || imag_t == 0)
@@ -522,22 +546,22 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
       /* Compute (a+ib)/(c+id) as
         (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
 
-      temp1 = expand_binop (submode, smul_optab, real0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, imag0,
+      real_t = expand_binop (submode, this_add_optab, temp1, imag0,
                             NULL_RTX, unsignedp, methods);
 
-      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, temp1, real0,
+      imag_t = expand_binop (submode, this_sub_optab, temp1, real0,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -1491,7 +1515,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else if (imag0)
            res = imag0;
          else if (binoptab->code == MINUS)
-           res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp);
+            res = expand_unop (submode,
+                                binoptab == subv_optab ? negv_optab : neg_optab,
+                                imag1, imagr, unsignedp);
          else
            res = imag1;
 
@@ -1525,8 +1551,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              if (temp1 == 0 || temp2 == 0)
                break;
 
-             res = expand_binop (submode, sub_optab, temp1, temp2,
-                                 realr, unsignedp, methods);
+             res = (expand_binop
+                     (submode,
+                      binoptab == smulv_optab ? subv_optab : sub_optab,
+                      temp1, temp2, realr, unsignedp, methods));
 
              if (res == 0)
                break;
@@ -1542,8 +1570,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              if (temp1 == 0 || temp2 == 0)
                  break;
 
-             res = expand_binop (submode, add_optab, temp1, temp2,
-                                 imagr, unsignedp, methods);
+             res = (expand_binop
+                     (submode,
+                      binoptab == smulv_optab ? addv_optab : add_optab,
+                      temp1, temp2, imagr, unsignedp, methods));
 
              if (res == 0)
                break;
@@ -2120,7 +2150,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
     }
 
   /* Open-code the complex negation operation.  */
-  else if (unoptab == neg_optab
+  else if (unoptab->code == NEG
           && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
     {
       rtx target_piece;
@@ -2231,11 +2261,13 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
   /* If there is no negate operation, try doing a subtract from zero.
      The US Software GOFAST library needs this.  */
-  if (unoptab == neg_optab)
+  if (unoptab->code == NEG)
     {    
       rtx temp;
-      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
-                          target, unsignedp, OPTAB_LIB_WIDEN);
+      temp = expand_binop (mode,
+                           unoptab == negv_optab ? subv_optab : sub_optab,
+                           CONST0_RTX (mode), op0,
+                           target, unsignedp, OPTAB_LIB_WIDEN);
       if (temp)
        return temp;
     }
@@ -2253,16 +2285,21 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
  */
 
 rtx
-expand_abs (mode, op0, target, safe)
+expand_abs (mode, op0, target, result_unsignedp, safe)
      enum machine_mode mode;
      rtx op0;
      rtx target;
+     int result_unsignedp;
      int safe;
 {
   rtx temp, op1;
 
+  if (! flag_trapv)
+    result_unsignedp = 1;
+
   /* First try to do it with a special abs instruction.  */
-  temp = expand_unop (mode, abs_optab, op0, target, 0);
+  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
+                      op0, target, 0);
   if (temp != 0)
     return temp;
 
@@ -2298,8 +2335,8 @@ expand_abs (mode, op0, target, safe)
       temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
                           OPTAB_LIB_WIDEN);
       if (temp != 0)
-       temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
-                            OPTAB_LIB_WIDEN);
+       temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
+                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
 
       if (temp != 0)
        return temp;
@@ -2335,7 +2372,8 @@ expand_abs (mode, op0, target, safe)
     do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
                             NULL_RTX, 0, NULL_RTX, op1);
 
-  op0 = expand_unop (mode, neg_optab, target, target, 0);
+  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
+                     target, target, 0);
   if (op0 != target)
     emit_move_insn (target, op0);
   emit_label (op1);
@@ -2365,6 +2403,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
   rtx entry_last = get_last_insn ();
   rtx last;
   rtx pat;
+  optab this_abs_optab;
 
   /* Find the correct mode for the real and imaginary parts.  */
   enum machine_mode submode
@@ -2387,9 +2426,13 @@ expand_complex_abs (mode, op0, target, unsignedp)
   if (target)
     target = protect_from_queue (target, 1);
 
-  if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  this_abs_optab = ! unsignedp && flag_trapv
+                   && (GET_MODE_CLASS(mode) == MODE_INT)
+                   ? absv_optab : abs_optab;
+
+  if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
-      int icode = (int) abs_optab->handlers[(int) mode].insn_code;
+      int icode = (int) this_abs_optab->handlers[(int) mode].insn_code;
       enum machine_mode mode0 = insn_data[icode].operand[1].mode;
       rtx xop0 = op0;
 
@@ -2414,10 +2457,12 @@ expand_complex_abs (mode, op0, target, unsignedp)
       if (pat)
        {
          if (GET_CODE (pat) == SEQUENCE
-             && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX))
+             && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 
+                                  NULL_RTX))
            {
              delete_insns_since (last);
-             return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp);
+             return expand_unop (mode, this_abs_optab, op0, NULL_RTX, 
+                                 unsignedp);
            }
 
          emit_insn (pat);
@@ -2433,7 +2478,8 @@ expand_complex_abs (mode, op0, target, unsignedp)
   for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
        wider_mode = GET_MODE_WIDER_MODE (wider_mode))
     {
-      if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
+      if (this_abs_optab->handlers[(int) wider_mode].insn_code 
+         != CODE_FOR_nothing)
        {
          rtx xop0 = op0;
 
@@ -2459,7 +2505,8 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
   /* Open-code the complex absolute-value operation
      if we can open-code sqrt.  Otherwise it's not worth while.  */
-  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)
+  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
+      && ! flag_trapv)
     {
       rtx real, imag, total;
 
@@ -2483,7 +2530,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
     }
 
   /* Now try a library call in this mode.  */
-  if (abs_optab->handlers[(int) mode].libfunc)
+  if (this_abs_optab->handlers[(int) mode].libfunc)
     {
       rtx insns;
       rtx value;
@@ -2499,7 +2546,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
       target = gen_reg_rtx (submode);
       emit_libcall_block (insns, target, value,
-                         gen_rtx_fmt_e (abs_optab->code, mode, op0));
+                         gen_rtx_fmt_e (this_abs_optab->code, mode, op0));
 
       return target;
     }
@@ -2509,9 +2556,9 @@ expand_complex_abs (mode, op0, target, unsignedp)
   for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
        wider_mode = GET_MODE_WIDER_MODE (wider_mode))
     {
-      if ((abs_optab->handlers[(int) wider_mode].insn_code
+      if ((this_abs_optab->handlers[(int) wider_mode].insn_code
           != CODE_FOR_nothing)
-         || abs_optab->handlers[(int) wider_mode].libfunc)
+         || this_abs_optab->handlers[(int) wider_mode].libfunc)
        {
          rtx xop0 = op0;
 
@@ -4419,8 +4466,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
     {
       register const char *mname = GET_MODE_NAME(mode);
       register unsigned mname_len = strlen (mname);
-      register char *libfunc_name
-       = ggc_alloc_string (NULL, 2 + opname_len + mname_len + 1 + 1);
+      register char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
       register char *p;
       register const char *q;
 
@@ -4432,10 +4478,11 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
       for (q = mname; *q; q++)
        *p++ = TOLOWER (*q);
       *p++ = suffix;
-      *p++ = '\0';
+      *p = '\0';
 
       optable->handlers[(int) mode].libfunc
-       = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+       = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
+                                                      p - libfunc_name));
     }
 }
 
@@ -4528,13 +4575,17 @@ init_optabs ()
 #endif
 
   add_optab = init_optab (PLUS);
+  addv_optab = init_optab (PLUS);
   sub_optab = init_optab (MINUS);
+  subv_optab = init_optab (MINUS);
   smul_optab = init_optab (MULT);
+  smulv_optab = init_optab (MULT);
   smul_highpart_optab = init_optab (UNKNOWN);
   umul_highpart_optab = init_optab (UNKNOWN);
   smul_widen_optab = init_optab (UNKNOWN);
   umul_widen_optab = init_optab (UNKNOWN);
   sdiv_optab = init_optab (DIV);
+  sdivv_optab = init_optab (DIV);
   sdivmod_optab = init_optab (UNKNOWN);
   udiv_optab = init_optab (UDIV);
   udivmod_optab = init_optab (UNKNOWN);
@@ -4560,7 +4611,9 @@ init_optabs ()
   ucmp_optab = init_optab (UNKNOWN);
   tst_optab = init_optab (UNKNOWN);
   neg_optab = init_optab (NEG);
+  negv_optab = init_optab (NEG);
   abs_optab = init_optab (ABS);
+  absv_optab = init_optab (ABS);
   one_cmpl_optab = init_optab (NOT);
   ffs_optab = init_optab (FFS);
   sqrt_optab = init_optab (SQRT);
@@ -4595,11 +4648,18 @@ init_optabs ()
   /* Initialize the optabs with the names of the library functions.  */
   init_integral_libfuncs (add_optab, "add", '3');
   init_floating_libfuncs (add_optab, "add", '3');
+  init_integral_libfuncs (addv_optab, "addv", '3');
+  init_floating_libfuncs (addv_optab, "add", '3');
   init_integral_libfuncs (sub_optab, "sub", '3');
   init_floating_libfuncs (sub_optab, "sub", '3');
+  init_integral_libfuncs (subv_optab, "subv", '3');
+  init_floating_libfuncs (subv_optab, "sub", '3');
   init_integral_libfuncs (smul_optab, "mul", '3');
   init_floating_libfuncs (smul_optab, "mul", '3');
+  init_integral_libfuncs (smulv_optab, "mulv", '3');
+  init_floating_libfuncs (smulv_optab, "mul", '3');
   init_integral_libfuncs (sdiv_optab, "div", '3');
+  init_integral_libfuncs (sdivv_optab, "divv", '3');
   init_integral_libfuncs (udiv_optab, "udiv", '3');
   init_integral_libfuncs (sdivmod_optab, "divmod", '4');
   init_integral_libfuncs (udivmod_optab, "udivmod", '4');
@@ -4621,6 +4681,8 @@ init_optabs ()
   init_integral_libfuncs (umax_optab, "umax", '3');
   init_integral_libfuncs (neg_optab, "neg", '2');
   init_floating_libfuncs (neg_optab, "neg", '2');
+  init_integral_libfuncs (negv_optab, "negv", '2');
+  init_floating_libfuncs (negv_optab, "neg", '2');
   init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
   init_integral_libfuncs (ffs_optab, "ffs", '2');