* regrename.c: Include "target.h".
(regrename_optimize): Call targetm.regrename_ok.
* targhooks.c (default_regrename_ok): New.
* targhooks.h (default_regrename_ok): Declare.
* target.def (regrename_ok): New.
* doc/tm.texi.in: Document TARGET_REGRENAME_OK.
* doc/tm.texi: Regenerate.
* config/arm/arm.c (arm_regrename_ok): New.
(TARGET_REGRENAME_OK): Define.
* config/arm/arm.md (*push_multi): Rename to push_multi.
===================================================================
@@ -36,6 +36,7 @@
#include "flags.h"
#include "toplev.h"
#include "obstack.h"
+#include "target.h"
#include "timevar.h"
#include "tree-pass.h"
#include "df.h"
@@ -301,7 +302,8 @@ regrename_optimize (void)
&& ! (HARD_REGNO_CALL_PART_CLOBBERED
(reg, GET_MODE (*tmp->loc)))
&& (HARD_REGNO_CALL_PART_CLOBBERED
- (new_reg, GET_MODE (*tmp->loc)))))
+ (new_reg, GET_MODE (*tmp->loc))))
+ || ! targetm.regrename_ok (tmp->insn, reg, new_reg))
break;
if (! tmp)
{
===================================================================
@@ -2256,6 +2256,18 @@ is not saved by a prologue in an interru
The default version of this hook always returns @code{true}.
@end deftypefn
+@hook TARGET_REGRENAME_OK
+
+This target hook should return @code{true} if it is OK to rename a register
+@var{reg} to a new register @var{new_reg}.
+
+This macro can be used to prevent register renaming in some cases. ARM port uses
+this macro to prevent register renaming generating non-ascending register list
+in push multiple instruction.
+
+The default version of this hook always returns @code{true}.
+@end deftypefn
+
@defmac AVOID_CCMODE_COPIES
Define this macro if the compiler should avoid copies to/from @code{CCmode}
registers. You should only define this macro if support for copying to/from
===================================================================
@@ -1102,6 +1102,16 @@ default_mode_dependent_address_p (const_
#endif
}
+/* The default implementation of TARGET_REGRENAME_OK. */
+
+bool
+default_regrename_ok (rtx insn ATTRIBUTE_UNUSED,
+ int reg ATTRIBUTE_UNUSED,
+ int new_reg ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
bool
default_target_option_valid_attribute_p (tree ARG_UNUSED (fndecl),
tree ARG_UNUSED (name),
===================================================================
@@ -130,6 +130,7 @@ extern tree default_mangle_decl_assemble
extern tree default_emutls_var_fields (tree, tree *);
extern tree default_emutls_var_init (tree, tree, tree);
extern bool default_hard_regno_scratch_ok (unsigned int);
+extern bool default_regrename_ok (rtx, int, int);
extern bool default_mode_dependent_address_p (const_rtx addr);
extern bool default_target_option_valid_attribute_p (tree, tree, tree, int);
extern bool default_target_option_pragma_parse (tree, tree);
===================================================================
@@ -1980,6 +1980,13 @@ DEFHOOK
bool, (unsigned int regno),
default_hard_regno_scratch_ok)
+/* Return true if is OK to rename REG to NEW_REG in INSN. */
+DEFHOOK
+(regrename_ok,
+ "",
+ bool, (rtx insn, int reg, int new_reg),
+ default_regrename_ok)
+
/* Return the smallest number of different values for which it is best to
use a jump-table instead of a tree of conditional branches. */
DEFHOOK
===================================================================
@@ -219,6 +219,7 @@ static const char *arm_invalid_parameter
static const char *arm_invalid_return_type (const_tree t);
static tree arm_promoted_type (const_tree t);
static tree arm_convert_to_type (tree type, tree expr);
+static bool arm_regrename_ok (rtx, int, int);
static bool arm_scalar_mode_supported_p (enum machine_mode);
static bool arm_frame_pointer_required (void);
static bool arm_can_eliminate (const int, const int);
@@ -507,6 +508,9 @@ static const struct attribute_spec arm_a
#undef TARGET_CONVERT_TO_TYPE
#define TARGET_CONVERT_TO_TYPE arm_convert_to_type
+#undef TARGET_REGRENAME_OK
+#define TARGET_REGRENAME_OK arm_regrename_ok
+
#undef TARGET_SCALAR_MODE_SUPPORTED_P
#define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p
@@ -18118,6 +18122,43 @@ arm_convert_to_type (tree type, tree exp
return NULL_TREE;
}
+/* Implement TARGET_REGRENAME_OK.
+ We cannot rename REG to NEW_REG in INSN if INSN is a push_multi instruction
+ and the registers aren't in ascending order any more after renaming. */
+
+static bool
+arm_regrename_ok (rtx insn, int reg, int new_reg)
+{
+ if (recog_memoized (insn) == CODE_FOR_push_multi)
+ {
+ int regs[MAX_RECOG_OPERANDS + 2];
+ int num_regs, i;
+
+ extract_insn (insn);
+
+ num_regs = XVECLEN (recog_data.operand[2], 0);
+
+ if (num_regs == 1)
+ return true;
+
+ regs[0] = -1;
+ regs[1] = REGNO (recog_data.operand[1]);
+ regs[num_regs + 1] = FIRST_PSEUDO_REGISTER;
+ for (i = 1; i < num_regs; i++)
+ regs[i + 1] = REGNO (XEXP (XVECEXP (recog_data.operand[2], 0, i), 0));
+
+ for (i = 1; i <= num_regs; i++)
+ if (reg == regs[i])
+ {
+ if (new_reg > regs[i - 1] && new_reg < regs[i + 1])
+ return true;
+ else
+ return false;
+ }
+ }
+ return true;
+}
+
/* Implement TARGET_SCALAR_MODE_SUPPORTED_P.
This simply adds HFmode as a supported mode; even though we don't
implement arithmetic on this type directly, it's supported by
===================================================================
@@ -10868,7 +10868,7 @@
;; Push multiple registers to the stack. Registers are in parallel (use ...)
;; expressions. For simplicity, the first register is also in the unspec
;; part.
-(define_insn "*push_multi"
+(define_insn "push_multi"
[(match_parallel 2 "multi_register_push"
[(set (match_operand:BLK 0 "memory_operand" "=m")
(unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")]