aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2005-04-08 13:34:27 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2005-04-08 13:34:27 +0000
commitb4a58f80ff157c8dd62151294fa935820540fc05 (patch)
treee066b3727e892d15e4d8ba5a00b57704b24ed8f2
parent3623aa7017f2a9e867c4703e755933c10ebd4f94 (diff)
downloadgcc-b4a58f80ff157c8dd62151294fa935820540fc05.zip
gcc-b4a58f80ff157c8dd62151294fa935820540fc05.tar.gz
gcc-b4a58f80ff157c8dd62151294fa935820540fc05.tar.bz2
arm.c (arm_const_double_by_parts): New function.
* arm.c (arm_const_double_by_parts): New function. * arm-protos.h (arm_const_double_by_parts): Add prototype. * arm.md (define_split for 64-bit constants): Add another one. From-SVN: r97828
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c35
-rw-r--r--gcc/config/arm/arm.md24
4 files changed, 66 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 33d84cf..ed81d90 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-04-08 Richard Earnshaw <richard.earnshaw@arm.com>
+
+ * arm.c (arm_const_double_by_parts): New function.
+ * arm-protos.h (arm_const_double_by_parts): Add prototype.
+ * arm.md (define_split for 64-bit constants): Add another one.
+
2005-04-08 Andrew MacLeod <amacleod@redhat.com>
* tree-ssa-operands.c (correct_use_link): Remove linear scan.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 0baca57..087b475a9 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -91,6 +91,7 @@ extern rtx arm_gen_return_addr_mask (void);
extern void arm_reload_in_hi (rtx *);
extern void arm_reload_out_hi (rtx *);
extern int arm_const_double_inline_cost (rtx);
+extern bool arm_const_double_by_parts (rtx);
extern const char *fp_immediate_constant (rtx);
extern const char *output_call (rtx *);
extern const char *output_call_mem (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 27c6f75..a1abe96 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -7418,6 +7418,41 @@ arm_const_double_inline_cost (rtx val)
NULL_RTX, NULL_RTX, 0, 0));
}
+/* Return true if it is worthwile to split a 64-bit constant into two
+ 32-bit operations. This is the case if optimizing for size, or
+ if we have load delay slots, or if one 32-bit part can be done with
+ a single data operation. */
+bool
+arm_const_double_by_parts (rtx val)
+{
+ enum machine_mode mode = GET_MODE (val);
+ rtx part;
+
+ if (optimize_size || arm_ld_sched)
+ return true;
+
+ if (mode == VOIDmode)
+ mode = DImode;
+
+ part = gen_highpart_mode (SImode, mode, val);
+
+ gcc_assert (GET_CODE (part) == CONST_INT);
+
+ if (const_ok_for_arm (INTVAL (part))
+ || const_ok_for_arm (~INTVAL (part)))
+ return true;
+
+ part = gen_lowpart (SImode, val);
+
+ gcc_assert (GET_CODE (part) == CONST_INT);
+
+ if (const_ok_for_arm (INTVAL (part))
+ || const_ok_for_arm (~INTVAL (part)))
+ return true;
+
+ return false;
+}
+
/* Scan INSN and note any of its operands that need fixing.
If DO_PUSHES is false we do not actually push any of the fixups
needed. The function returns TRUE if any fixups were needed/pushed.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 9474c0d..e94ceb8 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -4192,6 +4192,30 @@
"
)
+; If optimizing for size, or if we have load delay slots, then
+; we want to split the constant into two separate operations.
+; In both cases this may split a trivial part into a single data op
+; leaving a single complex constant to load. We can also get longer
+; offsets in a LDR which means we get better chances of sharing the pool
+; entries. Finally, we can normally do a better job of scheduling
+; LDR instructions than we can with LDM.
+; This pattern will only match if the one above did not.
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "const_double_operand" ""))]
+ "TARGET_ARM && reload_completed
+ && arm_const_double_by_parts (operands[1])"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ "
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]),
+ operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ "
+)
+
(define_split
[(set (match_operand:ANY64 0 "arm_general_register_operand" "")
(match_operand:ANY64 1 "arm_general_register_operand" ""))]