コード例 #1
0
void
genrtl_if_stmt (tree t)
{
    tree cond;
    genrtl_do_pushlevel ();
    cond = expand_cond (IF_COND (t));
    emit_line_note (input_location);
    expand_start_cond (cond, 0);
    if (THEN_CLAUSE (t))
    {
        tree nextt = THEN_CLAUSE (t);

        if (cond && integer_zerop (cond))
            nextt = expand_unreachable_stmt (nextt, warn_notreached);
        expand_stmt (nextt);
    }

    if (ELSE_CLAUSE (t))
    {
        tree nextt = ELSE_CLAUSE (t);
        expand_start_else ();
        if (cond && integer_nonzerop (cond))
            nextt = expand_unreachable_stmt (nextt, warn_notreached);
        expand_stmt (nextt);
    }
    expand_end_cond ();
}
コード例 #2
0
ファイル: cp-gimplify.c プロジェクト: AhmadTux/DragonFlyBSD
static void
genericize_if_stmt (tree *stmt_p)
{
  tree stmt, cond, then_, else_;
  location_t locus = EXPR_LOCATION (*stmt_p);

  stmt = *stmt_p;
  cond = IF_COND (stmt);
  then_ = THEN_CLAUSE (stmt);
  else_ = ELSE_CLAUSE (stmt);

  if (!then_)
    then_ = build_empty_stmt ();
  if (!else_)
    else_ = build_empty_stmt ();

  if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_))
    stmt = then_;
  else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_))
    stmt = else_;
  else
    stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_);
  if (CAN_HAVE_LOCATION_P (stmt) && !EXPR_HAS_LOCATION (stmt))
    SET_EXPR_LOCATION (stmt, locus);
  *stmt_p = stmt;
}
コード例 #3
0
ファイル: c-ubsan.c プロジェクト: hnaik/gcc
tree
ubsan_instrument_division (location_t loc, tree op0, tree op1)
{
    tree t, tt;
    tree type = TREE_TYPE (op0);

    /* At this point both operands should have the same type,
       because they are already converted to RESULT_TYPE.
       Use TYPE_MAIN_VARIANT since typedefs can confuse us.  */
    gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
                == TYPE_MAIN_VARIANT (TREE_TYPE (op1)));

    /* TODO: REAL_TYPE is not supported yet.  */
    if (TREE_CODE (type) != INTEGER_TYPE)
        return NULL_TREE;

    /* If we *know* that the divisor is not -1 or 0, we don't have to
       instrument this expression.
       ??? We could use decl_constant_value to cover up more cases.  */
    if (TREE_CODE (op1) == INTEGER_CST
            && integer_nonzerop (op1)
            && !integer_minus_onep (op1))
        return NULL_TREE;

    t = fold_build2 (EQ_EXPR, boolean_type_node,
                     op1, build_int_cst (type, 0));

    /* We check INT_MIN / -1 only for signed types.  */
    if (!TYPE_UNSIGNED (type))
    {
        tree x;
        tt = fold_build2 (EQ_EXPR, boolean_type_node, op1,
                          build_int_cst (type, -1));
        x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
                         TYPE_MIN_VALUE (type));
        x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
        t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
    }

    /* In case we have a SAVE_EXPR in a conditional context, we need to
       make sure it gets evaluated before the condition.  */
    t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), op0, t);
    tree data = ubsan_create_data ("__ubsan_overflow_data",
                                   loc, ubsan_type_descriptor (type),
                                   NULL_TREE);
    data = build_fold_addr_expr_loc (loc, data);
    tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW);
    tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
                              ubsan_encode_value (op1));
    t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);

    return t;
}
コード例 #4
0
void
genrtl_for_stmt (tree t)
{
    tree cond = FOR_COND (t);
    location_t saved_loc;

    if (NEW_FOR_SCOPE_P (t))
        genrtl_do_pushlevel ();

    expand_stmt (FOR_INIT_STMT (t));

    /* Expand the initialization.  */
    emit_line_note (input_location);
    if (FOR_EXPR (t))
        expand_start_loop_continue_elsewhere (1);
    else
        expand_start_loop (1);
    genrtl_do_pushlevel ();

    /* Save the filename and line number so that we expand the FOR_EXPR
       we can reset them back to the saved values.  */
    saved_loc = input_location;

    /* Expand the condition.  */
    if (cond && !integer_nonzerop (cond))
    {
        cond = expand_cond (cond);
        emit_line_note (input_location);
        expand_exit_loop_top_cond (0, cond);
        genrtl_do_pushlevel ();
    }

    /* Expand the body.  */
    expand_stmt (FOR_BODY (t));

    /* Expand the increment expression.  */
    input_location = saved_loc;
    emit_line_note (input_location);
    if (FOR_EXPR (t))
    {
        expand_loop_continue_here ();
        genrtl_expr_stmt (FOR_EXPR (t));
    }
    expand_end_loop ();
}
コード例 #5
0
void
genrtl_while_stmt (tree t)
{
    tree cond = WHILE_COND (t);

    emit_line_note (input_location);
    expand_start_loop (1);
    genrtl_do_pushlevel ();

    if (cond && !integer_nonzerop (cond))
    {
        cond = expand_cond (cond);
        emit_line_note (input_location);
        expand_exit_loop_top_cond (0, cond);
        genrtl_do_pushlevel ();
    }

    expand_stmt (WHILE_BODY (t));

    expand_end_loop ();
}
コード例 #6
0
static void
genrtl_do_stmt_1 (tree cond, tree body)
{
    /* Recognize the common special-case of do { ... } while (0) and do
       not emit the loop widgetry in this case.  In particular this
       avoids cluttering the rtl with dummy loop notes, which can affect
       alignment of adjacent labels.  COND can be NULL due to parse
       errors.  */
    if (!cond || integer_zerop (cond))
    {
        expand_start_null_loop ();
        expand_stmt (body);
        expand_end_null_loop ();
    }
    else if (integer_nonzerop (cond))
    {
        emit_line_note (input_location);
        expand_start_loop (1);

        expand_stmt (body);

        emit_line_note (input_location);
        expand_end_loop ();
    }
    else
    {
        emit_line_note (input_location);
        expand_start_loop_continue_elsewhere (1);

        expand_stmt (body);

        expand_loop_continue_here ();
        cond = expand_cond (cond);
        emit_line_note (input_location);
        expand_exit_loop_if_false (0, cond);
        expand_end_loop ();
    }
}
コード例 #7
0
static void
gimplify_if_stmt (tree *stmt_p)
{
  tree stmt, cond, then_, else_;

  stmt = *stmt_p;
  cond = IF_COND (stmt);
  then_ = THEN_CLAUSE (stmt);
  else_ = ELSE_CLAUSE (stmt);

  if (!then_)
    then_ = build_empty_stmt ();
  if (!else_)
    else_ = build_empty_stmt ();

  if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_))
    stmt = then_;
  else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_))
    stmt = else_;
  else
    stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_);
  *stmt_p = stmt;
}
コード例 #8
0
static tree
gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first)
{
  tree top, entry, exit, cont_block, break_block, stmt_list, t;
  location_t stmt_locus;

  stmt_locus = input_location;
  stmt_list = NULL_TREE;
  entry = NULL_TREE;

  break_block = begin_bc_block (bc_break);
  cont_block = begin_bc_block (bc_continue);

  /* If condition is zero don't generate a loop construct.  */
  if (cond && integer_zerop (cond))
    {
      top = NULL_TREE;
      exit = NULL_TREE;
      if (cond_is_first)
	{
	  t = build_bc_goto (bc_break);
	  append_to_statement_list (t, &stmt_list);
	}
    }
  else
    {
      /* If we use a LOOP_EXPR here, we have to feed the whole thing
	 back through the main gimplifier to lower it.  Given that we
	 have to gimplify the loop body NOW so that we can resolve
	 break/continue stmts, seems easier to just expand to gotos.  */
      top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);

      /* If we have an exit condition, then we build an IF with gotos either
	 out of the loop, or to the top of it.  If there's no exit condition,
	 then we just build a jump back to the top.  */
      exit = build_and_jump (&LABEL_EXPR_LABEL (top));
      if (cond && !integer_nonzerop (cond))
	{
	  t = build_bc_goto (bc_break);
	  exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
	  exit = fold (exit);
	  gimplify_stmt (&exit);

	  if (cond_is_first)
	    {
	      if (incr)
		{
		  entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
		  t = build_and_jump (&LABEL_EXPR_LABEL (entry));
		}
	      else
		t = build_bc_goto (bc_continue);
	      append_to_statement_list (t, &stmt_list);
	    }
	}
    }

  gimplify_stmt (&body);
  gimplify_stmt (&incr);

  body = finish_bc_block (bc_continue, cont_block, body);

  append_to_statement_list (top, &stmt_list);
  append_to_statement_list (body, &stmt_list);
  append_to_statement_list (incr, &stmt_list);
  append_to_statement_list (entry, &stmt_list);
  append_to_statement_list (exit, &stmt_list);

  annotate_all_with_locus (&stmt_list, stmt_locus);

  return finish_bc_block (bc_break, break_block, stmt_list);
}
コード例 #9
0
static bool
minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                    edge e0, edge e1, gimple phi,
                    tree arg0, tree arg1)
{
    tree result, type;
    gimple cond, new_stmt;
    edge true_edge, false_edge;
    enum tree_code cmp, minmax, ass_code;
    tree smaller, larger, arg_true, arg_false;
    gimple_stmt_iterator gsi, gsi_from;

    type = TREE_TYPE (PHI_RESULT (phi));

    /* The optimization may be unsafe due to NaNs.  */
    if (HONOR_NANS (TYPE_MODE (type)))
        return false;

    cond = last_stmt (cond_bb);
    cmp = gimple_cond_code (cond);
    result = PHI_RESULT (phi);

    /* This transformation is only valid for order comparisons.  Record which
       operand is smaller/larger if the result of the comparison is true.  */
    if (cmp == LT_EXPR || cmp == LE_EXPR)
    {
        smaller = gimple_cond_lhs (cond);
        larger = gimple_cond_rhs (cond);
    }
    else if (cmp == GT_EXPR || cmp == GE_EXPR)
    {
        smaller = gimple_cond_rhs (cond);
        larger = gimple_cond_lhs (cond);
    }
    else
        return false;

    /* We need to know which is the true edge and which is the false
        edge so that we know if have abs or negative abs.  */
    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);

    /* Forward the edges over the middle basic block.  */
    if (true_edge->dest == middle_bb)
        true_edge = EDGE_SUCC (true_edge->dest, 0);
    if (false_edge->dest == middle_bb)
        false_edge = EDGE_SUCC (false_edge->dest, 0);

    if (true_edge == e0)
    {
        gcc_assert (false_edge == e1);
        arg_true = arg0;
        arg_false = arg1;
    }
    else
    {
        gcc_assert (false_edge == e0);
        gcc_assert (true_edge == e1);
        arg_true = arg1;
        arg_false = arg0;
    }

    if (empty_block_p (middle_bb))
    {
        if (operand_equal_for_phi_arg_p (arg_true, smaller)
                && operand_equal_for_phi_arg_p (arg_false, larger))
        {
            /* Case

               if (smaller < larger)
               rslt = smaller;
               else
               rslt = larger;  */
            minmax = MIN_EXPR;
        }
        else if (operand_equal_for_phi_arg_p (arg_false, smaller)
                 && operand_equal_for_phi_arg_p (arg_true, larger))
            minmax = MAX_EXPR;
        else
            return false;
    }
    else
    {
        /* Recognize the following case, assuming d <= u:

        if (a <= u)
           b = MAX (a, d);
         x = PHI <b, u>

         This is equivalent to

         b = MAX (a, d);
         x = MIN (b, u);  */

        gimple assign = last_and_only_stmt (middle_bb);
        tree lhs, op0, op1, bound;

        if (!assign
                || gimple_code (assign) != GIMPLE_ASSIGN)
            return false;

        lhs = gimple_assign_lhs (assign);
        ass_code = gimple_assign_rhs_code (assign);
        if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
            return false;
        op0 = gimple_assign_rhs1 (assign);
        op1 = gimple_assign_rhs2 (assign);

        if (true_edge->src == middle_bb)
        {
            /* We got here if the condition is true, i.e., SMALLER < LARGER.  */
            if (!operand_equal_for_phi_arg_p (lhs, arg_true))
                return false;

            if (operand_equal_for_phi_arg_p (arg_false, larger))
            {
                /* Case

                if (smaller < larger)
                   {
                     r' = MAX_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MIN_EXPR.  */
                if (ass_code != MAX_EXPR)
                    return false;

                minmax = MIN_EXPR;
                if (operand_equal_for_phi_arg_p (op0, smaller))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, smaller))
                    bound = op0;
                else
                    return false;

                /* We need BOUND <= LARGER.  */
                if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
                                                    bound, larger)))
                    return false;
            }
            else if (operand_equal_for_phi_arg_p (arg_false, smaller))
            {
                /* Case

                if (smaller < larger)
                   {
                     r' = MIN_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MAX_EXPR.  */
                if (ass_code != MIN_EXPR)
                    return false;

                minmax = MAX_EXPR;
                if (operand_equal_for_phi_arg_p (op0, larger))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, larger))
                    bound = op0;
                else
                    return false;

                /* We need BOUND >= SMALLER.  */
                if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
                                                    bound, smaller)))
                    return false;
            }
            else
                return false;
        }
        else
        {
            /* We got here if the condition is false, i.e., SMALLER > LARGER.  */
            if (!operand_equal_for_phi_arg_p (lhs, arg_false))
                return false;

            if (operand_equal_for_phi_arg_p (arg_true, larger))
            {
                /* Case

                if (smaller > larger)
                   {
                     r' = MIN_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MAX_EXPR.  */
                if (ass_code != MIN_EXPR)
                    return false;

                minmax = MAX_EXPR;
                if (operand_equal_for_phi_arg_p (op0, smaller))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, smaller))
                    bound = op0;
                else
                    return false;

                /* We need BOUND >= LARGER.  */
                if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
                                                    bound, larger)))
                    return false;
            }
            else if (operand_equal_for_phi_arg_p (arg_true, smaller))
            {
                /* Case

                if (smaller > larger)
                   {
                     r' = MAX_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MIN_EXPR.  */
                if (ass_code != MAX_EXPR)
                    return false;

                minmax = MIN_EXPR;
                if (operand_equal_for_phi_arg_p (op0, larger))
                    bound = op1;
                else if (operand_equal_for_phi_arg_p (op1, larger))
                    bound = op0;
                else
                    return false;

                /* We need BOUND <= SMALLER.  */
                if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
                                                    bound, smaller)))
                    return false;
            }
            else
                return false;
        }

        /* Move the statement from the middle block.  */
        gsi = gsi_last_bb (cond_bb);
        gsi_from = gsi_last_bb (middle_bb);
        gsi_move_before (&gsi_from, &gsi);
    }

    /* Emit the statement to compute min/max.  */
    result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
    new_stmt = gimple_build_assign_with_ops (minmax, result, arg0, arg1);
    gsi = gsi_last_bb (cond_bb);
    gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);

    replace_phi_edge_with_variable (cond_bb, e1, phi, result);
    return true;
}
コード例 #10
0
ファイル: cp-gimplify.c プロジェクト: AhmadTux/DragonFlyBSD
static gimple_seq
gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first)
{
  gimple top, entry, stmt;
  gimple_seq stmt_list, body_seq, incr_seq, exit_seq;
  tree cont_block, break_block;
  location_t stmt_locus;

  stmt_locus = input_location;
  stmt_list = NULL;
  body_seq = NULL;
  incr_seq = NULL;
  exit_seq = NULL;
  entry = NULL;

  break_block = begin_bc_block (bc_break);
  cont_block = begin_bc_block (bc_continue);

  /* If condition is zero don't generate a loop construct.  */
  if (cond && integer_zerop (cond))
    {
      top = NULL;
      if (cond_is_first)
	{
	  stmt = gimple_build_goto (get_bc_label (bc_break));
	  gimple_set_location (stmt, stmt_locus);
	  gimple_seq_add_stmt (&stmt_list, stmt);
	}
    }
  else
    {
      /* If we use a LOOP_EXPR here, we have to feed the whole thing
	 back through the main gimplifier to lower it.  Given that we
	 have to gimplify the loop body NOW so that we can resolve
	 break/continue stmts, seems easier to just expand to gotos.  */
      top = gimple_build_label (create_artificial_label ());

      /* If we have an exit condition, then we build an IF with gotos either
	 out of the loop, or to the top of it.  If there's no exit condition,
	 then we just build a jump back to the top.  */
      if (cond && !integer_nonzerop (cond))
	{
	  if (cond != error_mark_node)
	    { 
	      gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue);
	      stmt = gimple_build_cond (NE_EXPR, cond,
					build_int_cst (TREE_TYPE (cond), 0),
					gimple_label_label (top),
					get_bc_label (bc_break));
	      gimple_seq_add_stmt (&exit_seq, stmt);
	    }

	  if (cond_is_first)
	    {
	      if (incr)
		{
		  entry = gimple_build_label (create_artificial_label ());
		  stmt = gimple_build_goto (gimple_label_label (entry));
		}
	      else
		stmt = gimple_build_goto (get_bc_label (bc_continue));
	      gimple_set_location (stmt, stmt_locus);
	      gimple_seq_add_stmt (&stmt_list, stmt);
	    }
	}
      else
	{
	  stmt = gimple_build_goto (gimple_label_label (top));
	  gimple_seq_add_stmt (&exit_seq, stmt);
	}
    }

  gimplify_stmt (&body, &body_seq);
  gimplify_stmt (&incr, &incr_seq);

  body_seq = finish_bc_block (bc_continue, cont_block, body_seq);

  gimple_seq_add_stmt (&stmt_list, top);
  gimple_seq_add_seq (&stmt_list, body_seq);
  gimple_seq_add_seq (&stmt_list, incr_seq);
  gimple_seq_add_stmt (&stmt_list, entry);
  gimple_seq_add_seq (&stmt_list, exit_seq);

  annotate_all_with_location (stmt_list, stmt_locus);

  return finish_bc_block (bc_break, break_block, stmt_list);
}
コード例 #11
0
ファイル: cp-gimplify.c プロジェクト: didemoto/gcc
static void
genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
		    tree incr, bool cond_is_first, int *walk_subtrees,
		    void *data)
{
  tree blab, clab;
  tree entry = NULL, exit = NULL, t;
  tree stmt_list = NULL;

  blab = begin_bc_block (bc_break, start_locus);
  clab = begin_bc_block (bc_continue, start_locus);

  if (incr && EXPR_P (incr))
    SET_EXPR_LOCATION (incr, start_locus);

  cp_walk_tree (&cond, cp_genericize_r, data, NULL);
  cp_walk_tree (&body, cp_genericize_r, data, NULL);
  cp_walk_tree (&incr, cp_genericize_r, data, NULL);
  *walk_subtrees = 0;

  /* If condition is zero don't generate a loop construct.  */
  if (cond && integer_zerop (cond))
    {
      if (cond_is_first)
	{
	  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
			  get_bc_label (bc_break));
	  append_to_statement_list (t, &stmt_list);
	}
    }
  else
    {
      /* Expand to gotos, just like c_finish_loop.  TODO: Use LOOP_EXPR.  */
      tree top = build1 (LABEL_EXPR, void_type_node,
			 create_artificial_label (start_locus));

      /* If we have an exit condition, then we build an IF with gotos either
	 out of the loop, or to the top of it.  If there's no exit condition,
	 then we just build a jump back to the top.  */
      exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top));

      if (cond && !integer_nonzerop (cond))
	{
	  /* Canonicalize the loop condition to the end.  This means
	     generating a branch to the loop condition.  Reuse the
	     continue label, if possible.  */
	  if (cond_is_first)
	    {
	      if (incr)
		{
		  entry = build1 (LABEL_EXPR, void_type_node,
				  create_artificial_label (start_locus));
		  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
				  LABEL_EXPR_LABEL (entry));
		}
	      else
		t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
				get_bc_label (bc_continue));
	      append_to_statement_list (t, &stmt_list);
	    }

	  t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
	  exit = fold_build3_loc (start_locus,
				  COND_EXPR, void_type_node, cond, exit, t);
	}

      append_to_statement_list (top, &stmt_list);
    }

  append_to_statement_list (body, &stmt_list);
  finish_bc_block (&stmt_list, bc_continue, clab);
  append_to_statement_list (incr, &stmt_list);
  append_to_statement_list (entry, &stmt_list);
  append_to_statement_list (exit, &stmt_list);
  finish_bc_block (&stmt_list, bc_break, blab);

  if (stmt_list == NULL_TREE)
    stmt_list = build1 (NOP_EXPR, void_type_node, integer_zero_node);

  *stmt_p = stmt_list;
}
コード例 #12
0
ファイル: cp-gimplify.c プロジェクト: 0mp/freebsd
static tree
/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
gimplify_cp_loop (tree cond, tree body, tree incr, tree attrs,
		  bool cond_is_first, tree inner_foreach)
/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
{
  tree top, entry, exit, cont_block, break_block, stmt_list, t;
  location_t stmt_locus;

  stmt_locus = input_location;
  stmt_list = NULL_TREE;
  entry = NULL_TREE;

  /* APPLE LOCAL begin C* language */
  /* Order of label addition to stack is important for objc's foreach-stmt. */
  /* APPLE LOCAL radar 4667060 */
  if (inner_foreach == integer_zero_node)
    {
      cont_block = begin_bc_block (bc_continue);
      break_block = begin_bc_block (bc_break);
    }
  else
    {
      break_block = begin_bc_block (bc_break);
      cont_block = begin_bc_block (bc_continue);
    }
  /* APPLE LOCAL end C* language */

  /* If condition is zero don't generate a loop construct.  */
  if (cond && integer_zerop (cond))
    {
      top = NULL_TREE;
      exit = NULL_TREE;
      if (cond_is_first)
	{
	  t = build_bc_goto (bc_break);
	  append_to_statement_list (t, &stmt_list);
	}
    }
  else
    {
      /* If we use a LOOP_EXPR here, we have to feed the whole thing
	 back through the main gimplifier to lower it.  Given that we
	 have to gimplify the loop body NOW so that we can resolve
	 break/continue stmts, seems easier to just expand to gotos.  */
      top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);

      /* If we have an exit condition, then we build an IF with gotos either
	 out of the loop, or to the top of it.  If there's no exit condition,
	 then we just build a jump back to the top.  */
      exit = build_and_jump (&LABEL_EXPR_LABEL (top));
/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \

      /* Add the attributes to the 'top' label.  */
      decl_attributes (&LABEL_EXPR_LABEL (top), attrs, 0);

/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
      if (cond && !integer_nonzerop (cond))
	{
	  t = build_bc_goto (bc_break);
	  exit = fold_build3 (COND_EXPR, void_type_node, cond, exit, t);
	  gimplify_stmt (&exit);

	  if (cond_is_first)
	    {
	      if (incr)
		{
		  entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
		  t = build_and_jump (&LABEL_EXPR_LABEL (entry));
		}
	      else
		t = build_bc_goto (bc_continue);
	      append_to_statement_list (t, &stmt_list);
	    }
	}
    }

  /* APPLE LOCAL begin radar 4547045 */
  /* Pop foreach's inner loop break label so outer loop's
     break label becomes target of inner loop body's break statements.
  */
  t = NULL_TREE;
  gimplify_stmt (&body);
  gimplify_stmt (&incr);

  body = finish_bc_block (bc_continue, cont_block, body);
  /* APPLE LOCAL begin radar 4547045 */
  /* Push back inner loop's own 'break' label so rest
     of code works seemlessly. */
  /* APPLE LOCAL radar 4667060 */

  append_to_statement_list (top, &stmt_list);
  append_to_statement_list (body, &stmt_list);
  append_to_statement_list (incr, &stmt_list);
  append_to_statement_list (entry, &stmt_list);
  append_to_statement_list (exit, &stmt_list);

  annotate_all_with_locus (&stmt_list, stmt_locus);

  return finish_bc_block (bc_break, break_block, stmt_list);
}