OSDN Git Service

* arm.c (arm_const_double_by_parts): New function.
authorrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Apr 2005 13:34:27 +0000 (13:34 +0000)
committerrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Apr 2005 13:34:27 +0000 (13:34 +0000)
* arm-protos.h (arm_const_double_by_parts): Add prototype.
* arm.md (define_split for 64-bit constants): Add another one.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97828 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.md

index 33d84cf..ed81d90 100644 (file)
@@ -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.
index 0baca57..087b475 100644 (file)
@@ -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 *);
index 27c6f75..a1abe96 100644 (file)
@@ -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.
index 9474c0d..e94ceb8 100644 (file)
   "
 )
 
+; 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" ""))]