diff options
author | Richard Earnshaw <rearnsha@arm.com> | 2005-04-08 13:34:27 +0000 |
---|---|---|
committer | Richard Earnshaw <rearnsha@gcc.gnu.org> | 2005-04-08 13:34:27 +0000 |
commit | b4a58f80ff157c8dd62151294fa935820540fc05 (patch) | |
tree | e066b3727e892d15e4d8ba5a00b57704b24ed8f2 /gcc | |
parent | 3623aa7017f2a9e867c4703e755933c10ebd4f94 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 35 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 24 |
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" ""))] |