Commit 4023fb28 by Ulrich Weigand Committed by Ulrich Weigand

s390.md (prologue, [...]): New.

	* s390.md (prologue, epilogue, *return_si, *return_di): New.
	s390.c (find_unused_clobbered_reg, s390_frame_info,
	save_fpr, restore_fpr, s390_emit_prologue, s390_emit_epilogue): New.
	s390-protos.h (s390_emit_prologue, s390_emit_epilogue): Declare.
	s390.c (s390_arg_frame_offset): Use s390_frame_info.
	(leaf_function_flag, cur_is_leaf_function,
	save_fprs, restore_fprs, force_const_mem_late): Remove.
	(s390_function_prologue, s390_function_epilogue): Mostly remove.
	s390.md (lit): New.  Uses ...
	s390.c (s390_output_constant_pool): ... this, so adapt and make global.
	s390-protos.h (s390_output_constant_pool): Declare.
	s390.md (load_multiple, store_multiple): Allow use after reload.
	s390.c (load_multiple_operation, store_multiple_operation): Likewise.
	s390.h (INCOMING_FRAME_SP_OFFSET): Define.
	s390.h (CALL_REALLY_USED_REGISTERS): Define.
	config/s390/linux64.h (CALL_USED_REGISTERS): Remove, now handled ...
	s390.h (CONDITIONAL_REGISTER_USAGE): ... here.
	s390.c (s390_sr_alias_set): New global variable, initialized ...
	(override_options): ... here.  New.
	s390-protos.h (override_options): Declare.
	s390.h (OVERRIDE_OPTIONS): Call it.
	s390.c (s390_function_profiler): New.
	s390-protos.h (s390_function_profiler): Declare.
	s390.h (FUNCTION_PROFILER): Call it.
	s390.c (s390_profile): Remove.

	* s390.c (reg_used_in_mem_p): PC reload counts as memory access.
	(addr_generation_dependency_p): Consider literal pool register loads.
	(s390_adjust_priority): Do not schedule load_multiple.
	s390.md (attribute "type"): Define some additional types.
	(function_unit "integer"): Adapt.
	(many insns): Adapt "type" attribute setting.

	* s390.c (general_s_operand, s_imm_operand): New.
	(s_operand): Remove old definition, call general_s_operand instead.
	s390-protos.h (s_imm_operand): Declare.
	s390.c (base_n_index_p, r_or_s_operand, r_or_s_or_im8_operand,
	r_or_x_or_im16_operand, r_or_im8_operand): Remove.
	s390-protos.h (r_or_s_operand, r_or_s_or_im8_operand,
	r_or_x_or_im16_operand, r_or_im8_operand): Likewise.
	s390.h (PREDICATE_CODES): Add s_imm_operand, remove r_or_s*_operand.
	s390.md (many insns): Rework insn predicates.

	* s390.c (legitimate_pic_operand_p, legitimate_constant_p): Accept all
	non-symbolic constants.  Reload will force them because of ...
	(s390_preferred_reload_class): ... this.  New.
	s390-protos.h (s390_preferred_reload_class): Declare.
	s390.h (PREFERRED_RELOAD_CLASS): Call it.
	s390.md (movdi, movsi, movdf, movsf, *reload_la_64 splitters,
	*reload_la_31 splitters): Handle constants after reload.
	(many insns): no longer force all constants immediately.
	s390.c (legitimate_reload_constant_p): New helper routine.
	s390-protos.h (legitimate_reload_constant_p): Declare.
	s390.c (print_operand): Clean up CONST_INT case, add CONST_DOUBLE case.

	* s390.h (FIRST_PSEUDO_REGISTER, FRAME_POINTER_REGNUM,
	HARD_FRAME_POINTER_REGNUM, REGISTER_NAMES): Add virtual frame pointer.
	(CALL_USED_REGISTERS, CALL_REALLY_USED_REGISTERS): Update.
	(ELIMINABLE_REGS, INITIAL_ELIMINATION_OFFSET): Likewise.
	(REGNO_OK_FOR_INDEX_P, REG_OK_FOR_INDEX_NONSTRICT_P): Likewise.
	(DWARF_FRAME_REGISTERS): Define.
	s390.c (regclass_map): Add virtual frame pointer.
	(legitimate_la_operand_p): Allow use of virtual frame pointer.
	s390.md (*la_ccclobber, *addaddr_ccclobber): New.
	(addaddr, addsi_64): Delete.

	* s390.h (HARD_REGNO_MODE_OK): Allow SImode and DImode values in
	floating point registers.
	(CLASS_CANNOT_CHANGE_MODE, CLASS_CANNOT_CHANGE_MODE_P): Define.
	(ADDR_FP_REGS, GENERAL_FP_REGS): New register classes.
	(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update.

	* s390.md (movti): Replace multi-insn output with splitters.
	(movdi_31, movdf_31): Likewise.
	(movti_ss, movdi_ss, movsi_ss, movdf_ss, movsf_ss): New.
	(movdi_lhi, movdi_lli, movdi_larl, movsi_lhi, movsi_lli): New.
	(movdi_64, movdi_31, movsi, movdf_64, movdf_31): Adapt.
	(movdf_soft_64, movdf_soft_31, movsf_soft): Remove.
	(movsf_64, movsf_31): Remove, replace by ...
	(movsf): ... this.
	(movqi_64): Use lhi instead of llill.
	(*movstrictqi, *movstricthi): Don't use (strict_low_part (mem)).

	* s390.md (extendsidi2, *extendsidi2, extendhidi2, *extendhidi2,
	extendqidi2, extendhisi2, *extendhisi2, extendqisi2,
	extendqihi2 and associated splitters): Reworked.
	(zero_extendsidi2, zero_extendsidi2, *zero_extendsidi2,
	zero_extendhidi2, *zero_extendhidi2, zero_extendqidi2,
	zero_extendqidi2, *zero_extendqidi2, zero_extendhisi2,
	*zero_extendhisi2_64, zero_extendhisi2_31, zero_extendqisi2,
	*zero_extendqisi2_64, *zero_extendqisi2_mem_31,
	zero_extendqisi2_reg_31, zero_extendqihi2, *zero_extendqisi2_64,
	zero_extendqihi2, zero_extendqihi2_64, zero_extendqihi2_31,
	and associated splitters): Likewise.
	(*sethighqisi, *sethighhisi, *sethighqidi_64, *sethighqidi_31
	and associated splitters): New.
	(truncdisi2, truncdihi2, truncdiqi2, truncsihi2, do_truncsihi2,
	*truncsihi2_64, truncsiqi2, trunchiqi2): Remove.
	(ashlhi3, ashrhi3, lshrhi3, abshi3): Remove.
	s390.h (PROMOTE_PROTOTYPES): Remove.
	config/s390/linux64.h (PROMOTE_PROTOTYPES): Likewise.

	* s390.md (muldi3): Delete, use instead ...
	(mulsidi3): ... this.
	(*muldi3_64): Rename to muldi3.
	(mulsi_6432): Fix template.
	(divdi3, moddi3): Delete, replace by ...
	(divmoddi4): ... this.
	(divmodtidi3): Fix template.
	(divmodtisi3): New.
	(udivdi3, umoddi3): Delete, replace by ...
	(udivmoddi4): ... this.
	(udivmodtidi3): Fix template.
	(divsi3, modsi3): Delete, replace by ...
	(divmodsi4): ... this.
	(divmoddisi3): Fix template.
	(udivsi3, umodsi3): Adapt.

	* s390.md (anddi3): Remove SS alternative, use instead ...
	(anddi3_ss, anddi3_ss_inv): ... these.
	(anddi3_ni): New.
	(andsi3*, andhi3*, andqi3*): Likewise.
	(iordi3): Remove SS alternative, use instead ...
	(iordi3_ss, iordi3_ss_inv): ... these.
	(iordi3_oi): New.
	(iorsi3*, iorhi3*, iorqi3*): Likewise.
	(iordi3_cc, iordi3_cconly, iorsi3_cc, iorsi3_cconly): New.
	(xordi3): Remove SS alternative, use instead ...
	(xordi3_ss, xordi3_ss_inv): ... these.
	(xordi3_oi): New.
	(xorsi3*, xorhi3*, xorqi3*): Likewise.
	(xordi3_cc, xordi3_cconly, xorsi3_cc, xorsi3_cconly): New.
	(one_cmpldi2, one_cmplsi2, one_cmplhi2, one_cmplqi2):
	Expand to XOR with -1.
	(*one_cmpldi2, *one_cmplsi2, *one_cmplhi2): Remove.
	(cmpdi_tm): Delete, replace by ...
	(cmpdi_tm_reg, cmpdi_tm_mem): ... these.
	(cmpsi_cct): Delete, replace by ...
	(cmpsi_tm_reg, cmpsi_tm_mem): ... these.
	(cmpdi_tm2, cmpsi_tm2): Improve.
	(cmphi_tm_sub, cmpqi_tm_sub, cmpqi_tm2, cmpqi_tm): New.
	s390.c (s390_single_hi, s390_extract_hi,
	s390_single_qi, s390_extract_qi): New helper routines.
	s390-protos.h (s390_single_hi, s390_extract_hi,
	s390_single_qi, s390_extract_qi): Declare.
	s390.c (tmxx_operand, const1_operand): Remove.
	s390-protos.h (tmxx_operand, const1_operand): Likewise.
	s390.h (PREDICATE_CODES): Likewise.

	* s390.md (sqrtdf2, sqrtsf2): New.

	* s390.h (CRT_CALL_STATIC_FUNCTION): Define.
	(check_and_change_labels): Remove section-change special case.

	* s390.h (RETURN_ADDR_RTX): Fix use of __builtin_return_address
	in leaf functions.  Needs ...
	(DYNAMIC_CHAIN_RTX):  ... this.  New.

	* s390.c (emit_pic_move): Don't generate pseudos if no_new_pseudos.

	* s390.md (movstrdix_64, movstrsix_31, movstrdi_64, movstrsi_31,
	clrstrsi_64, clrstrsi_31, cmpstr_64, cmpstr_31): Do not clobber
	input operands using a match_dup clause.
	(movstrdi, movstrsi, clrstrdi, clrstrsi, cmpstrdi, cmpstrsi): Adapt.

	* s390.md (floatdidf2, floatdisf2, floatsidf2, floatsidf2_ieee,
	floatsisf2, floatsisf2_ieee): Add missing CC clobber.

	* s390.md (floatsidf2_ibm): Use correct operand.

	* s390.md (fixuns_truncdfdi2, fixuns_truncdfsi2, fix_truncdfsi2,
	fixuns_truncsfdi2, fixuns_truncsfsi2, floatsidf2): Remove use of
	non-portable constants.
	s390.c (s390_gen_rtx_const_DI): New helper routine.
	s390-protos.h (s390_gen_rtx_const_DI): Declare.

	* s390.h (ASM_OUTPUT_SPECIAL_POOL_ENTRY): Fix alignment.

	* config/s390/linux.h (ASM_OUTPUT_SHORT, ASM_OUTPUT_CHAR,
	ASM_OUTPUT_BYTE): Clean up assembly output.
	(ASM_OUTPUT_SKIP, ASM_OUTPUT_ALIGN): Remove duplicate definitions.
	(ASM_OUTPUT_ASCII): Remove.

	* config/s390/t-linux (CRTSTUFF_T_CFLAGS_S): Define.

From-SVN: r48058
parent 8aab0f2b
2001-12-15 Ulrich Weigand <uweigand@de.ibm.com>
* s390.md (prologue, epilogue, *return_si, *return_di): New.
s390.c (find_unused_clobbered_reg, s390_frame_info,
save_fpr, restore_fpr, s390_emit_prologue, s390_emit_epilogue): New.
s390-protos.h (s390_emit_prologue, s390_emit_epilogue): Declare.
s390.c (s390_arg_frame_offset): Use s390_frame_info.
(leaf_function_flag, cur_is_leaf_function,
save_fprs, restore_fprs, force_const_mem_late): Remove.
(s390_function_prologue, s390_function_epilogue): Mostly remove.
s390.md (lit): New. Uses ...
s390.c (s390_output_constant_pool): ... this, so adapt and make global.
s390-protos.h (s390_output_constant_pool): Declare.
s390.md (load_multiple, store_multiple): Allow use after reload.
s390.c (load_multiple_operation, store_multiple_operation): Likewise.
s390.h (INCOMING_FRAME_SP_OFFSET): Define.
s390.h (CALL_REALLY_USED_REGISTERS): Define.
config/s390/linux64.h (CALL_USED_REGISTERS): Remove, now handled ...
s390.h (CONDITIONAL_REGISTER_USAGE): ... here.
s390.c (s390_sr_alias_set): New global variable, initialized ...
(override_options): ... here. New.
s390-protos.h (override_options): Declare.
s390.h (OVERRIDE_OPTIONS): Call it.
s390.c (s390_function_profiler): New.
s390-protos.h (s390_function_profiler): Declare.
s390.h (FUNCTION_PROFILER): Call it.
s390.c (s390_profile): Remove.
* s390.c (reg_used_in_mem_p): PC reload counts as memory access.
(addr_generation_dependency_p): Consider literal pool register loads.
(s390_adjust_priority): Do not schedule load_multiple.
s390.md (attribute "type"): Define some additional types.
(function_unit "integer"): Adapt.
(many insns): Adapt "type" attribute setting.
* s390.c (general_s_operand, s_imm_operand): New.
(s_operand): Remove old definition, call general_s_operand instead.
s390-protos.h (s_imm_operand): Declare.
s390.c (base_n_index_p, r_or_s_operand, r_or_s_or_im8_operand,
r_or_x_or_im16_operand, r_or_im8_operand): Remove.
s390-protos.h (r_or_s_operand, r_or_s_or_im8_operand,
r_or_x_or_im16_operand, r_or_im8_operand): Likewise.
s390.h (PREDICATE_CODES): Add s_imm_operand, remove r_or_s*_operand.
s390.md (many insns): Rework insn predicates.
* s390.c (legitimate_pic_operand_p, legitimate_constant_p): Accept all
non-symbolic constants. Reload will force them because of ...
(s390_preferred_reload_class): ... this. New.
s390-protos.h (s390_preferred_reload_class): Declare.
s390.h (PREFERRED_RELOAD_CLASS): Call it.
s390.md (movdi, movsi, movdf, movsf, *reload_la_64 splitters,
*reload_la_31 splitters): Handle constants after reload.
(many insns): no longer force all constants immediately.
s390.c (legitimate_reload_constant_p): New helper routine.
s390-protos.h (legitimate_reload_constant_p): Declare.
s390.c (print_operand): Clean up CONST_INT case, add CONST_DOUBLE case.
* s390.h (FIRST_PSEUDO_REGISTER, FRAME_POINTER_REGNUM,
HARD_FRAME_POINTER_REGNUM, REGISTER_NAMES): Add virtual frame pointer.
(CALL_USED_REGISTERS, CALL_REALLY_USED_REGISTERS): Update.
(ELIMINABLE_REGS, INITIAL_ELIMINATION_OFFSET): Likewise.
(REGNO_OK_FOR_INDEX_P, REG_OK_FOR_INDEX_NONSTRICT_P): Likewise.
(DWARF_FRAME_REGISTERS): Define.
s390.c (regclass_map): Add virtual frame pointer.
(legitimate_la_operand_p): Allow use of virtual frame pointer.
s390.md (*la_ccclobber, *addaddr_ccclobber): New.
(addaddr, addsi_64): Delete.
* s390.h (HARD_REGNO_MODE_OK): Allow SImode and DImode values in
floating point registers.
(CLASS_CANNOT_CHANGE_MODE, CLASS_CANNOT_CHANGE_MODE_P): Define.
(ADDR_FP_REGS, GENERAL_FP_REGS): New register classes.
(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update.
* s390.md (movti): Replace multi-insn output with splitters.
(movdi_31, movdf_31): Likewise.
(movti_ss, movdi_ss, movsi_ss, movdf_ss, movsf_ss): New.
(movdi_lhi, movdi_lli, movdi_larl, movsi_lhi, movsi_lli): New.
(movdi_64, movdi_31, movsi, movdf_64, movdf_31): Adapt.
(movdf_soft_64, movdf_soft_31, movsf_soft): Remove.
(movsf_64, movsf_31): Remove, replace by ...
(movsf): ... this.
(movqi_64): Use lhi instead of llill.
(*movstrictqi, *movstricthi): Don't use (strict_low_part (mem)).
* s390.md (extendsidi2, *extendsidi2, extendhidi2, *extendhidi2,
extendqidi2, extendhisi2, *extendhisi2, extendqisi2,
extendqihi2 and associated splitters): Reworked.
(zero_extendsidi2, zero_extendsidi2, *zero_extendsidi2,
zero_extendhidi2, *zero_extendhidi2, zero_extendqidi2,
zero_extendqidi2, *zero_extendqidi2, zero_extendhisi2,
*zero_extendhisi2_64, zero_extendhisi2_31, zero_extendqisi2,
*zero_extendqisi2_64, *zero_extendqisi2_mem_31,
zero_extendqisi2_reg_31, zero_extendqihi2, *zero_extendqisi2_64,
zero_extendqihi2, zero_extendqihi2_64, zero_extendqihi2_31,
and associated splitters): Likewise.
(*sethighqisi, *sethighhisi, *sethighqidi_64, *sethighqidi_31
and associated splitters): New.
(truncdisi2, truncdihi2, truncdiqi2, truncsihi2, do_truncsihi2,
*truncsihi2_64, truncsiqi2, trunchiqi2): Remove.
(ashlhi3, ashrhi3, lshrhi3, abshi3): Remove.
s390.h (PROMOTE_PROTOTYPES): Remove.
config/s390/linux64.h (PROMOTE_PROTOTYPES): Likewise.
* s390.md (muldi3): Delete, use instead ...
(mulsidi3): ... this.
(*muldi3_64): Rename to muldi3.
(mulsi_6432): Fix template.
(divdi3, moddi3): Delete, replace by ...
(divmoddi4): ... this.
(divmodtidi3): Fix template.
(divmodtisi3): New.
(udivdi3, umoddi3): Delete, replace by ...
(udivmoddi4): ... this.
(udivmodtidi3): Fix template.
(divsi3, modsi3): Delete, replace by ...
(divmodsi4): ... this.
(divmoddisi3): Fix template.
(udivsi3, umodsi3): Adapt.
* s390.md (anddi3): Remove SS alternative, use instead ...
(anddi3_ss, anddi3_ss_inv): ... these.
(anddi3_ni): New.
(andsi3*, andhi3*, andqi3*): Likewise.
(iordi3): Remove SS alternative, use instead ...
(iordi3_ss, iordi3_ss_inv): ... these.
(iordi3_oi): New.
(iorsi3*, iorhi3*, iorqi3*): Likewise.
(iordi3_cc, iordi3_cconly, iorsi3_cc, iorsi3_cconly): New.
(xordi3): Remove SS alternative, use instead ...
(xordi3_ss, xordi3_ss_inv): ... these.
(xordi3_oi): New.
(xorsi3*, xorhi3*, xorqi3*): Likewise.
(xordi3_cc, xordi3_cconly, xorsi3_cc, xorsi3_cconly): New.
(one_cmpldi2, one_cmplsi2, one_cmplhi2, one_cmplqi2):
Expand to XOR with -1.
(*one_cmpldi2, *one_cmplsi2, *one_cmplhi2): Remove.
(cmpdi_tm): Delete, replace by ...
(cmpdi_tm_reg, cmpdi_tm_mem): ... these.
(cmpsi_cct): Delete, replace by ...
(cmpsi_tm_reg, cmpsi_tm_mem): ... these.
(cmpdi_tm2, cmpsi_tm2): Improve.
(cmphi_tm_sub, cmpqi_tm_sub, cmpqi_tm2, cmpqi_tm): New.
s390.c (s390_single_hi, s390_extract_hi,
s390_single_qi, s390_extract_qi): New helper routines.
s390-protos.h (s390_single_hi, s390_extract_hi,
s390_single_qi, s390_extract_qi): Declare.
s390.c (tmxx_operand, const1_operand): Remove.
s390-protos.h (tmxx_operand, const1_operand): Likewise.
s390.h (PREDICATE_CODES): Likewise.
* s390.md (sqrtdf2, sqrtsf2): New.
* s390.h (CRT_CALL_STATIC_FUNCTION): Define.
(check_and_change_labels): Remove section-change special case.
* s390.h (RETURN_ADDR_RTX): Fix use of __builtin_return_address
in leaf functions. Needs ...
(DYNAMIC_CHAIN_RTX): ... this. New.
* s390.c (emit_pic_move): Don't generate pseudos if no_new_pseudos.
* s390.md (movstrdix_64, movstrsix_31, movstrdi_64, movstrsi_31,
clrstrsi_64, clrstrsi_31, cmpstr_64, cmpstr_31): Do not clobber
input operands using a match_dup clause.
(movstrdi, movstrsi, clrstrdi, clrstrsi, cmpstrdi, cmpstrsi): Adapt.
* s390.md (floatdidf2, floatdisf2, floatsidf2, floatsidf2_ieee,
floatsisf2, floatsisf2_ieee): Add missing CC clobber.
* s390.md (floatsidf2_ibm): Use correct operand.
* s390.md (fixuns_truncdfdi2, fixuns_truncdfsi2, fix_truncdfsi2,
fixuns_truncsfdi2, fixuns_truncsfsi2, floatsidf2): Remove use of
non-portable constants.
s390.c (s390_gen_rtx_const_DI): New helper routine.
s390-protos.h (s390_gen_rtx_const_DI): Declare.
* s390.h (ASM_OUTPUT_SPECIAL_POOL_ENTRY): Fix alignment.
* config/s390/linux.h (ASM_OUTPUT_SHORT, ASM_OUTPUT_CHAR,
ASM_OUTPUT_BYTE): Clean up assembly output.
(ASM_OUTPUT_SKIP, ASM_OUTPUT_ALIGN): Remove duplicate definitions.
(ASM_OUTPUT_ASCII): Remove.
* config/s390/t-linux (CRTSTUFF_T_CFLAGS_S): Define.
2001-12-15 Zack Weinberg <zack@codesourcery.com>
* unwind-dw2-fde-glibc.c: #define _Unwind_Find_FDE to itself
......
......@@ -154,19 +154,19 @@ do { fprintf (FILE, "%s\t", ASM_LONG); \
is this supposed to do align too?? */
#define ASM_OUTPUT_SHORT(FILE, VALUE) \
( fprintf (FILE, "%s ", ASM_SHORT), \
( fprintf (FILE, "%s\t", ASM_SHORT), \
output_addr_const (FILE, (VALUE)), \
putc ('\n',FILE))
#define ASM_OUTPUT_CHAR(FILE, VALUE) \
( fprintf (FILE, "%s ", ASM_BYTE_OP), \
( fprintf (FILE, "\t%s\t", ASM_BYTE_OP), \
output_addr_const (FILE, (VALUE)), \
putc ('\n', FILE))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE, VALUE) \
fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (int)(VALUE))
fprintf ((FILE), "\t%s\t0x%x\n", ASM_BYTE_OP, (int)(VALUE))
/* internal macro to output long */
#define _ASM_OUTPUT_LONG(FILE, VALUE) \
......@@ -191,75 +191,16 @@ do { fprintf (FILE, "%s\t", ASM_LONG); \
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#define ASM_OUTPUT_ALIGN(FILE, LOG) \
if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG))
/* This is how to output an assembler line
that says to advance the location counter by SIZE bytes. */
#undef ASM_OUTPUT_SKIP
#define ASM_OUTPUT_SKIP(FILE, SIZE) \
fprintf ((FILE), "\t.set .,.+%u\n", (SIZE))
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#undef ASM_OUTPUT_ALIGN
#define ASM_OUTPUT_ALIGN(FILE, LOG) \
if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG))
if ((LOG)!=0) fprintf ((FILE), "\t.align\t%d\n", 1<<(LOG))
/* This is how to output an assembler line
that says to advance the location counter by SIZE bytes. */
#undef ASM_OUTPUT_SKIP
#define ASM_OUTPUT_SKIP(FILE, SIZE) \
fprintf ((FILE), "\t.set .,.+%u\n", (SIZE))
/* The routine used to output sequences of byte values. We use a special
version of this for most svr4 targets because doing so makes the
generated assembly code more compact (and thus faster to assemble)
as well as more readable. Note that if we find subparts of the
character sequence which end with NUL (and which are shorter than
STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */
#undef ASM_OUTPUT_ASCII
#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \
do { \
register const unsigned char *_ascii_bytes = (const unsigned char *) (STR); \
register const unsigned char *limit = _ascii_bytes + (LENGTH); \
register unsigned bytes_in_chunk = 0; \
for (; _ascii_bytes < limit; _ascii_bytes++) \
{ \
register const unsigned char *p; \
if (bytes_in_chunk >= 64) \
{ \
fputc ('\n', (FILE)); \
bytes_in_chunk = 0; \
} \
for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \
continue; \
if (p < limit && (p - _ascii_bytes) <= (long)STRING_LIMIT) \
{ \
if (bytes_in_chunk > 0) \
{ \
fputc ('\n', (FILE)); \
bytes_in_chunk = 0; \
} \
ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \
_ascii_bytes = p; \
} \
else \
{ \
if (bytes_in_chunk == 0) \
fprintf ((FILE), "%s\t", ASM_BYTE_OP); \
else \
fputc (',', (FILE)); \
fprintf ((FILE), "0x%02x", *_ascii_bytes); \
bytes_in_chunk += 5; \
} \
} \
if (bytes_in_chunk > 0) \
fprintf ((FILE), "\n"); \
} while (0)
fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE))
/* Output before read-only data. */
......
......@@ -59,21 +59,7 @@ Boston, MA 02111-1307, USA. */
%{static:-static}}}"
#endif
#undef PROMOTE_PROTOTYPES
#undef MASK_RETURN_ADDR
#undef SELECT_SECTION
/* With 64 bit new linkage for floating point registers. */
#undef CALL_USED_REGISTERS
#define CALL_USED_REGISTERS \
{ 1, 1, 1, 1, \
1, 1, 0, 0, \
0, 0, 0, 0, \
0, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
0, 0, 0, 0, \
0, 0, 0, 0, \
1, 1 }
#endif
......@@ -22,24 +22,27 @@ Boston, MA 02111-1307, USA. */
/* Declare functions in s390.c. */
extern void optimization_options PARAMS ((int, int));
extern void override_options PARAMS ((void));
extern int s390_arg_frame_offset PARAMS ((void));
extern void s390_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
extern void s390_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
extern void s390_emit_prologue PARAMS ((void));
extern void s390_emit_epilogue PARAMS ((void));
extern void s390_function_profiler PARAMS ((FILE *, int));
#ifdef RTX_CODE
extern int const0_operand PARAMS ((rtx, enum machine_mode));
extern int const1_operand PARAMS ((rtx, enum machine_mode));
extern int larl_operand PARAMS ((rtx, enum machine_mode));
extern int fp_operand PARAMS ((rtx, enum machine_mode));
extern int s_operand PARAMS ((rtx, enum machine_mode));
extern int r_or_s_operand PARAMS ((rtx, enum machine_mode));
extern int r_or_s_or_im8_operand PARAMS ((rtx, enum machine_mode));
extern int r_or_x_or_im16_operand PARAMS ((rtx, enum machine_mode));
extern int r_or_im8_operand PARAMS ((rtx, enum machine_mode));
extern int tmxx_operand PARAMS ((rtx, enum machine_mode));
extern int s_imm_operand PARAMS ((rtx, enum machine_mode));
extern int bras_sym_operand PARAMS ((rtx, enum machine_mode));
extern int load_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int s390_single_hi PARAMS ((rtx, enum machine_mode, int));
extern int s390_extract_hi PARAMS ((rtx, enum machine_mode, int));
extern int s390_single_qi PARAMS ((rtx, enum machine_mode, int));
extern int s390_extract_qi PARAMS ((rtx, enum machine_mode, int));
extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode));
extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
......@@ -47,18 +50,22 @@ extern int symbolic_reference_mentioned_p PARAMS ((rtx));
extern int legitimate_la_operand_p PARAMS ((rtx));
extern int legitimate_pic_operand_p PARAMS ((rtx));
extern int legitimate_constant_p PARAMS ((rtx));
extern int legitimate_reload_constant_p PARAMS ((rtx));
extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
extern rtx legitimize_pic_address PARAMS ((rtx, rtx));
extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class));
extern void emit_pic_move PARAMS ((rtx *, enum machine_mode));
extern void s390_output_symbolic_const PARAMS ((FILE *, rtx));
extern void print_operand_address PARAMS ((FILE *, rtx));
extern void print_operand PARAMS ((FILE *, rtx, int));
extern void s390_output_constant_pool PARAMS ((FILE *));
extern int s390_stop_dump_lit_p PARAMS ((rtx));
extern void s390_dump_literal_pool PARAMS ((rtx, rtx));
extern void s390_trampoline_template PARAMS ((FILE *));
extern void s390_initialize_trampoline PARAMS ((rtx, rtx, rtx));
extern rtx s390_gen_rtx_const_DI PARAMS ((int, int));
#endif /* RTX_CODE */
#ifdef TREE_CODE
......
......@@ -39,6 +39,7 @@ Boston, MA 02111-1307, USA. */
#include "expr.h"
#include "toplev.h"
#include "basic-block.h"
#include "integrate.h"
#include "ggc.h"
#include "target.h"
#include "target-def.h"
......@@ -70,6 +71,9 @@ struct gcc_target targetm = TARGET_INITIALIZER;
extern int reload_completed;
/* The alias set for prologue/epilogue register save/restore. */
static int s390_sr_alias_set = 0;
/* Function count for creating unique internal labels in a compile unit. */
int s390_function_count = 0;
......@@ -93,11 +97,26 @@ struct s390_address
rtx disp;
};
/* Structure containing information for prologue and epilogue. */
struct s390_frame
{
int frame_pointer_p;
int return_reg_saved_p;
int save_fprs_p;
int first_save_gpr;
int first_restore_gpr;
int last_save_gpr;
int arg_frame_offset;
HOST_WIDE_INT frame_size;
};
static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
static int s390_branch_condition_mask PARAMS ((rtx));
static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));
static int base_n_index_p PARAMS ((rtx));
static int check_mode PARAMS ((rtx, enum machine_mode *));
static int general_s_operand PARAMS ((rtx, enum machine_mode, int));
static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
static int reg_used_in_mem_p PARAMS ((int, rtx));
static int addr_generation_dependency_p PARAMS ((rtx, rtx));
......@@ -106,12 +125,10 @@ static int far_away PARAMS ((int, int));
static rtx check_and_change_labels PARAMS ((rtx, int *));
static void s390_final_chunkify PARAMS ((int));
static int save_fprs_p PARAMS ((void));
static int cur_is_leaf_function PARAMS ((void));
static int save_fprs PARAMS ((FILE *, long, int));
static int restore_fprs PARAMS ((FILE *, long, int));
static void s390_output_constant_pool PARAMS ((FILE *));
static rtx s390_force_const_mem_late PARAMS ((rtx));
static rtx s390_force_const_mem_symbol PARAMS ((const char *, int, int));
static int find_unused_clobbered_reg PARAMS ((void));
static void s390_frame_info PARAMS ((struct s390_frame *));
static rtx save_fpr PARAMS ((rtx, int, int));
static rtx restore_fpr PARAMS ((rtx, int, int));
static int s390_function_arg_size PARAMS ((enum machine_mode, tree));
......@@ -339,6 +356,212 @@ s390_branch_condition_mnemonic (code, inv)
return mnemonic[mask];
}
/* If OP is an integer constant of mode MODE with exactly one
HImode subpart unequal to DEF, return the number of that
subpart. As a special case, all HImode subparts of OP are
equal to DEF, return zero. Otherwise, return -1. */
int
s390_single_hi (op, mode, def)
rtx op;
enum machine_mode mode;
int def;
{
if (GET_CODE (op) == CONST_INT)
{
unsigned HOST_WIDE_INT value;
int n_parts = GET_MODE_SIZE (mode) / 2;
int i, part = -1;
for (i = 0; i < n_parts; i++)
{
if (i == 0)
value = (unsigned HOST_WIDE_INT) INTVAL (op);
else
value >>= 16;
if ((value & 0xffff) != (unsigned)(def & 0xffff))
{
if (part != -1)
return -1;
else
part = i;
}
}
return part == -1 ? 0 : (n_parts - 1 - part);
}
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
unsigned HOST_WIDE_INT value;
int n_parts = GET_MODE_SIZE (mode) / 2;
int i, part = -1;
for (i = 0; i < n_parts; i++)
{
if (i == 0)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
else if (i == HOST_BITS_PER_WIDE_INT / 16)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
else
value >>= 16;
if ((value & 0xffff) != (unsigned)(def & 0xffff))
{
if (part != -1)
return -1;
else
part = i;
}
}
return part == -1 ? 0 : (n_parts - 1 - part);
}
return -1;
}
/* Extract the HImode part number PART from integer
constant OP of mode MODE. */
int
s390_extract_hi (op, mode, part)
rtx op;
enum machine_mode mode;
int part;
{
int n_parts = GET_MODE_SIZE (mode) / 2;
if (part < 0 || part >= n_parts)
abort();
else
part = n_parts - 1 - part;
if (GET_CODE (op) == CONST_INT)
{
unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
return ((value >> (16 * part)) & 0xffff);
}
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
unsigned HOST_WIDE_INT value;
if (part < HOST_BITS_PER_WIDE_INT / 16)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
else
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
part -= HOST_BITS_PER_WIDE_INT / 16;
return ((value >> (16 * part)) & 0xffff);
}
abort ();
}
/* If OP is an integer constant of mode MODE with exactly one
QImode subpart unequal to DEF, return the number of that
subpart. As a special case, all QImode subparts of OP are
equal to DEF, return zero. Otherwise, return -1. */
int
s390_single_qi (op, mode, def)
rtx op;
enum machine_mode mode;
int def;
{
if (GET_CODE (op) == CONST_INT)
{
unsigned HOST_WIDE_INT value;
int n_parts = GET_MODE_SIZE (mode);
int i, part = -1;
for (i = 0; i < n_parts; i++)
{
if (i == 0)
value = (unsigned HOST_WIDE_INT) INTVAL (op);
else
value >>= 8;
if ((value & 0xff) != (unsigned)(def & 0xff))
{
if (part != -1)
return -1;
else
part = i;
}
}
return part == -1 ? 0 : (n_parts - 1 - part);
}
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
unsigned HOST_WIDE_INT value;
int n_parts = GET_MODE_SIZE (mode);
int i, part = -1;
for (i = 0; i < n_parts; i++)
{
if (i == 0)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
else if (i == HOST_BITS_PER_WIDE_INT / 8)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op);
else
value >>= 8;
if ((value & 0xff) != (unsigned)(def & 0xff))
{
if (part != -1)
return -1;
else
part = i;
}
}
return part == -1 ? 0 : (n_parts - 1 - part);
}
return -1;
}
/* Extract the QImode part number PART from integer
constant OP of mode MODE. */
int
s390_extract_qi (op, mode, part)
rtx op;
enum machine_mode mode;
int part;
{
int n_parts = GET_MODE_SIZE (mode);
if (part < 0 || part >= n_parts)
abort();
else
part = n_parts - 1 - part;
if (GET_CODE (op) == CONST_INT)
{
unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op);
return ((value >> (8 * part)) & 0xff);
}
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
unsigned HOST_WIDE_INT value;
if (part < HOST_BITS_PER_WIDE_INT / 8)
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
else
value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op),
part -= HOST_BITS_PER_WIDE_INT / 8;
return ((value >> (8 * part)) & 0xff);
}
abort ();
}
/* Change optimizations to be performed, depending on the
optimization level.
......@@ -360,6 +583,13 @@ optimization_options (level, size)
#endif
}
void
override_options ()
{
/* Acquire a unique set number for our register saves and restores. */
s390_sr_alias_set = new_alias_set ();
}
/* Map for smallest class containing reg regno. */
......@@ -372,7 +602,7 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
ADDR_REGS, NO_REGS
ADDR_REGS, NO_REGS, ADDR_REGS
};
......@@ -388,32 +618,6 @@ const0_operand (op, mode)
return op == CONST0_RTX (mode);
}
/* Return true if OP a (const_int 1) operand.
OP is the current operation.
MODE is the current operation mode. */
int
const1_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return op == CONST1_RTX (mode);
}
/* Return true if OP needs base and index register. */
static int
base_n_index_p (op)
register rtx op;
{
if ((GET_CODE (op) == PLUS) &&
(GET_CODE (XEXP (op, 0)) == PLUS ||
GET_CODE (XEXP (op, 1)) == PLUS ||
GET_CODE (XEXP (op, 1)) == REG ))
return 1;
return 0;
}
/* Return true if the mode of operand OP matches MODE.
If MODE is set to VOIDmode, set it to the mode of OP. */
......@@ -503,146 +707,90 @@ fp_operand (op, mode)
return 0;
}
/* Return true if OP is a valid S operand for an RS, SI or SS type instruction.
OP is the current operation.
MODE is the current operation mode. */
int
s_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
register enum rtx_code code = GET_CODE (op);
if (! check_mode (op,&mode))
return 0;
if (code == MEM) {
if (base_n_index_p (XEXP (op, 0)))
return 0;
}
return memory_operand (op, mode);
}
/* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
instruction.
/* Helper routine to implement s_operand and s_imm_operand.
OP is the current operation.
MODE is the current operation mode. */
MODE is the current operation mode.
ALLOW_IMMEDIATE specifies whether immediate operands should
be accepted or not. */
int
r_or_s_operand (op, mode)
static int
general_s_operand (op, mode, allow_immediate)
register rtx op;
enum machine_mode mode;
int allow_immediate;
{
register enum rtx_code code = GET_CODE (op);
struct s390_address addr;
/* Call general_operand first, so that we don't have to
check for many special cases. */
if (!general_operand (op, mode))
return 0;
if (code == MEM) {
if (base_n_index_p (XEXP (op, 0)))
return 0;
else
return memory_operand (op, mode);
}
return register_operand (op, mode);
}
/* Just like memory_operand, allow (subreg (mem ...))
after reload. */
if (reload_completed
&& GET_CODE (op) == SUBREG
&& GET_CODE (SUBREG_REG (op)) == MEM)
op = SUBREG_REG (op);
/* Return true if OP is a valid R or S or immediate operand for
RS, SI or SS type instruction.
OP is the current operation.
MODE is the current operation mode. */
int
r_or_s_or_im8_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
register enum rtx_code code = GET_CODE (op);
switch (GET_CODE (op))
{
/* Constants that we are sure will be forced to the
literal pool in reload are OK as s-operand. Note
that we cannot call s390_preferred_reload_class here
because it might not be known yet at this point
whether the current function is a leaf or not. */
case CONST_INT:
case CONST_DOUBLE:
if (!allow_immediate || reload_completed)
break;
if (!legitimate_reload_constant_p (op))
return 1;
if (!TARGET_64BIT)
return 1;
break;
/* Memory operands are OK unless they already use an
index register. */
case MEM:
if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
return 1;
if (s390_decompose_address (XEXP (op, 0), &addr, FALSE)
&& !addr.indx)
return 1;
break;
if (!general_operand (op, mode))
return 0;
default:
break;
}
if (code == MEM) {
if (base_n_index_p (XEXP (op, 0)))
return 0;
else
return memory_operand (op, mode);
}
return register_operand (op, mode) || immediate_operand (op, mode);
return 0;
}
/* Return true if OP is a valid R or X or 16 bit immediate operand for
RX, RR or RI type instruction.
/* Return true if OP is a valid S-type operand.
OP is the current operation.
MODE is the current operation mode. */
int
r_or_x_or_im16_operand (op, mode)
s_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (! general_operand (op, mode))
return 0;
if (GET_CODE (op) == CONST_INT)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'));
return register_operand (op, mode) || memory_operand (op, mode);
return general_s_operand (op, mode, 0);
}
/* Return true if OP is a valid R or 8 bit immediate operand.
/* Return true if OP is a valid S-type operand or an immediate
operand that can be addressed as S-type operand by forcing
it into the literal pool.
OP is the current operation.
MODE is the current operation mode. */
int
r_or_im8_operand (op, mode)
s_imm_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (!general_operand (op, mode))
return 0;
if (GET_CODE (op) == CONST_INT)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'));
return register_operand (op, mode) || memory_operand (op, mode);
}
/* Return true if OP is a valid operand for the 'test under mask'
instruction with 16 bit immediate.
The value should only have set bits in one halfword.
OP is the current operation.
MODE is the current operation mode. */
int
tmxx_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx con;
if (GET_CODE (op) == CONST_INT)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == SYMBOL_REF &&
CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
{
con = get_pool_constant (XEXP (op, 0));
if (GET_CODE (con) == CONST_INT)
{
unsigned HOST_WIDEST_INT c;
c = (unsigned HOST_WIDEST_INT) INTVAL (con);
return ((c & 0xffff) ? ((c & 0xffffffffffff0000ULL)==0) :
(c & 0xffff0000U) ? ((c & 0xffffffff0000ffffULL)==0) :
(c & 0xffff00000000ULL) ? ((c & 0xffff0000ffffffffULL)==0) :
(c & 0xffff000000000000ULL) ? ((c & 0xffffffffffffULL)==0) : 1);
}
}
return 0;
return general_s_operand (op, mode, 1);
}
/* Return true if OP is a valid operand for the BRAS instruction.
......@@ -682,7 +830,7 @@ load_multiple_operation (op, mode)
int count = XVECLEN (op, 0);
unsigned int dest_regno;
rtx src_addr;
int i;
int i, off;
/* Perform a quick check so we don't blow up below. */
......@@ -695,6 +843,23 @@ load_multiple_operation (op, mode)
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
/* Check, is base, or base + displacement. */
if (GET_CODE (src_addr) == REG)
off = 0;
else if (GET_CODE (src_addr) == PLUS
&& GET_CODE (XEXP (src_addr, 0)) == REG
&& GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
{
off = INTVAL (XEXP (src_addr, 1));
src_addr = XEXP (src_addr, 0);
}
else
return 0;
if (src_addr == frame_pointer_rtx || src_addr == arg_pointer_rtx)
return 0;
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i);
......@@ -708,7 +873,8 @@ load_multiple_operation (op, mode)
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|| ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|| GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
!= off + i * UNITS_PER_WORD)
return 0;
}
......@@ -725,10 +891,10 @@ store_multiple_operation (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int count = XVECLEN (op, 0) - 1;
int count = XVECLEN (op, 0);
unsigned int src_regno;
rtx dest_addr;
int i;
int i, off;
/* Perform a quick check so we don't blow up below. */
if (count <= 1
......@@ -740,6 +906,23 @@ store_multiple_operation (op, mode)
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
/* Check, is base, or base + displacement. */
if (GET_CODE (dest_addr) == REG)
off = 0;
else if (GET_CODE (dest_addr) == PLUS
&& GET_CODE (XEXP (dest_addr, 0)) == REG
&& GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
{
off = INTVAL (XEXP (dest_addr, 1));
dest_addr = XEXP (dest_addr, 0);
}
else
return 0;
if (dest_addr == frame_pointer_rtx || dest_addr == arg_pointer_rtx)
return 0;
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i);
......@@ -753,7 +936,8 @@ store_multiple_operation (op, mode)
|| GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|| ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|| GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
!= off + i * UNITS_PER_WORD)
return 0;
}
return 1;
......@@ -800,8 +984,7 @@ int
legitimate_pic_operand_p (op)
register rtx op;
{
/* All non-symbolic constants that made it
up to here are fine. */
/* Accept all non-symbolic constants. */
if (!SYMBOLIC_CONST (op))
return 1;
......@@ -821,13 +1004,7 @@ int
legitimate_constant_p (op)
register rtx op;
{
/* Reject doubles and integers out of range. */
if (GET_CODE (op) == CONST_DOUBLE ||
(GET_CODE (op) == CONST_INT &&
(INTVAL (op) < -32768 || INTVAL (op) > 32767)))
return 0;
/* Accept all other non-symbolic constants. */
/* Accept all non-symbolic constants. */
if (!SYMBOLIC_CONST (op))
return 1;
......@@ -847,6 +1024,93 @@ legitimate_constant_p (op)
return 0;
}
/* Returns true if the constant value OP is a legitimate general
operand during and after reload. The difference to
legitimate_constant_p is that this function will not accept
a constant that would need to be forced to the literal pool
before it can be used as operand. */
int
legitimate_reload_constant_p (op)
register rtx op;
{
/* Accept l(g)hi operands. */
if (GET_CODE (op) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
return 1;
/* Accept lliXX operands. */
if (TARGET_64BIT
&& s390_single_hi (op, DImode, 0) >= 0)
return 1;
/* Accept larl operands. */
if (TARGET_64BIT
&& larl_operand (op, VOIDmode))
return 1;
/* If reload is completed, and we do not already have a
literal pool, and OP must be forced to the literal
pool, then something must have gone wrong earlier.
We *cannot* force the constant any more, because the
prolog generation already decided we don't need to
set up the base register. */
if (reload_completed && !regs_ever_live[BASE_REGISTER])
abort ();
/* Everything else cannot be handled without reload. */
return 0;
}
/* Given an rtx OP being reloaded into a reg required to be in class CLASS,
return the class of reg to actually use. */
enum reg_class
s390_preferred_reload_class (op, class)
rtx op;
enum reg_class class;
{
/* This can happen if a floating point constant is being
reloaded into an integer register. Leave well alone. */
if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
&& class != FP_REGS)
return class;
switch (GET_CODE (op))
{
/* Constants we cannot reload must be forced into the
literal pool. For constants we *could* handle directly,
it might still be preferable to put them in the pool and
use a memory-to-memory instruction.
However, try to avoid needlessly allocating a literal
pool in a routine that wouldn't otherwise need any.
Heuristically, we assume that 64-bit leaf functions
typically don't need a literal pool, all others do. */
case CONST_DOUBLE:
case CONST_INT:
if (!legitimate_reload_constant_p (op))
return NO_REGS;
if (TARGET_64BIT && current_function_is_leaf)
return class;
return NO_REGS;
/* If a symbolic constant or a PLUS is reloaded,
it is most likely being used as an address. */
case PLUS:
case LABEL_REF:
case SYMBOL_REF:
case CONST:
return ADDR_REGS;
default:
break;
}
return class;
}
/* Decompose a RTL expression ADDR for a memory address into
its components, returned in OUT. The boolean STRICT
......@@ -1063,14 +1327,16 @@ legitimate_la_operand_p (op)
if (addr.base && GET_CODE (addr.base) == REG)
{
if (REGNO (addr.base) == BASE_REGISTER
|| REGNO (addr.base) == STACK_POINTER_REGNUM)
|| REGNO (addr.base) == STACK_POINTER_REGNUM
|| REGNO (addr.base) == FRAME_POINTER_REGNUM)
return TRUE;
}
if (addr.indx && GET_CODE (addr.indx) == REG)
{
if (REGNO (addr.indx) == BASE_REGISTER
|| REGNO (addr.indx) == STACK_POINTER_REGNUM)
|| REGNO (addr.indx) == STACK_POINTER_REGNUM
|| REGNO (addr.base) == FRAME_POINTER_REGNUM)
return TRUE;
}
......@@ -1364,7 +1630,7 @@ emit_pic_move (operands, mode)
rtx *operands;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
operands[1] = force_reg (Pmode, operands[1]);
......@@ -1532,7 +1798,7 @@ print_operand_address (file, addr)
struct s390_address ad;
if (!s390_decompose_address (addr, &ad, TRUE))
output_operand_lossage ("cannot decompose address.\n");
output_operand_lossage ("Cannot decompose address.");
if (ad.disp)
s390_output_symbolic_const (file, ad.disp);
......@@ -1657,15 +1923,26 @@ print_operand (file, x, code)
case CONST_INT:
if (code == 'b')
fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
else if (code == 'X')
fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff);
else if (code == 'x')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
else if (code == 'h')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000);
else
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST_DOUBLE:
if (GET_MODE (x) != VOIDmode)
abort ();
if (code == 'b')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff);
else if (code == 'x')
fprintf (file, "0x%x", (int)(INTVAL (x) & 0xffff));
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff);
else if (code == 'h')
fprintf (file, "%d", (int)(INTVAL (x) << 16) >> 16);
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000);
else
fprintf (file, "%d", (int)INTVAL (x));
abort ();
break;
default:
......@@ -1694,6 +1971,13 @@ reg_used_in_mem_p (regno, x)
XEXP (x, 0), 0))
return 1;
}
else if (code == SET
&& GET_CODE (SET_DEST (x)) == PC)
{
if (refers_to_regno_p (regno, regno+1,
SET_SRC (x), 0))
return 1;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
......@@ -1718,7 +2002,7 @@ addr_generation_dependency_p (dep_rtx, insn)
rtx dep_rtx;
rtx insn;
{
rtx target;
rtx target, pat;
if (GET_CODE (dep_rtx) == SET)
{
......@@ -1729,11 +2013,22 @@ addr_generation_dependency_p (dep_rtx, insn)
int regno = REGNO (target);
if (get_attr_type (insn) == TYPE_LA)
return refers_to_regno_p (regno, regno+1,
SET_SRC (PATTERN (insn)), 0);
else if (get_attr_atype (insn) == ATYPE_MEM)
return reg_used_in_mem_p (regno, PATTERN (insn));
}
{
pat = PATTERN (insn);
if (GET_CODE (pat) == PARALLEL)
{
if (XVECLEN (pat, 0) != 2)
abort();
pat = XVECEXP (pat, 0, 0);
}
if (GET_CODE (pat) == SET)
return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0);
else
abort();
}
else if (get_attr_atype (insn) == ATYPE_MEM)
return reg_used_in_mem_p (regno, PATTERN (insn));
}
}
return 0;
}
......@@ -1839,6 +2134,14 @@ s390_adjust_priority (insn, priority)
if (priority >= 0 && priority < 0x01000000)
priority <<= 3;
break;
case TYPE_LM:
/* LM in epilogue should never be scheduled. This
is due to literal access done in function body.
The usage of register 13 is not mentioned explicitly,
leading to scheduling 'LM' accross this instructions.
*/
priority = 0x7fffffff;
break;
}
return priority;
......@@ -2114,8 +2417,6 @@ s390_final_chunkify (chunkify)
int addr, naddr = 0, uids;
int chunk_max = 0;
const char *asms;
int size = insn_current_address;
int *ltorg_uids;
......@@ -2171,19 +2472,6 @@ s390_final_chunkify (chunkify)
warning ("no code label found");
}
}
else if (GET_CODE (PATTERN (insn)) == ASM_INPUT && !TARGET_64BIT)
{
asms = XSTR (PATTERN (insn),0);
if ((memcmp (asms,".section",8) == 0) ||
(memcmp (asms,".text",5) == 0) ||
(memcmp (asms,"\t.section",9) == 0) ||
(memcmp (asms,"\t.text",6) == 0)) {
ltorg_uids[max_ltorg++] = INSN_UID (insn);
INSN_ADDRESSES_NEW (emit_insn_before (gen_rtx_ASM_INPUT (VOIDmode,
".align 4"), insn), -1);
}
}
}
ltorg_uids[max_ltorg] = 0;
for (insn=get_insns (),uids=0; insn;insn = next_real_insn (insn))
......@@ -2253,19 +2541,6 @@ s390_dump_literal_pool (act_insn, stop)
function_section (current_function_decl);
}
#ifdef DWARF2_DEBUGGING_INFO
extern char *dwarf2out_cfi_label PARAMS ((void));
#endif
/* Flag set in prologue, used in epilog to know
if stack is allocated or not. */
static int leaf_function_flag;
/* Symbol references needed by the profile code;
set up by the function prologue routine if necessary. */
rtx s390_profile[10];
/* Number of elements of current constant pool. */
int s390_nr_constants;
......@@ -2285,111 +2560,14 @@ save_fprs_p ()
return 0;
}
/* Return true if urrent function is a leaf function,
without automatics, alloca or vararg stuff. */
static int
cur_is_leaf_function ()
{
int lsize = get_frame_size () + current_function_outgoing_args_size
+ save_fprs_p () * 64;
if (leaf_function_p () && ((lsize) == 0) &&
! (current_function_calls_alloca) &&
! (current_function_stdarg) && ! (current_function_varargs))
return 1;
return 0;
}
/* Return offset between argument pointer and frame pointer
initially after prologue. */
int
s390_arg_frame_offset ()
{
int lsize = get_frame_size () + current_function_outgoing_args_size
+ save_fprs_p () * 64;
if (cur_is_leaf_function ())
return STACK_POINTER_OFFSET;
else
return 2*STACK_POINTER_OFFSET + lsize;
}
/* Output code to stdio stream FILE to save floating point
registers on current stack, at offset OFFSET to the frame
pointer register FP. */
static int
save_fprs (file, offset, fp)
FILE *file;
long offset;
int fp;
{
int i;
if (!TARGET_64BIT)
return 0;
for (i=24; i<=31; i++)
{
if (regs_ever_live[i] == 1)
{
fprintf (file, "\tstd\t%s,%ld(%s)\n", reg_names[i],
(i-24) * 8 + offset, reg_names[fp]);
}
}
return 1;
}
/* Output code to stdio stream FILE to restore floating point
registers from current stack, at offset OFFSET to the frame
pointer register FP. */
static int
restore_fprs (file, offset, fp)
FILE *file;
long offset;
int fp;
{
int i;
if (!TARGET_64BIT)
return 0;
if (!save_fprs_p ())
return 0;
if (offset < 0)
{
fp = 1;
offset = 0;
fprintf (file, "\tlgr\t%s,%s\n", reg_names[fp],
reg_names[STACK_POINTER_REGNUM]);
fprintf (file, "\taghi\t%s,-64\n", reg_names[fp]);
}
for (i=24; i<=31; i++)
{
if (regs_ever_live[i] == 1)
{
fprintf (file, "\tld\t%s,%ld(%s)\n", reg_names[i],
(i-24) * 8 + offset, reg_names[fp]);
}
}
return 1;
}
/* Output main constant pool to stdio stream FILE. */
static void
void
s390_output_constant_pool (file)
FILE *file;
{
/* Output constant pool. */
if (s390_nr_constants || regs_ever_live[BASE_REGISTER])
if (s390_nr_constants)
{
s390_pool_count = 0;
if (TARGET_64BIT)
......@@ -2410,66 +2588,150 @@ s390_output_constant_pool (file)
s390_pool_count);
if (TARGET_64BIT)
function_section (current_function_decl);
regs_ever_live[BASE_REGISTER] = 1;
}
}
/* Add constant CTX to the constant pool at a late time
(after the initial pass to count the number of constants
was already done). Returns the resulting constant
pool reference. */
/* Find first call clobbered register unsused in a function.
This could be used as base register in a leaf function
or for holding the return address before epilogue. */
static rtx
s390_force_const_mem_late (cst)
rtx cst;
static int
find_unused_clobbered_reg ()
{
int i;
for (i = 0; i < 6; i++)
if (!regs_ever_live[i])
return i;
return 0;
}
/* Fill FRAME with info about frame of current function. */
static void
s390_frame_info (frame)
struct s390_frame *frame;
{
int i, j;
HOST_WIDE_INT fsize = get_frame_size ();
if (fsize > 0x7fff0000)
fatal_error ("Total size of local variables exceeds architecture limit.");
/* fprs 8 - 15 are caller saved for 64 Bit ABI. */
frame->save_fprs_p = save_fprs_p ();
frame->frame_size = fsize + frame->save_fprs_p * 64;
/* Does function need to setup frame and save area. */
if (! current_function_is_leaf
|| frame->frame_size > 0
|| current_function_calls_alloca
|| current_function_stdarg
|| current_function_varargs)
frame->frame_size += STARTING_FRAME_OFFSET;
/* If we need to allocate a frame, the stack pointer is changed. */
if (frame->frame_size > 0)
regs_ever_live[STACK_POINTER_REGNUM] = 1;
/* If there is (possibly) any pool entry, we need to
load base register. */
if (get_pool_size ()
|| !CONST_OK_FOR_LETTER_P (frame->frame_size, 'K')
|| (!TARGET_64BIT && current_function_uses_pic_offset_table))
regs_ever_live[BASE_REGISTER] = 1;
/* If we need the GOT pointer, remember to save/restore it. */
if (current_function_uses_pic_offset_table)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
/* Frame pointer needed. */
frame->frame_pointer_p = frame_pointer_needed;
/* Find first and last gpr to be saved. */
for (i = 6; i < 16; i++)
if (regs_ever_live[i])
break;
for (j = 15; j > i; j--)
if (regs_ever_live[j])
break;
if (i == 16)
{
/* Nothing to save / restore. */
frame->first_save_gpr = -1;
frame->first_restore_gpr = -1;
frame->last_save_gpr = -1;
frame->return_reg_saved_p = 0;
}
else
{
/* Save / Restore from gpr i to j. */
frame->first_save_gpr = i;
frame->first_restore_gpr = i;
frame->last_save_gpr = j;
frame->return_reg_saved_p = (j >= RETURN_REGNUM && i <= RETURN_REGNUM);
}
if (current_function_stdarg || current_function_varargs)
{
/* Varargs function need to save from gpr 2 to gpr 15. */
frame->first_save_gpr = 2;
}
}
/* Return offset between argument pointer and frame pointer
initially after prologue. */
int
s390_arg_frame_offset ()
{
cst = force_const_mem (Pmode, cst);
struct s390_frame frame;
s390_nr_constants++;
regs_ever_live[BASE_REGISTER] = 1;
/* Compute frame_info. */
emit_insn_before (gen_rtx (USE, Pmode, cst), get_insns ());
s390_frame_info (&frame);
return cst;
return frame.frame_size + STACK_POINTER_OFFSET;
}
/* Add a reference to the symbol NAME to the constant pool.
FUNC specifies whether NAME refers to a function, while
GLOBAL specifies whether NAME is a global symbol. Depending
on these flags, the appopriate PLT or GOT references are
generated. Returns the constant pool reference. */
/* Emit insn to save fpr REGNUM at offset OFFSET relative
to register BASE. Return generated insn. */
static rtx
s390_force_const_mem_symbol (name, func, global)
const char *name;
int func;
int global;
save_fpr (base, offset, regnum)
rtx base;
int offset;
int regnum;
{
rtx symbol;
rtx addr;
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
set_mem_alias_set (addr, s390_sr_alias_set);
if (TARGET_64BIT)
abort ();
return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum));
}
symbol = gen_rtx (SYMBOL_REF, Pmode, name);
SYMBOL_REF_FLAG (symbol) = !global;
/* Emit insn to restore fpr REGNUM from offset OFFSET relative
to register BASE. Return generated insn. */
if (flag_pic)
{
if (global)
{
current_function_uses_pic_offset_table = 1;
symbol = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, symbol), func? 114 : 112);
symbol = gen_rtx_CONST (VOIDmode, symbol);
}
else
{
symbol = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, symbol), 100);
symbol = gen_rtx_CONST (VOIDmode, symbol);
}
}
static rtx
restore_fpr (base, offset, regnum)
rtx base;
int offset;
int regnum;
{
rtx addr;
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
set_mem_alias_set (addr, s390_sr_alias_set);
return s390_force_const_mem_late (symbol);
return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
}
/* Output the function prologue assembly code to the
......@@ -2478,401 +2740,396 @@ s390_force_const_mem_symbol (name, func, global)
void
s390_function_prologue (file, lsize)
FILE *file;
HOST_WIDE_INT lsize;
FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
{
extern int profile_label_no;
int i, j;
long frame_size;
rtx stack_label = 0, got_label = 0;
char *l;
const char *const b64 = TARGET_64BIT ? "g" : "";
if (get_pool_size () > S390_POOL_MAX)
s390_final_chunkify (1);
else
s390_final_chunkify (0);
}
/* Check for too large size of local variables */
/* Output the function epilogue assembly code to the
stdio stream FILE. The local frame size is passed
in LSIZE. */
if (lsize > 0x7fff0000)
fatal_error ("total size of local variables exceeds architecture limit");
void
s390_function_epilogue (file, lsize)
FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
{
current_function_uses_pic_offset_table = 0;
s390_pool_start_insn = NULL_RTX;
s390_pool_count = -1;
s390_function_count++;
}
/* Profile code (-p, -a, -ax needs some literals). */
/* Expand the prologue into a bunch of separate insns. */
if (profile_flag && !TARGET_64BIT)
{
static char label[128];
sprintf (label, "%sP%d", LPREFIX, profile_label_no);
void
s390_emit_prologue ()
{
struct s390_frame frame;
rtx insn, addr;
rtx temp_reg;
int i, limit;
s390_profile[4] = s390_force_const_mem_symbol ("_mcount", 1, 1);
s390_profile[9] = s390_force_const_mem_symbol (label, 0, 0);
}
/* Compute frame_info. */
if (get_pool_size () > S390_POOL_MAX)
s390_final_chunkify (1);
s390_frame_info (&frame);
/* Choose best register to use for temp use within prologue. */
if (frame.return_reg_saved_p
&& !has_hard_reg_initial_val (Pmode, RETURN_REGNUM))
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
else
s390_final_chunkify (0);
temp_reg = gen_rtx_REG (Pmode, 1);
if (current_function_uses_pic_offset_table)
regs_ever_live[12] = 1;
/* Save call saved gprs. */
if (!TARGET_64BIT && current_function_uses_pic_offset_table)
if (frame.first_save_gpr != -1)
{
got_label = s390_force_const_mem_symbol ("_GLOBAL_OFFSET_TABLE_", 0, 0);
}
addr = plus_constant (stack_pointer_rtx,
frame.first_save_gpr * UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set);
if ((frame_size =
STARTING_FRAME_OFFSET + lsize + save_fprs_p () * 64) > 0x7fff)
{
stack_label = s390_force_const_mem_late (GEN_INT (frame_size));
}
if (frame.first_save_gpr != frame.last_save_gpr )
{
insn = emit_insn (gen_store_multiple (addr,
gen_rtx_REG (Pmode, frame.first_save_gpr),
GEN_INT (frame.last_save_gpr
- frame.first_save_gpr + 1)));
if (!optimize)
{
/* Stupid register allocation is stupid ...
It does not always recognize the base register is used. */
regs_ever_live[BASE_REGISTER] = 1;
}
if (cur_is_leaf_function ())
{
leaf_function_flag = 1;
fprintf (file, "%s\tleaf function\n", ASM_COMMENT_START);
fprintf (file, "%s\thas varargs %d\n", ASM_COMMENT_START,
current_function_stdarg);
fprintf (file, "%s\tincoming args (stack) %d\n", ASM_COMMENT_START,
current_function_args_size);
fprintf (file, "%s\tfunction length %d\n", ASM_COMMENT_START,
insn_current_address);
fprintf (file, "%s\tregister live ", ASM_COMMENT_START);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
fprintf (file, "%d", regs_ever_live[i]);
fputc ('\n',file);
/* Save gprs 6 - 15 and fprs 4 and 6. */
for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
/* Set RTX_FRAME_RELATED_P for all sets within store multiple. */
if (s390_nr_constants || regs_ever_live[13] || i != 13)
{
fprintf (file, "\tstm%s\t%s,%s,%d(%s)\n",
b64, reg_names[i], reg_names[13],
i * UNITS_PER_WORD,
reg_names[STACK_POINTER_REGNUM]);
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
limit = XVECLEN (PATTERN (insn), 0);
for (i = 0; i < limit; i++)
{
l = dwarf2out_cfi_label ();
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM,
STACK_POINTER_OFFSET);
for (j = i; j <= 14; j++)
dwarf2out_reg_save (l, j, (TARGET_64BIT ? (j-20) : (j-24))
* UNITS_PER_WORD);
if (regs_ever_live[18])
dwarf2out_reg_save (l, 18, -16);
if (regs_ever_live[19])
dwarf2out_reg_save (l, 19, -8);
rtx x = XVECEXP (PATTERN (insn), 0, i);
if (GET_CODE (x) == SET)
RTX_FRAME_RELATED_P (x) = 1;
}
#endif
}
s390_output_constant_pool (file);
/* Save fprs. */
if (!TARGET_64BIT)
else
{
if (regs_ever_live[18])
fprintf (file, "\tstd\t4,80(%s)\n", reg_names[STACK_POINTER_REGNUM]);
if (regs_ever_live[19])
fprintf (file, "\tstd\t6,88(%s)\n", reg_names[STACK_POINTER_REGNUM]);
insn = emit_move_insn (addr,
gen_rtx_REG (Pmode, frame.first_save_gpr));
}
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{ /* No leaf function. */
fprintf (file, "%s\tleaf function %d\n", ASM_COMMENT_START,
leaf_function_p ());
fprintf (file, "%s\tautomatics %d\n", ASM_COMMENT_START,
(int)lsize);
fprintf (file, "%s\toutgoing args %d\n", ASM_COMMENT_START,
current_function_outgoing_args_size);
fprintf (file, "%s\tneed frame pointer %d\n", ASM_COMMENT_START,
frame_pointer_needed);
fprintf (file, "%s\tcall alloca %d\n", ASM_COMMENT_START,
current_function_calls_alloca);
fprintf (file, "%s\thas varargs %d\n", ASM_COMMENT_START,
current_function_stdarg || current_function_varargs);
fprintf (file, "%s\tincoming args (stack) %d\n", ASM_COMMENT_START,
current_function_args_size);
fprintf (file, "%s\tfunction length %d\n", ASM_COMMENT_START,
insn_current_address);
fprintf (file, "%s\tregister live ", ASM_COMMENT_START);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
fprintf (file, "%d", regs_ever_live[i]);
fputc ('\n',file);
/* Save gprs 6 - 15 and fprs 4 and 6. */
/* Dump constant pool and set constant pool register (13). */
insn = emit_insn (gen_lit ());
/* Save fprs for variable args. */
if (current_function_stdarg || current_function_varargs)
{
/* Save fpr 0 and 2. */
save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 32, 16);
save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 24, 17);
if (current_function_stdarg || current_function_varargs)
{
i = 2;
}
else
if (TARGET_64BIT)
{
for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
/* Save fpr 4 and 6. */
save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
}
}
fprintf (file, "\tstm%s\t%s,%s,%d(%s)\n",
b64, reg_names[i], reg_names[15], i * UNITS_PER_WORD,
reg_names[STACK_POINTER_REGNUM]);
/* Save fprs 4 and 6 if used (31 bit ABI). */
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
if (!TARGET_64BIT)
{
/* Save fpr 4 and 6. */
if (regs_ever_live[18])
{
l = dwarf2out_cfi_label ();
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, STACK_POINTER_OFFSET);
for (j = i; j <= 15; j++)
dwarf2out_reg_save (l, j, (TARGET_64BIT ? (j-20) : (j-24)) *
UNITS_PER_WORD);
if (regs_ever_live[18])
dwarf2out_reg_save (l, 18, -16);
if (regs_ever_live[19])
dwarf2out_reg_save (l, 19, -8);
insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
RTX_FRAME_RELATED_P (insn) = 1;
}
#endif
if (regs_ever_live[19])
{
insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
RTX_FRAME_RELATED_P (insn) = 1;
}
}
s390_output_constant_pool (file);
/* Decrement stack pointer. */
/* Save fprs. */
if (frame.frame_size > 0)
{
rtx frame_off = GEN_INT (-frame.frame_size);
if (current_function_stdarg || current_function_varargs)
{
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[16],
STACK_POINTER_OFFSET-32,
reg_names[STACK_POINTER_REGNUM]);
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[17],
STACK_POINTER_OFFSET-24,
reg_names[STACK_POINTER_REGNUM]);
if (TARGET_64BIT)
{
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[18],
STACK_POINTER_OFFSET-16,
reg_names[STACK_POINTER_REGNUM]);
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[19],
STACK_POINTER_OFFSET-8,
reg_names[STACK_POINTER_REGNUM]);
}
}
if (!TARGET_64BIT)
/* Save incoming stack pointer into temp reg. */
if (TARGET_BACKCHAIN || frame.save_fprs_p)
{
if (regs_ever_live[18])
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[18],
STACK_POINTER_OFFSET-16,
reg_names[STACK_POINTER_REGNUM]);
if (regs_ever_live[19])
fprintf (file, "\tstd\t%s,%d(%s)\n",
reg_names[19],
STACK_POINTER_OFFSET-8,
reg_names[STACK_POINTER_REGNUM]);
insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
}
if (save_fprs_p () && frame_size > 4095)
/* Substract frame size from stack pointer. */
frame_off = GEN_INT (-frame.frame_size);
if (!CONST_OK_FOR_LETTER_P (-frame.frame_size, 'K'))
frame_off = force_const_mem (Pmode, frame_off);
insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (-frame.frame_size))),
REG_NOTES (insn));
/* Set backchain. */
if (TARGET_BACKCHAIN)
{
int fp = 1;
fprintf (file, "\tlgr\t%s,%s\n", reg_names[fp],
reg_names[STACK_POINTER_REGNUM]);
fprintf (file, "\taghi\t%s,-64\n", reg_names[fp]);
save_fprs (file, 0, fp);
addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
set_mem_alias_set (addr, s390_sr_alias_set);
insn = emit_insn (gen_move_insn (addr, temp_reg));
}
}
/* Decrement stack. */
/* Save fprs 8 - 15 (64 bit ABI). */
if (frame.save_fprs_p)
{
insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64)));
if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
for (i = 24; i < 32; i++)
if (regs_ever_live[i])
{
rtx addr = plus_constant (stack_pointer_rtx,
frame.frame_size - 64 + (i-24)*8);
insn = save_fpr (temp_reg, (i-24)*8, i);
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (DFmode, addr),
gen_rtx_REG (DFmode, i)),
REG_NOTES (insn));
}
}
/* Set frame pointer, if needed. */
if (frame.frame_pointer_p)
{
insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
fprintf (file, "\tl%sr\t%s,%s\n", b64,
reg_names[1], reg_names[STACK_POINTER_REGNUM]);
}
/* Set up got pointer, if needed. */
if (current_function_uses_pic_offset_table)
{
rtx got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
SYMBOL_REF_FLAG (got_symbol) = 1;
if (stack_label)
if (TARGET_64BIT)
{
rtx operands[2];
insn = emit_insn (gen_movdi (pic_offset_table_rtx,
got_symbol));
operands[0] = stack_pointer_rtx;
operands[1] = stack_label;
if (TARGET_64BIT)
output_asm_insn ("sg\t%0,%1", operands);
else
output_asm_insn ("s\t%0,%1", operands);
/* It can happen that the GOT pointer isn't really needed ... */
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
else
{
fprintf (file, "\ta%shi\t%s,-%ld\n",b64,
reg_names[STACK_POINTER_REGNUM], frame_size);
}
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
{
if (frame_pointer_needed)
dwarf2out_def_cfa ("", HARD_FRAME_POINTER_REGNUM,
STACK_POINTER_OFFSET+frame_size);
else
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM,
STACK_POINTER_OFFSET+frame_size);
got_symbol = gen_rtx_UNSPEC (VOIDmode,
gen_rtvec (1, got_symbol), 100);
got_symbol = gen_rtx_CONST (VOIDmode, got_symbol);
got_symbol = force_const_mem (Pmode, got_symbol);
insn = emit_move_insn (pic_offset_table_rtx,
got_symbol);
insn = emit_insn (gen_add2_insn (pic_offset_table_rtx,
gen_rtx_REG (Pmode, BASE_REGISTER)));
/* We need the GOT pointer even if we don't know it ... */
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
}
#endif
}
}
/* Expand the epilogue into a bunch of separate insns. */
/* Generate backchain. */
void
s390_emit_epilogue ()
{
struct s390_frame frame;
rtx frame_pointer, return_reg;
int area_bottom, area_top, offset;
rtvec p;
if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
fprintf (file, "\tst%s\t%s,0(%s)\n",
b64, reg_names[1], reg_names[STACK_POINTER_REGNUM]);
}
}
/* Compute frame_info. */
s390_frame_info (&frame);
/* Check whether to use frame or stack pointer for restore. */
if (frame_pointer_needed)
frame_pointer = frame.frame_pointer_p ?
hard_frame_pointer_rtx : stack_pointer_rtx;
/* Compute which parts of the save area we need to access. */
if (frame.first_restore_gpr != -1)
{
fprintf (file, "\tl%sr\t%s,%s\n", b64,
reg_names[FRAME_POINTER_REGNUM],
reg_names[STACK_POINTER_REGNUM]);
area_bottom = frame.first_restore_gpr * UNITS_PER_WORD;
area_top = (frame.last_save_gpr + 1) * UNITS_PER_WORD;
}
else
{
area_bottom = INT_MAX;
area_top = INT_MIN;
}
/* Load GOT if used and emit use insn that optimizer does not
erase literal pool entry. */
if (current_function_uses_pic_offset_table)
if (TARGET_64BIT)
{
rtx operands[3];
if (TARGET_64BIT)
if (frame.save_fprs_p)
{
fprintf (file, "\tlarl\t%s,_GLOBAL_OFFSET_TABLE_\n",
reg_names[PIC_OFFSET_TABLE_REGNUM]);
if (area_bottom > -64)
area_bottom = -64;
if (area_top < 0)
area_top = 0;
}
else
}
else
{
if (regs_ever_live[18])
{
operands[0] = gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM);
operands[1] = got_label;
operands[2] = gen_rtx (REG, Pmode, BASE_REGISTER);
output_asm_insn ("l\t%0,%1\n\tar\t%0,%2", operands);
if (area_bottom > STACK_POINTER_OFFSET - 16)
area_bottom = STACK_POINTER_OFFSET - 16;
if (area_top < STACK_POINTER_OFFSET - 8)
area_top = STACK_POINTER_OFFSET - 8;
}
if (regs_ever_live[19])
{
if (area_bottom > STACK_POINTER_OFFSET - 8)
area_bottom = STACK_POINTER_OFFSET - 8;
if (area_top < STACK_POINTER_OFFSET)
area_top = STACK_POINTER_OFFSET;
}
}
/* Save FPRs below save area. */
if (frame_size <= 4095)
save_fprs (file, frame_size - 64, STACK_POINTER_REGNUM);
/* Check whether we can access the register save area.
If not, increment the frame pointer as required. */
return;
}
if (area_top <= area_bottom)
{
/* Nothing to restore. */
}
else if (frame.frame_size + area_bottom >= 0
&& frame.frame_size + area_top <= 4096)
{
/* Area is in range. */
offset = frame.frame_size;
}
else
{
rtx insn, frame_off;
/* Output the function epilogue assembly code to the
stdio stream FILE. The local frame size is passed
in LSIZE. */
offset = area_bottom < 0 ? -area_bottom : 0;
frame_off = GEN_INT (frame.frame_size - offset);
void
s390_function_epilogue (file, lsize)
FILE *file;
HOST_WIDE_INT lsize;
{
/* Register is call clobbered and not used for eh or return. */
#define FREE_REG 4
if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K'))
frame_off = force_const_mem (Pmode, frame_off);
int i;
long frame_size;
int return_reg = RETURN_REGNUM;
int fp, offset;
const char *const b64 = TARGET_64BIT ? "g" : "";
insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
RTX_FRAME_RELATED_P (insn) = 1;
}
frame_size = STARTING_FRAME_OFFSET + lsize + save_fprs_p () * 64;
if (current_function_uses_pic_offset_table)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
if (leaf_function_flag)
/* Restore call saved fprs. */
if (TARGET_64BIT)
{
for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
int i;
if (s390_nr_constants || regs_ever_live[13] || i != 13)
{
fprintf (file, "\tlm%s\t%s,%s,%d(%s)\n", b64,
reg_names[i], reg_names[13],
UNITS_PER_WORD * i,
reg_names[STACK_POINTER_REGNUM]);
}
if (!TARGET_64BIT)
{
if (regs_ever_live[18])
fprintf (file, "\tld\t%s,%d(%s)\n",
reg_names[18],
STACK_POINTER_OFFSET-16,
reg_names[STACK_POINTER_REGNUM]);
if (regs_ever_live[19])
fprintf (file, "\tld\t%s,%d(%s)\n",
reg_names[19],
STACK_POINTER_OFFSET-8,
reg_names[STACK_POINTER_REGNUM]);
}
if (frame.save_fprs_p)
for (i = 24; i < 32; i++)
if (regs_ever_live[i])
restore_fpr (frame_pointer,
offset - 64 + (i-24) * 8, i);
}
else
{
for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
if (regs_ever_live[18])
restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 16, 18);
if (regs_ever_live[19])
restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 8, 19);
}
if (frame_size + STACK_POINTER_OFFSET > 4095)
/* Return register. */
return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
/* Restore call saved gprs. */
if (frame.first_restore_gpr != -1)
{
rtx addr;
/* Fetch return address from stack before load multiple,
this will do good for scheduling. */
if (frame.last_save_gpr >= RETURN_REGNUM
&& frame.first_restore_gpr < RETURN_REGNUM)
{
offset = 0;
fp = STACK_POINTER_REGNUM;
int return_regnum = find_unused_clobbered_reg();
if (!return_regnum)
return_regnum = 4;
return_reg = gen_rtx_REG (Pmode, return_regnum);
addr = plus_constant (frame_pointer,
offset + RETURN_REGNUM * UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set);
emit_move_insn (return_reg, addr);
}
else if (frame_pointer_needed || current_function_calls_alloca)
/* ??? As references to the base register are not made
explicit in insn RTX code, we have to add a barrier here
to prevent incorrect scheduling. */
emit_insn (gen_blockage());
addr = plus_constant (frame_pointer,
offset + frame.first_restore_gpr * UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set);
if (frame.first_restore_gpr != frame.last_save_gpr)
{
offset = frame_size;
fp = FRAME_POINTER_REGNUM;
emit_insn (gen_load_multiple (
gen_rtx_REG (Pmode, frame.first_restore_gpr),
addr,
GEN_INT (frame.last_save_gpr - frame.first_restore_gpr + 1)));
}
else
{
offset = frame_size;
fp = STACK_POINTER_REGNUM;
emit_move_insn (gen_rtx_REG (Pmode, frame.first_restore_gpr),
addr);
}
}
/* Restore from offset below save area. */
/* Return to caller. */
if (offset == 0)
fprintf (file, "\tl%s\t%s,0(%s)\n", b64,
reg_names[fp], reg_names[fp]);
restore_fprs (file, offset-64, fp);
return_reg = FREE_REG;
fprintf (file, "\tl%s\t%s,%d(%s)\n", b64, reg_names[return_reg],
UNITS_PER_WORD*RETURN_REGNUM+offset, reg_names[fp]);
if (!TARGET_64BIT)
{
if (regs_ever_live[18])
fprintf (file, "\tld\t%s,%d(%s)\n",
reg_names[18],
offset+STACK_POINTER_OFFSET-16, reg_names[fp]);
if (regs_ever_live[19])
fprintf (file, "\tld\t%s,%d(%s)\n",
reg_names[19],
offset+STACK_POINTER_OFFSET-8, reg_names[fp]);
}
fprintf (file, "\tlm%s\t%s,%s,%d(%s)\n", b64,
reg_names[i], reg_names[15],
(UNITS_PER_WORD * i) + offset, reg_names[fp]);
}
p = rtvec_alloc (2);
fprintf (file, "\tbr\t%s\n", reg_names[return_reg]);
current_function_uses_pic_offset_table = 0;
leaf_function_flag = 0;
s390_pool_start_insn = NULL_RTX;
s390_pool_count = -1;
s390_function_count++;
return;
RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
}
......@@ -3369,3 +3626,98 @@ s390_initialize_trampoline (addr, fnaddr, cxt)
memory_address (Pmode,
plus_constant (addr, (TARGET_64BIT ? 28 : 16) ))), fnaddr);
}
/* Return rtx for 64-bit constant formed from the 32-bit subwords
LOW and HIGH, independent of the host word size. */
rtx
s390_gen_rtx_const_DI (high, low)
int high;
int low;
{
#if HOST_BITS_PER_WIDE_INT >= 64
HOST_WIDE_INT val;
val = (HOST_WIDE_INT)high;
val <<= 32;
val |= (HOST_WIDE_INT)low;
return GEN_INT (val);
#else
#if HOST_BITS_PER_WIDE_INT >= 32
return immed_double_const ((HOST_WIDE_INT)low, (HOST_WIDE_INT)high, DImode);
#else
abort ();
#endif
#endif
}
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
void
s390_function_profiler (file, labelno)
FILE *file;
int labelno;
{
rtx op[7];
char label[128];
sprintf (label, "%sP%d", LPREFIX, labelno);
fprintf (file, "# function profiler \n");
op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM);
op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_WORD));
op[2] = gen_rtx_REG (Pmode, 1);
op[3] = gen_rtx_SYMBOL_REF (Pmode, label);
SYMBOL_REF_FLAG (op[3]) = 1;
op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount");
if (flag_pic)
{
op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), 113);
op[4] = gen_rtx_CONST (Pmode, op[4]);
}
if (TARGET_64BIT)
{
output_asm_insn ("stg\t%0,%1", op);
output_asm_insn ("larl\t%2,%3", op);
output_asm_insn ("brasl\t%0,%4", op);
output_asm_insn ("lg\t%0,%1", op);
}
else if (!flag_pic)
{
op[6] = gen_label_rtx ();
output_asm_insn ("st\t%0,%1", op);
output_asm_insn ("bras\t%2,%l6", op);
output_asm_insn (".long\t%3", op);
output_asm_insn (".long\t%4", op);
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
output_asm_insn ("l\t%0,0(%2)", op);
output_asm_insn ("l\t%2,4(%2)", op);
output_asm_insn ("basr\t%0,%0", op);
output_asm_insn ("l\t%0,%1", op);
}
else
{
op[5] = gen_label_rtx ();
op[6] = gen_label_rtx ();
output_asm_insn ("st\t%0,%1", op);
output_asm_insn ("bras\t%2,%l6", op);
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5]));
output_asm_insn (".long\t%3-%l5", op);
output_asm_insn (".long\t%4-%l5", op);
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
output_asm_insn ("lr\t%0,%2", op);
output_asm_insn ("a\t%0,0(%2)", op);
output_asm_insn ("a\t%2,4(%2)", op);
output_asm_insn ("basr\t%0,%0", op);
output_asm_insn ("l\t%0,%1", op);
}
}
......@@ -65,6 +65,14 @@ extern int target_flags;
/* Define this to change the optimizations performed by default. */
#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options(LEVEL, SIZE)
/* Sometimes certain combinations of command options do not make sense
on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
defined, is executed once just after all the command options have
been parsed. */
#define OVERRIDE_OPTIONS override_options ()
/* Defines for REAL_ARITHMETIC. */
#define IEEE_FLOAT 1
#define TARGET_IBM_FLOAT 0
......@@ -236,7 +244,12 @@ if (INTEGRAL_MODE_P (MODE) && \
G5 and following have 16 IEEE floating point register,
which get numbers 16-31. */
#define FIRST_PSEUDO_REGISTER 34
#define FIRST_PSEUDO_REGISTER 35
/* Number of hardware registers that go into the DWARF-2 unwind info.
If not defined, equals FIRST_PSEUDO_REGISTER. */
#define DWARF_FRAME_REGISTERS 34
/* The following register have a fix usage
GPR 12: GOT register points to the GOT, setup in prologue,
......@@ -260,7 +273,7 @@ if (INTEGRAL_MODE_P (MODE) && \
0, 0, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 0, \
1, 1 }
1, 1, 1 }
/* 1 for registers not available across function calls. These must include
the FIXED_REGISTERS and also any registers that can be used without being
......@@ -273,22 +286,49 @@ if (INTEGRAL_MODE_P (MODE) && \
1, 1, 0, 0, \
0, 0, 0, 0, \
0, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1 }
/* Like `CALL_USED_REGISTERS' except this macro doesn't require that
the entire set of `FIXED_REGISTERS' be included.
(`CALL_USED_REGISTERS' must be a superset of `FIXED_REGISTERS'). */
#define CALL_REALLY_USED_REGISTERS \
{ 1, 1, 1, 1, \
1, 1, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 0, \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1 }
1, 1, 1, 1, \
1, 1, 1 }
/* If not pic code, gpr 12 can be used. */
/* Macro to conditionally modify fixed_regs/call_used_regs. */
#define CONDITIONAL_REGISTER_USAGE \
do \
{ \
int i; \
\
if (flag_pic) \
{ \
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
} \
if (TARGET_64BIT) \
{ \
for (i = 24; i < 32; i++) \
call_used_regs[i] = call_really_used_regs[i] = 0; \
} \
else \
{ \
for (i = 18; i < 20; i++) \
call_used_regs[i] = call_really_used_regs[i] = 0; \
} \
} while (0)
/* The following register have a special usage
......@@ -298,7 +338,8 @@ do \
with stack- or frame-pointer.
GPR 33: Condition code 'register' */
#define FRAME_POINTER_REGNUM 11
#define HARD_FRAME_POINTER_REGNUM 11
#define FRAME_POINTER_REGNUM 34
#define ARG_POINTER_REGNUM 32
......@@ -333,7 +374,8 @@ do \
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(FLOAT_REGNO_P(REGNO)? \
(GET_MODE_CLASS(MODE) == MODE_FLOAT || \
GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT) : \
GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT || \
(MODE) == SImode || (MODE) == DImode) : \
INT_REGNO_P(REGNO)? \
(HARD_REGNO_NREGS(REGNO, MODE) == 1 || !((REGNO) & 1)) : \
CC_REGNO_P(REGNO)? \
......@@ -349,6 +391,15 @@ do \
(((MODE1) == SFmode || (MODE1) == DFmode) \
== ((MODE2) == SFmode || (MODE2) == DFmode))
/* If defined, gives a class of registers that cannot be used as the
operand of a SUBREG that changes the mode of the object illegally. */
#define CLASS_CANNOT_CHANGE_MODE FP_REGS
/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
/* Define this macro if references to a symbol must be treated
differently depending on something about the variable or
......@@ -383,15 +434,20 @@ while (0)
#define ELIMINABLE_REGS \
{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}}
{ ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
#define CAN_ELIMINATE(FROM, TO) (1)
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
{ (OFFSET) = 0; } \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
else if ((FROM) == FRAME_POINTER_REGNUM \
&& (TO) == HARD_FRAME_POINTER_REGNUM) \
{ (OFFSET) = 0; } \
else if ((FROM) == ARG_POINTER_REGNUM \
&& (TO) == HARD_FRAME_POINTER_REGNUM) \
{ (OFFSET) = s390_arg_frame_offset (); } \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
{ (OFFSET) = s390_arg_frame_offset (); } \
......@@ -433,7 +489,8 @@ while (0)
enum reg_class
{
NO_REGS, ADDR_REGS, GENERAL_REGS,
FP_REGS, ALL_REGS, LIM_REG_CLASSES
FP_REGS, ADDR_FP_REGS, GENERAL_FP_REGS,
ALL_REGS, LIM_REG_CLASSES
};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
......@@ -441,7 +498,8 @@ enum reg_class
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{ "NO_REGS","ADDR_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" }
{ "NO_REGS", "ADDR_REGS", "GENERAL_REGS", \
"FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" }
/* Define which registers fit in which classes. This is an initializer for
a vector of HARD_REG_SET of length N_REG_CLASSES.
......@@ -450,10 +508,12 @@ enum reg_class
#define REG_CLASS_CONTENTS \
{ \
{ 0x00000000, 0x00000000 }, /* NO_REGS */ \
{ 0x0000fffe, 0x00000001 }, /* ADDR_REGS */ \
{ 0x0000ffff, 0x00000001 }, /* GENERAL_REGS */ \
{ 0x0000fffe, 0x00000005 }, /* ADDR_REGS */ \
{ 0x0000ffff, 0x00000005 }, /* GENERAL_REGS */ \
{ 0xffff0000, 0x00000000 }, /* FP_REGS */ \
{ 0xffffffff, 0x00000003 }, /* ALL_REGS */ \
{ 0xfffffffe, 0x00000005 }, /* ADDR_FP_REGS */ \
{ 0xffffffff, 0x00000005 }, /* GENERAL_FP_REGS */ \
{ 0xffffffff, 0x00000007 }, /* ALL_REGS */ \
}
......@@ -506,15 +566,8 @@ extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
but on some machines in some cases it is preferable to use a more
restrictive class. */
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
(GET_CODE (X) == CONST_DOUBLE ? \
(GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? FP_REGS : ADDR_REGS) :\
(GET_CODE (X) == CONST_INT ? \
(GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? FP_REGS : ADDR_REGS) :\
GET_CODE (X) == PLUS || \
GET_CODE (X) == LABEL_REF || \
GET_CODE (X) == SYMBOL_REF || \
GET_CODE (X) == CONST ? ADDR_REGS : (CLASS)))
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
s390_preferred_reload_class ((X), (CLASS))
/* Return the maximum number of consecutive registers needed to represent
mode MODE in a register of class CLASS. */
......@@ -557,26 +610,21 @@ extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
/* Stack layout; function entry, exit and calling. */
/* The current return address is on Offset 56 of the current frame
if we are in an leaf_function. Otherwise we have to go one stack
back.
The return address of anything farther back is accessed normally
at an offset of 56 from the frame pointer.
FIXME: builtin_return_addr does not work correctly in a leaf
function, we need to find way to find out, if we
are in a leaf function
*/
#define _RETURN_ADDR_OFFSET (TARGET_64BIT ? 112 : 56)
#define RETURN_ADDR_RTX(count, frame) \
gen_rtx (MEM, Pmode, \
memory_address (Pmode, \
plus_constant ( \
copy_to_reg (gen_rtx (MEM, Pmode, \
memory_address (Pmode, frame))), \
_RETURN_ADDR_OFFSET)));
/* The return address of the current frame is retrieved
from the initial value of register RETURN_REGNUM.
For frames farther back, we use the stack slot where
the corresponding RETURN_REGNUM register was saved. */
#define DYNAMIC_CHAIN_ADDRESS(FRAME) \
((FRAME) != hard_frame_pointer_rtx ? (FRAME) : \
plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET))
#define RETURN_ADDR_RTX(COUNT, FRAME) \
((COUNT) == 0 ? get_hard_reg_initial_val (Pmode, RETURN_REGNUM) : \
gen_rtx_MEM (Pmode, \
memory_address (Pmode, \
plus_constant (DYNAMIC_CHAIN_ADDRESS ((FRAME)), \
RETURN_REGNUM * UNITS_PER_WORD))))
/* The following macros will turn on dwarf2 exception hndling
Other code location for this exception handling are
......@@ -588,6 +636,11 @@ extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
#define MASK_RETURN_ADDR (GEN_INT (0x7fffffff))
/* The offset from the incoming value of %sp to the top of the stack frame
for the current function. */
#define INCOMING_FRAME_SP_OFFSET STACK_POINTER_OFFSET
/* Location, from where return address to load. */
#define DWARF_FRAME_RETURN_COLUMN 14
......@@ -813,47 +866,7 @@ CUMULATIVE_ARGS;
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
do { \
extern rtx s390_profile[]; \
extern int s390_pool_count; \
static char label[128]; \
fprintf (FILE, "# function profiler \n"); \
if (TARGET_64BIT) \
{ \
rtx tmp[1]; \
output_asm_insn ("stg\t14,8(15)", tmp); \
sprintf (label, "%sP%d", LPREFIX, LABELNO); \
tmp[0] = gen_rtx_SYMBOL_REF (Pmode, label); \
SYMBOL_REF_FLAG (tmp[0]) = 1; \
output_asm_insn ("larl\t1,%0", tmp); \
tmp[0] = gen_rtx_SYMBOL_REF (Pmode, "_mcount"); \
if (flag_pic) \
{ \
tmp[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, tmp[0]), 113); \
tmp[0] = gen_rtx_CONST (Pmode, tmp[0]); \
} \
output_asm_insn ("brasl\t14,%0", tmp); \
output_asm_insn ("lg\t14,8(15)", tmp); \
} \
else \
{ \
output_asm_insn ("l 14,4(15)", s390_profile); \
s390_pool_count = 0; \
output_asm_insn ("st 14,4(15)", s390_profile); \
output_asm_insn ("l 14,%4", s390_profile); \
output_asm_insn ("l 1,%9", s390_profile); \
if (flag_pic) \
{ \
output_asm_insn ("ar 1,13", s390_profile); \
output_asm_insn ("bas 14,0(14,13)", s390_profile); \
} \
else \
{ \
output_asm_insn ("basr 14,14", s390_profile); \
} \
output_asm_insn ("l 14,4(15)", s390_profile); \
} \
} while (0)
s390_function_profiler ((FILE), ((LABELNO)))
/* #define PROFILE_BEFORE_PROLOGUE */
......@@ -875,9 +888,9 @@ do { \
reg currently allocated to a suitable hard reg.
These definitions are NOT overridden anywhere. */
#define REGNO_OK_FOR_INDEX_P(REGNO) \
(((REGNO) > 0 && (REGNO) < 16) || (REGNO) == ARG_POINTER_REGNUM \
/* || (REGNO) == FRAME_POINTER_REGNUM */ \
#define REGNO_OK_FOR_INDEX_P(REGNO) \
(((REGNO) < FIRST_PSEUDO_REGISTER \
&& REGNO_REG_CLASS ((REGNO)) == ADDR_REGS) \
|| (reg_renumber[REGNO] > 0 && reg_renumber[REGNO] < 16))
#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_INDEX_P (REGNO)
......@@ -947,11 +960,10 @@ do { \
* a pseudo reg.
*/
#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
((GET_MODE (X) == Pmode) && \
((REGNO (X) > 0 && REGNO (X) < 16) || \
(REGNO (X) == ARG_POINTER_REGNUM) || \
(REGNO (X) >= FIRST_PSEUDO_REGISTER)))
#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
((GET_MODE (X) == Pmode) && \
((REGNO (X) >= FIRST_PSEUDO_REGISTER) \
|| REGNO_REG_CLASS (REGNO (X)) == ADDR_REGS))
/* Nonzero if X is a hard reg that can be used as a base reg or if it is
a pseudo reg. */
......@@ -1080,10 +1092,6 @@ do { \
/* #define STORE_FLAG_VALUE -1 */
/* When a prototype says `char' or `short', really pass an `int'. */
#define PROMOTE_PROTOTYPES 1
/* Don't perform CSE on function addresses. */
#define NO_FUNCTION_CSE
......@@ -1269,13 +1277,14 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", \
"%f0", "%f2", "%f4", "%f6", "%f1", "%f3", "%f5", "%f7", \
"%f8", "%f10", "%f12", "%f14", "%f9", "%f11", "%f13", "%f15", \
"%ap", "%cc" \
"%ap", "%cc", "%fp" \
}
/* implicit call of memcpy, not bcopy */
#define TARGET_MEM_FUNCTIONS
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null. */
......@@ -1287,17 +1296,29 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
/* Define the codes that are matched by predicates in aux-output.c. */
#define PREDICATE_CODES \
{"s_operand", { MEM }}, \
{"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
{"r_or_s_operand", { MEM, SUBREG, REG }}, \
{"r_or_im8_operand", { CONST_INT, SUBREG, REG }}, \
{"r_or_s_or_im8_operand", { MEM, SUBREG, REG, CONST_INT }}, \
{"r_or_x_or_im16_operand", { MEM, SUBREG, REG, CONST_INT }}, \
{"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
{"const1_operand", { CONST_INT, CONST_DOUBLE }}, \
{"tmxx_operand", { CONST_INT, MEM }},
#define PREDICATE_CODES \
{"s_operand", { SUBREG, MEM }}, \
{"s_imm_operand", { CONST_INT, CONST_DOUBLE, SUBREG, MEM }}, \
{"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
{"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
{"load_multiple_operation", {PARALLEL}}, \
{"store_multiple_operation", {PARALLEL}}, \
{"const0_operand", { CONST_INT, CONST_DOUBLE }},
/* S/390 constant pool breaks the devices in crtstuff.c to control section
in where code resides. We have to write it as asm code. */
#ifndef __s390x__
#define CRT_CALL_STATIC_FUNCTION(func) \
if (0) \
func (); /* ... to avoid warnings. */ \
else \
asm \
("bras\t%%r2,1f\n\
0: .long\t" #func " - 0b\n\
1: l\t%%r3,0(%%r2)\n\
bas\t%%r14,0(%%r3,%%r2)" : : : "2", "3", "cc", "memory");
#endif
/* Constant Pool for all symbols operands which are changed with
force_const_mem during insn generation (expand_insn). */
......@@ -1397,7 +1418,11 @@ extern int s390_nr_constants;
fputc ('\n', (FILE)); \
} \
else \
assemble_integer (EXP, GET_MODE_SIZE (MODE), ALIGN, 1); \
{ \
assemble_integer (EXP, GET_MODE_SIZE (MODE), ALIGN, 1); \
if (GET_MODE_SIZE (MODE) == 1) \
ASM_OUTPUT_SKIP ((FILE), 1); \
} \
break; \
\
default: \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
# The crtbegin and crtend must not depend on a small GOT
CRTSTUFF_T_CFLAGS = -O2 -fPIC
CRTSTUFF_T_CFLAGS_S = -O2 -fPIC
# Compile libgcc2.a with pic.
TARGET_LIBGCC2_CFLAGS = -fPIC -include $(srcdir)/config/s390/fixdfdi.h
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment