]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-sra.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / tree-sra.c
index 0cfac0a81924bcd9255e270b6069db04f72010d4..4793b48f32c4d048ba50d471f50d8ac1354563cf 100644 (file)
@@ -285,6 +285,9 @@ static object_allocator<assign_link> assign_link_pool ("SRA links");
 /* Base (tree) -> Vector (vec<access_p> *) map.  */
 static hash_map<tree, auto_vec<access_p> > *base_access_vec;
 
+/* Hash to limit creation of artificial accesses */
+static hash_map<tree, unsigned> *propagation_budget;
+
 /* Candidate hash table helpers.  */
 
 struct uid_decl_hasher : nofree_ptr_hash <tree_node>
@@ -926,6 +929,8 @@ create_access (tree expr, gimple *stmt, bool write)
       size = max_size;
       unscalarizable_region = true;
     }
+  if (size == 0)
+    return NULL;
   if (size < 0)
     {
       disqualify_candidate (base, "Encountered an unconstrained access.");
@@ -958,6 +963,9 @@ scalarizable_type_p (tree type, bool const_decl)
   if (type_contains_placeholder_p (type))
     return false;
 
+  bool have_predecessor_field = false;
+  HOST_WIDE_INT prev_pos = 0;
+
   switch (TREE_CODE (type))
   {
   case RECORD_TYPE:
@@ -966,6 +974,17 @@ scalarizable_type_p (tree type, bool const_decl)
        {
          tree ft = TREE_TYPE (fld);
 
+         if (zerop (DECL_SIZE (fld)))
+           continue;
+
+         HOST_WIDE_INT pos = int_bit_position (fld);
+         if (have_predecessor_field
+             && pos <= prev_pos)
+           return false;
+
+         have_predecessor_field = true;
+         prev_pos = pos;
+
          if (DECL_BIT_FIELD (fld))
            return false;
 
@@ -2126,7 +2145,7 @@ sort_and_splice_var_accesses (tree var)
 /* Create a variable for the given ACCESS which determines the type, name and a
    few other properties.  Return the variable declaration and store it also to
    ACCESS->replacement.  REG_TREE is used when creating a declaration to base a
-   default-definition SSA name on on in order to facilitate an uninitialized
+   default-definition SSA name on in order to facilitate an uninitialized
    warning.  It is used instead of the actual ACCESS type if that is not of a
    gimple register type.  */
 
@@ -2149,15 +2168,9 @@ create_access_replacement (struct access *access, tree reg_type = NULL_TREE)
        variant.  This avoids issues with weirdo ABIs like AAPCS.  */
     repl = create_tmp_var (build_qualified_type (TYPE_MAIN_VARIANT (type),
                                                 TYPE_QUALS (type)), "SR");
-  if (TREE_CODE (type) == COMPLEX_TYPE
-      || TREE_CODE (type) == VECTOR_TYPE)
-    {
-      if (!access->grp_partial_lhs)
-       DECL_GIMPLE_REG_P (repl) = 1;
-    }
-  else if (access->grp_partial_lhs
-          && is_gimple_reg_type (type))
-    TREE_ADDRESSABLE (repl) = 1;
+  if (access->grp_partial_lhs
+      && is_gimple_reg_type (type))
+    DECL_NOT_GIMPLE_REG_P (repl) = 1;
 
   DECL_SOURCE_LOCATION (repl) = DECL_SOURCE_LOCATION (access->base);
   DECL_ARTIFICIAL (repl) = 1;
@@ -2238,7 +2251,7 @@ create_access_replacement (struct access *access, tree reg_type = NULL_TREE)
          print_generic_expr (dump_file, access->base);
          fprintf (dump_file, " offset: %u, size: %u: ",
                   (unsigned) access->offset, (unsigned) access->size);
-         print_generic_expr (dump_file, repl);
+         print_generic_expr (dump_file, repl, TDF_UID);
          fprintf (dump_file, "\n");
        }
     }
@@ -2338,8 +2351,11 @@ verify_sra_access_forest (struct access *root)
       gcc_assert (base == first_base);
       gcc_assert (offset == access->offset);
       gcc_assert (access->grp_unscalarizable_region
+                 || access->grp_total_scalarization
                  || size == max_size);
-      gcc_assert (max_size == access->size);
+      gcc_assert (access->grp_unscalarizable_region
+                 || !is_gimple_reg_type (access->type)
+                 || size == access->size);
       gcc_assert (reverse == access->reverse);
 
       if (access->first_child)
@@ -2670,6 +2686,32 @@ subtree_mark_written_and_rhs_enqueue (struct access *access)
     subtree_mark_written_and_rhs_enqueue (child);
 }
 
+/* If there is still budget to create a propagation access for DECL, return
+   true and decrement the budget.  Otherwise return false.  */
+
+static bool
+budget_for_propagation_access (tree decl)
+{
+  unsigned b, *p = propagation_budget->get (decl);
+  if (p)
+    b = *p;
+  else
+    b = param_sra_max_propagations;
+
+  if (b == 0)
+    return false;
+  b--;
+
+  if (b == 0 && dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "The propagation budget of ");
+      print_generic_expr (dump_file, decl);
+      fprintf (dump_file, " (UID: %u) has been exhausted.\n", DECL_UID (decl));
+    }
+  propagation_budget->put (decl, b);
+  return true;
+}
+
 /* Propagate subaccesses and grp_write flags of RACC across an assignment link
    to LACC.  Enqueue sub-accesses as necessary so that the write flag is
    propagated transitively.  Return true if anything changed.  Additionally, if
@@ -2774,7 +2816,8 @@ propagate_subaccesses_from_rhs (struct access *lacc, struct access *racc)
          continue;
        }
 
-      if (rchild->grp_unscalarizable_region)
+      if (rchild->grp_unscalarizable_region
+         || !budget_for_propagation_access (lacc->base))
        {
          if (rchild->grp_write && !lacc->grp_write)
            {
@@ -2834,7 +2877,8 @@ propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc)
 
       if (lchild->grp_unscalarizable_region
          || child_would_conflict_in_acc (racc, norm_offset, lchild->size,
-                                         &matching_acc))
+                                         &matching_acc)
+         || !budget_for_propagation_access (racc->base))
        {
          if (matching_acc
              && propagate_subaccesses_from_lhs (lchild, matching_acc))
@@ -2865,6 +2909,7 @@ propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc)
 static void
 propagate_all_subaccesses (void)
 {
+  propagation_budget = new hash_map<tree, unsigned>;
   while (rhs_work_queue_head)
     {
       struct access *racc = pop_access_from_rhs_work_queue ();
@@ -2928,6 +2973,7 @@ propagate_all_subaccesses (void)
            add_access_to_lhs_work_queue (racc);
        }
     }
+  delete propagation_budget;
 }
 
 /* Return true if the forest beginning with ROOT does not contain
@@ -3629,7 +3675,8 @@ get_access_for_expr (tree expr)
        return NULL;
     }
 
-  if (!bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
+  if (max_size == 0
+      || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
     return NULL;
 
   return get_var_base_offset_size_access (base, offset, max_size);
@@ -3647,6 +3694,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
   location_t loc;
   struct access *access;
   tree type, bfr, orig_expr;
+  bool partial_cplx_access = false;
 
   if (TREE_CODE (*expr) == BIT_FIELD_REF)
     {
@@ -3657,7 +3705,10 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
     bfr = NULL_TREE;
 
   if (TREE_CODE (*expr) == REALPART_EXPR || TREE_CODE (*expr) == IMAGPART_EXPR)
-    expr = &TREE_OPERAND (*expr, 0);
+    {
+      expr = &TREE_OPERAND (*expr, 0);
+      partial_cplx_access = true;
+    }
   access = get_access_for_expr (*expr);
   if (!access)
     return false;
@@ -3685,13 +3736,32 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
          be accessed as a different type too, potentially creating a need for
          type conversion (see PR42196) and when scalarized unions are involved
          in assembler statements (see PR42398).  */
-      if (!useless_type_conversion_p (type, access->type))
+      if (!bfr && !useless_type_conversion_p (type, access->type))
        {
          tree ref;
 
          ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);
 
-         if (write)
+         if (partial_cplx_access)
+           {
+           /* VIEW_CONVERT_EXPRs in partial complex access are always fine in
+              the case of a write because in such case the replacement cannot
+              be a gimple register.  In the case of a load, we have to
+              differentiate in between a register an non-register
+              replacement.  */
+             tree t = build1 (VIEW_CONVERT_EXPR, type, repl);
+             gcc_checking_assert (!write || access->grp_partial_lhs);
+             if (!access->grp_partial_lhs)
+               {
+                 tree tmp = make_ssa_name (type);
+                 gassign *stmt = gimple_build_assign (tmp, t);
+                 /* This is always a read. */
+                 gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+                 t = tmp;
+               }
+             *expr = t;
+           }
+         else if (write)
            {
              gassign *stmt;