[AArch64 costs 4/18] Better estimate cost of building a constant 68/41168/1
authorjgreenhalgh <jgreenhalgh@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 16 May 2014 08:47:59 +0000 (08:47 +0000)
committerNikolai Bozhenov <n.bozhenov@samsung.com>
Thu, 11 Jun 2015 11:06:05 +0000 (14:06 +0300)
git cherry-pick 3967ee6

gcc/

* config/aarch64/aarch64.c (aarch64_build_constant): Conditionally
emit instructions, return number of instructions which would
be emitted.
(aarch64_add_constant): Update call to aarch64_build_constant.
(aarch64_output_mi_thunk): Likewise.
(aarch64_rtx_costs): Estimate cost of a CONST_INT, cost
a CONST_DOUBLE.

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

gcc/ChangeLog
gcc/config/aarch64/aarch64.c

index 8900efc..2071d8c 100644 (file)
@@ -1,4 +1,15 @@
 2014-05-16  James Greenhalgh  <james.greenhalgh@arm.com>
+           Philipp Tomsich  <philipp.tomsich@theobroma-systems.com>
+
+       * config/aarch64/aarch64.c (aarch64_build_constant): Conditionally
+       emit instructions, return number of instructions which would
+       be emitted.
+       (aarch64_add_constant): Update call to aarch64_build_constant.
+       (aarch64_output_mi_thunk): Likewise.
+       (aarch64_rtx_costs): Estimate cost of a CONST_INT, cost
+       a CONST_DOUBLE.
+
+2014-05-16  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * config/aarch64/aarch64.c (aarch64_rtx_costs_wrapper): New.
        (TARGET_RTX_COSTS): Call it.
index 9b4b5c1..ed49d7f 100644 (file)
@@ -2500,12 +2500,22 @@ aarch64_final_eh_return_addr (void)
                                       - 2 * UNITS_PER_WORD));
 }
 
-/* Output code to build up a constant in a register.  */
-static void
-aarch64_build_constant (int regnum, HOST_WIDE_INT val)
+/* Possibly output code to build up a constant in a register.  For
+   the benefit of the costs infrastructure, returns the number of
+   instructions which would be emitted.  GENERATE inhibits or
+   enables code generation.  */
+
+static int
+aarch64_build_constant (int regnum, HOST_WIDE_INT val, bool generate)
 {
+  int insns = 0;
+
   if (aarch64_bitmask_imm (val, DImode))
-    emit_move_insn (gen_rtx_REG (Pmode, regnum), GEN_INT (val));
+    {
+      if (generate)
+       emit_move_insn (gen_rtx_REG (Pmode, regnum), GEN_INT (val));
+      insns = 1;
+    }
   else
     {
       int i;
@@ -2536,15 +2546,19 @@ aarch64_build_constant (int regnum, HOST_WIDE_INT val)
         the same.  */
       if (ncount < zcount)
        {
-         emit_move_insn (gen_rtx_REG (Pmode, regnum),
-                         GEN_INT (val | ~(HOST_WIDE_INT) 0xffff));
+         if (generate)
+           emit_move_insn (gen_rtx_REG (Pmode, regnum),
+                           GEN_INT (val | ~(HOST_WIDE_INT) 0xffff));
          tval = 0xffff;
+         insns++;
        }
       else
        {
-         emit_move_insn (gen_rtx_REG (Pmode, regnum),
-                         GEN_INT (val & 0xffff));
+         if (generate)
+           emit_move_insn (gen_rtx_REG (Pmode, regnum),
+                           GEN_INT (val & 0xffff));
          tval = 0;
+         insns++;
        }
 
       val >>= 16;
@@ -2552,11 +2566,17 @@ aarch64_build_constant (int regnum, HOST_WIDE_INT val)
       for (i = 16; i < 64; i += 16)
        {
          if ((val & 0xffff) != tval)
-           emit_insn (gen_insv_immdi (gen_rtx_REG (Pmode, regnum),
-                                      GEN_INT (i), GEN_INT (val & 0xffff)));
+           {
+             if (generate)
+               emit_insn (gen_insv_immdi (gen_rtx_REG (Pmode, regnum),
+                                          GEN_INT (i),
+                                          GEN_INT (val & 0xffff)));
+             insns++;
+           }
          val >>= 16;
        }
     }
+  return insns;
 }
 
 static void
@@ -2571,7 +2591,7 @@ aarch64_add_constant (int regnum, int scratchreg, HOST_WIDE_INT delta)
 
   if (mdelta >= 4096 * 4096)
     {
-      aarch64_build_constant (scratchreg, delta);
+      (void) aarch64_build_constant (scratchreg, delta, true);
       emit_insn (gen_add3_insn (this_rtx, this_rtx, scratch_rtx));
     }
   else if (mdelta > 0)
@@ -2645,7 +2665,7 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
          addr = plus_constant (Pmode, temp0, vcall_offset);
       else
        {
-         aarch64_build_constant (IP1_REGNUM, vcall_offset);
+         (void) aarch64_build_constant (IP1_REGNUM, vcall_offset, true);
          addr = gen_rtx_PLUS (Pmode, temp0, temp1);
        }
 
@@ -4655,6 +4675,7 @@ aarch64_rtx_costs (rtx x, int code, int outer ATTRIBUTE_UNUSED,
   rtx op0, op1;
   const struct cpu_cost_table *extra_cost
     = aarch64_tune_params->insn_extra_cost;
+  enum machine_mode mode = GET_MODE (x);
 
   switch (code)
     {
@@ -4701,6 +4722,57 @@ aarch64_rtx_costs (rtx x, int code, int outer ATTRIBUTE_UNUSED,
        }
       return false;
 
+    case CONST_INT:
+      /* If an instruction can incorporate a constant within the
+        instruction, the instruction's expression avoids calling
+        rtx_cost() on the constant.  If rtx_cost() is called on a
+        constant, then it is usually because the constant must be
+        moved into a register by one or more instructions.
+
+        The exception is constant 0, which can be expressed
+        as XZR/WZR and is therefore free.  The exception to this is
+        if we have (set (reg) (const0_rtx)) in which case we must cost
+        the move.  However, we can catch that when we cost the SET, so
+        we don't need to consider that here.  */
+      if (x == const0_rtx)
+       *cost = 0;
+      else
+       {
+         /* To an approximation, building any other constant is
+            proportionally expensive to the number of instructions
+            required to build that constant.  This is true whether we
+            are compiling for SPEED or otherwise.  */
+         *cost = COSTS_N_INSNS (aarch64_build_constant (0,
+                                                        INTVAL (x),
+                                                        false));
+       }
+      return true;
+
+    case CONST_DOUBLE:
+      if (speed)
+       {
+         /* mov[df,sf]_aarch64.  */
+         if (aarch64_float_const_representable_p (x))
+           /* FMOV (scalar immediate).  */
+           *cost += extra_cost->fp[mode == DFmode].fpconst;
+         else if (!aarch64_float_const_zero_rtx_p (x))
+           {
+             /* This will be a load from memory.  */
+             if (mode == DFmode)
+               *cost += extra_cost->ldst.loadd;
+             else
+               *cost += extra_cost->ldst.loadf;
+           }
+         else
+           /* Otherwise this is +0.0.  We get this using MOVI d0, #0
+              or MOV v0.s[0], wzr - neither of which are modeled by the
+              cost tables.  Just use the default cost.  */
+           {
+           }
+       }
+
+      return true;
+
     case MEM:
       if (speed)
        *cost += extra_cost->ldst.load;