OSDN Git Service

2009-10-14 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 3f94ac7..8a5cf50 100644 (file)
@@ -685,6 +685,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       rtx xop0 = op0;
       rtx last = get_last_insn ();
       rtx pat;
+      bool copy_back = false;
 
       /* Add OFFSET into OP0's address.  */
       if (MEM_P (xop0))
@@ -699,6 +700,23 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
        xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
 
+      /* If the destination is a paradoxical subreg such that we need a
+        truncate to the inner mode, perform the insertion on a temporary and
+        truncate the result to the original destination.  Note that we can't
+        just truncate the paradoxical subreg as (truncate:N (subreg:W (reg:N
+        X) 0)) is (reg:N X).  */
+      if (GET_CODE (xop0) == SUBREG
+         && REG_P (SUBREG_REG (xop0))
+         && (!TRULY_NOOP_TRUNCATION
+             (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (xop0))),
+              GET_MODE_BITSIZE (op_mode))))
+       {
+         rtx tem = gen_reg_rtx (op_mode);
+         emit_move_insn (tem, xop0);
+         xop0 = tem;
+         copy_back = true;
+       }
+
       /* On big-endian machines, we count bits from the most significant.
         If the bit field insn does not, we must invert.  */
 
@@ -758,15 +776,8 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        {
          emit_insn (pat);
 
-         /* If the mode of the insertion is wider than the mode of the
-            target register we created a paradoxical subreg for the
-            target.  Truncate the paradoxical subreg of the target to
-            itself properly.  */
-         if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (op0)),
-                                     GET_MODE_BITSIZE (op_mode))
-             && (REG_P (xop0)
-                 || GET_CODE (xop0) == SUBREG))
-             convert_move (op0, xop0, true);
+         if (copy_back)
+           convert_move (op0, xop0, true);
          return true;
        }
       delete_insns_since (last);
@@ -5078,10 +5089,11 @@ make_tree (tree type, rtx x)
     default:
       t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type);
 
-      /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
-        ptr_mode.  So convert.  */
+      /* If TYPE is a POINTER_TYPE, we might need to convert X from
+        address mode to pointer mode.  */
       if (POINTER_TYPE_P (type))
-       x = convert_memory_address (TYPE_MODE (type), x);
+       x = convert_memory_address_addr_space
+             (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type)));
 
       /* Note that we do *not* use SET_DECL_RTL here, because we do not
         want set_decl_rtl to go adjusting REG_ATTRS for this temporary.  */
@@ -5117,10 +5129,10 @@ expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
 static rtx
 emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
             enum machine_mode mode, enum machine_mode compare_mode,
-            int unsignedp, rtx x, rtx y, int normalizep)
+            int unsignedp, rtx x, rtx y, int normalizep,
+            enum machine_mode target_mode)
 {
   rtx op0, last, comparison, subtarget, pattern;
-  enum machine_mode target_mode;
   enum machine_mode result_mode = insn_data[(int) icode].operand[0].mode;
 
   last = get_last_insn ();
@@ -5138,8 +5150,12 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
       return NULL_RTX;
     }
 
-  if (!target
-      || optimize
+  if (target_mode == VOIDmode)
+    target_mode = result_mode;
+  if (!target)
+    target = gen_reg_rtx (target_mode);
+  
+  if (optimize
       || !(insn_data[(int) icode].operand[0].predicate (target, result_mode)))
     subtarget = gen_reg_rtx (result_mode);
   else
@@ -5150,10 +5166,6 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
     return NULL_RTX;
   emit_insn (pattern);
 
-  if (!target)
-    target = gen_reg_rtx (GET_MODE (subtarget));
-  target_mode = GET_MODE (target);
-  
   /* If we are converting to a wider mode, first convert to
      TARGET_MODE, then normalize.  This produces better combining
      opportunities on machines that have a SIGN_EXTRACT when we are
@@ -5224,12 +5236,12 @@ emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
 
 static rtx
 emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
-                  enum machine_mode mode, int unsignedp, int normalizep)
+                  enum machine_mode mode, int unsignedp, int normalizep,
+                  enum machine_mode target_mode)
 {
   rtx subtarget;
   enum insn_code icode;
   enum machine_mode compare_mode;
-  enum machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
   enum mode_class mclass;
   enum rtx_code scode;
   rtx tem;
@@ -5308,7 +5320,7 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
          if (tem != 0)
            tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode,
-                                   unsignedp, normalizep);
+                                  unsignedp, normalizep);
        }
       else if ((code == LT || code == GE) && op1 == const0_rtx)
        {
@@ -5326,11 +5338,13 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
       if (tem)
        {
-         if (target_mode == VOIDmode)
+         if (target_mode == VOIDmode || GET_MODE (tem) == target_mode)
            return tem;
+         if (!target)
+           target = gen_reg_rtx (target_mode);
 
          convert_move (target, tem,
-                       0 == (STORE_FLAG_VALUE
+                       0 == ((normalizep ? normalizep : STORE_FLAG_VALUE)
                              & ((HOST_WIDE_INT) 1
                                 << (GET_MODE_BITSIZE (word_mode) -1))));
          return target;
@@ -5393,14 +5407,14 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
        {
          do_pending_stack_adjust ();
          tem = emit_cstore (target, icode, code, mode, compare_mode,
-                            unsignedp, op0, op1, normalizep);
+                            unsignedp, op0, op1, normalizep, target_mode);
          if (tem)
            return tem;
 
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
              tem = emit_cstore (target, icode, scode, mode, compare_mode,
-                                unsignedp, op1, op0, normalizep);
+                                unsignedp, op1, op0, normalizep, target_mode);
              if (tem)
                return tem;
            }
@@ -5435,7 +5449,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
   rtx subtarget;
   rtx tem, last, trueval;
 
-  tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep);
+  tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep,
+                          target_mode);
   if (tem)
     return tem;
 
@@ -5483,21 +5498,27 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
              || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
              || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
        {
+          int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+                         || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
          /* For the reverse comparison, use either an addition or a XOR.  */
-         if ((STORE_FLAG_VALUE == 1 && normalizep == -1)
-             || (STORE_FLAG_VALUE == -1 && normalizep == 1))
+          if (want_add
+             && rtx_cost (GEN_INT (normalizep), PLUS,
+                          optimize_insn_for_speed_p ()) == 0)
            {
              tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
-                                      STORE_FLAG_VALUE);
+                                      STORE_FLAG_VALUE, target_mode);
              if (tem)
                 return expand_binop (target_mode, add_optab, tem,
                                     GEN_INT (normalizep),
                                     target, 0, OPTAB_WIDEN);
            }
-         else
+          else if (!want_add
+                  && rtx_cost (trueval, XOR,
+                               optimize_insn_for_speed_p ()) == 0)
            {
              tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
-                                      normalizep);
+                                      normalizep, target_mode);
              if (tem)
                 return expand_binop (target_mode, xor_optab, tem, trueval,
                                     target, INTVAL (trueval) >= 0, OPTAB_WIDEN);
@@ -5517,13 +5538,15 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
       if (!HONOR_NANS (mode))
        {
           gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
-         return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep);
+         return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep,
+                                   target_mode);
        }
 
 #ifdef HAVE_conditional_move
       /* Try using a setcc instruction for ORDERED/UNORDERED, followed by a
         conditional move.  */
-      tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0, normalizep);
+      tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0,
+                              normalizep, target_mode);
       if (tem == 0)
        return 0;
 
@@ -5561,8 +5584,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
        tem = expand_binop (mode, sub_optab, op0, op1, subtarget, 1,
                            OPTAB_WIDEN);
       if (tem != 0)
-       tem = emit_store_flag_1 (target, code, tem, const0_rtx,
-                                mode, unsignedp, normalizep);
+       tem = emit_store_flag (target, code, tem, const0_rtx,
+                              mode, unsignedp, normalizep);
       if (tem != 0)
        return tem;
 
@@ -5579,20 +5602,26 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
            && GET_MODE_SIZE (mode) < UNITS_PER_WORD
            && op1 == const0_rtx))
     {
+      int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+                     || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
       /* Again, for the reverse comparison, use either an addition or a XOR.  */
-      if ((STORE_FLAG_VALUE == 1 && normalizep == -1)
-         || (STORE_FLAG_VALUE == -1 && normalizep == 1))
+      if (want_add
+         && rtx_cost (GEN_INT (normalizep), PLUS,
+                      optimize_insn_for_speed_p ()) == 0)
        {
          tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
-                                  STORE_FLAG_VALUE);
+                                  STORE_FLAG_VALUE, target_mode);
          if (tem != 0)
             tem = expand_binop (target_mode, add_optab, tem,
                                GEN_INT (normalizep), target, 0, OPTAB_WIDEN);
        }
-      else
+      else if (!want_add
+              && rtx_cost (trueval, XOR,
+                           optimize_insn_for_speed_p ()) == 0)
        {
          tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
-                                  normalizep);
+                                  normalizep, target_mode);
          if (tem != 0)
             tem = expand_binop (target_mode, xor_optab, tem, trueval, target,
                                INTVAL (trueval) >= 0, OPTAB_WIDEN);