utils.c (scale_by_factor_of): When handling a function call expression, process the...
authorPierre-Marie de Rodat <derodat@adacore.com>
Mon, 1 Jun 2015 09:03:34 +0000 (09:03 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 1 Jun 2015 09:03:34 +0000 (09:03 +0000)
* gcc-interface/utils.c (scale_by_factor_of): When handling a function
call expression, process the corresponding function body.  Also handle
potential addends.

From-SVN: r223921

gcc/ada/ChangeLog
gcc/ada/gcc-interface/utils.c

index 7c03f7e547ed1f30c69ddc0cce949ec3b091ea0e..61fb680ddb0feb87dd0bc5875fe1acbc09ae3bcf 100644 (file)
@@ -1,3 +1,9 @@
+2015-06-01  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * gcc-interface/utils.c (scale_by_factor_of): When handling a function
+       call expression, process the corresponding function body.  Also handle
+       potential addends.
+
 2015-06-01  Pierre-Marie de Rodat  <derodat@adacore.com>
 
        * gcc-interface/decl.c (gnat_to_gnu_entity): Replace pointer types with
index 7ec0974f912c998dc0f62a4fd64be43482f80a99..77d00b325f39b03ea996dc227abf1d72b0d7faf6 100644 (file)
@@ -2908,7 +2908,24 @@ process_deferred_decl_context (bool force)
 static unsigned int
 scale_by_factor_of (tree expr, unsigned int value)
 {
+  unsigned HOST_WIDE_INT addend = 0;
+  unsigned HOST_WIDE_INT factor = 1;
+
+  /* Peel conversions around EXPR and try to extract bodies from function
+     calls: it is possible to get the scale factor from size functions.  */
   expr = remove_conversions (expr, true);
+  if (TREE_CODE (expr) == CALL_EXPR)
+    expr = maybe_inline_call_in_expr (expr);
+
+  /* Sometimes we get PLUS_EXPR (BIT_AND_EXPR (..., X), Y), where Y is a
+     multiple of the scale factor we are looking for.  */
+  if (TREE_CODE (expr) == PLUS_EXPR
+      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
+      && tree_fits_uhwi_p (TREE_OPERAND (expr, 1)))
+    {
+      addend = TREE_INT_CST_LOW (TREE_OPERAND (expr, 1));
+      expr = TREE_OPERAND (expr, 0);
+    }
 
   /* An expression which is a bitwise AND with a mask has a power-of-2 factor
      corresponding to the number of trailing zeros of the mask.  */
@@ -2921,12 +2938,21 @@ scale_by_factor_of (tree expr, unsigned int value)
       while ((mask & 1) == 0 && i < HOST_BITS_PER_WIDE_INT)
        {
          mask >>= 1;
-         value *= 2;
+         factor *= 2;
          i++;
        }
     }
 
-  return value;
+  /* If the addend is not a multiple of the factor we found, give up.  In
+     theory we could find a smaller common factor but it's useless for our
+     needs.  This situation arises when dealing with a field F1 with no
+     alignment requirement but that is following a field F2 with such
+     requirements.  As long as we have F2's offset, we don't need alignment
+     information to compute F1's.  */
+  if (addend % factor != 0)
+    factor = 1;
+
+  return factor * value;
 }
 
 /* Given two consecutive field decls PREV_FIELD and CURR_FIELD, return true