[AArch64][2/3] Optimize aarch64_add_constant to generate better addition sequences
authorJiong Wang <jiong.wang@arm.com>
Mon, 25 Jul 2016 13:36:33 +0000 (13:36 +0000)
committerJiong Wang <jiwang@gcc.gnu.org>
Mon, 25 Jul 2016 13:36:33 +0000 (13:36 +0000)
gcc/
* config/aarch64/aarch64.c (aarch64_add_constant): Optimize instruction
sequences.

From-SVN: r238713

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

index aa8cc14c020c92f798b7133621492b50ba639829..a2550d118b164210e752b35aecec943a03ea7585 100644 (file)
@@ -1,3 +1,8 @@
+2016-07-25  Jiong Wang  <jiong.wang@arm.com>
+
+       * config/aarch64/aarch64.c (aarch64_add_constant): Optimize instruction
+       sequences.
+
 2016-07-25  Jiong Wang  <jiong.wang@arm.com>
 
        * config/aarch64/aarch64.c (aarch64_add_constant): New parameter "mode".
index 92c4ae4777a99b0d94252e7f0458bbef0f723ab9..6cecb8fc47fe1c621e7c6d40c8302ad138afb514 100644 (file)
@@ -1940,6 +1940,47 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm)
   aarch64_internal_mov_immediate (dest, imm, true, GET_MODE (dest));
 }
 
+/* Add DELTA to REGNUM in mode MODE.  SCRATCHREG can be used to held
+   intermediate value if necessary.  */
+
+static void
+aarch64_add_constant (machine_mode mode, int regnum, int scratchreg,
+                     HOST_WIDE_INT delta)
+{
+  HOST_WIDE_INT mdelta = abs_hwi (delta);
+  rtx this_rtx = gen_rtx_REG (mode, regnum);
+
+  /* Do nothing if mdelta is zero.  */
+  if (!mdelta)
+    return;
+
+  /* We only need single instruction if the offset fit into add/sub.  */
+  if (aarch64_uimm12_shift (mdelta))
+    {
+      emit_insn (gen_add2_insn (this_rtx, GEN_INT (delta)));
+      return;
+    }
+
+  /* We need two add/sub instructions, each one performing part of the
+     calculation.  Don't do this if the addend can be loaded into register with
+     a single instruction, in that case we prefer a move to a scratch register
+     following by an addition.  */
+  if (mdelta < 0x1000000 && !aarch64_move_imm (delta, mode))
+    {
+      HOST_WIDE_INT low_off = mdelta & 0xfff;
+
+      low_off = delta < 0 ? -low_off : low_off;
+      emit_insn (gen_add2_insn (this_rtx, GEN_INT (low_off)));
+      emit_insn (gen_add2_insn (this_rtx, GEN_INT (delta - low_off)));
+      return;
+    }
+
+  /* Otherwise use generic function to handle all other situations.  */
+  rtx scratch_rtx = gen_rtx_REG (mode, scratchreg);
+  aarch64_internal_mov_immediate (scratch_rtx, GEN_INT (delta), true, mode);
+  emit_insn (gen_add2_insn (this_rtx, scratch_rtx));
+}
+
 static bool
 aarch64_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
                                 tree exp ATTRIBUTE_UNUSED)
@@ -3412,44 +3453,6 @@ aarch64_final_eh_return_addr (void)
                                       - 2 * UNITS_PER_WORD));
 }
 
-static void
-aarch64_add_constant (machine_mode mode, int regnum, int scratchreg,
-                     HOST_WIDE_INT delta)
-{
-  HOST_WIDE_INT mdelta = delta;
-  rtx this_rtx = gen_rtx_REG (mode, regnum);
-  rtx scratch_rtx = gen_rtx_REG (mode, scratchreg);
-
-  if (mdelta < 0)
-    mdelta = -mdelta;
-
-  if (mdelta >= 4096 * 4096)
-    {
-      aarch64_internal_mov_immediate (scratch_rtx, GEN_INT (delta), true, mode);
-      emit_insn (gen_add3_insn (this_rtx, this_rtx, scratch_rtx));
-    }
-  else if (mdelta > 0)
-    {
-      if (mdelta >= 4096)
-       {
-         emit_insn (gen_rtx_SET (scratch_rtx, GEN_INT (mdelta / 4096)));
-         rtx shift = gen_rtx_ASHIFT (mode, scratch_rtx, GEN_INT (12));
-         if (delta < 0)
-           emit_insn (gen_rtx_SET (this_rtx,
-                                   gen_rtx_MINUS (mode, this_rtx, shift)));
-         else
-           emit_insn (gen_rtx_SET (this_rtx,
-                                   gen_rtx_PLUS (mode, this_rtx, shift)));
-       }
-      if (mdelta % 4096 != 0)
-       {
-         scratch_rtx = GEN_INT ((delta < 0 ? -1 : 1) * (mdelta % 4096));
-         emit_insn (gen_rtx_SET (this_rtx,
-                                 gen_rtx_PLUS (mode, this_rtx, scratch_rtx)));
-       }
-    }
-}
-
 /* Output code to add DELTA to the first argument, and then jump
    to FUNCTION.  Used for C++ multiple inheritance.  */
 static void