Hi,
  The problem here is aarch64_rtx_costs for IF_THEN_ELSE does not
handle the case where the first operand is a non comparison.  This
happens when the combine is combing a few RTLs and calling
set_src_cost to check the costs of the newly created rtl.

At the same I noticed the code for rtx_costs was getting more complex
so I factored out the code for IF_THEN_ELSE

OK?  Built and tested on aarch64-elf with no regressions.

Thanks,
Andrew Pinski

ChangeLog:
* config/aarch64/aarch64.c (aarch64_if_then_else_costs): New function.
(aarch64_rtx_costs): Use aarch64_if_then_else_costs.

testsuite/ChangeLog:
* gcc.c-torture/compile/20140528-1.c: New testcase.
commit d2a89a0b21f13e676a863eeb3ac1f9ad927e65ac
Author: Andrew Pinski <apin...@cavium.com>
Date:   Wed May 28 15:44:05 2014 -0700

    Fix kernel.

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index c2f6c4f..32c5fcb 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -4848,6 +4848,80 @@ aarch64_rtx_arith_op_extract_p (rtx x, enum machine_mode 
mode)
   return false;
 }
 
+/* Calculate the cost of calculating (if_then_else (OP0) (OP1) (OP2)),
+   storing it in *COST.  Result is true if the total cost of the operation
+   has now been calculated.  */
+static bool
+aarch64_if_then_else_costs (rtx op0, rtx op1, rtx op2, int *cost, bool speed)
+{
+  rtx inner;
+  rtx comparator;
+  enum rtx_code cmpcode;
+  if (COMPARISON_P (op0))
+    {
+      inner = XEXP (op0, 0);
+      comparator = XEXP (op0, 1);
+      cmpcode = GET_CODE (op0);
+    }
+  else
+    {
+      inner = op0;
+      comparator = const0_rtx;
+      cmpcode = NE;
+    }
+
+  if (GET_CODE (op1) == PC || GET_CODE (op2) == PC)
+    {
+      /* Conditional branch.  */
+      if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_CC)
+       return true;
+      else
+       {
+         if (cmpcode == NE || cmpcode == EQ)
+           {
+             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, cmpcode, 0, speed);
+
+               return true;
+             }
+           }
+         else if (cmpcode == LT || cmpcode == GE)
+           {
+             /* TBZ/TBNZ.  */
+             if (comparator == const0_rtx)
+               return true;
+           }
+       }
+    }
+  else if (GET_MODE_CLASS (GET_MODE (inner)) == 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;
+
+}
+
 /* Calculate the cost of calculating X, storing it in *COST.  Result
    is true if the total cost of the operation has now been calculated.  */
 static bool
@@ -5582,67 +5656,9 @@ cost_plus:
       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;
-
+      return aarch64_if_then_else_costs (XEXP (x, 0), XEXP (x, 1),
+                                        XEXP (x, 2), cost, speed);
+      
     case EQ:
     case NE:
     case GT:
diff --git a/gcc/testsuite/gcc.c-torture/compile/20140528-1.c 
b/gcc/testsuite/gcc.c-torture/compile/20140528-1.c
new file mode 100644
index 0000000..d227802
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/20140528-1.c
@@ -0,0 +1,9 @@
+unsigned f(unsigned flags, unsigned capabilities)
+{
+  unsigned gfp_mask;
+  unsigned gfp_notmask = 0;
+  gfp_mask = flags & ((1 << 25) - 1);
+  if (!(capabilities & 0x00000001))
+    gfp_mask |= 0x1000000u;
+  return (gfp_mask & ~gfp_notmask);
+}

Reply via email to