/* Conditional constant propagation pass for the GNU compiler.
- Copyright (C) 2000-2019 Free Software Foundation, Inc.
+ Copyright (C) 2000-2020 Free Software Foundation, Inc.
Adapted from original RTL SSA-CCP by Daniel Berlin <dberlin@dberlin.org>
Adapted to GIMPLE trees by Diego Novillo <dnovillo@redhat.com>
#include "tree-cfg.h"
#include "tree-ssa-propagate.h"
#include "dbgcnt.h"
-#include "params.h"
#include "builtins.h"
#include "cfgloop.h"
#include "stor-layout.h"
#include "stringpool.h"
#include "attribs.h"
#include "tree-vector-builder.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-utils.h"
+#include "ipa-prop.h"
/* Possible lattice values. */
typedef enum
if (flag_tree_bit_ccp)
{
wide_int nonzero_bits = get_nonzero_bits (var);
- if (nonzero_bits != -1)
+ tree value;
+ widest_int mask;
+
+ if (SSA_NAME_VAR (var)
+ && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL
+ && ipcp_get_parm_bits (SSA_NAME_VAR (var), &value, &mask))
+ {
+ val.lattice_val = CONSTANT;
+ val.value = value;
+ val.mask = mask;
+ if (nonzero_bits != -1)
+ val.mask &= extend_mask (nonzero_bits,
+ TYPE_SIGN (TREE_TYPE (var)));
+ }
+ else if (nonzero_bits != -1)
{
val.lattice_val = CONSTANT;
val.value = build_zero_cst (TREE_TYPE (var));
- val.mask = extend_mask (nonzero_bits, TYPE_SIGN (TREE_TYPE (var)));
+ val.mask = extend_mask (nonzero_bits,
+ TYPE_SIGN (TREE_TYPE (var)));
}
}
}
class ccp_folder : public substitute_and_fold_engine
{
public:
- tree get_value (tree) FINAL OVERRIDE;
+ tree get_value (tree, gimple *) FINAL OVERRIDE;
bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
};
of calling member functions. */
tree
-ccp_folder::get_value (tree op)
+ccp_folder::get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED)
{
return get_constant_value (op);
}
TYPE_SIGN (TREE_TYPE (rhs2)), TYPE_PRECISION (TREE_TYPE (rhs2)),
value_to_wide_int (r2val), r2val.mask);
+ /* (x * x) & 2 == 0. */
+ if (code == MULT_EXPR && rhs1 == rhs2 && TYPE_PRECISION (type) > 1)
+ {
+ widest_int m = 2;
+ if (wi::sext (mask, TYPE_PRECISION (type)) != -1)
+ value = wi::bit_and_not (value, m);
+ else
+ value = 0;
+ mask = wi::bit_and_not (mask, m);
+ }
+
if (wi::sext (mask, TYPE_PRECISION (type)) != -1)
{
val.lattice_val = CONSTANT;
case BUILT_IN_BSWAP16:
case BUILT_IN_BSWAP32:
case BUILT_IN_BSWAP64:
+ case BUILT_IN_BSWAP128:
val = get_value_for_expr (gimple_call_arg (stmt, 0), true);
if (val.lattice_val == UNDEFINED)
break;
else if (gimple_assign_ssa_name_copy_p (stmt))
insert_clobber_before_stack_restore (gimple_assign_lhs (stmt), var,
visited);
- else
- gcc_assert (is_gimple_debug (stmt));
}
/* Advance the iterator to the previous non-debug gimple statement in the same
gsi_prev_nondebug (i);
while (gsi_end_p (*i))
{
- dom = get_immediate_dominator (CDI_DOMINATORS, i->bb);
+ dom = get_immediate_dominator (CDI_DOMINATORS, gsi_bb (*i));
if (dom == NULL || dom == ENTRY_BLOCK_PTR_FOR_FN (cfun))
return;
/* Find a BUILT_IN_STACK_SAVE dominating gsi_stmt (I), and insert
a clobber of VAR before each matching BUILT_IN_STACK_RESTORE.
- It is possible that BUILT_IN_STACK_SAVE cannot be find in a dominator when a
- previous pass (such as DOM) duplicated it along multiple paths to a BB. In
- that case the function gives up without inserting the clobbers. */
+ It is possible that BUILT_IN_STACK_SAVE cannot be found in a dominator when
+ a previous pass (such as DOM) duplicated it along multiple paths to a BB.
+ In that case the function gives up without inserting the clobbers. */
static void
insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
size = tree_to_uhwi (arg);
/* Heuristic: don't fold large allocas. */
- threshold = (unsigned HOST_WIDE_INT)PARAM_VALUE (PARAM_LARGE_STACK_FRAME);
+ threshold = (unsigned HOST_WIDE_INT)param_large_stack_frame;
/* In case the alloca is located at function entry, it has the same lifetime
as a declared array, so we allow a larger size. */
block = gimple_block (stmt);
elem_type = build_nonstandard_integer_type (BITS_PER_UNIT, 1);
n_elem = size * 8 / BITS_PER_UNIT;
array_type = build_array_type_nelts (elem_type, n_elem);
- var = create_tmp_var (array_type);
+
+ if (tree ssa_name = SSA_NAME_IDENTIFIER (lhs))
+ {
+ /* Give the temporary a name derived from the name of the VLA
+ declaration so it can be referenced in diagnostics. */
+ const char *name = IDENTIFIER_POINTER (ssa_name);
+ var = create_tmp_var (array_type, name);
+ }
+ else
+ var = create_tmp_var (array_type);
+
+ if (gimple *lhsdef = SSA_NAME_DEF_STMT (lhs))
+ {
+ /* Set the temporary's location to that of the VLA declaration
+ so it can be pointed to in diagnostics. */
+ location_t loc = gimple_location (lhsdef);
+ DECL_SOURCE_LOCATION (var) = loc;
+ }
+
SET_DECL_ALIGN (var, TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)));
if (uid != 0)
SET_DECL_PT_UID (var, uid);
if (!is_gimple_call (stmt) || gimple_no_warning_p (stmt))
continue;
- if (warn_nonnull)
+ tree fntype = gimple_call_fntype (stmt);
+ bitmap nonnullargs = get_nonnull_args (fntype);
+ if (!nonnullargs)
+ continue;
+
+ tree fndecl = gimple_call_fndecl (stmt);
+
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
{
- bitmap nonnullargs
- = get_nonnull_args (gimple_call_fntype (stmt));
- if (nonnullargs)
+ tree arg = gimple_call_arg (stmt, i);
+ if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+ continue;
+ if (!integer_zerop (arg))
+ continue;
+ if (!bitmap_empty_p (nonnullargs)
+ && !bitmap_bit_p (nonnullargs, i))
+ continue;
+
+ /* In C++ non-static member functions argument 0 refers
+ to the implicit this pointer. Use the same one-based
+ numbering for ordinary arguments. */
+ unsigned argno = TREE_CODE (fntype) == METHOD_TYPE ? i : i + 1;
+ location_t loc = (EXPR_HAS_LOCATION (arg)
+ ? EXPR_LOCATION (arg)
+ : gimple_location (stmt));
+ auto_diagnostic_group d;
+ if (argno == 0)
{
- for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
- {
- tree arg = gimple_call_arg (stmt, i);
- if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
- continue;
- if (!integer_zerop (arg))
- continue;
- if (!bitmap_empty_p (nonnullargs)
- && !bitmap_bit_p (nonnullargs, i))
- continue;
-
- location_t loc = gimple_location (stmt);
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wnonnull,
- "%Gargument %u null where non-null "
- "expected", stmt, i + 1))
- {
- tree fndecl = gimple_call_fndecl (stmt);
- if (fndecl && DECL_IS_BUILTIN (fndecl))
- inform (loc, "in a call to built-in function %qD",
- fndecl);
- else if (fndecl)
- inform (DECL_SOURCE_LOCATION (fndecl),
- "in a call to function %qD declared here",
- fndecl);
-
- }
- }
- BITMAP_FREE (nonnullargs);
+ if (warning_at (loc, OPT_Wnonnull,
+ "%G%qs pointer null", stmt, "this")
+ && fndecl)
+ inform (DECL_SOURCE_LOCATION (fndecl),
+ "in a call to non-static member function %qD",
+ fndecl);
+ continue;
}
+
+ if (!warning_at (loc, OPT_Wnonnull,
+ "%Gargument %u null where non-null "
+ "expected", stmt, argno))
+ continue;
+
+ tree fndecl = gimple_call_fndecl (stmt);
+ if (fndecl && DECL_IS_BUILTIN (fndecl))
+ inform (loc, "in a call to built-in function %qD",
+ fndecl);
+ else if (fndecl)
+ inform (DECL_SOURCE_LOCATION (fndecl),
+ "in a call to function %qD declared %qs",
+ fndecl, "nonnull");
}
+ BITMAP_FREE (nonnullargs);
}
}
return 0;