/* 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 "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)
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;