Commit 6cebc6cb by Bernd Schmidt Committed by Bernd Schmidt

Convert m68k to not use cc0

	* config/m68k/m68k.c (output_move_himode, output_move_qimode):
	Replace code for non-CONST_INT constants with gcc_unreachable.
	* config/m68k/m68k.md (cbranchdi): Don't generate individual
	compare and test.
	(CMPMODE): New mode_iterator.
	(cbranchsi4, cbranchqi4, cbranchhi4): Replace expanders with
	cbranch<mode>4.
	(cstoresi4, cstoreqi4, cstorehi4): Replace expanders with
	cstore<mode>4.
	(cmp<mode>_68881): Remove 'F' constraint from first comparison
	operand.
	(bit test insns patterns): Use nonimmediate_operand, not
	register_operand, for source operands that allow memory in
	their constraints.
	(divmodsi4, udivmodsi4, divmodhi4 and related unnamed patterns):
	Use register_operand, not nonimmediate_operand, for the
	destinations.
	(DBCC): New mode_iterator.
	(dbcc peepholes): Use it to reduce duplication.
	(trap): Use const_true_rtx, not const1_rtx.
	* config/m68k/predicates.md (m68k_comparison_operand): Renamed
	from m68k_subword_comparison_operand and changed to handle
	SImode.

	PR target/91851
	* config/m68k/m68k-protos.h (output-dbcc_and_branch): Adjust
	declaration.
	(m68k_init_cc): New declaration.
	(m68k_output_compare_di, m68k_output_compare_si)
	(m68k_output_compare_hi, m68k_output_compare_qi)
	(m68k_output_compare_fp, m68k_output_btst, m68k_output_bftst)
	(m68k_find_flags_value, m68k_output_scc, m68k_output_scc_float)
	(m68k_output_branch_integer, m68k_output_branch_integer_rev.
	m68k_output_branch_float, m68k_output_branch_float_rev):
	Likewise.
	(valid_dbcc_comparison_p_2, flags_in_68881)
	(output_btst): Remove declaration.
	* config/m68k/m68k.c (INCLDUE_STRING): Define.
	(TARGET_ASM_FINAL_POSTSCAN_INSN): Define.
	(valid_dbcc_comparison_p_2, flags_in_68881): Delete functions.
	(flags_compare_op0, flags_compare_op1, flags_operand1,
	flags_operand2, flags_valid): New static variables.
	(m68k_find_flags_value, m68k_init_cc): New functions.
	(handle_flags_for_move, m68k_asm_final_postscan_insn,
	remember_compare_flags): New static functions.
	(output_dbcc_and_branch): New argument CODE.  Use it, and add
	PLUS and MINUS to the possible codes.  All callers changed.
	(m68k_output_btst): Renamed from output_btst.  Remove OPERANDS
	and INSN arguments, add CODE arg.  Return the comparison code
	to use.  All callers changed.  Use CODE instead of
	next_insn_tests_no_inequality, and replace cc_status management
	with changing the return code.
	(m68k_rtx_costs): Instead of testing for COMPARE, test for
	RTX_COMPARE or RTX_COMM_COMPARE.
	(output_move_simode, output_move_qimode): Call
	handle_flags_for_move.
	(notice_update_cc): Delete function.
	(m68k_output_bftst, m68k_output_compare_di, m68k_output_compare_si,
	m68k_output_compare_hi, m68k_output_compare_qi,
	m68k_output_compare_fp, m68k_output_branch_integer,
	m68k_output_branch_integer_rev, m68k_output_scc,
	m68k_output_branch_float, m68k_output_branch_float_rev,
	m68k_output_scc_float): New functions.
	(output_andsi3, output_iorsi3, output_xorsi3): Call CC_STATUS_INIT
	once at the start, and set flags_valid and flags_operand1 if the
	flags are usable.
	* config/m68k/m68k.h (CC_IN_68881, NOTICE_UPDATE_CC,
	CC_OVERFLOW_UNUSABLE, CC_NO_CARRY, OUTPUT_JUMP): Remove
	definitions.
	(CC_STATUS_INIT): Define.
	* config/m68k/m68k.md (flags_valid): New define_attr.
	(tstdi, tstsi_internal_68020_cf, tstsi_internal, tsthi_internal,
	tstqi_internal, tst<mode>_68881, tst<mode>_cf, cmpdi_internal,
	cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf,
	cmp<mode>_68881, cmp<mode>_cf, unnamed btst patterns,
	tst_bftst_reg, tst_bftst_reg, unnamed scc patterns, scc,
	sls, sordered_1, sunordered_1, suneq_1, sunge_1, sungt_1,
	sunle_1, sunlt_1, sltgt_1, fsogt_1, fsoge_1, fsolt_1, fsole_1,
	bge0_di, blt0_di, beq, bne, bgt, bgtu, blt, bltu, bge, bgeu,
	ble, bleu, bordered, bunordered, buneq, bunge, bungt, bunle,
	bunlt, bltgt, beq_rev, bne_rev, bgt_rev, bgtu_rev,
	blt_rev, bltu_rev, bge_rev, bgeu_rev, ble_rev, bleu_rev,
	bordered_rev, bunordered_rev, buneq_rev, bunge_rv, bungt_rev,
	bunle_rev, bunlt_rev, bltgt_rev, ctrapdi4, ctrapsi4, ctraphi4,
	ctrapqi4, conditional_trap): Delete patterns.
	(cbranchdi4_insn): New pattern.
	(cbranchdi4): Don't generate cc0 patterns.  When testing LT or GE,
	test high part only.  When testing EQ or NE, generate beq0_di
	and bne0_di patterns directly.
	(cstoredi4): When testing LT or GE, test high part only.
	(both sets of cbranch<mode>4, cstore<mode>4): Don't generate cc0
	patterns.
	(scc0_constraints, cmp1_constraints, cmp2_constraints,
	scc0_cf_constraints, cmp1_cf_constraints, cmp2_cf_constraints,
	cmp2_cf_predicate): New define_mode_attrs.
	(cbranch<mode>4_insn, cbranch<mode>4_insn_rev,
	cbranch<mode>4_insn_cf, cbranch<mode>4_insn_cf_rev,
	cstore<mode>4_insn, cstore<mode>4_insn_cf for integer modes)
	New patterns.
	(cbranch<mode>4_insn_68881, cbranch<mode>4_insn_rev_68881):
	(cbranch<mode>4_insn_cf, cbranch<mode>4_insn_rev_cf,
	cstore<mode>4_insn_68881, cstore<mode>4_insn_cf for FP):
	New patterns.
	(cbranchsi4_btst_mem_insn, cbranchsi4_btst_reg_insn,
	cbranchsi4_btst_mem_insn_1, cbranchsi4_btst_reg_insn_1):
	Likewise.
	(BTST): New define_mode_iterator.
	(btst_predicate, btst_constraint, btst_range): New
	define_mode_attrs.
	(cbranch_bftst<mode>_insn, cstore_bftst<mode>_insn): New
	patterns.
	(movsi_m68k_movsi_m68k2, movsi_cf, unnamed movstrict patterns,
	unnamed movhi and movqi patterns, unnamed movsf, movdf and movxf
	patterns): Set attr "flags_valid".
	(truncsiqi2, trunchiqi2, truncsihi2): Remove manual CC_STATUS
	management.  Set attr "flags_valid".
	(extendsidi2, extendplussidi, unnamed float_extendsfdf pattern,
	extendsfdf2_cf, fix_truncdfsi2, fix_truncdfhi2, fix_truncdfqi2,
	addi_sexthishl32, adddi_dilshr32, adddi_dilshr32_cf,
	addi_dishl32, subdi_sexthishl32, subdi_dishl32, subdi3): Remove
	manual CC_STATUS management.
	(addsi3_internal, addhi3, addqi3, subsi3, subhi3, subqi3,
	unnamed strict_lowpart subhi and subqi patterns): Set attr
	"flags_valid".
	(unnamed strict_lowpart addhi3 and addqi3 patterns): Likewise.
	Remove code to operate on address regs and assert the case
	does not occur.
	(unnamed mulsidi patterns, divmodhi4, udivmodhi4): Remove
	manual CC_STATUS_INIT.
	(andsi3_internal, andhi3, andqi3, iorsi3_internal, iorhi3, iorqi3,
	xorsi3_internal, xorhi3, xorqi3, negsi2_internal,
	negsi2_5200, neghi2, negqi2, one_cmplsi2_internal, one_cmplhi2,
	one_cmplqi2, unnamed strict_lowpart patterns
	for andhi, andqi, iorhi, iorqi, xorhi, xorqi, neghi, negqi,
	one_cmplhi and one_cmplqi): Set attr "flags_valid".
	(iorsi_zext_ashl16, iorsi_zext): Remove manual CC_STATUS_INIT.
	(ashldi_sexthi, ashlsi_16, ashlsi_17_24): Remove manual
	CC_STATUS_INIT.
	(ashlsi3, ashlhi3, ashlqi3, ashrsi3, ashrhi3, ashrqi3, lshrsi3,
	lshrhi3, shrqi3, rotlsi3, rotlhi3, rotlhi3_lowpart, rotlqi3,
	rotlqi3_lowpart, rotrsi3, rotrhi3, rotrhi_lowpart, rotrqi3,
	unnamed strict_low_part patterns for HI and
	QI versions): Set attr "flags_valid".
	(bsetmemqi, bsetmemqi_ext, bsetdreg, bchgdreg, bclrdreg,
	bclrmemqi, extzv_8_16_reg, extzv_bfextu_mem, insv_bfchg_mem,
	insv_bfclr_mem, insv_bfset_mem, extv_bfextu_reg,
	insv_bfclr_reg, insv_bfset_reg, dbne_hi, dbne_si, dbge_hi,
	dbge_si, extendsfxf2, extenddfxf2, ): Remove manual cc_status management.
	(various unnamed peepholes): Adjust compare/branch sequences
	for new cbranch patterns.
	(dbcc peepholes): Likewise, and output the comparison here
	as well.
	* config/m68k/predicates.md (valid_dbcc_comparison_p): Delete.
	(fp_src_operand): Allow constant zero.
	(address_reg_operand): New predicate.

	* rtl.h (inequality_comparisons_p): Remove declaration.
	* recog.h (next_insn_tests_no_inequality): Likewise.
	* rtlanal.c (inequality_comparisons_p): Delete function.
	* recog.c (next_insn_tests_no_inequality): Likewise.

From-SVN: r278681
parent e9daced3
2019-11-25 Bernd Schmidt <bernds_cb1@t-online.de>
* config/m68k/m68k.c (output_move_himode, output_move_qimode):
Replace code for non-CONST_INT constants with gcc_unreachable.
* config/m68k/m68k.md (cbranchdi): Don't generate individual
compare and test.
(CMPMODE): New mode_iterator.
(cbranchsi4, cbranchqi4, cbranchhi4): Replace expanders with
cbranch<mode>4.
(cstoresi4, cstoreqi4, cstorehi4): Replace expanders with
cstore<mode>4.
(cmp<mode>_68881): Remove 'F' constraint from first comparison
operand.
(bit test insns patterns): Use nonimmediate_operand, not
register_operand, for source operands that allow memory in
their constraints.
(divmodsi4, udivmodsi4, divmodhi4 and related unnamed patterns):
Use register_operand, not nonimmediate_operand, for the
destinations.
(DBCC): New mode_iterator.
(dbcc peepholes): Use it to reduce duplication.
(trap): Use const_true_rtx, not const1_rtx.
* config/m68k/predicates.md (m68k_comparison_operand): Renamed
from m68k_subword_comparison_operand and changed to handle
SImode.
PR target/91851
* config/m68k/m68k-protos.h (output-dbcc_and_branch): Adjust
declaration.
(m68k_init_cc): New declaration.
(m68k_output_compare_di, m68k_output_compare_si)
(m68k_output_compare_hi, m68k_output_compare_qi)
(m68k_output_compare_fp, m68k_output_btst, m68k_output_bftst)
(m68k_find_flags_value, m68k_output_scc, m68k_output_scc_float)
(m68k_output_branch_integer, m68k_output_branch_integer_rev.
m68k_output_branch_float, m68k_output_branch_float_rev):
Likewise.
(valid_dbcc_comparison_p_2, flags_in_68881)
(output_btst): Remove declaration.
* config/m68k/m68k.c (INCLDUE_STRING): Define.
(TARGET_ASM_FINAL_POSTSCAN_INSN): Define.
(valid_dbcc_comparison_p_2, flags_in_68881): Delete functions.
(flags_compare_op0, flags_compare_op1, flags_operand1,
flags_operand2, flags_valid): New static variables.
(m68k_find_flags_value, m68k_init_cc): New functions.
(handle_flags_for_move, m68k_asm_final_postscan_insn,
remember_compare_flags): New static functions.
(output_dbcc_and_branch): New argument CODE. Use it, and add
PLUS and MINUS to the possible codes. All callers changed.
(m68k_output_btst): Renamed from output_btst. Remove OPERANDS
and INSN arguments, add CODE arg. Return the comparison code
to use. All callers changed. Use CODE instead of
next_insn_tests_no_inequality, and replace cc_status management
with changing the return code.
(m68k_rtx_costs): Instead of testing for COMPARE, test for
RTX_COMPARE or RTX_COMM_COMPARE.
(output_move_simode, output_move_qimode): Call
handle_flags_for_move.
(notice_update_cc): Delete function.
(m68k_output_bftst, m68k_output_compare_di, m68k_output_compare_si,
m68k_output_compare_hi, m68k_output_compare_qi,
m68k_output_compare_fp, m68k_output_branch_integer,
m68k_output_branch_integer_rev, m68k_output_scc,
m68k_output_branch_float, m68k_output_branch_float_rev,
m68k_output_scc_float): New functions.
(output_andsi3, output_iorsi3, output_xorsi3): Call CC_STATUS_INIT
once at the start, and set flags_valid and flags_operand1 if the
flags are usable.
* config/m68k/m68k.h (CC_IN_68881, NOTICE_UPDATE_CC,
CC_OVERFLOW_UNUSABLE, CC_NO_CARRY, OUTPUT_JUMP): Remove
definitions.
(CC_STATUS_INIT): Define.
* config/m68k/m68k.md (flags_valid): New define_attr.
(tstdi, tstsi_internal_68020_cf, tstsi_internal, tsthi_internal,
tstqi_internal, tst<mode>_68881, tst<mode>_cf, cmpdi_internal,
cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf,
cmp<mode>_68881, cmp<mode>_cf, unnamed btst patterns,
tst_bftst_reg, tst_bftst_reg, unnamed scc patterns, scc,
sls, sordered_1, sunordered_1, suneq_1, sunge_1, sungt_1,
sunle_1, sunlt_1, sltgt_1, fsogt_1, fsoge_1, fsolt_1, fsole_1,
bge0_di, blt0_di, beq, bne, bgt, bgtu, blt, bltu, bge, bgeu,
ble, bleu, bordered, bunordered, buneq, bunge, bungt, bunle,
bunlt, bltgt, beq_rev, bne_rev, bgt_rev, bgtu_rev,
blt_rev, bltu_rev, bge_rev, bgeu_rev, ble_rev, bleu_rev,
bordered_rev, bunordered_rev, buneq_rev, bunge_rv, bungt_rev,
bunle_rev, bunlt_rev, bltgt_rev, ctrapdi4, ctrapsi4, ctraphi4,
ctrapqi4, conditional_trap): Delete patterns.
(cbranchdi4_insn): New pattern.
(cbranchdi4): Don't generate cc0 patterns. When testing LT or GE,
test high part only. When testing EQ or NE, generate beq0_di
and bne0_di patterns directly.
(cstoredi4): When testing LT or GE, test high part only.
(both sets of cbranch<mode>4, cstore<mode>4): Don't generate cc0
patterns.
(scc0_constraints, cmp1_constraints, cmp2_constraints,
scc0_cf_constraints, cmp1_cf_constraints, cmp2_cf_constraints,
cmp2_cf_predicate): New define_mode_attrs.
(cbranch<mode>4_insn, cbranch<mode>4_insn_rev,
cbranch<mode>4_insn_cf, cbranch<mode>4_insn_cf_rev,
cstore<mode>4_insn, cstore<mode>4_insn_cf for integer modes)
New patterns.
(cbranch<mode>4_insn_68881, cbranch<mode>4_insn_rev_68881):
(cbranch<mode>4_insn_cf, cbranch<mode>4_insn_rev_cf,
cstore<mode>4_insn_68881, cstore<mode>4_insn_cf for FP):
New patterns.
(cbranchsi4_btst_mem_insn, cbranchsi4_btst_reg_insn,
cbranchsi4_btst_mem_insn_1, cbranchsi4_btst_reg_insn_1):
Likewise.
(BTST): New define_mode_iterator.
(btst_predicate, btst_constraint, btst_range): New
define_mode_attrs.
(cbranch_bftst<mode>_insn, cstore_bftst<mode>_insn): New
patterns.
(movsi_m68k_movsi_m68k2, movsi_cf, unnamed movstrict patterns,
unnamed movhi and movqi patterns, unnamed movsf, movdf and movxf
patterns): Set attr "flags_valid".
(truncsiqi2, trunchiqi2, truncsihi2): Remove manual CC_STATUS
management. Set attr "flags_valid".
(extendsidi2, extendplussidi, unnamed float_extendsfdf pattern,
extendsfdf2_cf, fix_truncdfsi2, fix_truncdfhi2, fix_truncdfqi2,
addi_sexthishl32, adddi_dilshr32, adddi_dilshr32_cf,
addi_dishl32, subdi_sexthishl32, subdi_dishl32, subdi3): Remove
manual CC_STATUS management.
(addsi3_internal, addhi3, addqi3, subsi3, subhi3, subqi3,
unnamed strict_lowpart subhi and subqi patterns): Set attr
"flags_valid".
(unnamed strict_lowpart addhi3 and addqi3 patterns): Likewise.
Remove code to operate on address regs and assert the case
does not occur.
(unnamed mulsidi patterns, divmodhi4, udivmodhi4): Remove
manual CC_STATUS_INIT.
(andsi3_internal, andhi3, andqi3, iorsi3_internal, iorhi3, iorqi3,
xorsi3_internal, xorhi3, xorqi3, negsi2_internal,
negsi2_5200, neghi2, negqi2, one_cmplsi2_internal, one_cmplhi2,
one_cmplqi2, unnamed strict_lowpart patterns
for andhi, andqi, iorhi, iorqi, xorhi, xorqi, neghi, negqi,
one_cmplhi and one_cmplqi): Set attr "flags_valid".
(iorsi_zext_ashl16, iorsi_zext): Remove manual CC_STATUS_INIT.
(ashldi_sexthi, ashlsi_16, ashlsi_17_24): Remove manual
CC_STATUS_INIT.
(ashlsi3, ashlhi3, ashlqi3, ashrsi3, ashrhi3, ashrqi3, lshrsi3,
lshrhi3, shrqi3, rotlsi3, rotlhi3, rotlhi3_lowpart, rotlqi3,
rotlqi3_lowpart, rotrsi3, rotrhi3, rotrhi_lowpart, rotrqi3,
unnamed strict_low_part patterns for HI and
QI versions): Set attr "flags_valid".
(bsetmemqi, bsetmemqi_ext, bsetdreg, bchgdreg, bclrdreg,
bclrmemqi, extzv_8_16_reg, extzv_bfextu_mem, insv_bfchg_mem,
insv_bfclr_mem, insv_bfset_mem, extv_bfextu_reg,
insv_bfclr_reg, insv_bfset_reg, dbne_hi, dbne_si, dbge_hi,
dbge_si, extendsfxf2, extenddfxf2, ): Remove manual cc_status management.
(various unnamed peepholes): Adjust compare/branch sequences
for new cbranch patterns.
(dbcc peepholes): Likewise, and output the comparison here
as well.
* config/m68k/predicates.md (valid_dbcc_comparison_p): Delete.
(fp_src_operand): Allow constant zero.
(address_reg_operand): New predicate.
* rtl.h (inequality_comparisons_p): Remove declaration.
* recog.h (next_insn_tests_no_inequality): Likewise.
* rtlanal.c (inequality_comparisons_p): Delete function.
* recog.c (next_insn_tests_no_inequality): Likewise.
2019-11-25 Richard Biener <rguenther@suse.de>
* tree-vect-slp.c (vect_detect_hybrid_slp_stmts): Add assertion.
......@@ -42,7 +42,23 @@ extern const char *output_iorsi3 (rtx *);
extern const char *output_xorsi3 (rtx *);
extern const char *output_call (rtx);
extern const char *output_sibcall (rtx);
extern void output_dbcc_and_branch (rtx *);
extern void m68k_init_cc ();
extern void output_dbcc_and_branch (rtx *, rtx_code);
extern rtx_code m68k_output_compare_di (rtx, rtx, rtx, rtx, rtx_insn *, rtx_code);
extern rtx_code m68k_output_compare_si (rtx, rtx, rtx_code);
extern rtx_code m68k_output_compare_hi (rtx, rtx, rtx_code);
extern rtx_code m68k_output_compare_qi (rtx, rtx, rtx_code);
extern rtx_code m68k_output_compare_fp (rtx, rtx, rtx_code);
extern rtx_code m68k_output_btst (rtx, rtx, rtx_code, int);
extern rtx_code m68k_output_bftst (rtx, rtx, rtx, rtx_code);
extern rtx_code m68k_find_flags_value (rtx, rtx, rtx_code);
extern const char *m68k_output_scc (rtx_code);
extern const char *m68k_output_scc_float (rtx_code);
extern const char *m68k_output_branch_integer (rtx_code);
extern const char *m68k_output_branch_integer_rev (rtx_code);
extern const char *m68k_output_branch_float (rtx_code);
extern const char *m68k_output_branch_float_rev (rtx_code);
extern int floating_exact_log2 (rtx);
extern bool strict_low_part_peephole_ok (machine_mode mode,
rtx_insn *first_insn, rtx target);
......@@ -88,7 +104,6 @@ extern enum attr_op_mem m68k_sched_attr_op_mem (rtx_insn *);
extern enum reg_class m68k_secondary_reload_class (enum reg_class,
machine_mode, rtx);
extern enum reg_class m68k_preferred_reload_class (rtx, enum reg_class);
extern int flags_in_68881 (void);
extern void m68k_expand_prologue (void);
extern bool m68k_use_return_insn (void);
extern void m68k_expand_epilogue (bool);
......
......@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#define IN_TARGET_CODE 1
#include "config.h"
#define INCLUDE_STRING
#include "system.h"
#include "coretypes.h"
#include "backend.h"
......@@ -194,6 +195,7 @@ static bool m68k_hard_regno_mode_ok (unsigned int, machine_mode);
static bool m68k_modes_tieable_p (machine_mode, machine_mode);
static machine_mode m68k_promote_function_mode (const_tree, machine_mode,
int *, const_tree, int);
static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int);
/* Initialize the GCC target structure. */
......@@ -355,6 +357,9 @@ static machine_mode m68k_promote_function_mode (const_tree, machine_mode,
#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
#undef TARGET_ASM_FINAL_POSTSCAN_INSN
#define TARGET_ASM_FINAL_POSTSCAN_INSN m68k_asm_final_postscan_insn
static const struct attribute_spec m68k_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req,
......@@ -1356,40 +1361,6 @@ m68k_expand_epilogue (bool sibcall_p)
emit_jump_insn (ret_rtx);
}
/* Return true if X is a valid comparison operator for the dbcc
instruction.
Note it rejects floating point comparison operators.
(In the future we could use Fdbcc).
It also rejects some comparisons when CC_NO_OVERFLOW is set. */
int
valid_dbcc_comparison_p_2 (rtx x, machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (x))
{
case EQ: case NE: case GTU: case LTU:
case GEU: case LEU:
return 1;
/* Reject some when CC_NO_OVERFLOW is set. This may be over
conservative */
case GT: case LT: case GE: case LE:
return ! (cc_prev_status.flags & CC_NO_OVERFLOW);
default:
return 0;
}
}
/* Return nonzero if flags are currently in the 68881 flag register. */
int
flags_in_68881 (void)
{
/* We could add support for these in the future */
return cc_status.flags & CC_IN_68881;
}
/* Return true if PARALLEL contains register REGNO. */
static bool
m68k_reg_present_p (const_rtx parallel, unsigned int regno)
......@@ -1580,18 +1551,186 @@ m68k_legitimize_address (rtx x, rtx oldx, machine_mode mode)
return x;
}
/* For eliding comparisons, we remember how the flags were set.
FLAGS_COMPARE_OP0 and FLAGS_COMPARE_OP1 are remembered for a direct
comparison, they take priority. FLAGS_OPERAND1 and FLAGS_OPERAND2
are used in more cases, they are a fallback for comparisons against
zero after a move or arithmetic insn.
FLAGS_VALID is set to FLAGS_VALID_NO if we should not use any of
these values. */
static rtx flags_compare_op0, flags_compare_op1;
static rtx flags_operand1, flags_operand2;
static attr_flags_valid flags_valid = FLAGS_VALID_NO;
/* Return a code other than UNKNOWN if we can elide a CODE comparison of
OP0 with OP1. */
rtx_code
m68k_find_flags_value (rtx op0, rtx op1, rtx_code code)
{
if (flags_compare_op0 != NULL_RTX)
{
if (rtx_equal_p (op0, flags_compare_op0)
&& rtx_equal_p (op1, flags_compare_op1))
return code;
if (rtx_equal_p (op0, flags_compare_op1)
&& rtx_equal_p (op1, flags_compare_op0))
return swap_condition (code);
return UNKNOWN;
}
machine_mode mode = GET_MODE (op0);
if (op1 != CONST0_RTX (mode))
return UNKNOWN;
/* Comparisons against 0 with these two should have been optimized out. */
gcc_assert (code != LTU && code != GEU);
if (flags_valid == FLAGS_VALID_NOOV && (code == GT || code == LE))
return UNKNOWN;
if (rtx_equal_p (flags_operand1, op0) || rtx_equal_p (flags_operand2, op0))
return (FLOAT_MODE_P (mode) ? code
: code == GE ? PLUS : code == LT ? MINUS : code);
/* See if we are testing whether the high part of a DImode value is
positive or negative and we have the full value as a remembered
operand. */
if (code != GE && code != LT)
return UNKNOWN;
if (mode == SImode
&& flags_operand1 != NULL_RTX && GET_MODE (flags_operand1) == DImode
&& REG_P (flags_operand1) && REG_P (op0)
&& hard_regno_nregs (REGNO (flags_operand1), DImode) == 2
&& REGNO (flags_operand1) == REGNO (op0))
return code == GE ? PLUS : MINUS;
if (mode == SImode
&& flags_operand2 != NULL_RTX && GET_MODE (flags_operand2) == DImode
&& REG_P (flags_operand2) && REG_P (op0)
&& hard_regno_nregs (REGNO (flags_operand2), DImode) == 2
&& REGNO (flags_operand2) == REGNO (op0))
return code == GE ? PLUS : MINUS;
return UNKNOWN;
}
/* Called through CC_STATUS_INIT, which is invoked by final whenever a
label is encountered. */
void
m68k_init_cc ()
{
flags_compare_op0 = flags_compare_op1 = NULL_RTX;
flags_operand1 = flags_operand2 = NULL_RTX;
flags_valid = FLAGS_VALID_NO;
}
/* Update flags for a move operation with OPERANDS. Called for move
operations where attr_flags_valid returns "set". */
static void
handle_flags_for_move (rtx *operands)
{
flags_compare_op0 = flags_compare_op1 = NULL_RTX;
if (!ADDRESS_REG_P (operands[0]))
{
flags_valid = FLAGS_VALID_MOVE;
flags_operand1 = side_effects_p (operands[0]) ? NULL_RTX : operands[0];
if (side_effects_p (operands[1])
/* ??? For mem->mem moves, this can discard the source as a
valid compare operand. If you assume aligned moves, this
is unnecessary, but in theory, we could have an unaligned
move overwriting parts of its source. */
|| modified_in_p (operands[1], current_output_insn))
flags_operand2 = NULL_RTX;
else
flags_operand2 = operands[1];
return;
}
if (flags_operand1 != NULL_RTX
&& modified_in_p (flags_operand1, current_output_insn))
flags_operand1 = NULL_RTX;
if (flags_operand2 != NULL_RTX
&& modified_in_p (flags_operand2, current_output_insn))
flags_operand2 = NULL_RTX;
}
/* Process INSN to remember flag operands if possible. */
static void
m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int)
{
enum attr_flags_valid v = get_attr_flags_valid (insn);
if (v == FLAGS_VALID_SET)
return;
/* Comparisons use FLAGS_VALID_SET, so we can be sure we need to clear these
now. */
flags_compare_op0 = flags_compare_op1 = NULL_RTX;
if (v == FLAGS_VALID_NO)
{
flags_operand1 = flags_operand2 = NULL_RTX;
return;
}
else if (v == FLAGS_VALID_UNCHANGED)
{
if (flags_operand1 != NULL_RTX && modified_in_p (flags_operand1, insn))
flags_operand1 = NULL_RTX;
if (flags_operand2 != NULL_RTX && modified_in_p (flags_operand2, insn))
flags_operand2 = NULL_RTX;
return;
}
flags_valid = v;
rtx set = single_set (insn);
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
if (side_effects_p (dest))
dest = NULL_RTX;
switch (v)
{
case FLAGS_VALID_YES:
case FLAGS_VALID_NOOV:
flags_operand1 = dest;
flags_operand2 = NULL_RTX;
break;
case FLAGS_VALID_MOVE:
/* fmoves to memory or data registers do not set the condition
codes. Normal moves _do_ set the condition codes, but not in
a way that is appropriate for comparison with 0, because -0.0
would be treated as a negative nonzero number. Note that it
isn't appropriate to conditionalize this restriction on
HONOR_SIGNED_ZEROS because that macro merely indicates whether
we care about the difference between -0.0 and +0.0. */
if (dest != NULL_RTX
&& !FP_REG_P (dest)
&& (FP_REG_P (src)
|| GET_CODE (src) == FIX
|| FLOAT_MODE_P (GET_MODE (dest))))
flags_operand1 = flags_operand2 = NULL_RTX;
else
{
flags_operand1 = dest;
if (GET_MODE (src) != VOIDmode && !side_effects_p (src)
&& !modified_in_p (src, insn))
flags_operand2 = src;
else
flags_operand2 = NULL_RTX;
}
break;
default:
gcc_unreachable ();
}
return;
}
/* Output a dbCC; jCC sequence. Note we do not handle the
floating point version of this sequence (Fdbcc). We also
do not handle alternative conditions when CC_NO_OVERFLOW is
set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will
kick those out before we get here. */
floating point version of this sequence (Fdbcc).
OPERANDS are as in the two peepholes. CODE is the code
returned by m68k_output_branch_<mode>. */
void
output_dbcc_and_branch (rtx *operands)
output_dbcc_and_branch (rtx *operands, rtx_code code)
{
switch (GET_CODE (operands[3]))
switch (code)
{
case EQ:
output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands);
......@@ -1633,6 +1772,14 @@ output_dbcc_and_branch (rtx *operands)
output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands);
break;
case PLUS:
output_asm_insn ("dbpl %0,%l1\n\tjle %l2", operands);
break;
case MINUS:
output_asm_insn ("dbmi %0,%l1\n\tjle %l2", operands);
break;
default:
gcc_unreachable ();
}
......@@ -1790,11 +1937,12 @@ output_scc_di (rtx op, rtx operand1, rtx operand2, rtx dest)
return "";
}
const char *
output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos)
rtx_code
m68k_output_btst (rtx countop, rtx dataop, rtx_code code, int signpos)
{
operands[0] = countop;
operands[1] = dataop;
rtx ops[2];
ops[0] = countop;
ops[1] = dataop;
if (GET_CODE (countop) == CONST_INT)
{
......@@ -1805,40 +1953,41 @@ output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos
{
int offset = (count & ~signpos) / 8;
count = count & signpos;
operands[1] = dataop = adjust_address (dataop, QImode, offset);
ops[1] = dataop = adjust_address (dataop, QImode, offset);
}
if (code == EQ || code == NE)
{
if (count == 31)
{
output_asm_insn ("tst%.l %1", ops);
return code == EQ ? PLUS : MINUS;
}
if (count == 15)
{
output_asm_insn ("tst%.w %1", ops);
return code == EQ ? PLUS : MINUS;
}
if (count == 7)
{
output_asm_insn ("tst%.b %1", ops);
return code == EQ ? PLUS : MINUS;
}
}
if (count == signpos)
cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
else
cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
/* These three statements used to use next_insns_test_no...
but it appears that this should do the same job. */
if (count == 31
&& next_insn_tests_no_inequality (insn))
return "tst%.l %1";
if (count == 15
&& next_insn_tests_no_inequality (insn))
return "tst%.w %1";
if (count == 7
&& next_insn_tests_no_inequality (insn))
return "tst%.b %1";
/* Try to use `movew to ccr' followed by the appropriate branch insn.
On some m68k variants unfortunately that's slower than btst.
On 68000 and higher, that should also work for all HImode operands. */
if (TUNE_CPU32 || TARGET_COLDFIRE || optimize_size)
{
if (count == 3 && DATA_REG_P (operands[1])
&& next_insn_tests_no_inequality (insn))
if (count == 3 && DATA_REG_P (ops[1]) && (code == EQ || code == NE))
{
cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N | CC_NO_OVERFLOW;
return "move%.w %1,%%ccr";
output_asm_insn ("move%.w %1,%%ccr", ops);
return code == EQ ? PLUS : MINUS;
}
if (count == 2 && DATA_REG_P (operands[1])
&& next_insn_tests_no_inequality (insn))
if (count == 2 && DATA_REG_P (ops[1]) && (code == EQ || code == NE))
{
cc_status.flags = CC_NOT_NEGATIVE | CC_INVERTED | CC_NO_OVERFLOW;
return "move%.w %1,%%ccr";
output_asm_insn ("move%.w %1,%%ccr", ops);
return code == EQ ? NE : EQ;
}
/* count == 1 followed by bvc/bvs and
count == 0 followed by bcc/bcs are also possible, but need
......@@ -1847,7 +1996,28 @@ output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos
cc_status.flags = CC_NOT_NEGATIVE;
}
return "btst %0,%1";
output_asm_insn ("btst %0,%1", ops);
return code;
}
/* Output a bftst instruction for a zero_extract with ZXOP0, ZXOP1 and ZXOP2
operands. CODE is the code of the comparison, and we return the code to
be actually used in the jump. */
rtx_code
m68k_output_bftst (rtx zxop0, rtx zxop1, rtx zxop2, rtx_code code)
{
if (zxop1 == const1_rtx && GET_CODE (zxop2) == CONST_INT)
{
int width = GET_CODE (zxop0) == REG ? 31 : 7;
/* Pass 1000 as SIGNPOS argument so that btst will
not think we are testing the sign bit for an `and'
and assume that nonzero implies a negative result. */
return m68k_output_btst (GEN_INT (width - INTVAL (zxop2)), zxop0, code, 1000);
}
rtx ops[3] = { zxop0, zxop1, zxop2 };
output_asm_insn ("bftst %0{%b2:%b1}", ops);
return code;
}
/* Return true if X is a legitimate base register. STRICT_P says
......@@ -2839,7 +3009,8 @@ m68k_rtx_costs (rtx x, machine_mode mode, int outer_code,
case CONST_DOUBLE:
/* Make 0.0 cheaper than other floating constants to
encourage creating tstsf and tstdf insns. */
if (outer_code == COMPARE
if ((GET_RTX_CLASS (outer_code) == RTX_COMPARE
|| GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
&& (x == CONST0_RTX (SFmode) || x == CONST0_RTX (DFmode)))
*total = 4;
else
......@@ -2953,7 +3124,8 @@ m68k_rtx_costs (rtx x, machine_mode mode, int outer_code,
return true;
case ZERO_EXTRACT:
if (outer_code == COMPARE)
if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
|| GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
*total = 0;
return false;
......@@ -3056,6 +3228,8 @@ output_move_simode_const (rtx *operands)
const char *
output_move_simode (rtx *operands)
{
handle_flags_for_move (operands);
if (GET_CODE (operands[1]) == CONST_INT)
return output_move_simode_const (operands);
else if ((GET_CODE (operands[1]) == SYMBOL_REF
......@@ -3072,7 +3246,7 @@ output_move_simode (rtx *operands)
const char *
output_move_himode (rtx *operands)
{
if (GET_CODE (operands[1]) == CONST_INT)
if (GET_CODE (operands[1]) == CONST_INT)
{
if (operands[1] == const0_rtx
&& (DATA_REG_P (operands[0])
......@@ -3094,16 +3268,18 @@ output_move_himode (rtx *operands)
return "move%.w %1,%0";
}
else if (CONSTANT_P (operands[1]))
return "move%.l %1,%0";
gcc_unreachable ();
return "move%.w %1,%0";
}
const char *
output_move_qimode (rtx *operands)
{
handle_flags_for_move (operands);
/* 68k family always modifies the stack pointer by at least 2, even for
byte pushes. The 5200 (ColdFire) does not do this. */
/* This case is generated by pushqi1 pattern now. */
gcc_assert (!(GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
......@@ -3134,11 +3310,15 @@ output_move_qimode (rtx *operands)
if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0]))
return "sub%.l %0,%0";
if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
return "move%.l %1,%0";
gcc_unreachable ();
/* 68k family (including the 5200 ColdFire) does not support byte moves to
from address registers. */
if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
return "move%.w %1,%0";
{
if (ADDRESS_REG_P (operands[1]))
CC_STATUS_INIT;
return "move%.w %1,%0";
}
return "move%.b %1,%0";
}
......@@ -4136,125 +4316,440 @@ output_addsi3 (rtx *operands)
}
return "add%.l %2,%0";
}
/* Store in cc_status the expressions that the condition codes will
describe after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
/* On the 68000, all the insns to store in an address register fail to
set the cc's. However, in some cases these instructions can make it
possibly invalid to use the saved cc's. In those cases we clear out
some or all of the saved cc's so they won't be used. */
void
notice_update_cc (rtx exp, rtx insn)
/* Emit a comparison between OP0 and OP1. Return true iff the comparison
was reversed. SC1 is an SImode scratch reg, and SC2 a DImode scratch reg,
as needed. CODE is the code of the comparison, we return it unchanged or
swapped, as necessary. */
rtx_code
m68k_output_compare_di (rtx op0, rtx op1, rtx sc1, rtx sc2, rtx_insn *insn,
rtx_code code)
{
if (GET_CODE (exp) == SET)
rtx ops[4];
ops[0] = op0;
ops[1] = op1;
ops[2] = sc1;
ops[3] = sc2;
if (op1 == const0_rtx)
{
if (GET_CODE (SET_SRC (exp)) == CALL)
CC_STATUS_INIT;
else if (ADDRESS_REG_P (SET_DEST (exp)))
if (!REG_P (op0) || ADDRESS_REG_P (op0))
{
if (cc_status.value1 && modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2 && modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
rtx xoperands[2];
xoperands[0] = sc2;
xoperands[1] = op0;
output_move_double (xoperands);
output_asm_insn ("neg%.l %R0\n\tnegx%.l %0", xoperands);
return swap_condition (code);
}
/* fmoves to memory or data registers do not set the condition
codes. Normal moves _do_ set the condition codes, but not in
a way that is appropriate for comparison with 0, because -0.0
would be treated as a negative nonzero number. Note that it
isn't appropriate to conditionalize this restriction on
HONOR_SIGNED_ZEROS because that macro merely indicates whether
we care about the difference between -0.0 and +0.0. */
else if (!FP_REG_P (SET_DEST (exp))
&& SET_DEST (exp) != cc0_rtx
&& (FP_REG_P (SET_SRC (exp))
|| GET_CODE (SET_SRC (exp)) == FIX
|| FLOAT_MODE_P (GET_MODE (SET_DEST (exp)))))
CC_STATUS_INIT;
/* A pair of move insns doesn't produce a useful overall cc. */
else if (!FP_REG_P (SET_DEST (exp))
&& !FP_REG_P (SET_SRC (exp))
&& GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4
&& (GET_CODE (SET_SRC (exp)) == REG
|| GET_CODE (SET_SRC (exp)) == MEM
|| GET_CODE (SET_SRC (exp)) == CONST_DOUBLE))
CC_STATUS_INIT;
else if (SET_DEST (exp) != pc_rtx)
if (find_reg_note (insn, REG_DEAD, op0))
{
cc_status.flags = 0;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
output_asm_insn ("neg%.l %R0\n\tnegx%.l %0", ops);
return swap_condition (code);
}
}
else if (GET_CODE (exp) == PARALLEL
&& GET_CODE (XVECEXP (exp, 0, 0)) == SET)
{
rtx dest = SET_DEST (XVECEXP (exp, 0, 0));
rtx src = SET_SRC (XVECEXP (exp, 0, 0));
if (ADDRESS_REG_P (dest))
CC_STATUS_INIT;
else if (dest != pc_rtx)
else
{
cc_status.flags = 0;
cc_status.value1 = dest;
cc_status.value2 = src;
/* 'sub' clears %1, and also clears the X cc bit.
'tst' sets the Z cc bit according to the low part of the DImode
operand.
'subx %1' (i.e. subx #0) acts as a (non-existent) tstx on the high
part. */
output_asm_insn ("sub%.l %2,%2\n\ttst%.l %R0\n\tsubx%.l %2,%0", ops);
return code;
}
}
if (rtx_equal_p (sc2, op0))
{
output_asm_insn ("sub%.l %R1,%R3\n\tsubx%.l %1,%3", ops);
return code;
}
else
{
output_asm_insn ("sub%.l %R0,%R3\n\tsubx%.l %0,%3", ops);
return swap_condition (code);
}
}
static void
remember_compare_flags (rtx op0, rtx op1)
{
if (side_effects_p (op0) || side_effects_p (op1))
CC_STATUS_INIT;
if (cc_status.value2 != 0
&& ADDRESS_REG_P (cc_status.value2)
&& GET_MODE (cc_status.value2) == QImode)
CC_STATUS_INIT;
if (cc_status.value2 != 0)
switch (GET_CODE (cc_status.value2))
{
case ASHIFT: case ASHIFTRT: case LSHIFTRT:
case ROTATE: case ROTATERT:
/* These instructions always clear the overflow bit, and set
the carry to the bit shifted out. */
cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
break;
else
{
flags_compare_op0 = op0;
flags_compare_op1 = op1;
flags_operand1 = flags_operand2 = NULL_RTX;
flags_valid = FLAGS_VALID_SET;
}
}
case PLUS: case MINUS: case MULT:
case DIV: case UDIV: case MOD: case UMOD: case NEG:
if (GET_MODE (cc_status.value2) != VOIDmode)
cc_status.flags |= CC_NO_OVERFLOW;
break;
case ZERO_EXTEND:
/* (SET r1 (ZERO_EXTEND r2)) on this machine
ends with a move insn moving r2 in r2's mode.
Thus, the cc's are set for r2.
This can set N bit spuriously. */
cc_status.flags |= CC_NOT_NEGATIVE;
/* Emit a comparison between OP0 and OP1. CODE is the code of the
comparison. It is returned, potentially modified if necessary. */
rtx_code
m68k_output_compare_si (rtx op0, rtx op1, rtx_code code)
{
rtx_code tmp = m68k_find_flags_value (op0, op1, code);
if (tmp != UNKNOWN)
return tmp;
default:
break;
}
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
/* Check for PRE_DEC in dest modifying a register used in src. */
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
&& GET_CODE (XEXP (cc_status.value1, 0)) == PRE_DEC
&& cc_status.value2
&& reg_overlap_mentioned_p (XEXP (XEXP (cc_status.value1, 0), 0),
cc_status.value2))
cc_status.value2 = 0;
if (((cc_status.value1 && FP_REG_P (cc_status.value1))
|| (cc_status.value2 && FP_REG_P (cc_status.value2))))
cc_status.flags = CC_IN_68881;
if (cc_status.value2 && GET_CODE (cc_status.value2) == COMPARE
&& GET_MODE_CLASS (GET_MODE (XEXP (cc_status.value2, 0))) == MODE_FLOAT)
{
cc_status.flags = CC_IN_68881;
if (!FP_REG_P (XEXP (cc_status.value2, 0))
&& FP_REG_P (XEXP (cc_status.value2, 1)))
cc_status.flags |= CC_REVERSED;
remember_compare_flags (op0, op1);
rtx ops[2];
ops[0] = op0;
ops[1] = op1;
if (op1 == const0_rtx && (TARGET_68020 || TARGET_COLDFIRE || !ADDRESS_REG_P (op0)))
output_asm_insn ("tst%.l %0", ops);
else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM)
output_asm_insn ("cmpm%.l %1,%0", ops);
else if (REG_P (op1)
|| (!REG_P (op0) && GET_CODE (op0) != MEM))
{
output_asm_insn ("cmp%.l %d0,%d1", ops);
std::swap (flags_compare_op0, flags_compare_op1);
return swap_condition (code);
}
else if (!TARGET_COLDFIRE
&& ADDRESS_REG_P (op0)
&& GET_CODE (op1) == CONST_INT
&& INTVAL (op1) < 0x8000
&& INTVAL (op1) >= -0x8000)
output_asm_insn ("cmp%.w %1,%0", ops);
else
output_asm_insn ("cmp%.l %d1,%d0", ops);
return code;
}
/* Emit a comparison between OP0 and OP1. CODE is the code of the
comparison. It is returned, potentially modified if necessary. */
rtx_code
m68k_output_compare_hi (rtx op0, rtx op1, rtx_code code)
{
rtx_code tmp = m68k_find_flags_value (op0, op1, code);
if (tmp != UNKNOWN)
return tmp;
remember_compare_flags (op0, op1);
rtx ops[2];
ops[0] = op0;
ops[1] = op1;
if (op1 == const0_rtx)
output_asm_insn ("tst%.w %d0", ops);
else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM)
output_asm_insn ("cmpm%.w %1,%0", ops);
else if ((REG_P (op1) && !ADDRESS_REG_P (op1))
|| (!REG_P (op0) && GET_CODE (op0) != MEM))
{
output_asm_insn ("cmp%.w %d0,%d1", ops);
std::swap (flags_compare_op0, flags_compare_op1);
return swap_condition (code);
}
else
output_asm_insn ("cmp%.w %d1,%d0", ops);
return code;
}
/* Emit a comparison between OP0 and OP1. CODE is the code of the
comparison. It is returned, potentially modified if necessary. */
rtx_code
m68k_output_compare_qi (rtx op0, rtx op1, rtx_code code)
{
rtx_code tmp = m68k_find_flags_value (op0, op1, code);
if (tmp != UNKNOWN)
return tmp;
remember_compare_flags (op0, op1);
rtx ops[2];
ops[0] = op0;
ops[1] = op1;
if (op1 == const0_rtx)
output_asm_insn ("tst%.b %d0", ops);
else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM)
output_asm_insn ("cmpm%.b %1,%0", ops);
else if (REG_P (op1) || (!REG_P (op0) && GET_CODE (op0) != MEM))
{
output_asm_insn ("cmp%.b %d0,%d1", ops);
std::swap (flags_compare_op0, flags_compare_op1);
return swap_condition (code);
}
else
output_asm_insn ("cmp%.b %d1,%d0", ops);
return code;
}
/* Emit a comparison between OP0 and OP1. CODE is the code of the
comparison. It is returned, potentially modified if necessary. */
rtx_code
m68k_output_compare_fp (rtx op0, rtx op1, rtx_code code)
{
rtx_code tmp = m68k_find_flags_value (op0, op1, code);
if (tmp != UNKNOWN)
return tmp;
rtx ops[2];
ops[0] = op0;
ops[1] = op1;
remember_compare_flags (op0, op1);
machine_mode mode = GET_MODE (op0);
std::string prec = mode == SFmode ? "s" : mode == DFmode ? "d" : "x";
if (op1 == CONST0_RTX (GET_MODE (op0)))
{
if (FP_REG_P (op0))
output_asm_insn ("ftst%.x %0", ops);
else
output_asm_insn (("ftst%." + prec + " %0").c_str (), ops);
return code;
}
switch (which_alternative)
{
case 0:
output_asm_insn ("fcmp%.x %1,%0", ops);
break;
case 1:
output_asm_insn (("fcmp%." + prec + " %f1,%0").c_str (), ops);
break;
case 2:
output_asm_insn (("fcmp%." + prec + " %0,%f1").c_str (), ops);
std::swap (flags_compare_op0, flags_compare_op1);
return swap_condition (code);
case 3:
/* This is the ftst case, handled earlier. */
gcc_unreachable ();
}
return code;
}
/* Return an output template for a branch with CODE. */
const char *
m68k_output_branch_integer (rtx_code code)
{
switch (code)
{
case EQ:
return "jeq %l3";
case NE:
return "jne %l3";
case GT:
return "jgt %l3";
case GTU:
return "jhi %l3";
case LT:
return "jlt %l3";
case LTU:
return "jcs %l3";
case GE:
return "jge %l3";
case GEU:
return "jcc %l3";
case LE:
return "jle %l3";
case LEU:
return "jls %l3";
case PLUS:
return "jpl %l3";
case MINUS:
return "jmi %l3";
default:
gcc_unreachable ();
}
}
/* Return an output template for a reversed branch with CODE. */
const char *
m68k_output_branch_integer_rev (rtx_code code)
{
switch (code)
{
case EQ:
return "jne %l3";
case NE:
return "jeq %l3";
case GT:
return "jle %l3";
case GTU:
return "jls %l3";
case LT:
return "jge %l3";
case LTU:
return "jcc %l3";
case GE:
return "jlt %l3";
case GEU:
return "jcs %l3";
case LE:
return "jgt %l3";
case LEU:
return "jhi %l3";
case PLUS:
return "jmi %l3";
case MINUS:
return "jpl %l3";
default:
gcc_unreachable ();
}
}
/* Return an output template for a scc instruction with CODE. */
const char *
m68k_output_scc (rtx_code code)
{
switch (code)
{
case EQ:
return "seq %0";
case NE:
return "sne %0";
case GT:
return "sgt %0";
case GTU:
return "shi %0";
case LT:
return "slt %0";
case LTU:
return "scs %0";
case GE:
return "sge %0";
case GEU:
return "scc %0";
case LE:
return "sle %0";
case LEU:
return "sls %0";
case PLUS:
return "spl %0";
case MINUS:
return "smi %0";
default:
gcc_unreachable ();
}
}
/* Return an output template for a floating point branch
instruction with CODE. */
const char *
m68k_output_branch_float (rtx_code code)
{
switch (code)
{
case EQ:
return "fjeq %l3";
case NE:
return "fjne %l3";
case GT:
return "fjgt %l3";
case LT:
return "fjlt %l3";
case GE:
return "fjge %l3";
case LE:
return "fjle %l3";
case ORDERED:
return "fjor %l3";
case UNORDERED:
return "fjun %l3";
case UNEQ:
return "fjueq %l3";
case UNGE:
return "fjuge %l3";
case UNGT:
return "fjugt %l3";
case UNLE:
return "fjule %l3";
case UNLT:
return "fjult %l3";
case LTGT:
return "fjogl %l3";
default:
gcc_unreachable ();
}
}
/* Return an output template for a reversed floating point branch
instruction with CODE. */
const char *
m68k_output_branch_float_rev (rtx_code code)
{
switch (code)
{
case EQ:
return "fjne %l3";
case NE:
return "fjeq %l3";
case GT:
return "fjngt %l3";
case LT:
return "fjnlt %l3";
case GE:
return "fjnge %l3";
case LE:
return "fjnle %l3";
case ORDERED:
return "fjun %l3";
case UNORDERED:
return "fjor %l3";
case UNEQ:
return "fjogl %l3";
case UNGE:
return "fjolt %l3";
case UNGT:
return "fjole %l3";
case UNLE:
return "fjogt %l3";
case UNLT:
return "fjoge %l3";
case LTGT:
return "fjueq %l3";
default:
gcc_unreachable ();
}
}
/* Return an output template for a floating point scc
instruction with CODE. */
const char *
m68k_output_scc_float (rtx_code code)
{
switch (code)
{
case EQ:
return "fseq %0";
case NE:
return "fsne %0";
case GT:
return "fsgt %0";
case GTU:
return "fshi %0";
case LT:
return "fslt %0";
case GE:
return "fsge %0";
case LE:
return "fsle %0";
case ORDERED:
return "fsor %0";
case UNORDERED:
return "fsun %0";
case UNEQ:
return "fsueq %0";
case UNGE:
return "fsuge %0";
case UNGT:
return "fsugt %0";
case UNLE:
return "fsule %0";
case UNLT:
return "fsult %0";
case LTGT:
return "fsogl %0";
default:
gcc_unreachable ();
}
}
......@@ -4932,6 +5427,7 @@ const char *
output_andsi3 (rtx *operands)
{
int logval;
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) | 0xffff) == -1
&& (DATA_REG_P (operands[0])
......@@ -4941,8 +5437,6 @@ output_andsi3 (rtx *operands)
if (GET_CODE (operands[0]) != REG)
operands[0] = adjust_address (operands[0], HImode, 2);
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
if (operands[2] == const0_rtx)
return "clr%.w %0";
return "and%.w %2,%0";
......@@ -4959,10 +5453,13 @@ output_andsi3 (rtx *operands)
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
/* This does not set condition codes in a standard way. */
CC_STATUS_INIT;
return "bclr %1,%0";
}
/* Only a standard logical operation on the whole word sets the
condition codes in a way we can use. */
if (!side_effects_p (operands[0]))
flags_operand1 = operands[0];
flags_valid = FLAGS_VALID_YES;
return "and%.l %2,%0";
}
......@@ -4970,6 +5467,7 @@ const char *
output_iorsi3 (rtx *operands)
{
register int logval;
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (DATA_REG_P (operands[0])
......@@ -4978,8 +5476,6 @@ output_iorsi3 (rtx *operands)
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adjust_address (operands[0], HImode, 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
if (INTVAL (operands[2]) == 0xffff)
return "mov%.w %2,%0";
return "or%.w %2,%0";
......@@ -4996,9 +5492,13 @@ output_iorsi3 (rtx *operands)
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
CC_STATUS_INIT;
return "bset %1,%0";
}
/* Only a standard logical operation on the whole word sets the
condition codes in a way we can use. */
if (!side_effects_p (operands[0]))
flags_operand1 = operands[0];
flags_valid = FLAGS_VALID_YES;
return "or%.l %2,%0";
}
......@@ -5006,6 +5506,7 @@ const char *
output_xorsi3 (rtx *operands)
{
register int logval;
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))
......@@ -5013,8 +5514,6 @@ output_xorsi3 (rtx *operands)
{
if (! DATA_REG_P (operands[0]))
operands[0] = adjust_address (operands[0], HImode, 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
if (INTVAL (operands[2]) == 0xffff)
return "not%.w %0";
return "eor%.w %2,%0";
......@@ -5031,9 +5530,13 @@ output_xorsi3 (rtx *operands)
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
CC_STATUS_INIT;
return "bchg %1,%0";
}
/* Only a standard logical operation on the whole word sets the
condition codes in a way we can use. */
if (!side_effects_p (operands[0]))
flags_operand1 = operands[0];
flags_valid = FLAGS_VALID_YES;
return "eor%.l %2,%0";
}
......
......@@ -671,36 +671,6 @@ __transfer_from_trampoline () \
#define FUNCTION_MODE QImode
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
/* Set if the cc value is actually in the 68881, so a floating point
conditional branch must be output. */
#define CC_IN_68881 04000
/* On the 68000, all the insns to store in an address register fail to
set the cc's. However, in some cases these instructions can make it
possibly invalid to use the saved cc's. In those cases we clear out
some or all of the saved cc's so they won't be used. */
#define NOTICE_UPDATE_CC(EXP,INSN) notice_update_cc (EXP, INSN)
/* The shift instructions always clear the overflow bit. */
#define CC_OVERFLOW_UNUSABLE 01000
/* The shift instructions use the carry bit in a way not compatible with
conditional branches. conditions.h uses CC_NO_OVERFLOW for this purpose.
Rename it to something more understandable. */
#define CC_NO_CARRY CC_NO_OVERFLOW
#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
do { if (cc_prev_status.flags & CC_IN_68881) \
return FLOAT; \
if (cc_prev_status.flags & CC_NO_OVERFLOW) \
return NO_OV; \
return NORMAL; } while (0)
/* Control the assembler format that we output. */
#define ASM_APP_ON "#APP\n"
......@@ -900,6 +870,8 @@ do { if (cc_prev_status.flags & CC_IN_68881) \
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
#define CC_STATUS_INIT m68k_init_cc ()
#include "config/m68k/m68k-opts.h"
enum fpu_type
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -115,15 +115,6 @@
&& (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
})
;; Return true if X is a valid comparison operator for the dbcc
;; instruction. Note it rejects floating point comparison
;; operators. (In the future we could use Fdbcc). It also rejects
;; some comparisons when CC_NO_OVERFLOW is set.
(define_predicate "valid_dbcc_comparison_p"
(and (match_code "eq,ne,gtu,ltu,geu,leu,gt,lt,ge,le")
(match_test "valid_dbcc_comparison_p_2 (op, mode)")))
(define_predicate "m68k_cstore_comparison_operator"
(if_then_else (match_test "TARGET_68881")
(match_operand 0 "comparison_operator")
......@@ -210,10 +201,10 @@
(and (match_code "const_int")
(match_test "op == const1_rtx")))
;; A valid operand for a HImode or QImode conditional operation.
;; ColdFire has tst patterns, but not cmp patterns.
(define_predicate "m68k_subword_comparison_operand"
(if_then_else (match_test "TARGET_COLDFIRE")
;; A valid operand for a conditional operation.
;; ColdFire has tst patterns for HImode and QImode, but not cmp patterns.
(define_predicate "m68k_comparison_operand"
(if_then_else (match_test "TARGET_COLDFIRE && mode != SImode")
(and (match_code "const_int")
(match_test "op == const0_rtx"))
(match_operand 0 "general_src_operand")))
......@@ -234,15 +225,17 @@
;; Special case of general_src_operand, which rejects a few fp
;; constants (which we prefer in registers) before reload.
;; Used only in comparisons, and we do want to allow zero.
(define_predicate "fp_src_operand"
(match_operand 0 "general_src_operand")
{
return !CONSTANT_P (op)
|| (TARGET_68881
&& (!standard_68881_constant_p (op)
|| reload_in_progress
|| reload_completed));
return (!CONSTANT_P (op)
|| op == CONST0_RTX (mode)
|| (TARGET_68881
&& (!standard_68881_constant_p (op)
|| reload_in_progress
|| reload_completed)));
})
;; Used to detect constants that are valid for addq/subq instructions
......@@ -282,3 +275,6 @@
(define_predicate "swap_peephole_relational_operator"
(match_code "gtu,leu,gt,le"))
(define_predicate "address_reg_operand"
(match_test ("ADDRESS_REG_P (op)")))
......@@ -923,23 +923,6 @@ validate_simplify_insn (rtx_insn *insn)
return ((num_changes_pending () > 0) && (apply_change_group () > 0));
}
/* Return 1 if the insn using CC0 set by INSN does not contain
any ordered tests applied to the condition codes.
EQ and NE tests do not count. */
int
next_insn_tests_no_inequality (rtx_insn *insn)
{
rtx_insn *next = next_cc0_user (insn);
/* If there is no next insn, we have to take the conservative choice. */
if (next == 0)
return 0;
return (INSN_P (next)
&& ! inequality_comparisons_p (PATTERN (next)));
}
/* Return 1 if OP is a valid general operand for machine mode MODE.
This is either a register reference, a memory reference,
or a constant. In the case of a memory reference, the address
......
......@@ -112,7 +112,6 @@ extern void validate_replace_rtx_group (rtx, rtx, rtx_insn *);
extern void validate_replace_src_group (rtx, rtx, rtx_insn *);
extern bool validate_simplify_insn (rtx_insn *insn);
extern int num_changes_pending (void);
extern int next_insn_tests_no_inequality (rtx_insn *);
extern bool reg_fits_class_p (const_rtx, reg_class_t, int, machine_mode);
extern int offsettable_memref_p (rtx);
......
......@@ -3514,7 +3514,6 @@ extern bool insn_nothrow_p (const_rtx);
extern bool can_nonlocal_goto (const rtx_insn *);
extern void copy_reg_eh_region_note_forward (rtx, rtx_insn *, rtx);
extern void copy_reg_eh_region_note_backward (rtx, rtx_insn *, rtx);
extern int inequality_comparisons_p (const_rtx);
extern rtx replace_rtx (rtx, rtx, rtx, bool = false);
extern void replace_label (rtx *, rtx, rtx, bool);
extern void replace_label_in_insn (rtx_insn *, rtx_insn *, rtx_insn *, bool);
......
......@@ -3021,64 +3021,6 @@ may_trap_or_fault_p (const_rtx x)
return may_trap_p_1 (x, 1);
}
/* Return nonzero if X contains a comparison that is not either EQ or NE,
i.e., an inequality. */
int
inequality_comparisons_p (const_rtx x)
{
const char *fmt;
int len, i;
const enum rtx_code code = GET_CODE (x);
switch (code)
{
case REG:
case SCRATCH:
case PC:
case CC0:
CASE_CONST_ANY:
case CONST:
case LABEL_REF:
case SYMBOL_REF:
return 0;
case LT:
case LTU:
case GT:
case GTU:
case LE:
case LEU:
case GE:
case GEU:
return 1;
default:
break;
}
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < len; i++)
{
if (fmt[i] == 'e')
{
if (inequality_comparisons_p (XEXP (x, i)))
return 1;
}
else if (fmt[i] == 'E')
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (inequality_comparisons_p (XVECEXP (x, i, j)))
return 1;
}
}
return 0;
}
/* Replace any occurrence of FROM in X with TO. The function does
not enter into CONST_DOUBLE for the replace.
......
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