OSDN Git Service

2008-02-14 Andreas Krebbel <krebbel1@de.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / s390 / s390.c
index 35e2fa6..280358c 100644 (file)
@@ -2056,8 +2056,7 @@ s390_O_constraint_str (const char c, HOST_WIDE_INT value)
        || s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1;
 
     case 'n':
-      return value == -1
-       || s390_single_part (GEN_INT (value), DImode, SImode, -1) == 1;
+      return s390_single_part (GEN_INT (value - 1), DImode, SImode, -1) == 1;
 
     default:
       gcc_unreachable ();
@@ -5326,6 +5325,7 @@ struct constant_pool
   rtx first_insn;
   rtx pool_insn;
   bitmap insns;
+  rtx emit_pool_after;
 
   struct constant *constants[NR_C_MODES];
   struct constant *execute;
@@ -5352,6 +5352,7 @@ s390_alloc_pool (void)
   pool->pool_insn = NULL_RTX;
   pool->insns = BITMAP_ALLOC (NULL);
   pool->size = 0;
+  pool->emit_pool_after = NULL_RTX;
 
   return pool;
 }
@@ -5711,6 +5712,17 @@ s390_mainpool_start (void)
              s390_add_constant (pool, constant, mode);
            }
        }
+
+      /* If hot/cold partitioning is enabled we have to make sure that
+        the literal pool is emitted in the same section where the
+        initialization of the literal pool base pointer takes place.
+        emit_pool_after is only used in the non-overflow case on non
+        Z cpus where we can emit the literal pool at the end of the
+        function body within the text section.  */
+      if (NOTE_P (insn)
+         && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS
+         && !pool->emit_pool_after)
+       pool->emit_pool_after = PREV_INSN (insn);
     }
 
   gcc_assert (pool->pool_insn || pool->size == 0);
@@ -5725,6 +5737,11 @@ s390_mainpool_start (void)
       pool = NULL;
     }
 
+  /* If the functions ends with the section where the literal pool
+     should be emitted set the marker to its end.  */
+  if (pool && !pool->emit_pool_after)
+    pool->emit_pool_after = get_last_insn ();
+
   return pool;
 }
 
@@ -5772,7 +5789,7 @@ s390_mainpool_finish (struct constant_pool *pool)
   /* On S/390, if the total size of the function's code plus literal pool
      does not exceed 4096 bytes, we use BASR to set up a function base
      pointer, and emit the literal pool at the end of the function.  */
-  else if (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
+  else if (INSN_ADDRESSES (INSN_UID (pool->emit_pool_after))
           + pool->size + 8 /* alignment slop */ < 4096)
     {
       insn = gen_main_base_31_small (base_reg, pool->label);
@@ -5783,7 +5800,11 @@ s390_mainpool_finish (struct constant_pool *pool)
       insn = emit_label_after (pool->label, insn);
       INSN_ADDRESSES_NEW (insn, -1);
 
-      insn = get_last_insn ();
+      /* emit_pool_after will be set by s390_mainpool_start to the
+        last insn of the section where the literal pool should be
+        emitted.  */
+      insn = pool->emit_pool_after;
+
       pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
       INSN_ADDRESSES_NEW (pool->pool_insn, -1);
 
@@ -5882,6 +5903,8 @@ s390_chunkify_start (void)
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
+      bool section_switch_p = false;
+
       /* Check for pending LTREL_BASE.  */
       if (INSN_P (insn))
        {
@@ -5936,6 +5959,9 @@ s390_chunkify_start (void)
          gcc_assert (!pending_ltrel);
        }
 
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+       section_switch_p = true;
+
       if (!curr_pool
          || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
           || INSN_ADDRESSES (INSN_UID (insn)) == -1)
@@ -5963,7 +5989,8 @@ s390_chunkify_start (void)
            extra_size += 6;
 
          if (chunk_size < S390_POOL_CHUNK_MIN
-             && curr_pool->size < S390_POOL_CHUNK_MIN)
+             && curr_pool->size < S390_POOL_CHUNK_MIN
+             && !section_switch_p)
            continue;
 
          /* Pool chunks can only be inserted after BARRIERs ...  */
@@ -5975,21 +6002,33 @@ s390_chunkify_start (void)
            }
 
          /* ... so if we don't find one in time, create one.  */
-          else if ((chunk_size > S390_POOL_CHUNK_MAX
-                  || curr_pool->size > S390_POOL_CHUNK_MAX))
+          else if (chunk_size > S390_POOL_CHUNK_MAX
+                  || curr_pool->size > S390_POOL_CHUNK_MAX
+                  || section_switch_p)
            {
               rtx label, jump, barrier;
 
-             /* We can insert the barrier only after a 'real' insn.  */
-             if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
-               continue;
-             if (get_attr_length (insn) == 0)
-               continue;
-
-             /* Don't separate LTREL_BASE from the corresponding
+             if (!section_switch_p)
+               {
+                 /* We can insert the barrier only after a 'real' insn.  */
+                 if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
+                   continue;
+                 if (get_attr_length (insn) == 0)
+                   continue;
+                 /* Don't separate LTREL_BASE from the corresponding
                 LTREL_OFFSET load.  */
-             if (pending_ltrel)
-               continue;
+                 if (pending_ltrel)
+                   continue;
+               }
+             else
+               {
+                 gcc_assert (!pending_ltrel);
+
+                 /* The old pool has to end before the section switch
+                    note in order to make it part of the current
+                    section.  */
+                 insn = PREV_INSN (insn);
+               }
 
              label = gen_label_rtx ();
              jump = emit_jump_insn_after (gen_jump (label), insn);
@@ -7162,6 +7201,18 @@ s390_load_got (void)
   return insns;
 }
 
+/* This ties together stack memory (MEM with an alias set of frame_alias_set)
+   and the change to the stack pointer.  */
+
+static void
+s390_emit_stack_tie (void)
+{
+  rtx mem = gen_frame_mem (BLKmode,
+                          gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
+
+  emit_insn (gen_stack_tie (mem));
+}
+
 /* Expand the prologue into a bunch of separate insns.  */
 
 void
@@ -7390,6 +7441,11 @@ s390_emit_prologue (void)
 
   if (cfun_save_high_fprs_p && next_fpr)
     {
+      /* If the stack might be accessed through a different register
+        we have to make sure that the stack pointer decrement is not
+        moved below the use of the stack slots.  */
+      s390_emit_stack_tie ();
+
       insn = emit_insn (gen_add2_insn (temp_reg, 
                                       GEN_INT (cfun_frame_layout.f8_offset)));
 
@@ -7961,7 +8017,7 @@ s390_build_builtin_va_list (void)
        holds the offset of the first anonymous stack argument
        (relative to the virtual arg pointer).  */
 
-void
+static void
 s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT n_gpr, n_fpr;
@@ -9314,6 +9370,8 @@ s390_reorg (void)
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START s390_va_start
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg