i386.c (legitimize_tls_address): Generate tls_initial_exec_64_sun only when !TARGET_X32.
[gcc.git] / gcc / gimple-fold.c
index 55e7344043c19760dc3454d8c54cede82abefb4d..b2bd33788028349ad5087231f0ae209d3de24046 100644 (file)
@@ -33,8 +33,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 
 /* Return true when DECL can be referenced from current unit.
-   We can get declarations that are not possible to reference for
-   various reasons:
+   FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
+   We can get declarations that are not possible to reference for various
+   reasons:
 
      1) When analyzing C++ virtual tables.
        C++ virtual tables do have known constructors even
@@ -54,26 +55,35 @@ along with GCC; see the file COPYING3.  If not see
         directly.  */
 
 static bool
-can_refer_decl_in_current_unit_p (tree decl)
+can_refer_decl_in_current_unit_p (tree decl, tree from_decl)
 {
   struct varpool_node *vnode;
   struct cgraph_node *node;
-
-  if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+  symtab_node snode;
+
+  /* We will later output the initializer, so we can reffer to it.
+     So we are concerned only when DECL comes from initializer of
+     external var.  */
+  if (!from_decl
+      || TREE_CODE (from_decl) != VAR_DECL
+      || !DECL_EXTERNAL (from_decl)
+      || (symtab_get_node (from_decl)->symbol.in_other_partition))
     return true;
-  /* External flag is set, so we deal with C++ reference
-     to static object from other file.  */
-  if (DECL_EXTERNAL (decl) && TREE_STATIC (decl)
-      && TREE_CODE (decl) == VAR_DECL)
-    {
-      /* Just be sure it is not big in frontend setting
-        flags incorrectly.  Those variables should never
-        be finalized.  */
-      gcc_checking_assert (!(vnode = varpool_get_node (decl))
-                          || vnode->alias
-                          || !vnode->finalized);
-      return false;
-    }
+  /* We are concerned ony about static/external vars and functions.  */
+  if ((!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+      || (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL))
+    return true;
+  /* Weakrefs have somewhat confusing DECL_EXTERNAL flag set; they are always safe.  */
+  if (DECL_EXTERNAL (decl)
+      && lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    return true;
+  /* We are folding reference from external vtable.  The vtable may reffer
+     to a symbol keyed to other compilation unit.  The other compilation
+     unit may be in separate DSO and the symbol may be hidden.  */
+  if (DECL_VISIBILITY_SPECIFIED (decl)
+      && DECL_EXTERNAL (decl)
+      && (!(snode = symtab_get_node (decl)) || !snode->symbol.in_other_partition))
+    return false;
   /* When function is public, we always can introduce new reference.
      Exception are the COMDAT functions where introducing a direct
      reference imply need to include function body in the curren tunit.  */
@@ -82,14 +92,19 @@ can_refer_decl_in_current_unit_p (tree decl)
   /* We are not at ltrans stage; so don't worry about WHOPR.
      Also when still gimplifying all referred comdat functions will be
      produced.
-     ??? as observed in PR20991 for already optimized out comdat virtual functions
-     we may not neccesarily give up because the copy will be output elsewhere when
-     corresponding vtable is output.  */
+
+     As observed in PR20991 for already optimized out comdat virtual functions
+     it may be tempting to not necessarily give up because the copy will be
+     output elsewhere when corresponding vtable is output.  
+     This is however not possible - ABI specify that COMDATs are output in
+     units where they are used and when the other unit was compiled with LTO
+     it is possible that vtable was kept public while the function itself
+     was privatized. */
   if (!flag_ltrans && (!DECL_COMDAT (decl) || !cgraph_function_flags_ready))
     return true;
-  /* If we already output the function body, we are safe.  */
-  if (TREE_ASM_WRITTEN (decl))
-    return true;
+
+  /* OK we are seeing either COMDAT or static variable.  In this case we must
+     check that the definition is still around so we can refer it.  */
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       node = cgraph_get_node (decl);
@@ -99,22 +114,29 @@ can_refer_decl_in_current_unit_p (tree decl)
          compilation stage when making a new reference no longer makes callee
          to be compiled.  */
       if (!node || !node->analyzed || node->global.inlined_to)
-       return false;
+       {
+         gcc_checking_assert (!TREE_ASM_WRITTEN (decl));
+         return false;
+       }
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
       vnode = varpool_get_node (decl);
-      if (!vnode || !vnode->finalized)
-       return false;
+      if (!vnode || !vnode->analyzed)
+       {
+         gcc_checking_assert (!TREE_ASM_WRITTEN (decl));
+         return false;
+       }
     }
   return true;
 }
 
 /* CVAL is value taken from DECL_INITIAL of variable.  Try to transform it into
-   acceptable form for is_gimple_min_invariant.   */
+   acceptable form for is_gimple_min_invariant.
+   FROM_DECL (if non-NULL) specify variable whose constructor contains CVAL.  */
 
 tree
-canonicalize_constructor_val (tree cval)
+canonicalize_constructor_val (tree cval, tree from_decl)
 {
   STRIP_NOPS (cval);
   if (TREE_CODE (cval) == POINTER_PLUS_EXPR
@@ -132,17 +154,24 @@ canonicalize_constructor_val (tree cval)
   if (TREE_CODE (cval) == ADDR_EXPR)
     {
       tree base = get_base_address (TREE_OPERAND (cval, 0));
+      if (!base && TREE_CODE (TREE_OPERAND (cval, 0)) == COMPOUND_LITERAL_EXPR)
+       {
+         base = COMPOUND_LITERAL_EXPR_DECL (TREE_OPERAND (cval, 0));
+         if (base)
+           TREE_OPERAND (cval, 0) = base;
+       }
       if (!base)
        return NULL_TREE;
 
       if ((TREE_CODE (base) == VAR_DECL
           || TREE_CODE (base) == FUNCTION_DECL)
-         && !can_refer_decl_in_current_unit_p (base))
+         && !can_refer_decl_in_current_unit_p (base, from_decl))
        return NULL_TREE;
       if (TREE_CODE (base) == VAR_DECL)
        {
          TREE_ADDRESSABLE (base) = 1;
-         if (cfun && gimple_referenced_vars (cfun))
+         if (cfun && gimple_referenced_vars (cfun)
+             && !is_global_var (base))
            add_referenced_var (base);
        }
       else if (TREE_CODE (base) == FUNCTION_DECL)
@@ -170,7 +199,7 @@ get_symbol_constant_value (tree sym)
       tree val = DECL_INITIAL (sym);
       if (val)
        {
-         val = canonicalize_constructor_val (val);
+         val = canonicalize_constructor_val (val, sym);
          if (val && is_gimple_min_invariant (val))
            return val;
          else
@@ -625,7 +654,7 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
       new_stmt = gsi_stmt (i);
       /* The replacement can expose previously unreferenced variables.  */
       if (gimple_in_ssa_p (cfun))
-       find_new_referenced_vars (new_stmt);
+       find_referenced_vars_in (new_stmt);
       /* If the new statement possibly has a VUSE, update it with exact SSA
         name we know will reach this one.  */
       if (gimple_has_mem_ops (new_stmt))
@@ -670,13 +699,10 @@ get_maxval_strlen (tree arg, tree *length, bitmap visited, int type)
 
   if (TREE_CODE (arg) != SSA_NAME)
     {
-      if (TREE_CODE (arg) == COND_EXPR)
-        return get_maxval_strlen (COND_EXPR_THEN (arg), length, visited, type)
-               && get_maxval_strlen (COND_EXPR_ELSE (arg), length, visited, type);
       /* We can end up with &(*iftmp_1)[0] here as well, so handle it.  */
-      else if (TREE_CODE (arg) == ADDR_EXPR
-              && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
-              && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
+      if (TREE_CODE (arg) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
+         && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
        {
          tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
          if (TREE_CODE (aop0) == INDIRECT_REF
@@ -736,6 +762,13 @@ get_maxval_strlen (tree arg, tree *length, bitmap visited, int type)
             tree rhs = gimple_assign_rhs1 (def_stmt);
             return get_maxval_strlen (rhs, length, visited, type);
           }
+       else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
+         {
+           tree op2 = gimple_assign_rhs2 (def_stmt);
+           tree op3 = gimple_assign_rhs3 (def_stmt);
+           return get_maxval_strlen (op2, length, visited, type)
+                  && get_maxval_strlen (op3, length, visited, type);
+          }
         return false;
 
       case GIMPLE_PHI:
@@ -1027,7 +1060,7 @@ gimple_extract_devirt_binfo_from_cst (tree cst)
       type = TREE_TYPE (fld);
       offset -= pos;
     }
-  /* Artifical sub-objects are ancestors, we do not want to use them for
+  /* Artificial sub-objects are ancestors, we do not want to use them for
      devirtualization, at least not here.  */
   if (last_artificial)
     return NULL_TREE;
@@ -2630,7 +2663,7 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree))
 
 static tree fold_ctor_reference (tree type, tree ctor,
                                 unsigned HOST_WIDE_INT offset,
-                                unsigned HOST_WIDE_INT size);
+                                unsigned HOST_WIDE_INT size, tree);
 
 /* See if we can find constructor defining value of BASE.
    When we know the consructor with constant offset (such as
@@ -2738,7 +2771,8 @@ fold_string_cst_ctor_reference (tree type, tree ctor,
 static tree
 fold_array_ctor_reference (tree type, tree ctor,
                           unsigned HOST_WIDE_INT offset,
-                          unsigned HOST_WIDE_INT size)
+                          unsigned HOST_WIDE_INT size,
+                          tree from_decl)
 {
   unsigned HOST_WIDE_INT cnt;
   tree cfield, cval;
@@ -2827,7 +2861,8 @@ fold_array_ctor_reference (tree type, tree ctor,
       /* Do we have match?  */
       if (double_int_cmp (access_index, index, 1) >= 0
          && double_int_cmp (access_index, max_index, 1) <= 0)
-       return fold_ctor_reference (type, cval, inner_offset, size);
+       return fold_ctor_reference (type, cval, inner_offset, size,
+                                   from_decl);
     }
   /* When memory is not explicitely mentioned in constructor,
      it is 0 (or out of range).  */
@@ -2840,7 +2875,8 @@ fold_array_ctor_reference (tree type, tree ctor,
 static tree
 fold_nonarray_ctor_reference (tree type, tree ctor,
                              unsigned HOST_WIDE_INT offset,
-                             unsigned HOST_WIDE_INT size)
+                             unsigned HOST_WIDE_INT size,
+                             tree from_decl)
 {
   unsigned HOST_WIDE_INT cnt;
   tree cfield, cval;
@@ -2895,7 +2931,8 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
          if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) < 0)
            return NULL_TREE;
          return fold_ctor_reference (type, cval,
-                                     double_int_to_uhwi (inner_offset), size);
+                                     double_int_to_uhwi (inner_offset), size,
+                                     from_decl);
        }
     }
   /* When memory is not explicitely mentioned in constructor, it is 0.  */
@@ -2907,14 +2944,14 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
 
 static tree
 fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
-                    unsigned HOST_WIDE_INT size)
+                    unsigned HOST_WIDE_INT size, tree from_decl)
 {
   tree ret;
 
   /* We found the field with exact match.  */
   if (useless_type_conversion_p (type, TREE_TYPE (ctor))
       && !offset)
-    return canonicalize_constructor_val (ctor);
+    return canonicalize_constructor_val (ctor, from_decl);
 
   /* We are at the end of walk, see if we can view convert the
      result.  */
@@ -2923,7 +2960,7 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
       && operand_equal_p (TYPE_SIZE (type),
                          TYPE_SIZE (TREE_TYPE (ctor)), 0))
     {
-      ret = canonicalize_constructor_val (ctor);
+      ret = canonicalize_constructor_val (ctor, from_decl);
       ret = fold_unary (VIEW_CONVERT_EXPR, type, ret);
       if (ret)
        STRIP_NOPS (ret);
@@ -2936,9 +2973,11 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
 
       if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE
          || TREE_CODE (TREE_TYPE (ctor)) == VECTOR_TYPE)
-       return fold_array_ctor_reference (type, ctor, offset, size);
+       return fold_array_ctor_reference (type, ctor, offset, size,
+                                         from_decl);
       else
-       return fold_nonarray_ctor_reference (type, ctor, offset, size);
+       return fold_nonarray_ctor_reference (type, ctor, offset, size,
+                                            from_decl);
     }
 
   return NULL_TREE;
@@ -3011,7 +3050,8 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
                return NULL_TREE;
              return fold_ctor_reference (TREE_TYPE (t), ctor, offset,
                                          TREE_INT_CST_LOW (unit_size)
-                                         * BITS_PER_UNIT);
+                                         * BITS_PER_UNIT,
+                                         base);
            }
        }
       /* Fallthru.  */
@@ -3037,7 +3077,8 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
       if (offset < 0)
        return NULL_TREE;
 
-      return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size);
+      return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size,
+                                 base);
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
@@ -3071,9 +3112,9 @@ tree
 gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
 {
   unsigned HOST_WIDE_INT offset, size;
-  tree v, fn;
+  tree v, fn, vtable;
 
-  v = BINFO_VTABLE (known_binfo);
+  vtable = v = BINFO_VTABLE (known_binfo);
   /* If there is no virtual methods table, leave the OBJ_TYPE_REF alone.  */
   if (!v)
     return NULL_TREE;
@@ -3099,7 +3140,7 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
   size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))), 1);
   offset += token * size;
   fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v),
-                           offset, size);
+                           offset, size, vtable);
   if (!fn || integer_zerop (fn))
     return NULL_TREE;
   gcc_assert (TREE_CODE (fn) == ADDR_EXPR
@@ -3111,7 +3152,7 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
      devirtualize.  This can happen in WHOPR when the actual method
      ends up in other partition, because we found devirtualization
      possibility too late.  */
-  if (!can_refer_decl_in_current_unit_p (fn))
+  if (!can_refer_decl_in_current_unit_p (fn, vtable))
     return NULL_TREE;
 
   /* Make sure we create a cgraph node for functions we'll reference.