aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJames Greenhalgh <james.greenhalgh@arm.com>2014-05-16 09:16:23 +0000
committerJames Greenhalgh <jgreenhalgh@gcc.gnu.org>2014-05-16 09:16:23 +0000
commita8eecd00ec2693734716d20592e5253ab135929a (patch)
tree139785b2f2b70b527d8178de13ce576137d290e9 /gcc
parent4105fe38857a36b4e604d98a7bbc888225bf187f (diff)
downloadgcc-a8eecd00ec2693734716d20592e5253ab135929a.zip
gcc-a8eecd00ec2693734716d20592e5253ab135929a.tar.gz
gcc-a8eecd00ec2693734716d20592e5253ab135929a.tar.bz2
[AArch64 costs 14/18] Cost comparisons, flag setting operators and IF_THEN_ELSE
gcc/ * config/aarch64/aarch64.c (aarch64_rtx_costs): Cost comparison operators. Co-Authored-By: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> From-SVN: r210506
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/aarch64/aarch64.c159
2 files changed, 154 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cdc7236..86a70cd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,6 +1,12 @@
2014-05-16 James Greenhalgh <james.greenhalgh@arm.com>
Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+ * config/aarch64/aarch64.c (aarch64_rtx_costs): Cost comparison
+ operators.
+
+2014-05-16 James Greenhalgh <james.greenhalgh@arm.com>
+ Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+
* config/aarch64/aarch64.c (aarch64_rtx_costs): Improve costs for
DIV/MOD.
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 6c2682a..8d863ed 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -4868,7 +4868,7 @@ static bool
aarch64_rtx_costs (rtx x, int code, int outer ATTRIBUTE_UNUSED,
int param ATTRIBUTE_UNUSED, int *cost, bool speed)
{
- rtx op0, op1;
+ rtx op0, op1, op2;
const struct cpu_cost_table *extra_cost
= aarch64_tune_params->insn_extra_cost;
enum machine_mode mode = GET_MODE (x);
@@ -5093,16 +5093,77 @@ aarch64_rtx_costs (rtx x, int code, int outer ATTRIBUTE_UNUSED,
goto cost_logic;
}
- /* Comparisons can work if the order is swapped.
- Canonicalization puts the more complex operation first, but
- we want it in op1. */
- if (! (REG_P (op0)
- || (GET_CODE (op0) == SUBREG && REG_P (SUBREG_REG (op0)))))
- {
- op0 = XEXP (x, 1);
- op1 = XEXP (x, 0);
- }
- goto cost_minus;
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
+ {
+ /* TODO: A write to the CC flags possibly costs extra, this
+ needs encoding in the cost tables. */
+
+ /* CC_ZESWPmode supports zero extend for free. */
+ if (GET_MODE (x) == CC_ZESWPmode && GET_CODE (op0) == ZERO_EXTEND)
+ op0 = XEXP (op0, 0);
+
+ /* ANDS. */
+ if (GET_CODE (op0) == AND)
+ {
+ x = op0;
+ goto cost_logic;
+ }
+
+ if (GET_CODE (op0) == PLUS)
+ {
+ /* ADDS (and CMN alias). */
+ x = op0;
+ goto cost_plus;
+ }
+
+ if (GET_CODE (op0) == MINUS)
+ {
+ /* SUBS. */
+ x = op0;
+ goto cost_minus;
+ }
+
+ if (GET_CODE (op1) == NEG)
+ {
+ /* CMN. */
+ if (speed)
+ *cost += extra_cost->alu.arith;
+
+ *cost += rtx_cost (op0, COMPARE, 0, speed);
+ *cost += rtx_cost (XEXP (op1, 0), NEG, 1, speed);
+ return true;
+ }
+
+ /* CMP.
+
+ Compare can freely swap the order of operands, and
+ canonicalization puts the more complex operation first.
+ But the integer MINUS logic expects the shift/extend
+ operation in op1. */
+ if (! (REG_P (op0)
+ || (GET_CODE (op0) == SUBREG && REG_P (SUBREG_REG (op0)))))
+ {
+ op0 = XEXP (x, 1);
+ op1 = XEXP (x, 0);
+ }
+ goto cost_minus;
+ }
+
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+ {
+ /* FCMP. */
+ if (speed)
+ *cost += extra_cost->fp[mode == DFmode].compare;
+
+ if (CONST_DOUBLE_P (op1) && aarch64_float_const_zero_rtx_p (op1))
+ {
+ /* FCMP supports constant 0.0 for no extra cost. */
+ return true;
+ }
+ return false;
+ }
+
+ return false;
case MINUS:
{
@@ -5173,6 +5234,7 @@ cost_minus:
op0 = XEXP (x, 0);
op1 = XEXP (x, 1);
+cost_plus:
if (GET_RTX_CLASS (GET_CODE (op0)) == RTX_COMPARE
|| GET_RTX_CLASS (GET_CODE (op0)) == RTX_COMM_COMPARE)
{
@@ -5504,6 +5566,81 @@ cost_minus:
}
return false; /* All arguments need to be in registers. */
+ case IF_THEN_ELSE:
+ op2 = XEXP (x, 2);
+ op0 = XEXP (x, 0);
+ op1 = XEXP (x, 1);
+
+ if (GET_CODE (op1) == PC || GET_CODE (op2) == PC)
+ {
+ /* Conditional branch. */
+ if (GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+ return true;
+ else
+ {
+ if (GET_CODE (op0) == NE
+ || GET_CODE (op0) == EQ)
+ {
+ rtx inner = XEXP (op0, 0);
+ rtx comparator = XEXP (op0, 1);
+
+ if (comparator == const0_rtx)
+ {
+ /* TBZ/TBNZ/CBZ/CBNZ. */
+ if (GET_CODE (inner) == ZERO_EXTRACT)
+ /* TBZ/TBNZ. */
+ *cost += rtx_cost (XEXP (inner, 0), ZERO_EXTRACT,
+ 0, speed);
+ else
+ /* CBZ/CBNZ. */
+ *cost += rtx_cost (inner, GET_CODE (op0), 0, speed);
+
+ return true;
+ }
+ }
+ else if (GET_CODE (op0) == LT
+ || GET_CODE (op0) == GE)
+ {
+ rtx comparator = XEXP (op0, 1);
+
+ /* TBZ/TBNZ. */
+ if (comparator == const0_rtx)
+ return true;
+ }
+ }
+ }
+ else if (GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+ {
+ /* It's a conditional operation based on the status flags,
+ so it must be some flavor of CSEL. */
+
+ /* CSNEG, CSINV, and CSINC are handled for free as part of CSEL. */
+ if (GET_CODE (op1) == NEG
+ || GET_CODE (op1) == NOT
+ || (GET_CODE (op1) == PLUS && XEXP (op1, 1) == const1_rtx))
+ op1 = XEXP (op1, 0);
+
+ *cost += rtx_cost (op1, IF_THEN_ELSE, 1, speed);
+ *cost += rtx_cost (op2, IF_THEN_ELSE, 2, speed);
+ return true;
+ }
+
+ /* We don't know what this is, cost all operands. */
+ return false;
+
+ case EQ:
+ case NE:
+ case GT:
+ case GTU:
+ case LT:
+ case LTU:
+ case GE:
+ case GEU:
+ case LE:
+ case LEU:
+
+ return false; /* All arguments must be in registers. */
+
default:
break;
}