static void gimple_make_forwarder_block (edge);
static void gimple_cfg2vcg (FILE *);
static gimple first_non_label_stmt (basic_block);
+static bool verify_gimple_transaction (gimple);
/* Flowgraph optimization and cleanup. */
static void gimple_merge_blocks (basic_block, basic_block);
}
break;
+ case GIMPLE_TRANSACTION:
+ {
+ tree abort_label = gimple_transaction_label (last);
+ if (abort_label)
+ make_edge (bb, label_to_block (abort_label), 0);
+ fallthru = true;
+ }
+ break;
+
default:
gcc_assert (!stmt_ends_bb_p (last));
fallthru = true;
FOR_EACH_BB (bb)
{
gimple stmt = last_stmt (bb);
+ tree label, new_label;
+
if (!stmt)
continue;
switch (gimple_code (stmt))
{
case GIMPLE_COND:
- {
- tree true_label = gimple_cond_true_label (stmt);
- tree false_label = gimple_cond_false_label (stmt);
+ label = gimple_cond_true_label (stmt);
+ if (label)
+ {
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_cond_set_true_label (stmt, new_label);
+ }
- if (true_label)
- gimple_cond_set_true_label (stmt, main_block_label (true_label));
- if (false_label)
- gimple_cond_set_false_label (stmt, main_block_label (false_label));
- break;
- }
+ label = gimple_cond_false_label (stmt);
+ if (label)
+ {
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_cond_set_false_label (stmt, new_label);
+ }
+ break;
case GIMPLE_SWITCH:
{
for (i = 0; i < n; ++i)
{
tree case_label = gimple_switch_label (stmt, i);
- tree label = main_block_label (CASE_LABEL (case_label));
- CASE_LABEL (case_label) = label;
+ label = CASE_LABEL (case_label);
+ new_label = main_block_label (label);
+ if (new_label != label)
+ CASE_LABEL (case_label) = new_label;
}
break;
}
/* We have to handle gotos until they're removed, and we don't
remove them until after we've created the CFG edges. */
case GIMPLE_GOTO:
- if (!computed_goto_p (stmt))
+ if (!computed_goto_p (stmt))
{
- tree new_dest = main_block_label (gimple_goto_dest (stmt));
- gimple_goto_set_dest (stmt, new_dest);
+ label = gimple_goto_dest (stmt);
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_goto_set_dest (stmt, new_label);
}
break;
+ case GIMPLE_TRANSACTION:
+ {
+ tree label = gimple_transaction_label (stmt);
+ if (label)
+ {
+ tree new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_transaction_set_label (stmt, new_label);
+ }
+ }
+ break;
+
default:
break;
}
break;
lab = gimple_label_label (stmt);
- /* Do not remove user labels. */
- if (!DECL_ARTIFICIAL (lab))
+ /* Do not remove user forced labels or for -O0 any user labels. */
+ if (!DECL_ARTIFICIAL (lab) && (!optimize || FORCED_LABEL (lab)))
return false;
}
if (gimple_code (stmt) != GIMPLE_PHI)
{
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
size_t i;
- fold_stmt_inplace (stmt);
+ fold_stmt (&gsi);
+ stmt = gsi_stmt (gsi);
if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt))
bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
gimple_stmt_iterator dest_gsi = gsi_start_bb (a);
gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
}
+ /* Other user labels keep around in a form of a debug stmt. */
+ else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+ {
+ gimple dbg = gimple_build_debug_bind (label,
+ integer_zero_node,
+ stmt);
+ gimple_debug_bind_reset_value (dbg);
+ gsi_insert_before (&gsi, dbg, GSI_SAME_STMT);
+ }
lp_nr = EH_LANDING_PAD_NR (label);
if (lp_nr)
if (flags & ECF_NORETURN)
return true;
+ /* TM ending statements have backedges out of the transaction.
+ Return true so we split the basic block containing them.
+ Note that the TM_BUILTIN test is merely an optimization. */
+ if ((flags & ECF_TM_BUILTIN)
+ && is_tm_ending_fndecl (gimple_call_fndecl (t)))
+ return true;
+
/* BUILT_IN_RETURN call is same as return statement. */
if (gimple_call_builtin_p (t, BUILT_IN_RETURN))
return true;
/* OpenMP directives alter control flow. */
return true;
+ case GIMPLE_TRANSACTION:
+ /* A transaction start alters control flow. */
+ return true;
+
default:
break;
}
error ("invalid operand to pointer plus, first operand is not a pointer");
return t;
}
- /* Check to make sure the second operand is an integer with type of
- sizetype. */
- if (!useless_type_conversion_p (sizetype,
- TREE_TYPE (TREE_OPERAND (t, 1))))
+ /* Check to make sure the second operand is a ptrofftype. */
+ if (!ptrofftype_p (TREE_TYPE (TREE_OPERAND (t, 1))))
{
error ("invalid operand to pointer plus, second operand is not an "
- "integer with type of sizetype");
+ "integer type of appropriate width");
return t;
}
/* FALLTHROUGH */
effective type the comparison is carried out in. Instead
we require that either the first operand is trivially
convertible into the second, or the other way around.
- The resulting type of a comparison may be any integral type.
Because we special-case pointers to void we allow
comparisons of pointers with the same mode as well. */
- if ((!useless_type_conversion_p (op0_type, op1_type)
- && !useless_type_conversion_p (op1_type, op0_type)
- && (!POINTER_TYPE_P (op0_type)
- || !POINTER_TYPE_P (op1_type)
- || TYPE_MODE (op0_type) != TYPE_MODE (op1_type)))
- || !INTEGRAL_TYPE_P (type)
- || (TREE_CODE (type) != BOOLEAN_TYPE
- && TYPE_PRECISION (type) != 1))
- {
- error ("type mismatch in comparison expression");
- debug_generic_expr (type);
+ if (!useless_type_conversion_p (op0_type, op1_type)
+ && !useless_type_conversion_p (op1_type, op0_type)
+ && (!POINTER_TYPE_P (op0_type)
+ || !POINTER_TYPE_P (op1_type)
+ || TYPE_MODE (op0_type) != TYPE_MODE (op1_type)))
+ {
+ error ("mismatching comparison operand types");
debug_generic_expr (op0_type);
debug_generic_expr (op1_type);
return true;
}
+ /* The resulting type of a comparison may be an effective boolean type. */
+ if (INTEGRAL_TYPE_P (type)
+ && (TREE_CODE (type) == BOOLEAN_TYPE
+ || TYPE_PRECISION (type) == 1))
+ ;
+ /* Or an integer vector type with the same size and element count
+ as the comparison operand types. */
+ else if (TREE_CODE (type) == VECTOR_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
+ {
+ if (TREE_CODE (op0_type) != VECTOR_TYPE
+ || TREE_CODE (op1_type) != VECTOR_TYPE)
+ {
+ error ("non-vector operands in vector comparison");
+ debug_generic_expr (op0_type);
+ debug_generic_expr (op1_type);
+ return true;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)
+ || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type)))
+ != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0_type)))))
+ {
+ error ("invalid vector comparison resulting type");
+ debug_generic_expr (type);
+ return true;
+ }
+ }
+ else
+ {
+ error ("bogus comparison result type");
+ debug_generic_expr (type);
+ return true;
+ }
+
return false;
}
{
/* Allow conversions between integral types and pointers only if
there is no sign or zero extension involved.
- For targets were the precision of sizetype doesn't match that
+ For targets were the precision of ptrofftype doesn't match that
of pointers we need to allow arbitrary conversions from and
- to sizetype. */
+ to ptrofftype. */
if ((POINTER_TYPE_P (lhs_type)
&& INTEGRAL_TYPE_P (rhs1_type)
&& (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type)
- || rhs1_type == sizetype))
+ || ptrofftype_p (rhs1_type)))
|| (POINTER_TYPE_P (rhs1_type)
&& INTEGRAL_TYPE_P (lhs_type)
&& (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type)
- || lhs_type == sizetype)))
+ || ptrofftype_p (sizetype))))
return false;
/* Allow conversion from integer to offset type and vice versa. */
case FLOAT_EXPR:
{
- if (!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
+ if ((!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
+ && (!VECTOR_INTEGER_TYPE_P (rhs1_type)
+ || !VECTOR_FLOAT_TYPE_P(lhs_type)))
{
error ("invalid types in conversion to floating point");
debug_generic_expr (lhs_type);
case FIX_TRUNC_EXPR:
{
- if (!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
+ if ((!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
+ && (!VECTOR_INTEGER_TYPE_P (lhs_type)
+ || !VECTOR_FLOAT_TYPE_P(rhs1_type)))
{
error ("invalid types in conversion to integer");
debug_generic_expr (lhs_type);
return false;
}
+ case WIDEN_LSHIFT_EXPR:
+ {
+ if (!INTEGRAL_TYPE_P (lhs_type)
+ || !INTEGRAL_TYPE_P (rhs1_type)
+ || TREE_CODE (rhs2) != INTEGER_CST
+ || (2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)))
+ {
+ error ("type mismatch in widening vector shift expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ return true;
+ }
+
+ return false;
+ }
+
+ case VEC_WIDEN_LSHIFT_HI_EXPR:
+ case VEC_WIDEN_LSHIFT_LO_EXPR:
+ {
+ if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+ || TREE_CODE (lhs_type) != VECTOR_TYPE
+ || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (lhs_type))
+ || TREE_CODE (rhs2) != INTEGER_CST
+ || (2 * TYPE_PRECISION (TREE_TYPE (rhs1_type))
+ > TYPE_PRECISION (TREE_TYPE (lhs_type))))
+ {
+ error ("type mismatch in widening vector shift expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ return true;
+ }
+
+ return false;
+ }
+
case PLUS_EXPR:
case MINUS_EXPR:
{
do_pointer_plus_expr_check:
if (!POINTER_TYPE_P (rhs1_type)
|| !useless_type_conversion_p (lhs_type, rhs1_type)
- || !useless_type_conversion_p (sizetype, rhs2_type))
+ || !ptrofftype_p (rhs2_type))
{
error ("type mismatch in pointer plus expression");
debug_generic_stmt (lhs_type);
case WIDEN_MULT_EXPR:
if (TREE_CODE (lhs_type) != INTEGER_TYPE)
return true;
- return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))
+ return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
|| (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
case WIDEN_SUM_EXPR:
return true;
}
- if (!is_gimple_val (rhs1)
+ if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
+ ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
|| !is_gimple_val (rhs2)
|| !is_gimple_val (rhs3))
{
&& !FIXED_POINT_TYPE_P (rhs1_type))
|| !useless_type_conversion_p (rhs1_type, rhs2_type)
|| !useless_type_conversion_p (lhs_type, rhs3_type)
- || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)
+ || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
|| TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
{
error ("type mismatch in widening multiply-accumulate expression");
}
break;
+ case COND_EXPR:
+ case VEC_COND_EXPR:
+ if (!useless_type_conversion_p (lhs_type, rhs2_type)
+ || !useless_type_conversion_p (lhs_type, rhs3_type))
+ {
+ error ("type mismatch in conditional expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ return true;
+ }
+ break;
+
+ case VEC_PERM_EXPR:
+ if (!useless_type_conversion_p (lhs_type, rhs1_type)
+ || !useless_type_conversion_p (lhs_type, rhs2_type))
+ {
+ error ("type mismatch in vector permute expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ return true;
+ }
+
+ if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+ || TREE_CODE (rhs2_type) != VECTOR_TYPE
+ || TREE_CODE (rhs3_type) != VECTOR_TYPE)
+ {
+ error ("vector types expected in vector permute expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ return true;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (rhs1_type) != TYPE_VECTOR_SUBPARTS (rhs2_type)
+ || TYPE_VECTOR_SUBPARTS (rhs2_type)
+ != TYPE_VECTOR_SUBPARTS (rhs3_type)
+ || TYPE_VECTOR_SUBPARTS (rhs3_type)
+ != TYPE_VECTOR_SUBPARTS (lhs_type))
+ {
+ error ("vectors with different element number found "
+ "in vector permute expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ return true;
+ }
+
+ if (TREE_CODE (TREE_TYPE (rhs3_type)) != INTEGER_TYPE
+ || GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs3_type)))
+ != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1_type))))
+ {
+ error ("invalid mask type in vector permute expression");
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ return true;
+ }
+
+ return false;
+
case DOT_PROD_EXPR:
case REALIGN_LOAD_EXPR:
/* FIXME. */
}
return res;
- case COND_EXPR:
- if (!is_gimple_reg (lhs)
- || (!is_gimple_reg (TREE_OPERAND (rhs1, 0))
- && !COMPARISON_CLASS_P (TREE_OPERAND (rhs1, 0)))
- || (!is_gimple_reg (TREE_OPERAND (rhs1, 1))
- && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 1)))
- || (!is_gimple_reg (TREE_OPERAND (rhs1, 2))
- && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 2))))
- {
- error ("invalid COND_EXPR in gimple assignment");
- debug_generic_stmt (rhs1);
- return true;
- }
- return res;
-
case CONSTRUCTOR:
case OBJ_TYPE_REF:
case ASSERT_EXPR:
case WITH_SIZE_EXPR:
- case VEC_COND_EXPR:
/* FIXME. */
return res;
return false;
}
-
/* Verify a gimple debug statement STMT.
Returns true if anything is wrong. */
case GIMPLE_ASM:
return false;
+ case GIMPLE_TRANSACTION:
+ return verify_gimple_transaction (stmt);
+
/* Tuples that do not have tree operands. */
case GIMPLE_NOP:
case GIMPLE_PREDICT:
err |= verify_gimple_in_seq_2 (gimple_eh_filter_failure (stmt));
break;
+ case GIMPLE_EH_ELSE:
+ err |= verify_gimple_in_seq_2 (gimple_eh_else_n_body (stmt));
+ err |= verify_gimple_in_seq_2 (gimple_eh_else_e_body (stmt));
+ break;
+
case GIMPLE_CATCH:
err |= verify_gimple_in_seq_2 (gimple_catch_handler (stmt));
break;
+ case GIMPLE_TRANSACTION:
+ err |= verify_gimple_transaction (stmt);
+ break;
+
default:
{
bool err2 = verify_gimple_stmt (stmt);
return err;
}
+/* Verify the contents of a GIMPLE_TRANSACTION. Returns true if there
+ is a problem, otherwise false. */
+
+static bool
+verify_gimple_transaction (gimple stmt)
+{
+ tree lab = gimple_transaction_label (stmt);
+ if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
+ return true;
+ return verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
+}
+
/* Verify the GIMPLE statements inside the statement list STMTS. */
redirect_eh_dispatch_edge (stmt, e, dest);
break;
+ case GIMPLE_TRANSACTION:
+ /* The ABORT edge has a stored label associated with it, otherwise
+ the edges are simply redirectable. */
+ if (e->flags == 0)
+ gimple_transaction_set_label (stmt, gimple_block_label (dest));
+ break;
+
default:
/* Otherwise it must be a fallthru edge, and we don't need to
do anything besides redirecting it. */
if (gimple_code (stmt) == GIMPLE_LABEL)
continue;
+ /* Don't duplicate label debug stmts. */
+ if (gimple_debug_bind_p (stmt)
+ && TREE_CODE (gimple_debug_bind_get_var (stmt))
+ == LABEL_DECL)
+ continue;
+
/* Create a new copy of STMT and duplicate STMT's virtual
operands. */
copy = gimple_copy (stmt);
bool ignore_topmost_bind = false, any_var = false;
basic_block bb;
tree chain;
+ bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn);
- fprintf (file, "%s (", lang_hooks.decl_printable_name (fn, 2));
+ fprintf (file, "%s %s(", lang_hooks.decl_printable_name (fn, 2),
+ tmclone ? "[tm-clone] " : "");
arg = DECL_ARGUMENTS (fn);
while (arg)