re PR target/49263 (SH Target: underutilized "TST #imm, R0" instruction)
gcc/ PR target/49263 PR target/53987 PR target/64345 PR target/59533 PR target/52933 PR target/54236 PR target/51244 * config/sh/sh-protos.h (sh_extending_set_of_reg::can_use_as_unextended_reg, sh_extending_set_of_reg::use_as_unextended_reg, sh_is_nott_insn, sh_movt_set_dest, sh_movrt_set_dest, sh_is_movt_insn, sh_is_movrt_insn, sh_insn_operands_modified_between_p, sh_reg_dead_or_unused_after_insn, sh_in_recog_treg_set_expr, sh_recog_treg_set_expr, sh_split_treg_set_expr): New functions. (sh_treg_insns): New class. * config/sh/sh.c (TARGET_LEGITIMATE_COMBINED_INSN): Define target hook. (scope_counter): New class. (sh_legitimate_combined_insn, sh_is_nott_insn, sh_movt_set_dest, sh_movrt_set_dest, sh_reg_dead_or_unused_after_insn, sh_extending_set_of_reg::can_use_as_unextended_reg, sh_extending_set_of_reg::use_as_unextended_reg, sh_recog_treg_set_expr, sh_in_recog_treg_set_expr, sh_try_split_insn_simple, sh_split_treg_set_expr): New functions. (addsubcosts): Handle treg_set_expr. (sh_rtx_costs): Handle IF_THEN_ELSE and ZERO_EXTRACT. (sh_rtx_costs): Use arith_reg_operand in SIGN_EXTEND and ZERO_EXTEND. (sh_rtx_costs): Handle additional bit test patterns in EQ and AND cases. (sh_insn_operands_modified_between_p): Make non-static. * config/sh/predicates.md (zero_extend_movu_operand): Allow simple_mem_operand in addition to displacement_mem_operand. (zero_extend_operand): Don't allow zero_extend_movu_operand. (treg_set_expr, treg_set_expr_not_const01, arith_reg_or_treg_set_expr): New predicates. * config/sh/sh.md (tstsi_t): Use arith_reg_operand and arith_or_int_operand instead of logical_operand. Convert to insn_and_split. Try to optimize constant operand in splitter. (tsthi_t, tstqi_t): Fold into *tst<mode>_t. Convert to insn_and_split. (*tstqi_t_zero): Delete. (*tst<mode>_t_subregs): Add !sh_in_recog_treg_set_expr split condition. (tstsi_t_and_not): Delete. (tst<mode>_t_zero_extract_eq): Rename to *tst<mode>_t_zero_extract. Convert to insn_and_split. (unnamed split, tstsi_t_zero_extract_xor, tstsi_t_zero_extract_subreg_xor_little, tstsi_t_zero_extract_subreg_xor_big): Delete. (*tstsi_t_shift_mask): New insn_and_split. (cmpeqsi_t, cmpgesi_t): Add new split for const_int 0 operands and try to recombine with surrounding insns when splitting. (*negtstsi): Add !sh_in_recog_treg_set_expr condition. (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0, *cmp_div0s_1): Rewrite as ... (cmp_div0s, *cmp_div0s_1, *cmp_div0s_2, *cmp_div0s_3, *cmp_div0s_4, *cmp_div0s_5, *cmp_div0s_6): ... these new insn_and_split patterns. (*cbranch_div0s: Delete. (*addc): Convert to insn_and_split. Use treg_set_expr as 3rd operand. Try to recombine with surrounding insns when splitting. Add operand order variants. (*addc_t_r, *addc_r_t): Use treg_set_expr_not_const01. (*addc_r_r_1, *addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_r_msb, *addc_r_r_msb, *addc_2r_msb): Delete. (*addc_2r_lsb): Rename to *addc_2r_t. Use treg_set_expr. Add operand order variant. (*addc_negreg_t): New insn_and_split. (*subc): Convert to insn_and_split. Use treg_set_expr as 3rd operand. Try to recombine with surrounding insns when splitting. Add operand order variants. (*subc_negt_reg, *subc_negreg_t, *reg_lsb_t, *reg_msb_t): New insn_and_split patterns. (*rotcr): Use arith_reg_or_treg_set_expr. Try to recombine with surrounding insns when splitting. (unnamed rotcr split): Use arith_reg_or_treg_set_expr. (*rotcl): Likewise. Add zero_extract variant. (*ashrsi2_31): New insn_and_split. (*negc): Convert to insn_and_split. Use treg_set_expr. (*zero_extend<mode>si2_disp_mem): Update comment. (movrt_negc, *movrt_negc, nott): Add !sh_in_recog_treg_set_expr split condition. (*mov_t_msb_neg, mov_neg_si_t): Use treg_set_expr. Try to recombine with surrounding insns when splitting. (any_treg_expr_to_reg): New insn_and_split. (*neg_zero_extract_0, *neg_zero_extract_1, *neg_zero_extract_2, *neg_zero_extract_3, *neg_zero_extract_4, *neg_zero_extract_5, *neg_zero_extract_6, *zero_extract_0, *zero_extract_1, *zero_extract_2): New single bit zero extract patterns. (bld_reg, *bld_regqi): Fold into bld<mode>_reg. (*get_thread_pointersi, store_gbr, *mov<mode>_gbr_load, *mov<mode>_gbr_load, *mov<mode>_gbr_load, *mov<mode>_gbr_load, *movdi_gbr_load): Use arith_reg_dest instead of register_operand for set destination. (set_thread_pointersi, load_gbr): Use arith_reg_operand instead of register_operand for set source. gcc/testsuite/ PR target/49263 PR target/53987 PR target/64345 PR target/59533 PR target/52933 PR target/54236 PR target/51244 * gcc.target/sh/pr64345-1.c: New. * gcc.target/sh/pr64345-2.c: New. * gcc.target/sh/pr59533-1.c: New. * gcc.target/sh/pr49263.c: Adjust matching of expected insns. * gcc.target/sh/pr52933-2.c: Likewise. * gcc.target/sh/pr54089-1.c: Likewise. * gcc.target/sh/pr54236-1.c: Likewise. * gcc.target/sh/pr51244-20-sh2a.c: Likewise. * gcc.target/sh/pr49263-1.c: Remove xfails. * gcc.target/sh/pr49263-2.c: Likewise. * gcc.target/sh/pr49263-3.c: Likewise. * gcc.target/sh/pr53987-1.c: Likewise. * gcc.target/sh/pr52933-1.c: Adjust matching of expected insns. (test_24, test_25, test_26, test_27, test_28, test_29, test_30): New. * gcc.target/sh/pr51244-12.c: Adjust matching of expected insns. (test05, test06, test07, test08, test09, test10, test11, test12): New. * gcc.target/sh/pr54236-3.c: Adjust matching of expected insns. (test_002, test_003, test_004, test_005, test_006, test_007, test_008, test_009): New. * gcc.target/sh/pr51244-4.c: Adjust matching of expected insns. (test_02): New. From-SVN: r220081
This commit is contained in:
parent
19bd4ebce2
commit
841dbf801d
22 changed files with 2411 additions and 537 deletions
|
@ -1,3 +1,96 @@
|
|||
2015-01-24 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
|
||||
PR target/49263
|
||||
PR target/53987
|
||||
PR target/64345
|
||||
PR target/59533
|
||||
PR target/52933
|
||||
PR target/54236
|
||||
PR target/51244
|
||||
* config/sh/sh-protos.h
|
||||
(sh_extending_set_of_reg::can_use_as_unextended_reg,
|
||||
sh_extending_set_of_reg::use_as_unextended_reg,
|
||||
sh_is_nott_insn, sh_movt_set_dest, sh_movrt_set_dest, sh_is_movt_insn,
|
||||
sh_is_movrt_insn, sh_insn_operands_modified_between_p,
|
||||
sh_reg_dead_or_unused_after_insn, sh_in_recog_treg_set_expr,
|
||||
sh_recog_treg_set_expr, sh_split_treg_set_expr): New functions.
|
||||
(sh_treg_insns): New class.
|
||||
* config/sh/sh.c (TARGET_LEGITIMATE_COMBINED_INSN): Define target hook.
|
||||
(scope_counter): New class.
|
||||
(sh_legitimate_combined_insn, sh_is_nott_insn, sh_movt_set_dest,
|
||||
sh_movrt_set_dest, sh_reg_dead_or_unused_after_insn,
|
||||
sh_extending_set_of_reg::can_use_as_unextended_reg,
|
||||
sh_extending_set_of_reg::use_as_unextended_reg, sh_recog_treg_set_expr,
|
||||
sh_in_recog_treg_set_expr, sh_try_split_insn_simple,
|
||||
sh_split_treg_set_expr): New functions.
|
||||
(addsubcosts): Handle treg_set_expr.
|
||||
(sh_rtx_costs): Handle IF_THEN_ELSE and ZERO_EXTRACT.
|
||||
(sh_rtx_costs): Use arith_reg_operand in SIGN_EXTEND and ZERO_EXTEND.
|
||||
(sh_rtx_costs): Handle additional bit test patterns in EQ and AND cases.
|
||||
(sh_insn_operands_modified_between_p): Make non-static.
|
||||
* config/sh/predicates.md (zero_extend_movu_operand): Allow
|
||||
simple_mem_operand in addition to displacement_mem_operand.
|
||||
(zero_extend_operand): Don't allow zero_extend_movu_operand.
|
||||
(treg_set_expr, treg_set_expr_not_const01,
|
||||
arith_reg_or_treg_set_expr): New predicates.
|
||||
* config/sh/sh.md (tstsi_t): Use arith_reg_operand and
|
||||
arith_or_int_operand instead of logical_operand. Convert to
|
||||
insn_and_split. Try to optimize constant operand in splitter.
|
||||
(tsthi_t, tstqi_t): Fold into *tst<mode>_t. Convert to insn_and_split.
|
||||
(*tstqi_t_zero): Delete.
|
||||
(*tst<mode>_t_subregs): Add !sh_in_recog_treg_set_expr split condition.
|
||||
(tstsi_t_and_not): Delete.
|
||||
(tst<mode>_t_zero_extract_eq): Rename to *tst<mode>_t_zero_extract.
|
||||
Convert to insn_and_split.
|
||||
(unnamed split, tstsi_t_zero_extract_xor,
|
||||
tstsi_t_zero_extract_subreg_xor_little,
|
||||
tstsi_t_zero_extract_subreg_xor_big): Delete.
|
||||
(*tstsi_t_shift_mask): New insn_and_split.
|
||||
(cmpeqsi_t, cmpgesi_t): Add new split for const_int 0 operands and try
|
||||
to recombine with surrounding insns when splitting.
|
||||
(*negtstsi): Add !sh_in_recog_treg_set_expr condition.
|
||||
(cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0, *cmp_div0s_1): Rewrite as ...
|
||||
(cmp_div0s, *cmp_div0s_1, *cmp_div0s_2, *cmp_div0s_3, *cmp_div0s_4,
|
||||
*cmp_div0s_5, *cmp_div0s_6): ... these new insn_and_split patterns.
|
||||
(*cbranch_div0s: Delete.
|
||||
(*addc): Convert to insn_and_split. Use treg_set_expr as 3rd operand.
|
||||
Try to recombine with surrounding insns when splitting. Add operand
|
||||
order variants.
|
||||
(*addc_t_r, *addc_r_t): Use treg_set_expr_not_const01.
|
||||
(*addc_r_r_1, *addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_r_msb,
|
||||
*addc_r_r_msb, *addc_2r_msb): Delete.
|
||||
(*addc_2r_lsb): Rename to *addc_2r_t. Use treg_set_expr. Add operand
|
||||
order variant.
|
||||
(*addc_negreg_t): New insn_and_split.
|
||||
(*subc): Convert to insn_and_split. Use treg_set_expr as 3rd operand.
|
||||
Try to recombine with surrounding insns when splitting.
|
||||
Add operand order variants.
|
||||
(*subc_negt_reg, *subc_negreg_t, *reg_lsb_t, *reg_msb_t): New
|
||||
insn_and_split patterns.
|
||||
(*rotcr): Use arith_reg_or_treg_set_expr. Try to recombine with
|
||||
surrounding insns when splitting.
|
||||
(unnamed rotcr split): Use arith_reg_or_treg_set_expr.
|
||||
(*rotcl): Likewise. Add zero_extract variant.
|
||||
(*ashrsi2_31): New insn_and_split.
|
||||
(*negc): Convert to insn_and_split. Use treg_set_expr.
|
||||
(*zero_extend<mode>si2_disp_mem): Update comment.
|
||||
(movrt_negc, *movrt_negc, nott): Add !sh_in_recog_treg_set_expr split
|
||||
condition.
|
||||
(*mov_t_msb_neg, mov_neg_si_t): Use treg_set_expr. Try to recombine
|
||||
with surrounding insns when splitting.
|
||||
(any_treg_expr_to_reg): New insn_and_split.
|
||||
(*neg_zero_extract_0, *neg_zero_extract_1, *neg_zero_extract_2,
|
||||
*neg_zero_extract_3, *neg_zero_extract_4, *neg_zero_extract_5,
|
||||
*neg_zero_extract_6, *zero_extract_0, *zero_extract_1,
|
||||
*zero_extract_2): New single bit zero extract patterns.
|
||||
(bld_reg, *bld_regqi): Fold into bld<mode>_reg.
|
||||
(*get_thread_pointersi, store_gbr, *mov<mode>_gbr_load,
|
||||
*mov<mode>_gbr_load, *mov<mode>_gbr_load, *mov<mode>_gbr_load,
|
||||
*movdi_gbr_load): Use arith_reg_dest instead of register_operand for
|
||||
set destination.
|
||||
(set_thread_pointersi, load_gbr): Use arith_reg_operand instead of
|
||||
register_operand for set source.
|
||||
|
||||
2015-01-23 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* i386.opt (prefetch_sse): New targetsave.
|
||||
|
|
|
@ -456,17 +456,17 @@
|
|||
|
||||
;; Returns 1 if the operand can be used in an SH2A movu.{b|w} insn.
|
||||
(define_predicate "zero_extend_movu_operand"
|
||||
(and (match_operand 0 "displacement_mem_operand")
|
||||
(match_test "GET_MODE (op) == QImode || GET_MODE (op) == HImode")))
|
||||
(and (ior (match_operand 0 "displacement_mem_operand")
|
||||
(match_operand 0 "simple_mem_operand"))
|
||||
(ior (match_test "GET_MODE (op) == QImode")
|
||||
(match_test "GET_MODE (op) == HImode"))))
|
||||
|
||||
;; Returns 1 if the operand can be used in a zero_extend.
|
||||
(define_predicate "zero_extend_operand"
|
||||
(ior (and (match_test "TARGET_SHMEDIA")
|
||||
(match_operand 0 "general_extend_operand"))
|
||||
(and (match_test "! TARGET_SHMEDIA")
|
||||
(match_operand 0 "arith_reg_operand"))
|
||||
(and (match_test "TARGET_SH2A")
|
||||
(match_operand 0 "zero_extend_movu_operand"))))
|
||||
(match_operand 0 "arith_reg_operand"))))
|
||||
|
||||
;; Returns 1 if OP can be source of a simple move operation. Same as
|
||||
;; general_operand, but a LABEL_REF is valid, PRE_DEC is invalid as
|
||||
|
@ -1152,6 +1152,18 @@
|
|||
(match_test "mode != HImode")
|
||||
(match_test "TARGET_SH4A"))))
|
||||
|
||||
;; A predicate that matches any expression for which there is an
|
||||
;; insn pattern that sets the T bit.
|
||||
(define_predicate "treg_set_expr"
|
||||
(match_test "sh_recog_treg_set_expr (op, mode)"))
|
||||
|
||||
;; Same as treg_set_expr but disallow constants 0 and 1 which can be loaded
|
||||
;; into the T bit.
|
||||
(define_predicate "treg_set_expr_not_const01"
|
||||
(and (match_test "op != const0_rtx")
|
||||
(match_test "op != const1_rtx")
|
||||
(match_operand 0 "treg_set_expr")))
|
||||
|
||||
;; A predicate describing the T bit register in any form.
|
||||
(define_predicate "t_reg_operand"
|
||||
(match_code "reg,subreg,sign_extend,zero_extend")
|
||||
|
@ -1206,6 +1218,10 @@
|
|||
(ior (match_operand 0 "arith_reg_operand")
|
||||
(match_operand 0 "t_reg_operand")))
|
||||
|
||||
(define_predicate "arith_reg_or_treg_set_expr"
|
||||
(ior (match_operand 0 "arith_reg_operand")
|
||||
(match_operand 0 "treg_set_expr")))
|
||||
|
||||
;; A predicate describing the negated value of the T bit register shifted
|
||||
;; left by 31.
|
||||
(define_predicate "negt_reg_shl31_operand"
|
||||
|
|
|
@ -264,6 +264,14 @@ struct sh_extending_set_of_reg : public set_of_reg
|
|||
ext_code = UNKNOWN;
|
||||
}
|
||||
|
||||
/* Returns true if it's possible to use the source reg of the sign
|
||||
or zero extending set directly, bypassing the extension. */
|
||||
bool can_use_as_unextended_reg (void) const;
|
||||
|
||||
/* Returns the reg rtx of the sign or zero extending set source, that can
|
||||
be safely used at the specified insn in SImode. */
|
||||
rtx use_as_unextended_reg (rtx_insn* use_at_insn) const;
|
||||
|
||||
/* Returns the reg rtx of the sign or zero extending result, that can be
|
||||
safely used at the specified insn in SImode. If the set source is an
|
||||
implicitly sign extending mem load, the mem load is converted into an
|
||||
|
@ -281,7 +289,66 @@ extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn,
|
|||
extern void sh_split_tst_subregs (rtx_insn* curr_insn,
|
||||
machine_mode subreg_mode, int subreg_offset,
|
||||
rtx operands[]);
|
||||
|
||||
extern bool sh_is_nott_insn (const rtx_insn* i);
|
||||
extern rtx sh_movt_set_dest (const rtx_insn* i);
|
||||
extern rtx sh_movrt_set_dest (const rtx_insn* i);
|
||||
|
||||
inline bool sh_is_movt_insn (const rtx_insn* i)
|
||||
{
|
||||
return sh_movt_set_dest (i) != NULL;
|
||||
}
|
||||
|
||||
inline bool sh_is_movrt_insn (const rtx_insn* i)
|
||||
{
|
||||
return sh_movrt_set_dest (i) != NULL;
|
||||
}
|
||||
|
||||
extern bool sh_insn_operands_modified_between_p (rtx_insn* operands_insn,
|
||||
const rtx_insn* from,
|
||||
const rtx_insn* to);
|
||||
|
||||
extern bool sh_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno);
|
||||
extern void sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno);
|
||||
|
||||
extern bool sh_in_recog_treg_set_expr (void);
|
||||
extern bool sh_recog_treg_set_expr (rtx op, machine_mode mode);
|
||||
|
||||
/* Result value of sh_split_treg_set_expr. Contains the first insn emitted
|
||||
and the optional trailing nott insn. */
|
||||
class sh_treg_insns
|
||||
{
|
||||
public:
|
||||
sh_treg_insns (void) : m_first_insn (NULL), m_trailing_nott_insn (NULL) { }
|
||||
sh_treg_insns (rtx_insn* first_insn, rtx_insn* nott_insn)
|
||||
: m_first_insn (first_insn),
|
||||
m_trailing_nott_insn (nott_insn)
|
||||
{ }
|
||||
|
||||
bool was_treg_operand (void) const { return m_first_insn == NULL; }
|
||||
bool has_trailing_nott (void) const { return m_trailing_nott_insn != NULL; }
|
||||
rtx_insn* trailing_nott (void) const { return m_trailing_nott_insn; }
|
||||
rtx_insn* first_insn (void) const { return m_first_insn; }
|
||||
|
||||
/* If there is a trailing nott, remove it from the emitted insns and
|
||||
return true. Return false otherwise. */
|
||||
bool
|
||||
remove_trailing_nott (void)
|
||||
{
|
||||
if (!has_trailing_nott ())
|
||||
return false;
|
||||
|
||||
remove_insn (trailing_nott ());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
rtx_insn* m_first_insn;
|
||||
rtx_insn* m_trailing_nott_insn;
|
||||
};
|
||||
|
||||
extern sh_treg_insns sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn);
|
||||
|
||||
#endif /* RTX_CODE */
|
||||
|
||||
extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
|
||||
|
|
|
@ -364,6 +364,8 @@ static bool sequence_insn_p (rtx_insn *);
|
|||
static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
|
||||
static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
|
||||
machine_mode, bool);
|
||||
static bool sh_legitimate_combined_insn (rtx_insn* insn);
|
||||
|
||||
static bool sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2);
|
||||
|
||||
static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
|
||||
|
@ -672,6 +674,9 @@ static const struct attribute_spec sh_attribute_table[] =
|
|||
#undef TARGET_CANONICALIZE_COMPARISON
|
||||
#define TARGET_CANONICALIZE_COMPARISON sh_canonicalize_comparison
|
||||
|
||||
#undef TARGET_LEGITIMATE_COMBINED_INSN
|
||||
#define TARGET_LEGITIMATE_COMBINED_INSN sh_legitimate_combined_insn
|
||||
|
||||
#undef TARGET_FIXED_CONDITION_CODE_REGS
|
||||
#define TARGET_FIXED_CONDITION_CODE_REGS sh_fixed_condition_code_regs
|
||||
|
||||
|
@ -2044,6 +2049,26 @@ sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
|
|||
*code = (int)tmp_code;
|
||||
}
|
||||
|
||||
/* This function implements the legitimate_combined_insn target hook,
|
||||
which the combine pass uses to early reject combined insns, before
|
||||
it tries to recog the insn and determine its cost. */
|
||||
static bool
|
||||
sh_legitimate_combined_insn (rtx_insn* insn)
|
||||
{
|
||||
/* Reject combinations of memory loads and zero extensions, as these
|
||||
interfere with other combine patterns such as zero extracts and bit
|
||||
tests. The SH2A movu.{b|w} insns are formed later in the
|
||||
'sh_optimize_extu_exts' pass after combine/split1. */
|
||||
rtx p = PATTERN (insn);
|
||||
if (GET_CODE (p) == SET
|
||||
&& REG_P (XEXP (p, 0)) && GET_MODE (XEXP (p, 0)) == SImode
|
||||
&& GET_CODE (XEXP (p, 1)) == ZERO_EXTEND
|
||||
&& MEM_P (XEXP (XEXP (p, 1), 0)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2)
|
||||
{
|
||||
|
@ -3330,6 +3355,12 @@ addsubcosts (rtx x)
|
|||
&& CONST_INT_P (XEXP (op1, 1)) && INTVAL (XEXP (op1, 1)) == 31)
|
||||
return 1;
|
||||
}
|
||||
/* Let's assume that adding the result of an insns that stores into
|
||||
the T bit is cheap. */
|
||||
if (treg_set_expr (op1, SImode))
|
||||
return 1;
|
||||
if (treg_set_expr (op0, SImode))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* On SH1-4 we have only max. SImode operations.
|
||||
|
@ -3445,10 +3476,36 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
|||
true);
|
||||
return true;
|
||||
|
||||
case IF_THEN_ELSE:
|
||||
/* This case is required for the if_then_else negc pattern. */
|
||||
if (treg_set_expr (XEXP (x, 0), SImode))
|
||||
{
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
/* Zero extracts of single bits are usually combine patterns for the
|
||||
tst insns. */
|
||||
case ZERO_EXTRACT:
|
||||
if (GET_CODE (XEXP (x, 0)) == XOR
|
||||
&& arith_reg_operand (XEXP (XEXP (x, 0), 0), VOIDmode)
|
||||
&& XEXP (x, 1) == const1_rtx
|
||||
&& CONST_INT_P (XEXP (x, 2))
|
||||
&& CONST_INT_P (XEXP (XEXP (x, 0), 1))
|
||||
/* Check that the xor constaint overlaps with the extracted bit. */
|
||||
&& (INTVAL (XEXP (XEXP (x, 0), 1)) & (1LL << INTVAL (XEXP (x, 2)))))
|
||||
{
|
||||
*total = 1; //COSTS_N_INSNS (1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
/* The cost of a sign or zero extend depends on whether the source is a
|
||||
reg or a mem. In case of a mem take the address into acount. */
|
||||
case SIGN_EXTEND:
|
||||
if (REG_P (XEXP (x, 0)))
|
||||
if (arith_reg_operand (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
|
||||
{
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return true;
|
||||
|
@ -3463,7 +3520,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
|||
return false;
|
||||
|
||||
case ZERO_EXTEND:
|
||||
if (REG_P (XEXP (x, 0)))
|
||||
if (arith_reg_operand (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
|
||||
{
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return true;
|
||||
|
@ -3555,8 +3612,21 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
|||
most likely going to be a TST #imm, R0 instruction.
|
||||
Notice that this does not catch the zero_extract variants from
|
||||
the md file. */
|
||||
if (GET_CODE (XEXP (x, 0)) == AND
|
||||
&& CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 0)
|
||||
if (XEXP (x, 1) == const0_rtx
|
||||
&& (GET_CODE (XEXP (x, 0)) == AND
|
||||
|| (SUBREG_P (XEXP (x, 0))
|
||||
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND)))
|
||||
{
|
||||
*total = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (XEXP (x, 1) == const0_rtx
|
||||
&& GET_CODE (XEXP (x, 0)) == AND
|
||||
&& CONST_INT_P (XEXP (XEXP (x, 0), 1))
|
||||
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
|
||||
&& arith_reg_operand (XEXP (XEXP (XEXP (x, 0), 0), 0), SImode)
|
||||
&& CONST_INT_P (XEXP (XEXP (XEXP (x, 0), 0), 1)))
|
||||
{
|
||||
*total = 1;
|
||||
return true;
|
||||
|
@ -3622,6 +3692,14 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
|||
return true;
|
||||
|
||||
case AND:
|
||||
/* Check for (and (not (reg)) (const_int 1)) which is a tst insn. */
|
||||
if (GET_CODE (XEXP (x, 0)) == NOT && XEXP (x, 1) == const1_rtx)
|
||||
{
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return true;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case XOR:
|
||||
case IOR:
|
||||
*total = COSTS_N_INSNS (and_xor_ior_costs (x, code));
|
||||
|
@ -13751,7 +13829,7 @@ sh_unspec_insn_p (rtx x)
|
|||
|
||||
/* Return true if the register operands of the specified insn are modified
|
||||
between the specified from and to insns (exclusive of those two). */
|
||||
static bool
|
||||
bool
|
||||
sh_insn_operands_modified_between_p (rtx_insn* operands_insn,
|
||||
const rtx_insn* from,
|
||||
const rtx_insn* to)
|
||||
|
@ -13770,6 +13848,57 @@ sh_insn_operands_modified_between_p (rtx_insn* operands_insn,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Given an insn, determine whether it's a 'nott' insn, i.e. an insn that
|
||||
negates the T bit and stores the result in the T bit. */
|
||||
bool
|
||||
sh_is_nott_insn (const rtx_insn* i)
|
||||
{
|
||||
return i != NULL && GET_CODE (PATTERN (i)) == SET
|
||||
&& t_reg_operand (XEXP (PATTERN (i), 0), VOIDmode)
|
||||
&& negt_reg_operand (XEXP (PATTERN (i), 1), VOIDmode);
|
||||
}
|
||||
|
||||
rtx
|
||||
sh_movt_set_dest (const rtx_insn* i)
|
||||
{
|
||||
if (i == NULL)
|
||||
return NULL;
|
||||
|
||||
const_rtx p = PATTERN (i);
|
||||
return GET_CODE (p) == SET
|
||||
&& arith_reg_dest (XEXP (p, 0), SImode)
|
||||
&& t_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
|
||||
}
|
||||
|
||||
/* Given an insn, check whether it's a 'movrt' kind of insn, i.e. an insn
|
||||
that stores the negated T bit in a register, and return the destination
|
||||
register rtx, or null. */
|
||||
rtx
|
||||
sh_movrt_set_dest (const rtx_insn* i)
|
||||
{
|
||||
if (i == NULL)
|
||||
return NULL;
|
||||
|
||||
const_rtx p = PATTERN (i);
|
||||
|
||||
/* The negc movrt replacement is inside a parallel. */
|
||||
if (GET_CODE (p) == PARALLEL)
|
||||
p = XVECEXP (p, 0, 0);
|
||||
|
||||
return GET_CODE (p) == SET
|
||||
&& arith_reg_dest (XEXP (p, 0), SImode)
|
||||
&& negt_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
|
||||
}
|
||||
|
||||
/* Given an insn and a reg number, tell whether the reg dies or is unused
|
||||
after the insn. */
|
||||
bool
|
||||
sh_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno)
|
||||
{
|
||||
return find_regno_note (i, REG_DEAD, regno) != NULL
|
||||
|| find_regno_note (i, REG_UNUSED, regno) != NULL;
|
||||
}
|
||||
|
||||
/* Given an insn and a reg number, remove reg dead or reg unused notes to
|
||||
mark it as being used after the insn. */
|
||||
void
|
||||
|
@ -14006,6 +14135,40 @@ sh_extending_set_of_reg::use_as_extended_reg (rtx_insn* use_at_insn) const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sh_extending_set_of_reg::can_use_as_unextended_reg (void) const
|
||||
{
|
||||
if ((ext_code == SIGN_EXTEND || ext_code == ZERO_EXTEND)
|
||||
&& (from_mode == QImode || from_mode == HImode)
|
||||
&& set_src != NULL)
|
||||
return arith_reg_operand (XEXP (set_src, 0), from_mode);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
rtx
|
||||
sh_extending_set_of_reg::use_as_unextended_reg (rtx_insn* use_at_insn) const
|
||||
{
|
||||
gcc_assert (can_use_as_unextended_reg ());
|
||||
|
||||
rtx r = XEXP (set_src, 0);
|
||||
rtx r0 = simplify_gen_subreg (SImode, r, from_mode, 0);
|
||||
|
||||
if (modified_between_p (r, insn, use_at_insn))
|
||||
{
|
||||
rtx r1 = gen_reg_rtx (SImode);
|
||||
emit_insn_after (gen_move_insn (r1, r0), insn);
|
||||
return r1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_remove_reg_dead_or_unused_notes (insn, SUBREG_P (r)
|
||||
? REGNO (SUBREG_REG (r))
|
||||
: REGNO (r));
|
||||
return r0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Given the current insn, which is assumed to be the *tst<mode>_t_subregs insn,
|
||||
perform the necessary checks on the operands and split it accordingly. */
|
||||
void
|
||||
|
@ -14059,6 +14222,276 @@ sh_split_tst_subregs (rtx_insn* curr_insn, machine_mode subreg_mode,
|
|||
emit_insn (gen_tstsi_t (tmp0, operands[1]));
|
||||
}
|
||||
|
||||
/* A helper class to increment/decrement a counter variable each time a
|
||||
function is entered/left. */
|
||||
class scope_counter
|
||||
{
|
||||
public:
|
||||
scope_counter (int& counter) : m_counter (counter) { ++m_counter; }
|
||||
|
||||
~scope_counter (void)
|
||||
{
|
||||
--m_counter;
|
||||
gcc_assert (m_counter >= 0);
|
||||
}
|
||||
|
||||
int count (void) const { return m_counter; }
|
||||
|
||||
private:
|
||||
int& m_counter;
|
||||
};
|
||||
|
||||
/* Given an rtx x, determine whether the expression can be used to create
|
||||
an insn that calulates x and stores the result in the T bit.
|
||||
This is used by the 'treg_set_expr' predicate to construct insns sequences
|
||||
where T bit results are fed into other insns, such as addc, subc, negc
|
||||
insns.
|
||||
|
||||
FIXME: The patterns that expand 'treg_set_expr' operands tend to
|
||||
distinguish between 'positive' and 'negative' forms. For now this has to
|
||||
be done in the preparation code. We could also introduce
|
||||
'pos_treg_set_expr' and 'neg_treg_set_expr' predicates for that and write
|
||||
two different patterns for the 'postive' and 'negative' forms. However,
|
||||
the total amount of lines of code seems to be about the same and the
|
||||
'{pos|neg}_treg_set_expr' predicates would be more expensive, because the
|
||||
recog function would need to look inside the expression by temporarily
|
||||
splitting it. */
|
||||
static int sh_recog_treg_set_expr_reent_count = 0;
|
||||
|
||||
bool
|
||||
sh_recog_treg_set_expr (rtx op, machine_mode mode)
|
||||
{
|
||||
scope_counter recursion (sh_recog_treg_set_expr_reent_count);
|
||||
|
||||
/* Limit the recursion count to avoid nested expressions which we can't
|
||||
resolve to a single treg set insn. */
|
||||
if (recursion.count () > 1)
|
||||
return false;
|
||||
|
||||
/* Early accept known possible operands before doing recog. */
|
||||
if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode))
|
||||
return true;
|
||||
|
||||
/* Early reject impossible operands before doing recog.
|
||||
There are some (set ((t) (subreg ...))) patterns, but we must be careful
|
||||
not to allow any invalid reg-reg or mem-reg moves, or else other passes
|
||||
such as lower-subreg will bail out. Some insns such as SH4A movua are
|
||||
done with UNSPEC, so must reject those, too, or else it would result
|
||||
in an invalid reg -> treg move. */
|
||||
if (register_operand (op, mode) || memory_operand (op, mode)
|
||||
|| sh_unspec_insn_p (op))
|
||||
return false;
|
||||
|
||||
if (!can_create_pseudo_p ())
|
||||
return false;
|
||||
|
||||
/* We are going to invoke recog in a re-entrant way and thus
|
||||
have to capture its current state and restore it afterwards. */
|
||||
recog_data_d prev_recog_data = recog_data;
|
||||
|
||||
rtx_insn* i = make_insn_raw (gen_rtx_SET (VOIDmode, get_t_reg_rtx (), op));
|
||||
SET_PREV_INSN (i) = NULL;
|
||||
SET_NEXT_INSN (i) = NULL;
|
||||
|
||||
int result = recog (PATTERN (i), i, 0);
|
||||
|
||||
/* It seems there is no insn like that. Create a simple negated
|
||||
version and try again. If we hit a negated form, we'll allow that
|
||||
and append a nott sequence when splitting out the insns. Insns that
|
||||
do the split can then remove the trailing nott if they know how to
|
||||
deal with it. */
|
||||
if (result < 0 && GET_CODE (op) == EQ)
|
||||
{
|
||||
PUT_CODE (op, NE);
|
||||
result = recog (PATTERN (i), i, 0);
|
||||
PUT_CODE (op, EQ);
|
||||
}
|
||||
if (result < 0 && GET_CODE (op) == NE)
|
||||
{
|
||||
PUT_CODE (op, EQ);
|
||||
result = recog (PATTERN (i), i, 0);
|
||||
PUT_CODE (op, NE);
|
||||
}
|
||||
|
||||
recog_data = prev_recog_data;
|
||||
return result >= 0;
|
||||
}
|
||||
|
||||
/* Returns true when recog of a 'treg_set_expr' is currently in progress.
|
||||
This can be used as a condition for insn/split patterns to allow certain
|
||||
T bit setting patters only to be matched as sub expressions of other
|
||||
patterns. */
|
||||
bool
|
||||
sh_in_recog_treg_set_expr (void)
|
||||
{
|
||||
return sh_recog_treg_set_expr_reent_count > 0;
|
||||
}
|
||||
|
||||
/* Given an rtx x, which is assumed to be some expression that has been
|
||||
matched by the 'treg_set_expr' predicate before, split and emit the
|
||||
insns that are necessary to calculate the expression and store the result
|
||||
in the T bit.
|
||||
The splitting is done recursively similar to 'try_split' in emit-rt.c.
|
||||
Unfortunately we can't use 'try_split' here directly, as it tries to invoke
|
||||
'delete_insn' which then causes the DF parts to bail out, because we
|
||||
currently are inside another gen_split* function and would invoke
|
||||
'try_split' in a reentrant way. */
|
||||
static std::pair<rtx_insn*, rtx_insn*>
|
||||
sh_try_split_insn_simple (rtx_insn* i, rtx_insn* curr_insn, int n = 0)
|
||||
{
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "sh_try_split_insn_simple n = %d i = \n", n);
|
||||
print_rtl_single (dump_file, i);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
rtx_insn* seq = safe_as_a<rtx_insn*> (split_insns (PATTERN (i), curr_insn));
|
||||
|
||||
if (seq == NULL)
|
||||
return std::make_pair (i, i);
|
||||
|
||||
/* Avoid infinite splitter loops if any insn of the result matches
|
||||
the original pattern. */
|
||||
for (rtx_insn* s = seq; s != NULL; s = NEXT_INSN (s))
|
||||
if (INSN_P (s) && rtx_equal_p (PATTERN (s), PATTERN (i)))
|
||||
return std::make_pair (i, i);
|
||||
|
||||
unshare_all_rtl_in_chain (seq);
|
||||
|
||||
/* 'seq' is now a replacement for 'i'. Assuming that 'i' is an insn in
|
||||
a linked list, replace the single insn with the new insns. */
|
||||
rtx_insn* seqlast = seq;
|
||||
while (NEXT_INSN (seqlast) != NULL)
|
||||
seqlast = NEXT_INSN (seqlast);
|
||||
|
||||
if (rtx_insn* iprev = PREV_INSN (i))
|
||||
SET_NEXT_INSN (iprev) = seq;
|
||||
if (rtx_insn* inext = NEXT_INSN (i))
|
||||
SET_PREV_INSN (inext) = seqlast;
|
||||
|
||||
SET_PREV_INSN (seq) = PREV_INSN (i);
|
||||
SET_NEXT_INSN (seqlast) = NEXT_INSN (i);
|
||||
|
||||
SET_PREV_INSN (i) = NULL;
|
||||
SET_NEXT_INSN (i) = NULL;
|
||||
|
||||
/* Recursively split all insns. */
|
||||
for (i = seq; ; i = NEXT_INSN (i))
|
||||
{
|
||||
std::pair<rtx_insn*, rtx_insn*> ii =
|
||||
sh_try_split_insn_simple (i, curr_insn, n + 1);
|
||||
if (i == seq)
|
||||
seq = ii.first;
|
||||
if (i == seqlast)
|
||||
{
|
||||
seqlast = ii.second;
|
||||
break;
|
||||
}
|
||||
i = ii.first;
|
||||
}
|
||||
|
||||
return std::make_pair (seq, seqlast);
|
||||
}
|
||||
|
||||
sh_treg_insns
|
||||
sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn)
|
||||
{
|
||||
if (t_reg_operand (x, VOIDmode))
|
||||
return sh_treg_insns ();
|
||||
|
||||
scope_counter in_treg_set_expr (sh_recog_treg_set_expr_reent_count);
|
||||
|
||||
rtx_insn* i = make_insn_raw (gen_rtx_SET (VOIDmode, get_t_reg_rtx (), x));
|
||||
SET_PREV_INSN (i) = NULL;
|
||||
SET_NEXT_INSN (i) = NULL;
|
||||
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "split_treg_set_expr insn:\n");
|
||||
print_rtl (dump_file, i);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
/* We are going to invoke recog/split_insns in a re-entrant way and thus
|
||||
have to capture its current state and restore it afterwards. */
|
||||
recog_data_d prev_recog_data = recog_data;
|
||||
|
||||
int insn_code = recog (PATTERN (i), i, 0);
|
||||
|
||||
/* If the insn was not found, see if we matched the negated form before
|
||||
and append a nott. */
|
||||
bool append_nott = false;
|
||||
|
||||
if (insn_code < 0 && GET_CODE (x) == EQ)
|
||||
{
|
||||
PUT_CODE (x, NE);
|
||||
insn_code = recog (PATTERN (i), i, 0);
|
||||
if (insn_code >= 0)
|
||||
append_nott = true;
|
||||
else
|
||||
PUT_CODE (x, EQ);
|
||||
}
|
||||
if (insn_code < 0 && GET_CODE (x) == NE)
|
||||
{
|
||||
PUT_CODE (x, EQ);
|
||||
insn_code = recog (PATTERN (i), i, 0);
|
||||
if (insn_code >= 0)
|
||||
append_nott = true;
|
||||
else
|
||||
PUT_CODE (x, NE);
|
||||
}
|
||||
|
||||
gcc_assert (insn_code >= 0);
|
||||
|
||||
/* Try to recursively split the insn. Some insns might refuse to split
|
||||
any further while we are in the treg_set_expr splitting phase. They
|
||||
will be emitted as part of the outer insn and then split again. */
|
||||
std::pair<rtx_insn*, rtx_insn*> insnlist =
|
||||
sh_try_split_insn_simple (i, curr_insn);
|
||||
|
||||
/* Restore recog state. */
|
||||
recog_data = prev_recog_data;
|
||||
|
||||
rtx_insn* nott_insn = sh_is_nott_insn (insnlist.second)
|
||||
? insnlist.second
|
||||
: NULL;
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "split_treg_set_expr insnlist:\n");
|
||||
print_rtl (dump_file, insnlist.first);
|
||||
fprintf (dump_file, "\n");
|
||||
|
||||
if (nott_insn != NULL)
|
||||
fprintf (dump_file, "trailing nott insn %d\n", INSN_UID (nott_insn));
|
||||
}
|
||||
|
||||
if (nott_insn != NULL && append_nott)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "removing trailing nott\n");
|
||||
remove_insn (nott_insn);
|
||||
nott_insn = NULL;
|
||||
append_nott = false;
|
||||
}
|
||||
|
||||
emit_insn (insnlist.first);
|
||||
|
||||
if (append_nott)
|
||||
nott_insn = emit_insn (gen_nott (get_t_reg_rtx ()));
|
||||
|
||||
rtx_insn* first_insn = get_insns ();
|
||||
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "resulting insns:\n");
|
||||
print_rtl (dump_file, first_insn);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
return sh_treg_insns (first_insn, nott_insn);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
Mode switching support code.
|
||||
*/
|
||||
|
|
1623
gcc/config/sh/sh.md
1623
gcc/config/sh/sh.md
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,34 @@
|
|||
2015-01-24 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
|
||||
PR target/49263
|
||||
PR target/53987
|
||||
PR target/64345
|
||||
PR target/59533
|
||||
PR target/52933
|
||||
PR target/54236
|
||||
PR target/51244
|
||||
* gcc.target/sh/pr64345-1.c: New.
|
||||
* gcc.target/sh/pr64345-2.c: New.
|
||||
* gcc.target/sh/pr59533-1.c: New.
|
||||
* gcc.target/sh/pr49263.c: Adjust matching of expected insns.
|
||||
* gcc.target/sh/pr52933-2.c: Likewise.
|
||||
* gcc.target/sh/pr54089-1.c: Likewise.
|
||||
* gcc.target/sh/pr54236-1.c: Likewise.
|
||||
* gcc.target/sh/pr51244-20-sh2a.c: Likewise.
|
||||
* gcc.target/sh/pr49263-1.c: Remove xfails.
|
||||
* gcc.target/sh/pr49263-2.c: Likewise.
|
||||
* gcc.target/sh/pr49263-3.c: Likewise.
|
||||
* gcc.target/sh/pr53987-1.c: Likewise.
|
||||
* gcc.target/sh/pr52933-1.c: Adjust matching of expected insns.
|
||||
(test_24, test_25, test_26, test_27, test_28, test_29, test_30): New.
|
||||
* gcc.target/sh/pr51244-12.c: Adjust matching of expected insns.
|
||||
(test05, test06, test07, test08, test09, test10, test11, test12): New.
|
||||
* gcc.target/sh/pr54236-3.c: Adjust matching of expected insns.
|
||||
(test_002, test_003, test_004, test_005, test_006, test_007, test_008,
|
||||
test_009): New.
|
||||
* gcc.target/sh/pr51244-4.c: Adjust matching of expected insns.
|
||||
(test_02): New.
|
||||
|
||||
2015-01-24 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
* gcc.target/i386/funcspec-5.c: Replace avx512 with avx512f.
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "and" } } */
|
||||
/* { dg-final { scan-assembler-not "bclr" { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "extu" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "exts" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-not "bclr" } } */
|
||||
/* { dg-final { scan-assembler-times "extu" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "exts" 1 } } */
|
||||
|
||||
#define make_func(__valtype__, __valget__, __tstval__, __suff__)\
|
||||
int test_imm_##__tstval__##__suff__ (__valtype__ val) \
|
||||
|
|
|
@ -3,13 +3,12 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "and" } } */
|
||||
/* { dg-final { scan-assembler-not "exts" { xfail *-*-* } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-not "exts" } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#127,r0" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#255,r0" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "65407" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "-129" 2 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "extu" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#255,r0" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "65407" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "-129" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "extu" 1 } } */
|
||||
|
||||
int
|
||||
test_00 (unsigned char x)
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
is shifted by a constant amount. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "and|shl|sha|exts" { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-not "and|shl|sha|exts" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst\t#7,r0" 3 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#12,r0" 1 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#24,r0" 6 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#13,r0" 3 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#242,r0" 3 { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#7,r0" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#12,r0" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#24,r0" 6 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#13,r0" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#242,r0" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#252,r0" 1 } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst\t#64,r0" 6 { target { ! sh2a } xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#64,r0" 4 { target { sh2a } xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#6" 2 { target { sh2a } xfail *-*-* } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#64,r0" 6 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#64,r0" 4 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#6" 2 { target { sh2a } } } } */
|
||||
|
||||
int
|
||||
test_00 (unsigned char* x, int y, int z)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "and" } } */
|
||||
/* { dg-final { scan-assembler-not "extu" } } */
|
||||
/* { dg-final { scan-assembler-not "exts" } } */
|
||||
|
||||
#define make_func(__valtype__, __valget__, __tstval__, __suff__)\
|
||||
int test_imm_##__tstval__##__suff__ (__valtype__ val) \
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
|
||||
/* { dg-final { scan-assembler-times "negc" 10 } } */
|
||||
/* { dg-final { scan-assembler-not "movrt|#-1|add|sub" } } */
|
||||
/* { dg-final { scan-assembler-times "negc" 15 } } */
|
||||
/* { dg-final { scan-assembler-times "addc" 3 } } */
|
||||
/* { dg-final { scan-assembler-not "movrt|#-1|add\t|sub\t|movt" } } */
|
||||
|
||||
int
|
||||
test00 (int a, int b, int* x)
|
||||
|
@ -66,3 +67,56 @@ test04_inv (int a)
|
|||
{
|
||||
return ((a & 0x55) != 0) ? 0x80000000 : 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
int
|
||||
test05 (int a, int b)
|
||||
{
|
||||
/* 1x addc */
|
||||
return a != b ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test06 (char a)
|
||||
{
|
||||
return ((a & 0x03) == 0) ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test07 (char a)
|
||||
{
|
||||
return ((a & 0x80) == 0) ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test08 (char a)
|
||||
{
|
||||
return ((a & 1) == 0) ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test09 (int a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x addc */
|
||||
return a < 0 ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test10 (int a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x negc */
|
||||
return a >= 0 ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test11 (int a)
|
||||
{
|
||||
/* 1x cmp/pl, 1x negc */
|
||||
return a > 0 ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
||||
int
|
||||
test12 (int a)
|
||||
{
|
||||
/* 1x cmp/pl, 1x addc */
|
||||
return a <= 0 ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
|
||||
/* { dg-final { scan-assembler-times "tst" 6 } } */
|
||||
/* { dg-final { scan-assembler-times "movt" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "nott" 1 } } */
|
||||
/* { dg-final { scan-assembler-not "movt" } } */
|
||||
/* { dg-final { scan-assembler-times "nott" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/eq" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/hi" 4 } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/gt" 3 } } */
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
/* Check that storing the (negated) T bit as all ones or zeros in a reg
|
||||
uses the subc instruction. On SH2A a sequence with the movrt instruction
|
||||
is also OK instead of subc. */
|
||||
uses the subc instruction. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -mbranch-cost=2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
|
||||
/* { dg-final { scan-assembler-not "movt|tst|negc" } } */
|
||||
/* { dg-final { scan-assembler "subc|movrt|neg|not" } } */
|
||||
/* { dg-final { scan-assembler-not "movt|tst|negc|movrt" } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "not\t" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "shll" 1 } } */
|
||||
/* { dg-final { scan-assembler-not "cmp/gt" } } */
|
||||
|
||||
int test_00 (int x, int y)
|
||||
int
|
||||
test_00 (int x, int y)
|
||||
{
|
||||
/* 1x subc, 1x not */
|
||||
return x != y ? -1 : 0;
|
||||
}
|
||||
|
||||
int test_01 (int x, int y)
|
||||
int
|
||||
test_01 (int x, int y)
|
||||
{
|
||||
/* 1x subc */
|
||||
return x == y ? -1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_02 (int x)
|
||||
{
|
||||
/* 1x shll, 1x subc */
|
||||
return 0 <= x ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,13 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
|
||||
/* { dg-final { scan-assembler-times "div0s" 25 } } */
|
||||
/* { dg-final { scan-assembler-times "div0s" 32 } } */
|
||||
/* { dg-final { scan-assembler-not "tst" } } */
|
||||
/* { dg-final { scan-assembler-not "not\t" } } */
|
||||
/* { dg-final { scan-assembler-not "nott" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } } */
|
||||
|
||||
typedef unsigned char bool;
|
||||
|
||||
|
@ -166,3 +171,45 @@ test_23 (int a, int b, int c, int d)
|
|||
/* Should emit 2x div0s. */
|
||||
return ((a < 0) == (b < 0)) | ((c < 0) == (d < 0));
|
||||
}
|
||||
|
||||
bool
|
||||
test_24 (int a, int b)
|
||||
{
|
||||
return a >= 0 != b >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
test_25 (int a, int b)
|
||||
{
|
||||
return !(a < 0 != b < 0);
|
||||
}
|
||||
|
||||
int
|
||||
test_26 (int a, int b, int c, int d)
|
||||
{
|
||||
return a >= 0 != b >= 0 ? c : d;
|
||||
}
|
||||
|
||||
int
|
||||
test_27 (int a, int b)
|
||||
{
|
||||
return a >= 0 == b >= 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_28 (int a, int b, int c, int d)
|
||||
{
|
||||
return a >= 0 == b >= 0 ? c : d;
|
||||
}
|
||||
|
||||
int
|
||||
test_29 (int a, int b)
|
||||
{
|
||||
return ((a >> 31) ^ (b >= 0)) & 1;
|
||||
}
|
||||
|
||||
int
|
||||
test_30 (int a, int b)
|
||||
{
|
||||
return ((a >> 31) ^ (b >> 31)) & 1;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -mpretend-cmove" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
|
||||
/* { dg-final { scan-assembler-times "div0s" 25 } } */
|
||||
/* { dg-final { scan-assembler-times "div0s" 32 } } */
|
||||
/* { dg-final { scan-assembler-not "tst" } } */
|
||||
/* { dg-final { scan-assembler-not "not\t" } } */
|
||||
/* { dg-final { scan-assembler-not "nott" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } } */
|
||||
|
||||
#include "pr52933-1.c"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/* { dg-final { scan-assembler-not "exts.b" } } */
|
||||
/* { dg-final { scan-assembler-not "exts.w" } } */
|
||||
/* { dg-final { scan-assembler-not "movu" } } */
|
||||
/* { dg-final { scan-assembler-not "tst\t#255" { xfail *-*-*} } } */
|
||||
/* { dg-final { scan-assembler-not "tst\t#255" } } */
|
||||
|
||||
int
|
||||
test_00 (unsigned char* x, char* xx, int y, int z)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
|
||||
/* { dg-final { scan-assembler-times "rotcr" 24 } } */
|
||||
/* { dg-final { scan-assembler-times "shll\t" 1 } } */
|
||||
/* { dg-final { scan-assembler-not "and\t#1" } } */
|
||||
/* { dg-final { scan-assembler-not "cmp/pl" } } */
|
||||
|
||||
typedef char bool;
|
||||
|
||||
|
|
|
@ -7,8 +7,12 @@
|
|||
/* { dg-final { scan-assembler-times "addc" 4 } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "sett" 5 } } */
|
||||
/* { dg-final { scan-assembler-times "negc" 1 } } */
|
||||
/* { dg-final { scan-assembler-not "movt" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "negc" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-not "movt" { target { ! sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "bld" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "movt" 1 { target { sh2a } } } } */
|
||||
|
||||
int
|
||||
test_00 (int a, int b, int c, int d)
|
||||
|
@ -64,7 +68,8 @@ test_07 (int *vec)
|
|||
{
|
||||
/* Must not see a 'sett' or 'addc' here.
|
||||
This is a case where combine tries to produce
|
||||
'a + (0 - b) + 1' out of 'a - b + 1'. */
|
||||
'a + (0 - b) + 1' out of 'a - b + 1'.
|
||||
On non-SH2A there is a 'tst + negc', on SH2A a 'bld + movt'. */
|
||||
int z = vec[0];
|
||||
int vi = vec[1];
|
||||
int zi = vec[2];
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
If everything works as expected we won't see any movt instructions in
|
||||
these cases. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1" } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
|
||||
/* { dg-final { scan-assembler-times "addc" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 1 } } */
|
||||
/* { dg-final { scan-assembler-not "movt" } } */
|
||||
/* { dg-final { scan-assembler-times "addc" 4 } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 5 } } */
|
||||
/* { dg-final { scan-assembler-times "movt" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "sub\t" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "neg\t" 2 } } */
|
||||
|
||||
int
|
||||
test_000 (int* x, unsigned int c)
|
||||
|
@ -29,3 +31,66 @@ test_001 (int* x, unsigned int c)
|
|||
s -= ! (x[i] & 0x3000);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
test_002 (int a, int b, int c)
|
||||
{
|
||||
/* 1x tst, 1x subc */
|
||||
return ((a & b) != 0) - c;
|
||||
}
|
||||
|
||||
int
|
||||
test_003 (int a, int b, int c)
|
||||
{
|
||||
/* 1x tst, 1x movt, 1x sub */
|
||||
return ((a & b) == 0) - c;
|
||||
}
|
||||
|
||||
int
|
||||
test_004 (int a, int b, int c)
|
||||
{
|
||||
/* 1x tst, 1x addc */
|
||||
return c - ((a & b) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
test_005 (int a, int b, int c)
|
||||
{
|
||||
/* 1x shll, 1x subc */
|
||||
int x = a < 0;
|
||||
return c - (b + x);
|
||||
}
|
||||
|
||||
int
|
||||
test_006 (int a, int b, int c)
|
||||
{
|
||||
/* 1x neg, 1x cmp/pl, 1x addc */
|
||||
int x = a > 0;
|
||||
int y = b + x;
|
||||
return y - c;
|
||||
}
|
||||
|
||||
int
|
||||
test_007 (int a, int b, int c)
|
||||
{
|
||||
/* 1x add #-1, 1x cmp/eq, 1x addc */
|
||||
int x = a != 1;
|
||||
int y = b - x;
|
||||
return c + y;
|
||||
}
|
||||
|
||||
int
|
||||
test_008 (int a, int b, int c)
|
||||
{
|
||||
/* 1x neg, 1x cmp/gt, 1x subc */
|
||||
int x = a > 1;
|
||||
int y = b - x;
|
||||
return c + y;
|
||||
}
|
||||
|
||||
int
|
||||
test_009 (int a, int b, int c, int d)
|
||||
{
|
||||
/* 1x div0s, 1x subc */
|
||||
return c - d - (a < 0 != b < 0);
|
||||
}
|
||||
|
|
185
gcc/testsuite/gcc.target/sh/pr59533-1.c
Normal file
185
gcc/testsuite/gcc.target/sh/pr59533-1.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/* Check that the cmp/pz instruction is generated as expected. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "shll" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "movt" 5 } } */
|
||||
/* { dg-final { scan-assembler-times "rotcl" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "and" 3 } } */
|
||||
/* { dg-final { scan-assembler-times "extu.b" 5 } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "cmp/pz" 22 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "addc" 3 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "cmp/pz" 20 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "addc" 5 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } } */
|
||||
|
||||
int
|
||||
test_00 (unsigned char* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x movt */
|
||||
return a[0] < 128;
|
||||
}
|
||||
|
||||
int
|
||||
test_01 (unsigned char* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x addc */
|
||||
return a[0] + (a[0] < 128);
|
||||
}
|
||||
|
||||
int
|
||||
test_02 (unsigned char* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x addc */
|
||||
return a[0] + ((a[0] & 0x80) == 0);
|
||||
}
|
||||
|
||||
int
|
||||
test_03 (unsigned char* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc
|
||||
SH2A: 1x bld, 1x addc */
|
||||
return a[0] + (a[0] > 127);
|
||||
}
|
||||
|
||||
int
|
||||
test_04 (unsigned char* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc
|
||||
SH2A: 1x bld, 1x addc */
|
||||
return a[0] + ((a[0] & 0x80) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
test_05 (unsigned char* a, int b, int c)
|
||||
{
|
||||
/* 1x cmp/pz */
|
||||
if (a[0] < 128)
|
||||
return c;
|
||||
else
|
||||
return b + 50;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_06 (unsigned int a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x movt */
|
||||
return ~a >> 31;
|
||||
}
|
||||
|
||||
int
|
||||
test_07 (unsigned short* a)
|
||||
{
|
||||
/* 1x cmp/pz */
|
||||
return a[0] < 32768;
|
||||
}
|
||||
|
||||
int
|
||||
test_08 (unsigned short* a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x addc */
|
||||
return a[0] + (a[0] < 32768);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_09 (unsigned int a)
|
||||
{
|
||||
/* 1x cmp/pz, 1x movt */
|
||||
return (a >> 31) ^ 1;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_10 (unsigned int a, unsigned int b)
|
||||
{
|
||||
/* 1x cmp/pz, 1x rotcl */
|
||||
return (a << 1) | ((a >> 31) ^ 1);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_11 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc */
|
||||
return ~(x >> 31);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_12 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc */
|
||||
return 0xFFFFFFFF - (x >> 31);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_13 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc, 1x add */
|
||||
return ~(x >> 31) << 1;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_14 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc */
|
||||
return ~(x >> 31) >> 1;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_15 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc */
|
||||
return ~(x >> 31) >> 31;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_16 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc, 1x and */
|
||||
return ~(x >> 31) & 0xFF000000;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_17 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc, 1x and */
|
||||
return ~(x >> 31) & 0x00FF0000;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_18 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc, 1x and */
|
||||
return ~(x >> 31) & 0x0000FF00;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_19 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc, 1x extu.b */
|
||||
return ~(x >> 31) & 0x000000FF;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_20 (int x, unsigned int y, unsigned int z)
|
||||
{
|
||||
/* 1x shll */
|
||||
return ~(x >> 31) ? y : z;
|
||||
}
|
||||
|
||||
int
|
||||
test_21 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x subc */
|
||||
return x >= 0 ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_22 (int x)
|
||||
{
|
||||
/* 1x cmp/pz, 1x movt */
|
||||
return (x >> 31) + 1;
|
||||
}
|
97
gcc/testsuite/gcc.target/sh/pr64345-1.c
Normal file
97
gcc/testsuite/gcc.target/sh/pr64345-1.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* Verify that single bit zero extractions emit the expected
|
||||
insns sequences. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "exts|extu|sha|shld|subc|xor" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst" 716 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/pz" 6 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "shll\t" 6 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "shlr\t" 8 { target { ! sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst" 442 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld" 276 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/pz" 6 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "shll\t" 4 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "shlr\t" 8 { target { sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "and\t#1" 32 } } */
|
||||
|
||||
#define make_func(type,shift)\
|
||||
int test_##type##_##_shift_##shift##_0 (type x)\
|
||||
{\
|
||||
return ((x >> shift) ^ 1) & 1 ? -40 : -10;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_1 (type x)\
|
||||
{\
|
||||
return ((x >> shift) ^ 0) & 1 ? -40 : -10;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_2 (type x)\
|
||||
{\
|
||||
return ((x >> shift) ^ 1) & 1;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_3 (type x)\
|
||||
{\
|
||||
return ((x >> shift) ^ 0) & 1;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_4 (type x)\
|
||||
{\
|
||||
return (x & (1 << shift)) == 0;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_5 (type x)\
|
||||
{\
|
||||
return (x & (1 << shift)) != 0;\
|
||||
}\
|
||||
\
|
||||
int test_##type##_##_shift_##shift##_6 (type* x)\
|
||||
{\
|
||||
return ((*x >> shift) ^ 1) & 1 ? -40 : -10;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_7 (type* x)\
|
||||
{\
|
||||
return ((*x >> shift) ^ 0) & 1 ? -40 : -10;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_8 (type* x)\
|
||||
{\
|
||||
return ((*x >> shift) ^ 1) & 1;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_9 (type* x)\
|
||||
{\
|
||||
return ((*x >> shift) ^ 0) & 1;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_10 (type* x)\
|
||||
{\
|
||||
return (*x & (1 << shift)) == 0;\
|
||||
}\
|
||||
int test_##type##_##_shift_##shift##_11 (type* x)\
|
||||
{\
|
||||
return (*x & (1 << shift)) != 0;\
|
||||
}
|
||||
|
||||
#define make_funcs(type)\
|
||||
make_func (type, 0)\
|
||||
make_func (type, 1)\
|
||||
make_func (type, 2)\
|
||||
make_func (type, 3)\
|
||||
make_func (type, 4)\
|
||||
make_func (type, 5)\
|
||||
make_func (type, 6)\
|
||||
make_func (type, 7)
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
make_funcs (int8_t)
|
||||
make_funcs (uint8_t)
|
||||
make_funcs (int16_t)
|
||||
make_funcs (uint16_t)
|
||||
make_funcs (int32_t)
|
||||
make_funcs (uint32_t)
|
||||
make_funcs (int64_t)
|
||||
make_funcs (uint64_t)
|
116
gcc/testsuite/gcc.target/sh/pr64345-2.c
Normal file
116
gcc/testsuite/gcc.target/sh/pr64345-2.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* Verify that the TST insn is used to extract a zero extended
|
||||
single bit into the T bit (for a following conditional branch) and into
|
||||
a GP register. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "exts|extu|sha|shld|subc|xor" } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst" 61 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#1," 1 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#2" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#4" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#8" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#16" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#32" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#64" 2 { target { ! sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#128" 2 { target { ! sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "tst" 54 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#1," 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#2" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#4" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#8" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#16" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#32" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#64" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "tst\t#128" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#1," 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#2" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#3" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#4" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#5" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#6" 1 { target { sh2a } } } } */
|
||||
/* { dg-final { scan-assembler-times "bld\t#7" 1 { target { sh2a } } } } */
|
||||
|
||||
/* { dg-final { scan-assembler-times "and\t#1" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/pz" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "shll" 1 } } */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int b31 : 1;
|
||||
unsigned int b30 : 1;
|
||||
unsigned int b29 : 1;
|
||||
unsigned int b28 : 1;
|
||||
unsigned int b27 : 1;
|
||||
unsigned int b26 : 1;
|
||||
unsigned int b25 : 1;
|
||||
unsigned int b24 : 1;
|
||||
unsigned int b23 : 1;
|
||||
unsigned int b22 : 1;
|
||||
unsigned int b21 : 1;
|
||||
unsigned int b20 : 1;
|
||||
unsigned int b19 : 1;
|
||||
unsigned int b18 : 1;
|
||||
unsigned int b17 : 1;
|
||||
unsigned int b16 : 1;
|
||||
unsigned int b15 : 1;
|
||||
unsigned int b14 : 1;
|
||||
unsigned int b13 : 1;
|
||||
unsigned int b12 : 1;
|
||||
unsigned int b11 : 1;
|
||||
unsigned int b10 : 1;
|
||||
unsigned int b9 : 1;
|
||||
unsigned int b8 : 1;
|
||||
unsigned int b7 : 1;
|
||||
unsigned int b6 : 1;
|
||||
unsigned int b5 : 1;
|
||||
unsigned int b4 : 1;
|
||||
unsigned int b3 : 1;
|
||||
unsigned int b2 : 1;
|
||||
unsigned int b1 : 1;
|
||||
unsigned int b0 : 1;
|
||||
} S;
|
||||
|
||||
#define make_funcs(bitpos)\
|
||||
unsigned int test_b##bitpos##_0 (S s)\
|
||||
{\
|
||||
return s.b##bitpos;\
|
||||
}\
|
||||
unsigned int test_b##bitpos##_1 (S s)\
|
||||
{\
|
||||
return !s.b##bitpos;\
|
||||
}\
|
||||
|
||||
make_funcs (0)
|
||||
make_funcs (1)
|
||||
make_funcs (2)
|
||||
make_funcs (3)
|
||||
make_funcs (4)
|
||||
make_funcs (5)
|
||||
make_funcs (6)
|
||||
make_funcs (7)
|
||||
make_funcs (8)
|
||||
make_funcs (9)
|
||||
make_funcs (10)
|
||||
make_funcs (11)
|
||||
make_funcs (12)
|
||||
make_funcs (13)
|
||||
make_funcs (14)
|
||||
make_funcs (15)
|
||||
make_funcs (16)
|
||||
make_funcs (17)
|
||||
make_funcs (18)
|
||||
make_funcs (19)
|
||||
make_funcs (20)
|
||||
make_funcs (21)
|
||||
make_funcs (22)
|
||||
make_funcs (23)
|
||||
make_funcs (24)
|
||||
make_funcs (25)
|
||||
make_funcs (26)
|
||||
make_funcs (27)
|
||||
make_funcs (28)
|
||||
make_funcs (29)
|
||||
make_funcs (30)
|
||||
make_funcs (31)
|
Loading…
Add table
Reference in a new issue