/* A pass for lowering trees to RTL.
- Copyright (C) 2004-2019 Free Software Foundation, Inc.
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
This file is part of GCC.
stack_vars[b].representative = a;
stack_vars[a].next = b;
+ /* Make sure A is big enough to hold B. */
+ stack_vars[a].size = upper_bound (stack_vars[a].size, stack_vars[b].size);
+
/* Update the required alignment of partition A to account for B. */
if (stack_vars[a].alignb < stack_vars[b].alignb)
stack_vars[a].alignb = stack_vars[b].alignb;
}
/* Ensure that variables in different stack protection phases conflict
- so that they are not merged and share the same stack slot. */
+ so that they are not merged and share the same stack slot.
+ Return true if there are any address taken variables. */
-static void
+static bool
add_stack_protection_conflicts (void)
{
size_t i, j, n = stack_vars_num;
unsigned char *phase;
+ bool ret = false;
phase = XNEWVEC (unsigned char, n);
for (i = 0; i < n; ++i)
- phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
+ {
+ phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
+ if (TREE_ADDRESSABLE (stack_vars[i].decl))
+ ret = true;
+ }
for (i = 0; i < n; ++i)
{
}
XDELETEVEC (phase);
+ return ret;
}
/* Create a decl for the guard at the top of the stack frame. */
return estimated_poly_value (size);
}
-/* Helper routine to check if a record or union contains an array field. */
-
-static int
-record_or_union_type_has_array_p (const_tree tree_type)
-{
- tree fields = TYPE_FIELDS (tree_type);
- tree f;
-
- for (f = fields; f; f = DECL_CHAIN (f))
- if (TREE_CODE (f) == FIELD_DECL)
- {
- tree field_type = TREE_TYPE (f);
- if (RECORD_OR_UNION_TYPE_P (field_type)
- && record_or_union_type_has_array_p (field_type))
- return 1;
- if (TREE_CODE (field_type) == ARRAY_TYPE)
- return 1;
- }
- return 0;
-}
-
-/* Check if the current function has local referenced variables that
- have their addresses taken, contain an array, or are arrays. */
-
-static bool
-stack_protect_decl_p ()
-{
- unsigned i;
- tree var;
-
- FOR_EACH_LOCAL_DECL (cfun, i, var)
- if (!is_global_var (var))
- {
- tree var_type = TREE_TYPE (var);
- if (VAR_P (var)
- && (TREE_CODE (var_type) == ARRAY_TYPE
- || TREE_ADDRESSABLE (var)
- || (RECORD_OR_UNION_TYPE_P (var_type)
- && record_or_union_type_has_array_p (var_type))))
- return true;
- }
- return false;
-}
-
/* Check if the current function has calls that use a return slot. */
static bool
}
if (flag_stack_protect == SPCT_FLAG_STRONG)
- gen_stack_protect_signal
- = stack_protect_decl_p () || stack_protect_return_slot_p ();
+ gen_stack_protect_signal = stack_protect_return_slot_p ();
/* At this point all variables on the local_decls with TREE_USED
set are not associated with any block scope. Lay them out. */
if (stack_vars_num > 0)
{
+ bool has_addressable_vars = false;
+
add_scope_conflicts ();
/* If stack protection is enabled, we don't share space between
|| (flag_stack_protect == SPCT_FLAG_EXPLICIT
&& lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))))
- add_stack_protection_conflicts ();
+ has_addressable_vars = add_stack_protection_conflicts ();
+
+ if (flag_stack_protect == SPCT_FLAG_STRONG && has_addressable_vars)
+ gen_stack_protect_signal = true;
/* Now that we have collected all stack variables, and have computed a
minimal interference graph, attempt to save some stack space. */
case SPCT_FLAG_STRONG:
if (gen_stack_protect_signal
- || cfun->calls_alloca || has_protected_decls
+ || cfun->calls_alloca
+ || has_protected_decls
|| lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
break;
case SPCT_FLAG_DEFAULT:
- if (cfun->calls_alloca || has_protected_decls
+ if (cfun->calls_alloca
+ || has_protected_decls
|| lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
break;
+
default:
- ;
+ break;
}
/* Assign rtl to each variable based on these partitions. */
case VEC_PERM_EXPR:
case VEC_DUPLICATE_EXPR:
case VEC_SERIES_EXPR:
+ case SAD_EXPR:
return NULL;
/* Misc codes. */
*walk_subtrees = 0;
}
+ /* References of size POLY_INT_CST to a fixed-size object must go
+ through memory. It's more efficient to force that here than
+ to create temporary slots on the fly. */
+ else if ((TREE_CODE (t) == MEM_REF || TREE_CODE (t) == TARGET_MEM_REF)
+ && TYPE_SIZE (TREE_TYPE (t))
+ && POLY_INT_CST_P (TYPE_SIZE (TREE_TYPE (t))))
+ {
+ tree base = get_base_address (t);
+ if (base
+ && DECL_P (base)
+ && DECL_MODE (base) != BLKmode
+ && GET_MODE_SIZE (DECL_MODE (base)).is_constant ())
+ TREE_ADDRESSABLE (base) = 1;
+ *walk_subtrees = 0;
+ }
return NULL_TREE;
}
+/* If there's a chance to get a pseudo for t then if it would be of float mode
+ and the actual access is via an integer mode (lowered memcpy or similar
+ access) then avoid the register expansion if the mode likely is not storage
+ suitable for raw bits processing (like XFmode on i?86). */
+
+static void
+avoid_type_punning_on_regs (tree t)
+{
+ machine_mode access_mode = TYPE_MODE (TREE_TYPE (t));
+ if (access_mode != BLKmode
+ && !SCALAR_INT_MODE_P (access_mode))
+ return;
+ tree base = get_base_address (t);
+ if (DECL_P (base)
+ && !TREE_ADDRESSABLE (base)
+ && FLOAT_MODE_P (DECL_MODE (base))
+ && maybe_lt (GET_MODE_PRECISION (DECL_MODE (base)),
+ GET_MODE_BITSIZE (GET_MODE_INNER (DECL_MODE (base))))
+ /* Double check in the expensive way we really would get a pseudo. */
+ && use_register_for_decl (base))
+ TREE_ADDRESSABLE (base) = 1;
+}
+
/* RTL expansion is not able to compile array references with variable
offsets for arrays stored in single register. Discover such
expressions and mark variables as addressable to avoid this
default:
break;
}
+ if (gimple_vdef (stmt))
+ {
+ tree t = gimple_get_lhs (stmt);
+ if (t && REFERENCE_CLASS_P (t))
+ avoid_type_punning_on_regs (t);
+ }
}
}
}
if (crtl->tail_call_emit)
fixup_tail_calls ();
- /* BB subdivision may have created basic blocks that are are only reachable
+ unsigned HOST_WIDE_INT patch_area_size = function_entry_patch_area_size;
+ unsigned HOST_WIDE_INT patch_area_entry = function_entry_patch_area_start;
+
+ tree patchable_function_entry_attr
+ = lookup_attribute ("patchable_function_entry",
+ DECL_ATTRIBUTES (cfun->decl));
+ if (patchable_function_entry_attr)
+ {
+ tree pp_val = TREE_VALUE (patchable_function_entry_attr);
+ tree patchable_function_entry_value1 = TREE_VALUE (pp_val);
+
+ patch_area_size = tree_to_uhwi (patchable_function_entry_value1);
+ patch_area_entry = 0;
+ if (TREE_CHAIN (pp_val) != NULL_TREE)
+ {
+ tree patchable_function_entry_value2
+ = TREE_VALUE (TREE_CHAIN (pp_val));
+ patch_area_entry = tree_to_uhwi (patchable_function_entry_value2);
+ }
+ }
+
+ if (patch_area_entry > patch_area_size)
+ {
+ if (patch_area_size > 0)
+ warning (OPT_Wattributes,
+ "patchable function entry %wu exceeds size %wu",
+ patch_area_entry, patch_area_size);
+ patch_area_entry = 0;
+ }
+
+ crtl->patch_area_size = patch_area_size;
+ crtl->patch_area_entry = patch_area_entry;
+
+ /* BB subdivision may have created basic blocks that are only reachable
from unlikely bbs but not marked as such in the profile. */
if (optimize)
propagate_unlikely_bbs_forward ();