gcc/
authoryroux <yroux@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 12 Jun 2014 11:54:42 +0000 (11:54 +0000)
committeryroux <yroux@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 12 Jun 2014 11:54:42 +0000 (11:54 +0000)
2014-05-23  Yvan Roux  <yvan.roux@linaro.org>

Backport from trunk r209701, 209702, 209703, 209704, 209705.
2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* config/arm/arm.md (arm_rev16si2): New pattern.
(arm_rev16si2_alt): Likewise.
* config/arm/arm.c (arm_new_rtx_costs): Handle rev16 case.

2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
* config/aarch64/aarch64.md (rev16<mode>2): New pattern.
(rev16<mode>2_alt): Likewise.
* config/aarch64/aarch64.c (aarch64_rtx_costs): Handle rev16 case.
* config/arm/aarch-common.c (aarch_rev16_shright_mask_imm_p): New.
(aarch_rev16_shleft_mask_imm_p): Likewise.
(aarch_rev16_p_1): Likewise.
(aarch_rev16_p): Likewise.
* config/arm/aarch-common-protos.h (aarch_rev16_p): Declare extern.
(aarch_rev16_shright_mask_imm_p): Likewise.
(aarch_rev16_shleft_mask_imm_p): Likewise.

2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* config/arm/aarch-common-protos.h (alu_cost_table): Add rev field.
* config/arm/aarch-cost-tables.h (generic_extra_costs): Specify
rev cost.
(cortex_a53_extra_costs): Likewise.
(cortex_a57_extra_costs): Likewise.
* config/arm/arm.c (cortexa9_extra_costs): Likewise.
(cortexa7_extra_costs): Likewise.
(cortexa8_extra_costs): Likewise.
(cortexa12_extra_costs): Likewise.
(cortexa15_extra_costs): Likewise.
(v7m_extra_costs): Likewise.
(arm_new_rtx_costs): Handle BSWAP.

2013-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* config/arm/arm.c (cortexa8_extra_costs): New table.
(arm_cortex_a8_tune): New tuning struct.
* config/arm/arm-cores.def (cortex-a8): Use cortex_a8 tuning struct.

2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* config/arm/arm.c (arm_new_rtx_costs): Handle FMA.

gcc/testsuite/
2014-05-23  Yvan Roux  <yvan.roux@linaro.org>

Backport from trunk r209704, 209705.
2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* gcc.target/arm/rev16.c: New test.

2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

* gcc.target/aarch64/rev16_1.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/linaro/gcc-4_9-branch@211520 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog.linaro
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/config/arm/aarch-common-protos.h
gcc/config/arm/aarch-common.c
gcc/config/arm/aarch-cost-tables.h
gcc/config/arm/arm-cores.def
gcc/config/arm/arm.c
gcc/config/arm/arm.md
gcc/testsuite/ChangeLog.linaro
gcc/testsuite/gcc.target/aarch64/rev16_1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/rev16.c [new file with mode: 0644]

index 4b299ee..451153a 100644 (file)
@@ -1,5 +1,51 @@
 2014-05-23  Yvan Roux  <yvan.roux@linaro.org>
 
+       Backport from trunk r209701, 209702, 209703, 209704, 209705.
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * config/arm/arm.md (arm_rev16si2): New pattern.
+       (arm_rev16si2_alt): Likewise.
+       * config/arm/arm.c (arm_new_rtx_costs): Handle rev16 case.
+
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+       * config/aarch64/aarch64.md (rev16<mode>2): New pattern.
+       (rev16<mode>2_alt): Likewise.
+       * config/aarch64/aarch64.c (aarch64_rtx_costs): Handle rev16 case.
+       * config/arm/aarch-common.c (aarch_rev16_shright_mask_imm_p): New.
+       (aarch_rev16_shleft_mask_imm_p): Likewise.
+       (aarch_rev16_p_1): Likewise.
+       (aarch_rev16_p): Likewise.
+       * config/arm/aarch-common-protos.h (aarch_rev16_p): Declare extern.
+       (aarch_rev16_shright_mask_imm_p): Likewise.
+       (aarch_rev16_shleft_mask_imm_p): Likewise.
+
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * config/arm/aarch-common-protos.h (alu_cost_table): Add rev field.
+       * config/arm/aarch-cost-tables.h (generic_extra_costs): Specify
+       rev cost.
+       (cortex_a53_extra_costs): Likewise.
+       (cortex_a57_extra_costs): Likewise.
+       * config/arm/arm.c (cortexa9_extra_costs): Likewise.
+       (cortexa7_extra_costs): Likewise.
+       (cortexa8_extra_costs): Likewise.
+       (cortexa12_extra_costs): Likewise.
+       (cortexa15_extra_costs): Likewise.
+       (v7m_extra_costs): Likewise.
+       (arm_new_rtx_costs): Handle BSWAP.
+
+       2013-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * config/arm/arm.c (cortexa8_extra_costs): New table.
+       (arm_cortex_a8_tune): New tuning struct.
+       * config/arm/arm-cores.def (cortex-a8): Use cortex_a8 tuning struct.
+
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * config/arm/arm.c (arm_new_rtx_costs): Handle FMA.
+
+2014-05-23  Yvan Roux  <yvan.roux@linaro.org>
+
        Backport from trunk r209659.
        2014-04-22  Richard Henderson  <rth@redhat.com>
 
index dacd7ee..68c29aa 100644 (file)
@@ -4695,6 +4695,16 @@ aarch64_rtx_costs (rtx x, int code, int outer ATTRIBUTE_UNUSED,
       return false;
 
     case IOR:
+      if (aarch_rev16_p (x))
+        {
+          *cost = COSTS_N_INSNS (1);
+
+          if (speed)
+            *cost += extra_cost->alu.rev;
+
+          return true;
+        }
+    /* Fall through.  */
     case XOR:
     case AND:
     cost_logic:
index 365192e..f81959d 100644 (file)
   [(set_attr "type" "rev")]
 )
 
+;; There are no canonicalisation rules for the position of the lshiftrt, ashift
+;; operations within an IOR/AND RTX, therefore we have two patterns matching
+;; each valid permutation.
+
+(define_insn "rev16<mode>2"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (ashift:GPI (match_operand:GPI 1 "register_operand" "r")
+                                      (const_int 8))
+                          (match_operand:GPI 3 "const_int_operand" "n"))
+                 (and:GPI (lshiftrt:GPI (match_dup 1)
+                                        (const_int 8))
+                          (match_operand:GPI 2 "const_int_operand" "n"))))]
+  "aarch_rev16_shleft_mask_imm_p (operands[3], <MODE>mode)
+   && aarch_rev16_shright_mask_imm_p (operands[2], <MODE>mode)"
+  "rev16\\t%<w>0, %<w>1"
+  [(set_attr "type" "rev")]
+)
+
+(define_insn "rev16<mode>2_alt"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (lshiftrt:GPI (match_operand:GPI 1 "register_operand" "r")
+                                        (const_int 8))
+                          (match_operand:GPI 2 "const_int_operand" "n"))
+                 (and:GPI (ashift:GPI (match_dup 1)
+                                      (const_int 8))
+                          (match_operand:GPI 3 "const_int_operand" "n"))))]
+  "aarch_rev16_shleft_mask_imm_p (operands[3], <MODE>mode)
+   && aarch_rev16_shright_mask_imm_p (operands[2], <MODE>mode)"
+  "rev16\\t%<w>0, %<w>1"
+  [(set_attr "type" "rev")]
+)
+
 ;; zero_extend version of above
 (define_insn "*bswapsi2_uxtw"
   [(set (match_operand:DI 0 "register_operand" "=r")
index 3e6e242..1b60d78 100644 (file)
@@ -24,6 +24,9 @@
 #define GCC_AARCH_COMMON_PROTOS_H
 
 extern int aarch_crypto_can_dual_issue (rtx, rtx);
+extern bool aarch_rev16_p (rtx);
+extern bool aarch_rev16_shleft_mask_imm_p (rtx, enum machine_mode);
+extern bool aarch_rev16_shright_mask_imm_p (rtx, enum machine_mode);
 extern int arm_early_load_addr_dep (rtx, rtx);
 extern int arm_early_store_addr_dep (rtx, rtx);
 extern int arm_mac_accumulator_is_mul_result (rtx, rtx);
@@ -54,6 +57,7 @@ struct alu_cost_table
   const int bfi;               /* Bit-field insert.  */
   const int bfx;               /* Bit-field extraction.  */
   const int clz;               /* Count Leading Zeros.  */
+  const int rev;               /* Reverse bits/bytes.  */
   const int non_exec;          /* Extra cost when not executing insn.  */
   const bool non_exec_costs_exec; /* True if non-execution must add the exec
                                     cost.  */
index af8fc99..884d4b3 100644 (file)
@@ -191,6 +191,79 @@ arm_get_set_operands (rtx producer, rtx consumer,
   return 0;
 }
 
+bool
+aarch_rev16_shright_mask_imm_p (rtx val, enum machine_mode mode)
+{
+  return CONST_INT_P (val)
+         && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff, mode);
+}
+
+bool
+aarch_rev16_shleft_mask_imm_p (rtx val, enum machine_mode mode)
+{
+  return CONST_INT_P (val)
+         && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff00, mode);
+}
+
+
+static bool
+aarch_rev16_p_1 (rtx lhs, rtx rhs, enum machine_mode mode)
+{
+  if (GET_CODE (lhs) == AND
+         && GET_CODE (XEXP (lhs, 0)) == ASHIFT
+            && CONST_INT_P (XEXP (XEXP (lhs, 0), 1))
+            && INTVAL (XEXP (XEXP (lhs, 0), 1)) == 8
+            && REG_P (XEXP (XEXP (lhs, 0), 0))
+         && CONST_INT_P (XEXP (lhs, 1))
+      && GET_CODE (rhs) == AND
+         && GET_CODE (XEXP (rhs, 0)) == LSHIFTRT
+            && REG_P (XEXP (XEXP (rhs, 0), 0))
+            && CONST_INT_P (XEXP (XEXP (rhs, 0), 1))
+            && INTVAL (XEXP (XEXP (rhs, 0), 1)) == 8
+         && CONST_INT_P (XEXP (rhs, 1))
+      && REGNO (XEXP (XEXP (rhs, 0), 0)) == REGNO (XEXP (XEXP (lhs, 0), 0)))
+
+    {
+      rtx lhs_mask = XEXP (lhs, 1);
+      rtx rhs_mask = XEXP (rhs, 1);
+
+      return aarch_rev16_shright_mask_imm_p (rhs_mask, mode)
+             && aarch_rev16_shleft_mask_imm_p (lhs_mask, mode);
+    }
+
+  return false;
+}
+
+/* Recognise a sequence of bitwise operations corresponding to a rev16 operation.
+   These will be of the form:
+     ((x >> 8) & 0x00ff00ff)
+   | ((x << 8) & 0xff00ff00)
+   for SImode and with similar but wider bitmasks for DImode.
+   The two sub-expressions of the IOR can appear on either side so check both
+   permutations with the help of aarch_rev16_p_1 above.  */
+
+bool
+aarch_rev16_p (rtx x)
+{
+  rtx left_sub_rtx, right_sub_rtx;
+  bool is_rev = false;
+
+  if (GET_CODE (x) != IOR)
+    return false;
+
+  left_sub_rtx = XEXP (x, 0);
+  right_sub_rtx = XEXP (x, 1);
+
+  /* There are no canonicalisation rules for the position of the two shifts
+     involved in a rev, so try both permutations.  */
+  is_rev = aarch_rev16_p_1 (left_sub_rtx, right_sub_rtx, GET_MODE (x));
+
+  if (!is_rev)
+    is_rev = aarch_rev16_p_1 (right_sub_rtx, left_sub_rtx, GET_MODE (x));
+
+  return is_rev;
+}
+
 /* Return nonzero if the CONSUMER instruction (a load) does need
    PRODUCER's value to calculate the address.  */
 int
index c30ea2f..adf8708 100644 (file)
@@ -39,6 +39,7 @@ const struct cpu_cost_table generic_extra_costs =
     0,                 /* bfi.  */
     0,                 /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     COSTS_N_INSNS (1), /* non_exec.  */
     false              /* non_exec_costs_exec.  */
   },
@@ -139,6 +140,7 @@ const struct cpu_cost_table cortexa53_extra_costs =
     COSTS_N_INSNS (1), /* bfi.  */
     COSTS_N_INSNS (1), /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
@@ -239,6 +241,7 @@ const struct cpu_cost_table cortexa57_extra_costs =
     COSTS_N_INSNS (1), /* bfi.  */
     0,                 /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
index 56041ec..a830a83 100644 (file)
@@ -141,7 +141,7 @@ ARM_CORE("cortex-m0plus",   cortexm0plus, cortexm0plus,     6M, FL_LDSCHED, v6m)
 ARM_CORE("generic-armv7-a",    genericv7a, genericv7a,         7A,  FL_LDSCHED, cortex)
 ARM_CORE("cortex-a5",          cortexa5, cortexa5,             7A,  FL_LDSCHED, cortex_a5)
 ARM_CORE("cortex-a7",          cortexa7, cortexa7,             7A,  FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a7)
-ARM_CORE("cortex-a8",          cortexa8, cortexa8,             7A,  FL_LDSCHED, cortex)
+ARM_CORE("cortex-a8",          cortexa8, cortexa8,             7A,  FL_LDSCHED, cortex_a8)
 ARM_CORE("cortex-a9",          cortexa9, cortexa9,             7A,  FL_LDSCHED, cortex_a9)
 ARM_CORE("cortex-a12",         cortexa12, cortexa15,           7A,  FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a12)
 ARM_CORE("cortex-a15",         cortexa15, cortexa15,           7A,  FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a15)
index fd5e225..326f2a3 100644 (file)
@@ -986,6 +986,7 @@ const struct cpu_cost_table cortexa9_extra_costs =
     COSTS_N_INSNS (1), /* bfi.  */
     COSTS_N_INSNS (1), /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
@@ -1069,6 +1070,108 @@ const struct cpu_cost_table cortexa9_extra_costs =
   }
 };
 
+const struct cpu_cost_table cortexa8_extra_costs =
+{
+  /* ALU */
+  {
+    0,                 /* arith.  */
+    0,                 /* logical.  */
+    COSTS_N_INSNS (1), /* shift.  */
+    0,                 /* shift_reg.  */
+    COSTS_N_INSNS (1), /* arith_shift.  */
+    0,                 /* arith_shift_reg.  */
+    COSTS_N_INSNS (1), /* log_shift.  */
+    0,                 /* log_shift_reg.  */
+    0,                 /* extend.  */
+    0,                 /* extend_arith.  */
+    0,                 /* bfi.  */
+    0,                 /* bfx.  */
+    0,                 /* clz.  */
+    0,                 /* rev.  */
+    0,                 /* non_exec.  */
+    true               /* non_exec_costs_exec.  */
+  },
+  {
+    /* MULT SImode */
+    {
+      COSTS_N_INSNS (1),       /* simple.  */
+      COSTS_N_INSNS (1),       /* flag_setting.  */
+      COSTS_N_INSNS (1),       /* extend.  */
+      COSTS_N_INSNS (1),       /* add.  */
+      COSTS_N_INSNS (1),       /* extend_add.  */
+      COSTS_N_INSNS (30)       /* idiv.  No HW div on Cortex A8.  */
+    },
+    /* MULT DImode */
+    {
+      0,                       /* simple (N/A).  */
+      0,                       /* flag_setting (N/A).  */
+      COSTS_N_INSNS (2),       /* extend.  */
+      0,                       /* add (N/A).  */
+      COSTS_N_INSNS (2),       /* extend_add.  */
+      0                                /* idiv (N/A).  */
+    }
+  },
+  /* LD/ST */
+  {
+    COSTS_N_INSNS (1), /* load.  */
+    COSTS_N_INSNS (1), /* load_sign_extend.  */
+    COSTS_N_INSNS (1), /* ldrd.  */
+    COSTS_N_INSNS (1), /* ldm_1st.  */
+    1,                 /* ldm_regs_per_insn_1st.  */
+    2,                 /* ldm_regs_per_insn_subsequent.  */
+    COSTS_N_INSNS (1), /* loadf.  */
+    COSTS_N_INSNS (1), /* loadd.  */
+    COSTS_N_INSNS (1),  /* load_unaligned.  */
+    COSTS_N_INSNS (1), /* store.  */
+    COSTS_N_INSNS (1), /* strd.  */
+    COSTS_N_INSNS (1), /* stm_1st.  */
+    1,                 /* stm_regs_per_insn_1st.  */
+    2,                 /* stm_regs_per_insn_subsequent.  */
+    COSTS_N_INSNS (1), /* storef.  */
+    COSTS_N_INSNS (1), /* stored.  */
+    COSTS_N_INSNS (1)  /* store_unaligned.  */
+  },
+  {
+    /* FP SFmode */
+    {
+      COSTS_N_INSNS (36),      /* div.  */
+      COSTS_N_INSNS (11),      /* mult.  */
+      COSTS_N_INSNS (20),      /* mult_addsub. */
+      COSTS_N_INSNS (30),      /* fma.  */
+      COSTS_N_INSNS (9),       /* addsub.  */
+      COSTS_N_INSNS (3),       /* fpconst.  */
+      COSTS_N_INSNS (3),       /* neg.  */
+      COSTS_N_INSNS (6),       /* compare.  */
+      COSTS_N_INSNS (4),       /* widen.  */
+      COSTS_N_INSNS (4),       /* narrow.  */
+      COSTS_N_INSNS (8),       /* toint.  */
+      COSTS_N_INSNS (8),       /* fromint.  */
+      COSTS_N_INSNS (8)                /* roundint.  */
+    },
+    /* FP DFmode */
+    {
+      COSTS_N_INSNS (64),      /* div.  */
+      COSTS_N_INSNS (16),      /* mult.  */
+      COSTS_N_INSNS (25),      /* mult_addsub.  */
+      COSTS_N_INSNS (30),      /* fma.  */
+      COSTS_N_INSNS (9),       /* addsub.  */
+      COSTS_N_INSNS (3),       /* fpconst.  */
+      COSTS_N_INSNS (3),       /* neg.  */
+      COSTS_N_INSNS (6),       /* compare.  */
+      COSTS_N_INSNS (6),       /* widen.  */
+      COSTS_N_INSNS (6),       /* narrow.  */
+      COSTS_N_INSNS (8),       /* toint.  */
+      COSTS_N_INSNS (8),       /* fromint.  */
+      COSTS_N_INSNS (8)                /* roundint.  */
+    }
+  },
+  /* Vector */
+  {
+    COSTS_N_INSNS (1)  /* alu.  */
+  }
+};
+
+
 
 const struct cpu_cost_table cortexa7_extra_costs =
 {
@@ -1087,6 +1190,7 @@ const struct cpu_cost_table cortexa7_extra_costs =
     COSTS_N_INSNS (1), /* bfi.  */
     COSTS_N_INSNS (1), /* bfx.  */
     COSTS_N_INSNS (1), /* clz.  */
+    COSTS_N_INSNS (1), /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
@@ -1188,6 +1292,7 @@ const struct cpu_cost_table cortexa12_extra_costs =
     0,                 /* bfi.  */
     COSTS_N_INSNS (1), /* bfx.  */
     COSTS_N_INSNS (1), /* clz.  */
+    COSTS_N_INSNS (1), /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
@@ -1288,6 +1393,7 @@ const struct cpu_cost_table cortexa15_extra_costs =
     COSTS_N_INSNS (1), /* bfi.  */
     0,                 /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     0,                 /* non_exec.  */
     true               /* non_exec_costs_exec.  */
   },
@@ -1388,6 +1494,7 @@ const struct cpu_cost_table v7m_extra_costs =
     0,                 /* bfi.  */
     0,                 /* bfx.  */
     0,                 /* clz.  */
+    0,                 /* rev.  */
     COSTS_N_INSNS (1), /* non_exec.  */
     false              /* non_exec_costs_exec.  */
   },
@@ -1594,6 +1701,22 @@ const struct tune_params arm_cortex_tune =
   false, false                                  /* Prefer 32-bit encodings.  */
 };
 
+const struct tune_params arm_cortex_a8_tune =
+{
+  arm_9e_rtx_costs,
+  &cortexa8_extra_costs,
+  NULL,                                                /* Sched adj cost.  */
+  1,                                           /* Constant limit.  */
+  5,                                           /* Max cond insns.  */
+  ARM_PREFETCH_NOT_BENEFICIAL,
+  false,                                       /* Prefer constant pool.  */
+  arm_default_branch_cost,
+  false,                                       /* Prefer LDRD/STRD.  */
+  {true, true},                                        /* Prefer non short circuit.  */
+  &arm_default_vec_cost,                        /* Vectorizer costs.  */
+  false                                         /* Prefer Neon for 64-bits bitops.  */
+};
+
 const struct tune_params arm_cortex_a7_tune =
 {
   arm_9e_rtx_costs,
@@ -9353,6 +9476,47 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       *cost = LIBCALL_COST (2);
       return false;
 
+    case BSWAP:
+      if (arm_arch6)
+        {
+          if (mode == SImode)
+            {
+              *cost = COSTS_N_INSNS (1);
+              if (speed_p)
+                *cost += extra_cost->alu.rev;
+
+              return false;
+            }
+        }
+      else
+        {
+        /* No rev instruction available.  Look at arm_legacy_rev
+           and thumb_legacy_rev for the form of RTL used then.  */
+          if (TARGET_THUMB)
+            {
+              *cost = COSTS_N_INSNS (10);
+
+              if (speed_p)
+                {
+                  *cost += 6 * extra_cost->alu.shift;
+                  *cost += 3 * extra_cost->alu.logical;
+                }
+            }
+          else
+            {
+              *cost = COSTS_N_INSNS (5);
+
+              if (speed_p)
+                {
+                  *cost += 2 * extra_cost->alu.shift;
+                  *cost += extra_cost->alu.arith_shift;
+                  *cost += 2 * extra_cost->alu.logical;
+                }
+            }
+          return true;
+        }
+      return false;
+
     case MINUS:
       if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
          && (mode == SFmode || !TARGET_VFP_SINGLE))
@@ -9735,8 +9899,17 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       /* Vector mode?  */
       *cost = LIBCALL_COST (2);
       return false;
+    case IOR:
+      if (mode == SImode && arm_arch6 && aarch_rev16_p (x))
+        {
+          *cost = COSTS_N_INSNS (1);
+          if (speed_p)
+            *cost += extra_cost->alu.rev;
 
-    case AND: case XOR: case IOR:
+          return true;
+        }
+    /* Fall through.  */
+    case AND: case XOR:
       if (mode == SImode)
        {
          enum rtx_code subcode = GET_CODE (XEXP (x, 0));
@@ -10635,6 +10808,36 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       *cost = LIBCALL_COST (1);
       return false;
 
+    case FMA:
+      if (TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FMA)
+        {
+          rtx op0 = XEXP (x, 0);
+          rtx op1 = XEXP (x, 1);
+          rtx op2 = XEXP (x, 2);
+
+          *cost = COSTS_N_INSNS (1);
+
+          /* vfms or vfnma.  */
+          if (GET_CODE (op0) == NEG)
+            op0 = XEXP (op0, 0);
+
+          /* vfnms or vfnma.  */
+          if (GET_CODE (op2) == NEG)
+            op2 = XEXP (op2, 0);
+
+          *cost += rtx_cost (op0, FMA, 0, speed_p);
+          *cost += rtx_cost (op1, FMA, 1, speed_p);
+          *cost += rtx_cost (op2, FMA, 2, speed_p);
+
+          if (speed_p)
+            *cost += extra_cost->fp[mode ==DFmode].fma;
+
+          return true;
+        }
+
+      *cost = LIBCALL_COST (3);
+      return false;
+
     case FIX:
     case UNSIGNED_FIX:
       if (TARGET_HARD_FLOAT)
index 91b1bb3..bb62c60 100644 (file)
    (set_attr "type" "rev")]
 )
 
+;; There are no canonicalisation rules for the position of the lshiftrt, ashift
+;; operations within an IOR/AND RTX, therefore we have two patterns matching
+;; each valid permutation.
+
+(define_insn "arm_rev16si2"
+  [(set (match_operand:SI 0 "register_operand" "=l,l,r")
+        (ior:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "l,l,r")
+                                   (const_int 8))
+                        (match_operand:SI 3 "const_int_operand" "n,n,n"))
+                (and:SI (lshiftrt:SI (match_dup 1)
+                                     (const_int 8))
+                        (match_operand:SI 2 "const_int_operand" "n,n,n"))))]
+  "arm_arch6
+   && aarch_rev16_shleft_mask_imm_p (operands[3], SImode)
+   && aarch_rev16_shright_mask_imm_p (operands[2], SImode)"
+  "rev16\\t%0, %1"
+  [(set_attr "arch" "t1,t2,32")
+   (set_attr "length" "2,2,4")
+   (set_attr "type" "rev")]
+)
+
+(define_insn "arm_rev16si2_alt"
+  [(set (match_operand:SI 0 "register_operand" "=l,l,r")
+        (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,l,r")
+                                     (const_int 8))
+                        (match_operand:SI 2 "const_int_operand" "n,n,n"))
+                (and:SI (ashift:SI (match_dup 1)
+                                   (const_int 8))
+                        (match_operand:SI 3 "const_int_operand" "n,n,n"))))]
+  "arm_arch6
+   && aarch_rev16_shleft_mask_imm_p (operands[3], SImode)
+   && aarch_rev16_shright_mask_imm_p (operands[2], SImode)"
+  "rev16\\t%0, %1"
+  [(set_attr "arch" "t1,t2,32")
+   (set_attr "length" "2,2,4")
+   (set_attr "type" "rev")]
+)
+
 (define_expand "bswaphi2"
   [(set (match_operand:HI 0 "s_register_operand" "=r")
        (bswap:HI (match_operand:HI 1 "s_register_operand" "r")))]
index a04afe8..71de75d 100644 (file)
@@ -1,5 +1,16 @@
 2014-05-23  Yvan Roux  <yvan.roux@linaro.org>
 
+       Backport from trunk r209704, 209705.
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/arm/rev16.c: New test.
+
+       2014-04-23  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/aarch64/rev16_1.c: New test.
+
+2014-05-23  Yvan Roux  <yvan.roux@linaro.org>
+
        Backport from trunk r209642.
        2014-04-22  Alex Velenko  <Alex.Velenko@arm.com>
 
diff --git a/gcc/testsuite/gcc.target/aarch64/rev16_1.c b/gcc/testsuite/gcc.target/aarch64/rev16_1.c
new file mode 100644 (file)
index 0000000..126d3c0
--- /dev/null
@@ -0,0 +1,59 @@
+/* { dg-options "-O2" } */
+/* { dg-do run } */
+
+extern void abort (void);
+
+typedef unsigned int __u32;
+
+__u32
+__rev16_32_alt (__u32 x)
+{
+  return (((__u32)(x) & (__u32)0xff00ff00UL) >> 8)
+         | (((__u32)(x) & (__u32)0x00ff00ffUL) << 8);
+}
+
+__u32
+__rev16_32 (__u32 x)
+{
+  return (((__u32)(x) & (__u32)0x00ff00ffUL) << 8)
+         | (((__u32)(x) & (__u32)0xff00ff00UL) >> 8);
+}
+
+typedef unsigned long long __u64;
+
+__u64
+__rev16_64_alt (__u64 x)
+{
+  return (((__u64)(x) & (__u64)0xff00ff00ff00ff00UL) >> 8)
+         | (((__u64)(x) & (__u64)0x00ff00ff00ff00ffUL) << 8);
+}
+
+__u64
+__rev16_64 (__u64 x)
+{
+  return (((__u64)(x) & (__u64)0x00ff00ff00ff00ffUL) << 8)
+         | (((__u64)(x) & (__u64)0xff00ff00ff00ff00UL) >> 8);
+}
+
+int
+main (void)
+{
+  volatile __u32 in32 = 0x12345678;
+  volatile __u32 expected32 = 0x34127856;
+  volatile __u64 in64 = 0x1234567890abcdefUL;
+  volatile __u64 expected64 = 0x34127856ab90efcdUL;
+
+  if (__rev16_32 (in32) != expected32)
+    abort ();
+
+  if (__rev16_32_alt (in32) != expected32)
+    abort ();
+
+  if (__rev16_64 (in64) != expected64)
+    abort ();
+
+  if (__rev16_64_alt (in64) != expected64)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/arm/rev16.c b/gcc/testsuite/gcc.target/arm/rev16.c
new file mode 100644 (file)
index 0000000..1c869b3
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-options "-O2" } */
+/* { dg-do run } */
+
+extern void abort (void);
+
+typedef unsigned int __u32;
+
+__u32
+__rev16_32_alt (__u32 x)
+{
+  return (((__u32)(x) & (__u32)0xff00ff00UL) >> 8)
+         | (((__u32)(x) & (__u32)0x00ff00ffUL) << 8);
+}
+
+__u32
+__rev16_32 (__u32 x)
+{
+  return (((__u32)(x) & (__u32)0x00ff00ffUL) << 8)
+         | (((__u32)(x) & (__u32)0xff00ff00UL) >> 8);
+}
+
+int
+main (void)
+{
+  volatile __u32 in32 = 0x12345678;
+  volatile __u32 expected32 = 0x34127856;
+
+  if (__rev16_32 (in32) != expected32)
+    abort ();
+
+  if (__rev16_32_alt (in32) != expected32)
+    abort ();
+
+  return 0;
+}