|| 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 ();
rtx first_insn;
rtx pool_insn;
bitmap insns;
+ rtx emit_pool_after;
struct constant *constants[NR_C_MODES];
struct constant *execute;
pool->pool_insn = NULL_RTX;
pool->insns = BITMAP_ALLOC (NULL);
pool->size = 0;
+ pool->emit_pool_after = NULL_RTX;
return pool;
}
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);
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;
}
/* 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);
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);
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
+ bool section_switch_p = false;
+
/* Check for pending LTREL_BASE. */
if (INSN_P (insn))
{
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)
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 ... */
}
/* ... 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);
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
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)));
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;
#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