+2003-08-23 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * config/s390/s390-protos.h (s390_output_pool_entry): Declare.
+ * config/s390/s390.c (gen_consttable): Remove.
+ (s390_dump_pool): Use UNSPECV_POOL_ENTRY for pool entry insns.
+ (s390_output_pool_entry): New function.
+ * config/s390/s390.md (UNSPECV_POOL_QI, UNSPECV_POOL_HI,
+ UNSPECV_POOL_SI, UNSPECV_POOL_DI, UNSPECV_POOL_TI,
+ UNSPECV_POOL_SF, UNSPECV_POOL_DF): Remove, replace by ...
+ (UNSPECV_POOL_ENTRY): ... this new constant.
+ ("consttable_qi", "consttable_hi", "consttable_si", "consttable_di",
+ "consttable_ti", "consttable_sf", "consttable_df"): Remove ...
+ ("*pool_entry"): ... and replace by this new insn.
+ ("literal_pool_31"): Do not emit anchor label if pool empty.
+
+ * config/s390/s390.c (struct machine_function): Add save_return_addr_p.
+ (s390_optimize_prolog): Save RETURN_REGNUM if save_return_addr_p.
+ (s390_fixup_clobbered_return_reg): Remove.
+ (s390_reorg): Don't call s390_fixup_clobbered_return_reg.
+ (s390_return_addr_rtx): Always retrieve return address from save area
+ slot. Use save_return_addr_p to force slot to be filled.
+ (s390_emit_prologue): Remove has_hard_reg_initial_val test.
+
2003-08-22 Chris Demetriou <cgd@broadcom.com>
* config/mips/mips.h (MASK_FIX_SB1, TARGET_FIX_SB1): New defines.
/* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
int save_fprs_p;
+ /* Set if return address needs to be saved because the current
+ function uses __builtin_return_addr (0). */
+ bool save_return_addr_p;
+
/* Number of first and last gpr to be saved, restored. */
int first_save_gpr;
int first_restore_gpr;
static rtx find_ltrel_base (rtx);
static void replace_ltrel_base (rtx *, rtx);
static void s390_optimize_prolog (int);
-static bool s390_fixup_clobbered_return_reg (rtx);
static int find_unused_clobbered_reg (void);
static void s390_frame_info (void);
static rtx save_fpr (rtx, int, int);
QImode
};
-rtx (*gen_consttable[NR_C_MODES])(rtx) =
-{
- gen_consttable_ti, gen_consttable_df, gen_consttable_di, gen_consttable_sf, gen_consttable_si, gen_consttable_hi, gen_consttable_qi
-};
-
struct constant
{
struct constant *next;
insn = emit_label_after (c->label, insn);
INSN_ADDRESSES_NEW (insn, -1);
- insn = emit_insn_after (gen_consttable[i] (value), insn);
+
+ value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i],
+ gen_rtvec (1, value),
+ UNSPECV_POOL_ENTRY);
+ insn = emit_insn_after (value, insn);
INSN_ADDRESSES_NEW (insn, -1);
}
}
}
+/* Output to FILE the constant pool entry EXP in mode MODE
+ with alignment ALIGN. */
+
+void
+s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
+ unsigned int align)
+{
+ REAL_VALUE_TYPE r;
+
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_FLOAT:
+ if (GET_CODE (exp) != CONST_DOUBLE)
+ abort ();
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, exp);
+ assemble_real (r, mode, align);
+ break;
+
+ case MODE_INT:
+ if (GET_CODE (exp) == CONST
+ || GET_CODE (exp) == SYMBOL_REF
+ || GET_CODE (exp) == LABEL_REF)
+ {
+ fputs (integer_asm_op (GET_MODE_SIZE (mode), TRUE), file);
+ s390_output_symbolic_const (file, exp);
+ fputc ('\n', file);
+ }
+ else
+ {
+ assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+
/* Rework the prolog/epilog to avoid saving/restoring
registers unnecessarily. If TEMP_REGNO is nonnegative,
it specifies the number of a caller-saved register used
regs_ever_live[BASE_REGISTER] = 1;
/* In non-leaf functions, the prolog/epilog code relies
- on RETURN_REGNUM being saved in any case. */
- if (!current_function_is_leaf)
+ on RETURN_REGNUM being saved in any case. We also need
+ to save the return register if __builtin_return_address (0)
+ was used in the current function. */
+ if (!current_function_is_leaf
+ || cfun->machine->save_return_addr_p)
regs_ever_live[RETURN_REGNUM] = 1;
/* We need to save/restore the temporary register. */
}
}
-/* Check whether any insn in the function makes use of the original
- value of RETURN_REG (e.g. for __builtin_return_address).
- If so, insert an insn reloading that value.
-
- Return true if any such insn was found. */
-
-static bool
-s390_fixup_clobbered_return_reg (rtx return_reg)
-{
- bool replacement_done = 0;
- rtx insn;
-
- /* If we never called __builtin_return_address, register 14
- might have been used as temp during the prolog; we do
- not want to touch those uses. */
- if (!has_hard_reg_initial_val (Pmode, REGNO (return_reg)))
- return false;
-
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- rtx reg, off, new_insn;
-
- if (GET_CODE (insn) != INSN)
- continue;
- if (!reg_referenced_p (return_reg, PATTERN (insn)))
- continue;
- if (GET_CODE (PATTERN (insn)) == PARALLEL
- && store_multiple_operation (PATTERN (insn), VOIDmode))
- continue;
-
- if (frame_pointer_needed)
- reg = hard_frame_pointer_rtx;
- else
- reg = stack_pointer_rtx;
-
- off = GEN_INT (cfun->machine->frame_size + REGNO (return_reg) * UNITS_PER_WORD);
- if (!DISP_IN_RANGE (INTVAL (off)))
- {
- off = force_const_mem (Pmode, off);
- new_insn = gen_rtx_SET (Pmode, return_reg, off);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
- off = return_reg;
- }
-
- new_insn = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, reg, off));
- new_insn = gen_rtx_SET (Pmode, return_reg, new_insn);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
-
- replacement_done = 1;
- }
-
- return replacement_done;
-}
-
/* Perform machine-dependent processing. */
static void
s390_reorg (void)
{
- bool fixed_up_clobbered_return_reg = 0;
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
bool temp_used = 0;
continue;
}
- /* Check whether we have clobbered a use of the return
- register (e.g. for __builtin_return_address). If so,
- add insns reloading the register where necessary. */
- if (temp_used && !fixed_up_clobbered_return_reg
- && s390_fixup_clobbered_return_reg (temp_reg))
- {
- fixed_up_clobbered_return_reg = 1;
-
- /* The fixup insns might have caused a jump to overflow. */
- if (pool_list)
- s390_chunkify_cancel (pool_list);
-
- continue;
- }
-
/* If we made it up to here, both conditions are satisfied.
Finish up pool chunkification if required. */
if (pool_list)
{
rtx addr;
- /* For the current frame, we use the initial value of RETURN_REGNUM.
- This works both in leaf and non-leaf functions. */
+ /* For the current frame, we need to make sure the initial
+ value of RETURN_REGNUM is actually saved. */
if (count == 0)
- return get_hard_reg_initial_val (Pmode, RETURN_REGNUM);
+ cfun->machine->save_return_addr_p = true;
- /* For frames farther back, we read the stack slot where the
+ /* To retrieve the return address we read the stack slot where the
corresponding RETURN_REGNUM value was saved. */
addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD);
See below for why TPF must use the register 1. */
if (!current_function_is_leaf
- && !has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
&& get_pool_size () < S390_POOL_CHUNK_MAX / 2
&& !TARGET_TPF)
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
(UNSPECV_POOL 200)
(UNSPECV_POOL_START 201)
(UNSPECV_POOL_END 202)
- (UNSPECV_POOL_QI 203)
- (UNSPECV_POOL_HI 204)
- (UNSPECV_POOL_SI 205)
- (UNSPECV_POOL_DI 206)
- (UNSPECV_POOL_TI 207)
- (UNSPECV_POOL_SF 208)
- (UNSPECV_POOL_DF 209)
+ (UNSPECV_POOL_ENTRY 203)
(UNSPECV_MAIN_POOL 300)
; TLS support
; Special literal pool access instruction pattern(s).
;
-(define_insn "consttable_qi"
- [(unspec_volatile [(match_operand:QI 0 "consttable_operand" "X")]
- UNSPECV_POOL_QI)]
+(define_insn "*pool_entry"
+ [(unspec_volatile [(match_operand 0 "consttable_operand" "X")]
+ UNSPECV_POOL_ENTRY)]
""
{
- assemble_integer (operands[0], 1, BITS_PER_UNIT, 1);
+ enum machine_mode mode = GET_MODE (PATTERN (insn));
+ unsigned int align = GET_MODE_BITSIZE (mode);
+ s390_output_pool_entry (asm_out_file, operands[0], mode, align);
return "";
}
- [(set_attr "op_type" "NN")
- (set_attr "length" "1")])
-
-(define_insn "consttable_hi"
- [(unspec_volatile [(match_operand:HI 0 "consttable_operand" "X")]
- UNSPECV_POOL_HI)]
- ""
-{
- assemble_integer (operands[0], 2, 2*BITS_PER_UNIT, 1);
- return "";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "2")])
-
-(define_insn "consttable_si"
- [(unspec_volatile [(match_operand:SI 0 "consttable_operand" "X")]
- UNSPECV_POOL_SI)]
- ""
- ".long\t%0"
- [(set_attr "op_type" "NN")
- (set_attr "length" "4")])
-
-(define_insn "consttable_di"
- [(unspec_volatile [(match_operand:DI 0 "consttable_operand" "X")]
- UNSPECV_POOL_DI)]
- ""
- ".quad\t%0"
- [(set_attr "op_type" "NN")
- (set_attr "length" "8")])
-
-(define_insn "consttable_ti"
- [(unspec_volatile [(match_operand:TI 0 "consttable_operand" "X")]
- UNSPECV_POOL_TI)]
- ""
-{
- assemble_integer (operands[0], 16, 16*BITS_PER_UNIT, 1);
- return "";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "16")])
-
-(define_insn "consttable_sf"
- [(unspec_volatile [(match_operand:SF 0 "consttable_operand" "X")]
- UNSPECV_POOL_SF)]
- ""
-{
- REAL_VALUE_TYPE r;
-
- if (GET_CODE (operands[0]) != CONST_DOUBLE)
- abort ();
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
- assemble_real (r, SFmode, 4*BITS_PER_UNIT);
- return "";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "4")])
-
-(define_insn "consttable_df"
- [(unspec_volatile [(match_operand:DF 0 "consttable_operand" "X")]
- UNSPECV_POOL_DF)]
- ""
-{
- REAL_VALUE_TYPE r;
-
- if (GET_CODE (operands[0]) != CONST_DOUBLE)
- abort ();
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
- assemble_real (r, DFmode, 8*BITS_PER_UNIT);
- return "";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "8")])
+ [(set_attr "op_type" "NN")
+ (set (attr "length")
+ (symbol_ref "GET_MODE_SIZE (GET_MODE (PATTERN (insn)))"))])
(define_insn "pool_start_31"
[(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)]
output_asm_insn ("bras\t%0,%2", operands);
s390_output_constant_pool (operands[1], operands[2]);
}
- else if (flag_pic)
- {
- /* We need the anchor label in any case. */
- (*targetm.asm_out.internal_label) (asm_out_file, "L",
- CODE_LABEL_NUMBER (operands[1]));
- }
return "";
}