summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>2012-12-19 12:39:17 +0000
committerkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>2012-12-19 12:39:17 +0000
commitd5065e6e5546d31ca14bdf7105d94ca845b2a885 (patch)
treeb7f4e93614d364fb2bd6d9376c85d35b25544854
parent598006de8ec8b8edd22ce29c3def8d871eb52fc8 (diff)
downloadgcc-d5065e6e5546d31ca14bdf7105d94ca845b2a885.tar.gz
2012-12-19 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* target.def: Define canonicalize_comparison hook. * targhooks.h (default_canonicalize_comparison): New prototype. * targhooks.c (default_canonicalize_comparison): New function. * doc/tm.texi: Add documentation for the new target hook. * doc/tm.texi.in: Likewise. * combine.c (try_combine): Adjust to use the target hook. * config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro definition. * config/alpha/alpha.c (alpha_canonicalize_comparison): New function. (TARGET_CANONICALIZE_COMPARISON): New macro definition. * config/arm/arm-protos.h (arm_canonicalize_comparison): Remove prototype. * config/arm/arm.c (arm_canonicalize_comparison): Add new parameter. (TARGET_CANONICALIZE_COMPARISON): New macro definition. * config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro definition. * config/s390/s390-protos.h (s390_canonicalize_comparison): Remove prototype. * config/s390/s390.c (s390_canonicalize_comparison): Add new parameter. (TARGET_CANONICALIZE_COMPARISON): New macro definition. * config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro definition. * config/sh/sh-protos.h (sh_canonicalize_comparison): Remove prototype. * config/sh/sh.c (sh_canonicalize_comparison): Add new prototype. New function overloading the old one. (TARGET_CANONICALIZE_COMPARISON): New macro definition. * config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro definition. * config/spu/spu.c (spu_canonicalize_comparison): New function. (TARGET_CANONICALIZE_COMPARISON): New macro definition. * config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro definition. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@194608 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog39
-rw-r--r--gcc/combine.c19
-rw-r--r--gcc/config/alpha/alpha.c27
-rw-r--r--gcc/config/alpha/alpha.h20
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c68
-rw-r--r--gcc/config/arm/arm.h3
-rw-r--r--gcc/config/s390/s390-protos.h1
-rw-r--r--gcc/config/s390/s390.c13
-rw-r--r--gcc/config/s390/s390.h4
-rw-r--r--gcc/config/sh/sh-protos.h2
-rw-r--r--gcc/config/sh/sh.c34
-rw-r--r--gcc/config/sh/sh.h4
-rw-r--r--gcc/config/spu/spu.c17
-rw-r--r--gcc/config/spu/spu.h12
-rw-r--r--gcc/doc/tm.texi20
-rw-r--r--gcc/doc/tm.texi.in20
-rw-r--r--gcc/target.def8
-rw-r--r--gcc/targhooks.h2
19 files changed, 207 insertions, 107 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 34b5836fd56..fe52e01a93c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,42 @@
+2012-12-19 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+
+ * target.def: Define canonicalize_comparison hook.
+ * targhooks.h (default_canonicalize_comparison): New prototype.
+ * targhooks.c (default_canonicalize_comparison): New function.
+ * doc/tm.texi: Add documentation for the new target hook.
+ * doc/tm.texi.in: Likewise.
+ * combine.c (try_combine): Adjust to use the target hook.
+ * config/alpha/alpha.h (CANONICALIZE_COMPARISON): Remove macro
+ definition.
+ * config/alpha/alpha.c (alpha_canonicalize_comparison): New
+ function.
+ (TARGET_CANONICALIZE_COMPARISON): New macro definition.
+ * config/arm/arm-protos.h (arm_canonicalize_comparison): Remove
+ prototype.
+ * config/arm/arm.c (arm_canonicalize_comparison): Add new
+ parameter.
+ (TARGET_CANONICALIZE_COMPARISON): New macro definition.
+ * config/arm/arm.h (CANONICALIZE_COMPARISON): Remove macro
+ definition.
+ * config/s390/s390-protos.h (s390_canonicalize_comparison): Remove
+ prototype.
+ * config/s390/s390.c (s390_canonicalize_comparison): Add new
+ parameter.
+ (TARGET_CANONICALIZE_COMPARISON): New macro definition.
+ * config/s390/s390.h (CANONICALIZE_COMPARISON): Remove macro
+ definition.
+ * config/sh/sh-protos.h (sh_canonicalize_comparison): Remove
+ prototype.
+ * config/sh/sh.c (sh_canonicalize_comparison): Add new prototype. New
+ function overloading the old one.
+ (TARGET_CANONICALIZE_COMPARISON): New macro definition.
+ * config/sh/sh.h (CANONICALIZE_COMPARISON): Remove macro
+ definition.
+ * config/spu/spu.c (spu_canonicalize_comparison): New function.
+ (TARGET_CANONICALIZE_COMPARISON): New macro definition.
+ * config/spu/spu.h (CANONICALIZE_COMPARISON): Remove macro
+ definition.
+
2012-12-19 Jakub Jelinek <jakub@redhat.com>
PR debug/55730
diff --git a/gcc/combine.c b/gcc/combine.c
index abd67e8ab9c..001025cc36f 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -494,6 +494,17 @@ static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
+/* Convenience wrapper for the canonicalize_comparison target hook.
+ Target hooks cannot use enum rtx_code. */
+static inline void
+target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ int code_int = (int)*code;
+ targetm.canonicalize_comparison (&code_int, op0, op1, op0_preserve_value);
+ *code = (enum rtx_code)code_int;
+}
+
/* Try to split PATTERN found in INSN. This returns NULL_RTX if
PATTERN can not be split. Otherwise, it returns an insn sequence.
This is a wrapper around split_insns which ensures that the
@@ -2944,9 +2955,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
compare_code = simplify_compare_const (compare_code,
op0, &op1);
-#ifdef CANONICALIZE_COMPARISON
- CANONICALIZE_COMPARISON (compare_code, op0, op1);
-#endif
+ target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
}
/* Do the rest only if op1 is const0_rtx, which may be the
@@ -11959,11 +11968,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
}
}
-#ifdef CANONICALIZE_COMPARISON
/* If this machine only supports a subset of valid comparisons, see if we
can convert an unsupported one into a supported one. */
- CANONICALIZE_COMPARISON (code, op0, op1);
-#endif
+ target_canonicalize_comparison (&code, &op0, &op1, 0);
*pop0 = op0;
*pop1 = op1;
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 84112182426..fa2f7335881 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -9686,6 +9686,30 @@ alpha_conditional_register_usage (void)
for (i = 32; i < 63; i++)
fixed_regs[i] = call_used_regs[i] = 1;
}
+
+/* Canonicalize a comparison from one we don't have to one we do have. */
+
+static void
+alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ if (!op0_preserve_value
+ && (*code == GE || *code == GT || *code == GEU || *code == GTU)
+ && (REG_P (*op1) || *op1 == const0_rtx))
+ {
+ rtx tem = *op0;
+ *op0 = *op1;
+ *op1 = tem;
+ *code = (int)swap_condition ((enum rtx_code)*code);
+ }
+
+ if ((*code == LT || *code == LTU)
+ && CONST_INT_P (*op1) && INTVAL (*op1) == 256)
+ {
+ *code = *code == LT ? LE : LEU;
+ *op1 = GEN_INT (255);
+ }
+}
/* Initialize the GCC target structure. */
#if TARGET_ABI_OPEN_VMS
@@ -9853,6 +9877,9 @@ alpha_conditional_register_usage (void)
#undef TARGET_CONDITIONAL_REGISTER_USAGE
#define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index bc14d84055b..a70c7f89f47 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -922,26 +922,6 @@ do { \
#define FLOAT_STORE_FLAG_VALUE(MODE) \
REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
-/* Canonicalize a comparison from one we don't have to one we do have. */
-
-#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
- do { \
- if (((CODE) == GE || (CODE) == GT || (CODE) == GEU || (CODE) == GTU) \
- && (REG_P (OP1) || (OP1) == const0_rtx)) \
- { \
- rtx tem = (OP0); \
- (OP0) = (OP1); \
- (OP1) = tem; \
- (CODE) = swap_condition (CODE); \
- } \
- if (((CODE) == LT || (CODE) == LTU) \
- && CONST_INT_P (OP1) && INTVAL (OP1) == 256) \
- { \
- (CODE) = (CODE) == LT ? LE : LEU; \
- (OP1) = GEN_INT (255); \
- } \
- } while (0)
-
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index d942c5b07a1..4c61e35ea28 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -53,7 +53,6 @@ extern int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
HOST_WIDE_INT, rtx, rtx, int);
-extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
extern int legitimate_pic_operand_p (rtx);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
extern rtx legitimize_tls_address (rtx, rtx);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 15f9c9bf303..be4428b9206 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -269,7 +269,8 @@ static int arm_cortex_a5_branch_cost (bool, bool);
static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
const unsigned char *sel);
-
+static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value);
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -626,6 +627,10 @@ static const struct attribute_spec arm_attribute_table[] =
#define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
arm_vectorize_vec_perm_const_ok
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON \
+ arm_canonicalize_comparison
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Obstack for minipool constant handling. */
@@ -3543,8 +3548,9 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
This can be done for a few constant compares, where we can make the
immediate value easier to load. */
-enum rtx_code
-arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
+static void
+arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
{
enum machine_mode mode;
unsigned HOST_WIDE_INT i, maxval;
@@ -3563,15 +3569,15 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
{
rtx tem;
- if (code == GT || code == LE
- || (!TARGET_ARM && (code == GTU || code == LEU)))
+ if (*code == GT || *code == LE
+ || (!TARGET_ARM && (*code == GTU || *code == LEU)))
{
/* Missing comparison. First try to use an available
comparison. */
if (CONST_INT_P (*op1))
{
i = INTVAL (*op1);
- switch (code)
+ switch (*code)
{
case GT:
case LE:
@@ -3579,7 +3585,8 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& arm_const_double_by_immediates (GEN_INT (i + 1)))
{
*op1 = GEN_INT (i + 1);
- return code == GT ? GE : LT;
+ *code = *code == GT ? GE : LT;
+ return;
}
break;
case GTU:
@@ -3588,7 +3595,8 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& arm_const_double_by_immediates (GEN_INT (i + 1)))
{
*op1 = GEN_INT (i + 1);
- return code == GTU ? GEU : LTU;
+ *code = *code == GTU ? GEU : LTU;
+ return;
}
break;
default:
@@ -3597,19 +3605,22 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
}
/* If that did not work, reverse the condition. */
- tem = *op0;
- *op0 = *op1;
- *op1 = tem;
- return swap_condition (code);
+ if (!op0_preserve_value)
+ {
+ tem = *op0;
+ *op0 = *op1;
+ *op1 = tem;
+ *code = (int)swap_condition ((enum rtx_code)*code);
+ }
}
-
- return code;
+ return;
}
/* If *op0 is (zero_extend:SI (subreg:QI (reg:SI) 0)) and comparing
with const0_rtx, change it to (and:SI (reg:SI) (const_int 255)),
to facilitate possible combining with a cmp into 'ands'. */
- if (mode == SImode
+ if (!op0_preserve_value
+ && mode == SImode
&& GET_CODE (*op0) == ZERO_EXTEND
&& GET_CODE (XEXP (*op0, 0)) == SUBREG
&& GET_MODE (XEXP (*op0, 0)) == QImode
@@ -3624,15 +3635,15 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
if (!CONST_INT_P (*op1)
|| const_ok_for_arm (INTVAL (*op1))
|| const_ok_for_arm (- INTVAL (*op1)))
- return code;
+ return;
i = INTVAL (*op1);
- switch (code)
+ switch (*code)
{
case EQ:
case NE:
- return code;
+ return;
case GT:
case LE:
@@ -3640,7 +3651,8 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
{
*op1 = GEN_INT (i + 1);
- return code == GT ? GE : LT;
+ *code = *code == GT ? GE : LT;
+ return;
}
break;
@@ -3650,7 +3662,8 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
{
*op1 = GEN_INT (i - 1);
- return code == GE ? GT : LE;
+ *code = *code == GE ? GT : LE;
+ return;
}
break;
@@ -3660,7 +3673,8 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
{
*op1 = GEN_INT (i + 1);
- return code == GTU ? GEU : LTU;
+ *code = *code == GTU ? GEU : LTU;
+ return;
}
break;
@@ -3670,15 +3684,14 @@ arm_canonicalize_comparison (enum rtx_code code, rtx *op0, rtx *op1)
&& (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
{
*op1 = GEN_INT (i - 1);
- return code == GEU ? GTU : LEU;
+ *code = *code == GEU ? GTU : LEU;
+ return;
}
break;
default:
gcc_unreachable ();
}
-
- return code;
}
@@ -26981,7 +26994,7 @@ bool
arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
{
enum rtx_code code = GET_CODE (*comparison);
- enum rtx_code canonical_code;
+ int code_int;
enum machine_mode mode = (GET_MODE (*op1) == VOIDmode)
? GET_MODE (*op2) : GET_MODE (*op1);
@@ -26990,8 +27003,9 @@ arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
if (code == UNEQ || code == LTGT)
return false;
- canonical_code = arm_canonicalize_comparison (code, op1, op2);
- PUT_CODE (*comparison, canonical_code);
+ code_int = (int)code;
+ arm_canonicalize_comparison (&code_int, op1, op2, 0);
+ PUT_CODE (*comparison, (enum rtx_code)code_int);
switch (mode)
{
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index d0f351d861e..2fa945c0c04 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -2078,9 +2078,6 @@ extern int making_const_table;
? reverse_condition_maybe_unordered (code) \
: reverse_condition (code))
-#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
- (CODE) = arm_canonicalize_comparison (CODE, &(OP0), &(OP1))
-
/* The arm5 clz instruction returns 32. */
#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 79673d6d835..9b87914e471 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -58,7 +58,6 @@ extern int tls_symbolic_operand (rtx);
extern bool s390_match_ccmode (rtx, enum machine_mode);
extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
-extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
extern void s390_emit_jump (rtx, rtx);
extern bool symbolic_reference_mentioned_p (rtx);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 6517bce15e0..441d9c1fe5c 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -745,9 +745,13 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
that we can implement more efficiently. */
-void
-s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
+static void
+s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
{
+ if (op0_preserve_value)
+ return;
+
/* Convert ZERO_EXTRACT back to AND to enable TM patterns. */
if ((*code == EQ || *code == NE)
&& *op1 == const0_rtx
@@ -894,7 +898,7 @@ s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
if (MEM_P (*op0) && REG_P (*op1))
{
rtx tem = *op0; *op0 = *op1; *op1 = tem;
- *code = swap_condition (*code);
+ *code = (int)swap_condition ((enum rtx_code)*code);
}
}
@@ -11071,6 +11075,9 @@ s390_loop_unroll_adjust (unsigned nunroll, struct loop *loop)
#undef TARGET_UNWIND_WORD_MODE
#define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON s390_canonicalize_comparison
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 30408f4ac28..286046abdff 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -720,10 +720,6 @@ do { \
return the mode to be used for the comparison. */
#define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
-/* Canonicalize a comparison from one we don't have to one we do have. */
-#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
- s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
-
/* Relative costs of operations. */
/* A C expression for the cost of a branch instruction. A value of 1
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index d4e97db8902..793aadace95 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -159,8 +159,6 @@ extern bool sh_expand_t_scc (rtx *);
extern rtx sh_gen_truncate (enum machine_mode, rtx, int);
extern bool sh_vector_mode_supported_p (enum machine_mode);
extern bool sh_cfun_trap_exit_p (void);
-extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
- enum machine_mode mode = VOIDmode);
extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem);
extern int sh_eval_treg_value (rtx op);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index cf0abb474be..4a42d7eeb5c 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -314,6 +314,9 @@ static int max_mov_insn_displacement (enum machine_mode, bool);
static int mov_insn_alignment_mask (enum machine_mode, bool);
static HOST_WIDE_INT disp_addr_displacement (rtx);
static bool sequence_insn_p (rtx);
+static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool);
+static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&,
+ enum machine_mode, bool);
static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
@@ -586,6 +589,9 @@ static const struct attribute_spec sh_attribute_table[] =
#undef TARGET_LEGITIMATE_CONSTANT_P
#define TARGET_LEGITIMATE_CONSTANT_P sh_legitimate_constant_p
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON sh_canonicalize_comparison
+
/* Machine-specific symbol_ref flags. */
#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
@@ -1909,12 +1915,14 @@ prepare_move_operands (rtx operands[], enum machine_mode mode)
}
}
-/* Implement the CANONICALIZE_COMPARISON macro for the combine pass.
- This function is also re-used to canonicalize comparisons in cbranch
- pattern expanders. */
-void
+/* Implement the canonicalize_comparison target hook for the combine
+ pass. For the target hook this function is invoked via
+ sh_canonicalize_comparison. This function is also re-used to
+ canonicalize comparisons in cbranch pattern expanders. */
+static void
sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
- enum machine_mode mode)
+ enum machine_mode mode,
+ bool op0_preserve_value ATTRIBUTE_UNUSED)
{
/* When invoked from within the combine pass the mode is not specified,
so try to get it from one of the operands. */
@@ -2008,6 +2016,19 @@ sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1,
}
}
+/* This function implements the canonicalize_comparison target hook.
+ This wrapper around the internally used sh_canonicalize_comparison
+ function is needed to do the enum rtx_code <-> int conversion.
+ Target hooks cannot use enum rtx_code in its definition. */
+static void
+sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ enum rtx_code tmp_code = (enum rtx_code)*code;
+ sh_canonicalize_comparison (tmp_code, *op0, *op1,
+ VOIDmode, op0_preserve_value);
+ *code = (int)tmp_code;
+}
enum rtx_code
prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
enum rtx_code comparison)
@@ -2021,7 +2042,8 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
else
scratch = operands[4];
- sh_canonicalize_comparison (comparison, operands[1], operands[2], mode);
+ sh_canonicalize_comparison (comparison, operands[1], operands[2],
+ mode, false);
/* Notice that this function is also invoked after reload by
the cbranchdi4_i pattern, through expand_cbranchdi4. */
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 212b97d9c10..76a5cb1edda 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1873,10 +1873,6 @@ struct sh_args {
more compact code. */
#define SHIFT_COUNT_TRUNCATED (0)
-/* CANONICALIZE_COMPARISON macro for the combine pass. */
-#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
- sh_canonicalize_comparison ((CODE), (OP0), (OP1))
-
/* All integers have the same format so truncation is easy. */
/* But SHmedia must sign-extend DImode when truncating to SImode. */
#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index 82fb4340cf5..15e7c2e2bba 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -7095,6 +7095,20 @@ spu_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
final_end_function ();
}
+/* Canonicalize a comparison from one we don't have to one we do have. */
+static void
+spu_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ if (!op0_preserve_value
+ && (*code == LE || *code == LT || *code == LEU || *code == LTU))
+ {
+ rtx tem = *op0;
+ *op0 = *op1;
+ *op1 = tem;
+ *code = (int)swap_condition ((enum rtx_code)*code);
+ }
+}
/* Table of machine attributes. */
static const struct attribute_spec spu_attribute_table[] =
@@ -7308,6 +7322,9 @@ static const struct attribute_spec spu_attribute_table[] =
#undef TARGET_DELAY_VARTRACK
#define TARGET_DELAY_VARTRACK true
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-spu.h"
diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h
index ce0bc8edb5f..031b80e1602 100644
--- a/gcc/config/spu/spu.h
+++ b/gcc/config/spu/spu.h
@@ -520,18 +520,6 @@ do { \
#define NO_IMPLICIT_EXTERN_C 1
-/* Canonicalize a comparison from one we don't have to one we do have. */
-#define CANONICALIZE_COMPARISON(CODE,OP0,OP1) \
- do { \
- if (((CODE) == LE || (CODE) == LT || (CODE) == LEU || (CODE) == LTU)) \
- { \
- rtx tem = (OP0); \
- (OP0) = (OP1); \
- (OP1) = tem; \
- (CODE) = swap_condition (CODE); \
- } \
- } while (0)
-
/* Address spaces. */
#define ADDR_SPACE_EA 1
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 3ab99871c3b..75aa8672758 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -6024,25 +6024,27 @@ You should define this macro if and only if you define extra CC modes
in @file{@var{machine}-modes.def}.
@end defmac
-@defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
+@deftypefn {Target Hook} void TARGET_CANONICALIZE_COMPARISON (int *@var{code}, rtx *@var{op0}, rtx *@var{op1}, bool @var{op0_preserve_value}) (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
On some machines not all possible comparisons are defined, but you can
convert an invalid comparison into a valid one. For example, the Alpha
does not have a @code{GT} comparison, but you can use an @code{LT}
comparison instead and swap the order of the operands.
-On such machines, define this macro to be a C statement to do any
-required conversions. @var{code} is the initial comparison code
-and @var{op0} and @var{op1} are the left and right operands of the
-comparison, respectively. You should modify @var{code}, @var{op0}, and
-@var{op1} as required.
+On such machines, implement this hook to do any required conversions.
+@var{code} is the initial comparison code and @var{op0} and @var{op1}
+are the left and right operands of the comparison, respectively. If
+@var{op0_preserve_value} is @code{true} the implementation is not
+allowed to change the value of @var{op0} since the value might be used
+in RTXs which aren't comparisons. E.g. the implementation is not
+allowed to swap operands in that case.
GCC will not assume that the comparison resulting from this macro is
valid but will see if the resulting insn matches a pattern in the
@file{md} file.
-You need not define this macro if it would never change the comparison
-code or operands.
-@end defmac
+You need not to implement this hook if it would never change the
+comparison code or operands.
+@end deftypefn
@defmac REVERSIBLE_CC_MODE (@var{mode})
A C expression whose value is one if it is always safe to reverse a
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 6d48fe48b75..95fab189c70 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -5928,25 +5928,27 @@ You should define this macro if and only if you define extra CC modes
in @file{@var{machine}-modes.def}.
@end defmac
-@defmac CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1})
+@hook TARGET_CANONICALIZE_COMPARISON (@var{code}, @var{op0}, @var{op1}, @var{op0_preserve_value})
On some machines not all possible comparisons are defined, but you can
convert an invalid comparison into a valid one. For example, the Alpha
does not have a @code{GT} comparison, but you can use an @code{LT}
comparison instead and swap the order of the operands.
-On such machines, define this macro to be a C statement to do any
-required conversions. @var{code} is the initial comparison code
-and @var{op0} and @var{op1} are the left and right operands of the
-comparison, respectively. You should modify @var{code}, @var{op0}, and
-@var{op1} as required.
+On such machines, implement this hook to do any required conversions.
+@var{code} is the initial comparison code and @var{op0} and @var{op1}
+are the left and right operands of the comparison, respectively. If
+@var{op0_preserve_value} is @code{true} the implementation is not
+allowed to change the value of @var{op0} since the value might be used
+in RTXs which aren't comparisons. E.g. the implementation is not
+allowed to swap operands in that case.
GCC will not assume that the comparison resulting from this macro is
valid but will see if the resulting insn matches a pattern in the
@file{md} file.
-You need not define this macro if it would never change the comparison
-code or operands.
-@end defmac
+You need not to implement this hook if it would never change the
+comparison code or operands.
+@end deftypefn
@defmac REVERSIBLE_CC_MODE (@var{mode})
A C expression whose value is one if it is always safe to reverse a
diff --git a/gcc/target.def b/gcc/target.def
index 0f3164a41bd..bbda6c25d26 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2877,6 +2877,14 @@ DEFHOOK
enum unwind_info_type, (void),
default_debug_unwind_info)
+/* The code parameter should be of type enum rtx_code but this is not
+ defined at this time. */
+DEFHOOK
+(canonicalize_comparison,
+ "",
+ void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
+ default_canonicalize_comparison)
+
DEFHOOKPOD
(atomic_test_and_set_trueval,
"This value should be set if the result written by\
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index d4196024708..fc13a26546b 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -179,6 +179,8 @@ extern unsigned char default_class_max_nregs (reg_class_t, enum machine_mode);
extern enum unwind_info_type default_debug_unwind_info (void);
+extern bool default_canonicalize_comparison (int *, rtx *, rtx *, bool);
+
extern int default_label_align_after_barrier_max_skip (rtx);
extern int default_loop_align_max_skip (rtx);
extern int default_label_align_max_skip (rtx);