Exemplo n.º 1
0
static void perturb_latent_entropy(basic_block bb, tree rhs)
{
	gimple_stmt_iterator gsi;
	gimple assign;
	tree addxorrol, temp;

	// 1. create temporary copy of latent_entropy
	temp = create_tmp_var(unsigned_intDI_type_node, "temp_latent_entropy");
	add_referenced_var(temp);

	// 2. read...
	temp = make_ssa_name(temp, NULL);
	assign = gimple_build_assign(temp, latent_entropy_decl);
	SSA_NAME_DEF_STMT(temp) = assign;
	add_referenced_var(latent_entropy_decl);
	gsi = gsi_after_labels(bb);
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);

	// 3. ...modify...
	addxorrol = fold_build2_loc(UNKNOWN_LOCATION, get_op(NULL), unsigned_intDI_type_node, temp, rhs);
	temp = make_ssa_name(SSA_NAME_VAR(temp), NULL);
	assign = gimple_build_assign(temp, addxorrol);
	SSA_NAME_DEF_STMT(temp) = assign;
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);

	// 4. ...write latent_entropy
	assign = gimple_build_assign(latent_entropy_decl, temp);
	gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
	update_stmt(assign);
}
Exemplo n.º 2
0
void
ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
{
  gimple stmt = gsi_stmt (*gsi);
  location_t loc = gimple_location (stmt);
  gcc_assert (gimple_call_num_args (stmt) == 3);

  /* Pick up the arguments of the UBSAN_BOUNDS call.  */
  tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 0)));
  tree index = gimple_call_arg (stmt, 1);
  tree orig_index_type = TREE_TYPE (index);
  tree bound = gimple_call_arg (stmt, 2);

  gimple_stmt_iterator gsi_orig = *gsi;

  /* Create condition "if (index > bound)".  */
  basic_block then_bb, fallthru_bb;
  gimple_stmt_iterator cond_insert_point
    = create_cond_insert_point (gsi, 0/*before_p*/, false, true,
				&then_bb, &fallthru_bb);
  index = fold_convert (TREE_TYPE (bound), index);
  index = force_gimple_operand_gsi (&cond_insert_point, index,
				    true/*simple_p*/, NULL_TREE,
				    false/*before*/, GSI_NEW_STMT);
  gimple g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
  gimple_set_location (g, loc);
  gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);

  /* Generate __ubsan_handle_out_of_bounds call.  */
  *gsi = gsi_after_labels (then_bb);
  if (flag_sanitize_undefined_trap_on_error)
    g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  else
    {
      tree data
	= ubsan_create_data ("__ubsan_out_of_bounds_data", &loc, NULL,
			     ubsan_type_descriptor (type, UBSAN_PRINT_ARRAY),
			     ubsan_type_descriptor (orig_index_type),
			     NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS
	  : BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT;
      tree fn = builtin_decl_explicit (bcode);
      tree val = force_gimple_operand_gsi (gsi, ubsan_encode_value (index),
					   true, NULL_TREE, true,
					   GSI_SAME_STMT);
      g = gimple_build_call (fn, 2, data, val);
    }
  gimple_set_location (g, loc);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);

  /* Get rid of the UBSAN_BOUNDS call from the IR.  */
  unlink_stmt_vdef (stmt);
  gsi_remove (&gsi_orig, true);

  /* Point GSI to next logical statement.  */
  *gsi = gsi_start_bb (fallthru_bb);
}
Exemplo n.º 3
0
void
input_bb (struct lto_input_block *ib, enum LTO_tags tag,
	  struct data_in *data_in, struct function *fn,
	  int count_materialization_scale)
{
  unsigned int index;
  basic_block bb;
  gimple_stmt_iterator bsi;

  /* This routine assumes that CFUN is set to FN, as it needs to call
     basic GIMPLE routines that use CFUN.  */
  gcc_assert (cfun == fn);

  index = streamer_read_uhwi (ib);
  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);

  bb->count = (streamer_read_hwi (ib) * count_materialization_scale
	       + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
  bb->loop_depth = streamer_read_hwi (ib);
  bb->frequency = streamer_read_hwi (ib);
  bb->flags = streamer_read_hwi (ib);

  /* LTO_bb1 has statements.  LTO_bb0 does not.  */
  if (tag == LTO_bb0)
    return;

  bsi = gsi_start_bb (bb);
  tag = streamer_read_record_start (ib);
  while (tag)
    {
      gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
      if (!is_gimple_debug (stmt))
	find_referenced_vars_in (stmt);
      gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);

      /* After the statement, expect a 0 delimiter or the EH region
	 that the previous statement belongs to.  */
      tag = streamer_read_record_start (ib);
      lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);

      if (tag == LTO_eh_region)
	{
	  HOST_WIDE_INT region = streamer_read_hwi (ib);
	  gcc_assert (region == (int) region);
	  add_stmt_to_eh_lp (stmt, region);
	}

      tag = streamer_read_record_start (ib);
    }

  tag = streamer_read_record_start (ib);
  while (tag)
    {
      gimple phi = input_phi (ib, bb, data_in, fn);
      find_referenced_vars_in (phi);
      tag = streamer_read_record_start (ib);
    }
}
Exemplo n.º 4
0
void
gsi_move_after (gimple_stmt_iterator *from, gimple_stmt_iterator *to)
{
  gimple *stmt = gsi_stmt (*from);
  gsi_remove (from, false);

  /* We must have GSI_NEW_STMT here, as gsi_move_after is sometimes used to
     move statements to an empty block.  */
  gsi_insert_after (to, stmt, GSI_NEW_STMT);
}
Exemplo n.º 5
0
/*
 * add special KERNEXEC instrumentation: reload %r10 after it has been clobbered
 */
static void kernexec_reload_fptr_mask(gimple_stmt_iterator *gsi)
{
	gimple asm_movabs_stmt;

	// build asm volatile("movabs $0x8000000000000000, %%r10\n\t" : : : );
	asm_movabs_stmt = gimple_build_asm_vec("movabs $0x8000000000000000, %%r10\n\t", NULL, NULL, NULL, NULL);
	gimple_asm_set_volatile(asm_movabs_stmt, true);
	gsi_insert_after(gsi, asm_movabs_stmt, GSI_CONTINUE_LINKING);
	update_stmt(asm_movabs_stmt);
}
static void
insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p, tree op)
{
  /* We want the NULL pointer dereference to actually occur so that
     code that wishes to catch the signal can do so.

     If the dereference is a load, then there's nothing to do as the
     LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.

     If the dereference is a store and we can easily transform the RHS,
     then simplify the RHS to enable more DCE.   Note that we require the
     statement to be a GIMPLE_ASSIGN which filters out calls on the RHS.  */
  gimple stmt = gsi_stmt (*si_p);
  if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
      && is_gimple_assign (stmt)
      && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
    {
      /* We just need to turn the RHS into zero converted to the proper
         type.  */
      tree type = TREE_TYPE (gimple_assign_lhs (stmt));
      gimple_assign_set_rhs_code (stmt, INTEGER_CST);
      gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
      update_stmt (stmt);
    }

  gimple new_stmt
    = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  gimple_seq seq = NULL;
  gimple_seq_add_stmt (&seq, new_stmt);

  /* If we had a NULL pointer dereference, then we want to insert the
     __builtin_trap after the statement, for the other cases we want
     to insert before the statement.  */
  if (walk_stmt_load_store_ops (stmt, (void *)op,
			        check_loadstore,
				check_loadstore))
    gsi_insert_after (si_p, seq, GSI_NEW_STMT);
  else
    gsi_insert_before (si_p, seq, GSI_NEW_STMT);

  /* We must remove statements from the end of the block so that we
     never reference a released SSA_NAME.  */
  basic_block bb = gimple_bb (gsi_stmt (*si_p));
  for (gimple_stmt_iterator si = gsi_last_bb (bb);
       gsi_stmt (si) != gsi_stmt (*si_p);
       si = gsi_last_bb (bb))
    {
      stmt = gsi_stmt (si);
      unlink_stmt_vdef (stmt);
      gsi_remove (&si, true);
      release_defs (stmt);
    }
}
Exemplo n.º 7
0
static void
insert_reciprocals (gimple_stmt_iterator *def_gsi, struct occurrence *occ,
		    tree def, tree recip_def, int threshold)
{
  tree type;
  gimple new_stmt;
  gimple_stmt_iterator gsi;
  struct occurrence *occ_child;

  if (!recip_def
      && (occ->bb_has_division || !flag_trapping_math)
      && occ->num_divisions >= threshold)
    {
      /* Make a variable with the replacement and substitute it.  */
      type = TREE_TYPE (def);
      recip_def = make_rename_temp (type, "reciptmp");
      new_stmt = gimple_build_assign_with_ops (RDIV_EXPR, recip_def,
					       build_one_cst (type), def);
  
      if (occ->bb_has_division)
        {
          /* Case 1: insert before an existing division.  */
          gsi = gsi_after_labels (occ->bb);
          while (!gsi_end_p (gsi) && !is_division_by (gsi_stmt (gsi), def))
	    gsi_next (&gsi);

          gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
        }
      else if (def_gsi && occ->bb == def_gsi->bb)
        {
          /* Case 2: insert right after the definition.  Note that this will
	     never happen if the definition statement can throw, because in
	     that case the sole successor of the statement's basic block will
	     dominate all the uses as well.  */
          gsi_insert_after (def_gsi, new_stmt, GSI_NEW_STMT);
        }
      else
        {
          /* Case 3: insert in a basic block not containing defs/uses.  */
          gsi = gsi_after_labels (occ->bb);
          gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
        }

      occ->recip_def_stmt = new_stmt;
    }

  occ->recip_def = recip_def;
  for (occ_child = occ->children; occ_child; occ_child = occ_child->next)
    insert_reciprocals (def_gsi, occ_child, def, recip_def, threshold);
}
Exemplo n.º 8
0
void 
add_phi_node_to_bb (gimple phi, basic_block bb)
{
  gimple_stmt_iterator gsi;
  /* Add the new PHI node to the list of PHI nodes for block BB.  */
  if (phi_nodes (bb) == NULL)
    set_phi_nodes (bb, gimple_seq_alloc ());

  gsi = gsi_last (phi_nodes (bb));
  gsi_insert_after (&gsi, phi, GSI_NEW_STMT);

  /* Associate BB to the PHI node.  */
  gimple_set_bb (phi, bb);

}
Exemplo n.º 9
0
static void
unloop_loops (bitmap loop_closed_ssa_invalidated,
	      bool *irred_invalidated)
{
  while (loops_to_unloop.length ())
    {
      struct loop *loop = loops_to_unloop.pop ();
      int n_unroll = loops_to_unloop_nunroll.pop ();
      basic_block latch = loop->latch;
      edge latch_edge = loop_latch_edge (loop);
      int flags = latch_edge->flags;
      location_t locus = latch_edge->goto_locus;
      gcall *stmt;
      gimple_stmt_iterator gsi;

      remove_exits_and_undefined_stmts (loop, n_unroll);

      /* Unloop destroys the latch edge.  */
      unloop (loop, irred_invalidated, loop_closed_ssa_invalidated);

      /* Create new basic block for the latch edge destination and wire
	 it in.  */
      stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
      latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
      latch_edge->probability = 0;
      latch_edge->count = 0;
      latch_edge->flags |= flags;
      latch_edge->goto_locus = locus;

      latch_edge->dest->loop_father = current_loops->tree_root;
      latch_edge->dest->count = 0;
      latch_edge->dest->frequency = 0;
      set_immediate_dominator (CDI_DOMINATORS, latch_edge->dest, latch_edge->src);

      gsi = gsi_start_bb (latch_edge->dest);
      gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
    }
  loops_to_unloop.release ();
  loops_to_unloop_nunroll.release ();

  /* Remove edges in peeled copies.  */
  unsigned i;
  edge e;
  FOR_EACH_VEC_ELT (edges_to_remove, i, e)
    {
      bool ok = remove_path (e);
      gcc_assert (ok);
    }
Exemplo n.º 10
0
basic_block
gsi_insert_on_edge_immediate (edge e, gimple *stmt)
{
  gimple_stmt_iterator gsi;
  basic_block new_bb = NULL;
  bool ins_after;

  gcc_assert (!PENDING_STMT (e));

  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);

  update_call_edge_frequencies (stmt, gsi.bb);

  if (ins_after)
    gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
  else
    gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);

  return new_bb;
}
Exemplo n.º 11
0
static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi)
{
	gimple stmt;
	gcall *track_stack;
	cgraph_node_ptr node;
	int frequency;
	basic_block bb;

	// insert call to void pax_track_stack(void)
	stmt = gimple_build_call(track_function_decl, 0);
	track_stack = as_a_gcall(stmt);
	gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING);

	// update the cgraph
	bb = gimple_bb(track_stack);
	node = cgraph_get_create_node(track_function_decl);
	gcc_assert(node);
	frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
	cgraph_create_edge(cgraph_get_node(current_function_decl), node, track_stack, bb->count, frequency, bb->loop_depth);
}
Exemplo n.º 12
0
static tree
update_accumulator_with_ops (enum tree_code code, tree acc, tree op1,
			     gimple_stmt_iterator gsi)
{
  gimple stmt;
  tree var = copy_ssa_name (acc, NULL);
  if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)))
    stmt = gimple_build_assign_with_ops (code, var, acc, op1);
  else
    {
      tree rhs = fold_convert (TREE_TYPE (acc),
			       fold_build2 (code,
					    TREE_TYPE (op1),
					    fold_convert (TREE_TYPE (op1), acc),
					    op1));
      rhs = force_gimple_operand_gsi (&gsi, rhs,
				      false, NULL, false, GSI_CONTINUE_LINKING);
      stmt = gimple_build_assign (var, rhs);
    }
  gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
  return var;
}
Exemplo n.º 13
0
basic_block
gsi_insert_on_edge_immediate (edge e, gimple stmt)
{
  gimple_stmt_iterator gsi;
  struct gimple_seq_node_d node;
  basic_block new_bb = NULL;
  bool ins_after;

  gcc_assert (!PENDING_STMT (e));

  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);

  node.stmt = stmt;
  node.prev = node.next = NULL;
  update_call_edge_frequencies (&node, gsi.bb);

  if (ins_after)
    gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
  else
    gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);

  return new_bb;
}
Exemplo n.º 14
0
static void
lower_builtin_posix_memalign (gimple_stmt_iterator *gsi)
{
  gimple stmt, call = gsi_stmt (*gsi);
  tree pptr = gimple_call_arg (call, 0);
  tree align = gimple_call_arg (call, 1);
  tree res = gimple_call_lhs (call);
  tree ptr = create_tmp_reg (ptr_type_node, NULL);
  if (TREE_CODE (pptr) == ADDR_EXPR)
    {
      tree tem = create_tmp_var (ptr_type_node, NULL);
      TREE_ADDRESSABLE (tem) = 1;
      gimple_call_set_arg (call, 0, build_fold_addr_expr (tem));
      stmt = gimple_build_assign (ptr, tem);
    }
  else
    stmt = gimple_build_assign (ptr,
				fold_build2 (MEM_REF, ptr_type_node, pptr,
					     build_int_cst (ptr_type_node, 0)));
  if (res == NULL_TREE)
    {
      res = create_tmp_reg (integer_type_node, NULL);
      gimple_call_set_lhs (call, res);
    }
  tree align_label = create_artificial_label (UNKNOWN_LOCATION);
  tree noalign_label = create_artificial_label (UNKNOWN_LOCATION);
  gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node,
				   align_label, noalign_label);
  gsi_insert_after (gsi, cond, GSI_NEW_STMT);
  gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_ASSUME_ALIGNED),
			    2, ptr, align);
  gimple_call_set_lhs (stmt, ptr);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  stmt = gimple_build_assign (fold_build2 (MEM_REF, ptr_type_node, pptr,
					   build_int_cst (ptr_type_node, 0)),
			      ptr);
  gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
  gsi_insert_after (gsi, gimple_build_label (noalign_label), GSI_NEW_STMT);
}
Exemplo n.º 15
0
static void
instrument_bool_enum_load (gimple_stmt_iterator *gsi)
{
  gimple stmt = gsi_stmt (*gsi);
  tree rhs = gimple_assign_rhs1 (stmt);
  tree type = TREE_TYPE (rhs);
  tree minv = NULL_TREE, maxv = NULL_TREE;

  if (TREE_CODE (type) == BOOLEAN_TYPE && (flag_sanitize & SANITIZE_BOOL))
    {
      minv = boolean_false_node;
      maxv = boolean_true_node;
    }
  else if (TREE_CODE (type) == ENUMERAL_TYPE
	   && (flag_sanitize & SANITIZE_ENUM)
	   && TREE_TYPE (type) != NULL_TREE
	   && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
	   && (TYPE_PRECISION (TREE_TYPE (type))
	       < GET_MODE_PRECISION (TYPE_MODE (type))))
    {
      minv = TYPE_MIN_VALUE (TREE_TYPE (type));
      maxv = TYPE_MAX_VALUE (TREE_TYPE (type));
    }
  else
    return;

  int modebitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
  HOST_WIDE_INT bitsize, bitpos;
  tree offset;
  enum machine_mode mode;
  int volatilep = 0, unsignedp = 0;
  tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode,
				   &unsignedp, &volatilep, false);
  tree utype = build_nonstandard_integer_type (modebitsize, 1);

  if ((TREE_CODE (base) == VAR_DECL && DECL_HARD_REGISTER (base))
      || (bitpos % modebitsize) != 0
      || bitsize != modebitsize
      || GET_MODE_BITSIZE (TYPE_MODE (utype)) != modebitsize
      || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
    return;

  location_t loc = gimple_location (stmt);
  tree ptype = build_pointer_type (TREE_TYPE (rhs));
  tree atype = reference_alias_ptr_type (rhs);
  gimple g = gimple_build_assign (make_ssa_name (ptype, NULL),
				  build_fold_addr_expr (rhs));
  gimple_set_location (g, loc);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);
  tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g),
		     build_int_cst (atype, 0));
  tree urhs = make_ssa_name (utype, NULL);
  g = gimple_build_assign (urhs, mem);
  gimple_set_location (g, loc);
  gsi_insert_before (gsi, g, GSI_SAME_STMT);
  minv = fold_convert (utype, minv);
  maxv = fold_convert (utype, maxv);
  if (!integer_zerop (minv))
    {
      g = gimple_build_assign_with_ops (MINUS_EXPR,
					make_ssa_name (utype, NULL),
					urhs, minv);
      gimple_set_location (g, loc);
      gsi_insert_before (gsi, g, GSI_SAME_STMT);
    }

  gimple_stmt_iterator gsi2 = *gsi;
  basic_block then_bb, fallthru_bb;
  *gsi = create_cond_insert_point (gsi, true, false, true,
				   &then_bb, &fallthru_bb);
  g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g),
			 int_const_binop (MINUS_EXPR, maxv, minv),
			 NULL_TREE, NULL_TREE);
  gimple_set_location (g, loc);
  gsi_insert_after (gsi, g, GSI_NEW_STMT);

  gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE);
  update_stmt (stmt);

  gsi2 = gsi_after_labels (then_bb);
  if (flag_sanitize_undefined_trap_on_error)
    g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  else
    {
      tree data = ubsan_create_data ("__ubsan_invalid_value_data", &loc, NULL,
				     ubsan_type_descriptor (type), NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE
	  : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT;
      tree fn = builtin_decl_explicit (bcode);

      tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs),
					   true, NULL_TREE, true,
					   GSI_SAME_STMT);
      g = gimple_build_call (fn, 2, data, val);
    }
  gimple_set_location (g, loc);
  gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
}
Exemplo n.º 16
0
void
ubsan_expand_null_ifn (gimple_stmt_iterator gsi)
{
  gimple stmt = gsi_stmt (gsi);
  location_t loc = gimple_location (stmt);
  gcc_assert (gimple_call_num_args (stmt) == 2);
  tree ptr = gimple_call_arg (stmt, 0);
  tree ckind = gimple_call_arg (stmt, 1);

  basic_block cur_bb = gsi_bb (gsi);

  /* Split the original block holding the pointer dereference.  */
  edge e = split_block (cur_bb, stmt);

  /* Get a hold on the 'condition block', the 'then block' and the
     'else block'.  */
  basic_block cond_bb = e->src;
  basic_block fallthru_bb = e->dest;
  basic_block then_bb = create_empty_bb (cond_bb);
  add_bb_to_loop (then_bb, cond_bb->loop_father);
  loops_state_set (LOOPS_NEED_FIXUP);

  /* Make an edge coming from the 'cond block' into the 'then block';
     this edge is unlikely taken, so set up the probability accordingly.  */
  e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
  e->probability = PROB_VERY_UNLIKELY;

  /* Connect 'then block' with the 'else block'.  This is needed
     as the ubsan routines we call in the 'then block' are not noreturn.
     The 'then block' only has one outcoming edge.  */
  make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);

  /* Set up the fallthrough basic block.  */
  e = find_edge (cond_bb, fallthru_bb);
  e->flags = EDGE_FALSE_VALUE;
  e->count = cond_bb->count;
  e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY;

  /* Update dominance info for the newly created then_bb; note that
     fallthru_bb's dominance info has already been updated by
     split_bock.  */
  if (dom_info_available_p (CDI_DOMINATORS))
    set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);

  /* Put the ubsan builtin call into the newly created BB.  */
  gimple g;
  if (flag_sanitize_undefined_trap_on_error)
    g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
  else
    {
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
	  : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
      tree fn = builtin_decl_implicit (bcode);
      const struct ubsan_mismatch_data m
	= { build_zero_cst (pointer_sized_int_node), ckind };
      tree data
	= ubsan_create_data ("__ubsan_null_data", &loc, &m,
			     ubsan_type_descriptor (TREE_TYPE (ptr),
						    UBSAN_PRINT_POINTER),
			     NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);
      g = gimple_build_call (fn, 2, data,
			     build_zero_cst (pointer_sized_int_node));
    }
  gimple_set_location (g, loc);
  gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
  gsi_insert_after (&gsi2, g, GSI_NEW_STMT);

  /* Unlink the UBSAN_NULLs vops before replacing it.  */
  unlink_stmt_vdef (stmt);

  g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
			 NULL_TREE, NULL_TREE);
  gimple_set_location (g, loc);

  /* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
  gsi_replace (&gsi, g, false);
}
static bool
abs_replacement (basic_block cond_bb, basic_block middle_bb,
                 edge e0 ATTRIBUTE_UNUSED, edge e1,
                 gimple phi, tree arg0, tree arg1)
{
    tree result;
    gimple new_stmt, cond;
    gimple_stmt_iterator gsi;
    edge true_edge, false_edge;
    gimple assign;
    edge e;
    tree rhs, lhs;
    bool negate;
    enum tree_code cond_code;

    /* If the type says honor signed zeros we cannot do this
       optimization.  */
    if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
        return false;

    /* OTHER_BLOCK must have only one executable statement which must have the
       form arg0 = -arg1 or arg1 = -arg0.  */

    assign = last_and_only_stmt (middle_bb);
    /* If we did not find the proper negation assignment, then we can not
       optimize.  */
    if (assign == NULL)
        return false;

    /* If we got here, then we have found the only executable statement
       in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
       arg1 = -arg0, then we can not optimize.  */
    if (gimple_code (assign) != GIMPLE_ASSIGN)
        return false;

    lhs = gimple_assign_lhs (assign);

    if (gimple_assign_rhs_code (assign) != NEGATE_EXPR)
        return false;

    rhs = gimple_assign_rhs1 (assign);

    /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
    if (!(lhs == arg0 && rhs == arg1)
            && !(lhs == arg1 && rhs == arg0))
        return false;

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

    /* Only relationals comparing arg[01] against zero are interesting.  */
    cond_code = gimple_cond_code (cond);
    if (cond_code != GT_EXPR && cond_code != GE_EXPR
            && cond_code != LT_EXPR && cond_code != LE_EXPR)
        return false;

    /* Make sure the conditional is arg[01] OP y.  */
    if (gimple_cond_lhs (cond) != rhs)
        return false;

    if (FLOAT_TYPE_P (TREE_TYPE (gimple_cond_rhs (cond)))
            ? real_zerop (gimple_cond_rhs (cond))
            : integer_zerop (gimple_cond_rhs (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);

    /* For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
       will need to negate the result.  Similarly for LT_EXPR/LE_EXPR if
       the false edge goes to OTHER_BLOCK.  */
    if (cond_code == GT_EXPR || cond_code == GE_EXPR)
        e = true_edge;
    else
        e = false_edge;

    if (e->dest == middle_bb)
        negate = true;
    else
        negate = false;

    result = duplicate_ssa_name (result, NULL);

    if (negate)
    {
        tree tmp = create_tmp_var (TREE_TYPE (result), NULL);
        add_referenced_var (tmp);
        lhs = make_ssa_name (tmp, NULL);
    }
    else
        lhs = result;

    /* Build the modify expression with abs expression.  */
    new_stmt = gimple_build_assign_with_ops (ABS_EXPR, lhs, rhs, NULL);

    gsi = gsi_last_bb (cond_bb);
    gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);

    if (negate)
    {
        /* Get the right GSI.  We want to insert after the recently
        added ABS_EXPR statement (which we know is the first statement
         in the block.  */
        new_stmt = gimple_build_assign_with_ops (NEGATE_EXPR, result, lhs, NULL);

        gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
    }

    replace_phi_edge_with_variable (cond_bb, e1, phi, result);

    /* Note that we optimized this PHI.  */
    return true;
}
Exemplo n.º 18
0
void
gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
{
    size_t i, num_ops;
    tree lhs;
    gimple_seq pre = NULL;
    gimple post_stmt = NULL;

    push_gimplify_context (gimple_in_ssa_p (cfun));

    switch (gimple_code (stmt))
    {
    case GIMPLE_COND:
        gimplify_expr (gimple_cond_lhs_ptr (stmt), &pre, NULL,
                       is_gimple_val, fb_rvalue);
        gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL,
                       is_gimple_val, fb_rvalue);
        break;
    case GIMPLE_SWITCH:
        gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL,
                       is_gimple_val, fb_rvalue);
        break;
    case GIMPLE_OMP_ATOMIC_LOAD:
        gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL,
                       is_gimple_val, fb_rvalue);
        break;
    case GIMPLE_ASM:
    {
        size_t i, noutputs = gimple_asm_noutputs (stmt);
        const char *constraint, **oconstraints;
        bool allows_mem, allows_reg, is_inout;

        oconstraints
            = (const char **) alloca ((noutputs) * sizeof (const char *));
        for (i = 0; i < noutputs; i++)
        {
            tree op = gimple_asm_output_op (stmt, i);
            constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
            oconstraints[i] = constraint;
            parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
                                     &allows_reg, &is_inout);
            gimplify_expr (&TREE_VALUE (op), &pre, NULL,
                           is_inout ? is_gimple_min_lval : is_gimple_lvalue,
                           fb_lvalue | fb_mayfail);
        }
        for (i = 0; i < gimple_asm_ninputs (stmt); i++)
        {
            tree op = gimple_asm_input_op (stmt, i);
            constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
            parse_input_constraint (&constraint, 0, 0, noutputs, 0,
                                    oconstraints, &allows_mem, &allows_reg);
            if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem)
                allows_reg = 0;
            if (!allows_reg && allows_mem)
                gimplify_expr (&TREE_VALUE (op), &pre, NULL,
                               is_gimple_lvalue, fb_lvalue | fb_mayfail);
            else
                gimplify_expr (&TREE_VALUE (op), &pre, NULL,
                               is_gimple_asm_val, fb_rvalue);
        }
    }
    break;
    default:
        /* NOTE: We start gimplifying operands from last to first to
        make sure that side-effects on the RHS of calls, assignments
         and ASMs are executed before the LHS.  The ordering is not
         important for other statements.  */
        num_ops = gimple_num_ops (stmt);
        for (i = num_ops; i > 0; i--)
        {
            tree op = gimple_op (stmt, i - 1);
            if (op == NULL_TREE)
                continue;
            if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt)))
                gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue);
            else if (i == 2
                     && is_gimple_assign (stmt)
                     && num_ops == 2
                     && get_gimple_rhs_class (gimple_expr_code (stmt))
                     == GIMPLE_SINGLE_RHS)
                gimplify_expr (&op, &pre, NULL,
                               rhs_predicate_for (gimple_assign_lhs (stmt)),
                               fb_rvalue);
            else if (i == 2 && is_gimple_call (stmt))
            {
                if (TREE_CODE (op) == FUNCTION_DECL)
                    continue;
                gimplify_expr (&op, &pre, NULL, is_gimple_call_addr, fb_rvalue);
            }
            else
                gimplify_expr (&op, &pre, NULL, is_gimple_val, fb_rvalue);
            gimple_set_op (stmt, i - 1, op);
        }

        lhs = gimple_get_lhs (stmt);
        /* If the LHS changed it in a way that requires a simple RHS,
        create temporary.  */
        if (lhs && !is_gimple_reg (lhs))
        {
            bool need_temp = false;

            if (is_gimple_assign (stmt)
                    && num_ops == 2
                    && get_gimple_rhs_class (gimple_expr_code (stmt))
                    == GIMPLE_SINGLE_RHS)
                gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL,
                               rhs_predicate_for (gimple_assign_lhs (stmt)),
                               fb_rvalue);
            else if (is_gimple_reg (lhs))
            {
                if (is_gimple_reg_type (TREE_TYPE (lhs)))
                {
                    if (is_gimple_call (stmt))
                    {
                        i = gimple_call_flags (stmt);
                        if ((i & ECF_LOOPING_CONST_OR_PURE)
                                || !(i & (ECF_CONST | ECF_PURE)))
                            need_temp = true;
                    }
                    if (stmt_can_throw_internal (stmt))
                        need_temp = true;
                }
            }
            else
            {
                if (is_gimple_reg_type (TREE_TYPE (lhs)))
                    need_temp = true;
                else if (TYPE_MODE (TREE_TYPE (lhs)) != BLKmode)
                {
                    if (is_gimple_call (stmt))
                    {
                        tree fndecl = gimple_call_fndecl (stmt);

                        if (!aggregate_value_p (TREE_TYPE (lhs), fndecl)
                                && !(fndecl && DECL_RESULT (fndecl)
                                     && DECL_BY_REFERENCE (DECL_RESULT (fndecl))))
                            need_temp = true;
                    }
                    else
                        need_temp = true;
                }
            }
            if (need_temp)
            {
                tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL);
                if (gimple_in_ssa_p (cfun))
                    temp = make_ssa_name (temp, NULL);
                gimple_set_lhs (stmt, temp);
                post_stmt = gimple_build_assign (lhs, temp);
            }
        }
        break;
    }

    if (!gimple_seq_empty_p (pre))
        gsi_insert_seq_before (gsi_p, pre, GSI_SAME_STMT);
    if (post_stmt)
        gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT);

    pop_gimplify_context (NULL);
}
Exemplo n.º 19
0
static void
my_dump_gimple(gimple gnode, gimple_stmt_iterator *ptrgsi)
{
    int gcode;
    tree tnode;
    tree funcdecl;
    tree desc_node;
    tree ptr_desc_node;
    tree t;
    tree tmp_var;
    tree const_char_restrict_ptr_type_node;
    gimple tmp_gstmt;
    gimple new_gnode;
    const char *hellocstr = "Hello, GCC!\n";
    int i;
    struct c_binding *b;
    expanded_location xloc;

    /*
     * Extract the Gimple Code from a gimple node
     */

    gcode = gimple_code(gnode);

    /*
     * Get the line number of cooresponding 
     * source code from a gimple node
     */
    if(gimple_has_location(gnode))
    {
        xloc = expand_location(gimple_location(gnode));
        printf("line %d:", xloc.line);
    }
    printf("\t\t\t\t%s\n", gimple_code_name[gcode]);
    
    switch(gcode)
    {
        case GIMPLE_ASSIGN:
            /*
             * Add a printf("Hello, GCC!\n"); statement 
             * after the first appearing assignment
             * if yes equals to 1, then we have already
             * added the statement, and no need to add 
             * again
             */
            if(!yes)
            {
                /*
                 * Since printf is a builtin function, we need
                 * to get the function declaration using 
                 * built_in_decls[]. The index number can be
                 * found in gcc source gcc/builtins.def
                 */
                funcdecl = built_in_decls[BUILT_IN_PRINTF];

                if(funcdecl == NULL_TREE)
                {
                    printf("cannot find printf\n");
                }
                else
                {
                    /*
                     * In gimple, every statement is simplified into 
                     * three oprands mode. And our printf() statement 
                     * is change into following two gimple statements:
                     * 
                     * <D.XXX> = (const char * restrict) &"Hello, GCC!\n"[0]
                     * printf(<D.XXX>);
                     *
                     * Note that <D.XXX> is a temporary variable, we can 
                     * actually use any name we like as long as no 
                     * confliction.
                     */

                    /*
                     * Generate a STRING_CST, the value is "Hello, GCC!\n"
                     */
                    desc_node = build_string(strlen(hellocstr), hellocstr);

                    /*
                     * Two points need to notice here:
                     * 1. STRING_CST build by build_string() do
                     *    not have TREE_TYPE set, so we need to 
                     *    set it manually.
                     * 2. build_string() will add a trailing '\0'
                     *    when building the STRING_CST, so we do
                     *    not need to care with it.
                     */
                    TREE_TYPE(desc_node) = build_array_type(
                            char_type_node, 
                            build_index_type(
                                build_int_cst(NULL_TREE, 
                                    strlen(hellocstr))));

                    /*
                     * Define a const char * restrict type node
                     * here for convertion.
                     * I'm not sure why we need to add a restrict
                     * attribute, but GCC really does it when it 
                     * converting a STRING_CST from AST to Gimple.
                     */
                    const_char_restrict_ptr_type_node = 
                        build_qualified_type(
                            build_pointer_type(
                                    build_qualified_type(
                                        char_type_node,
                                        TYPE_QUAL_CONST)),
                            TYPE_QUAL_RESTRICT);

                    /*
                     * When we in AST, if we want to use STRING_CST
                     * the form is like this <ADDR_EXPR<STRING_CST>>,
                     * but when we turn to gimple, it is like this
                     * <ADDR_EXPR<ADDAR_REF<STRING_CST>>>.
                     * So we need to do a convertion there.
                     */

                    /*
                     * First wrap STRING_CST with ARRAY_REF
                     */
                    t = build4(ARRAY_REF, char_type_node, 
                            desc_node, build_int_cst(NULL_TREE, 0), 
                            NULL, NULL);

                    /*
                     * Second wrap ARRAY_REF with ADDR_EXPR
                     */
                    ptr_desc_node = build1(ADDR_EXPR, 
                            const_char_restrict_ptr_type_node,
                            t);

                    /*
                     * I'm not sure why we need to use fold_convert()
                     * here, but if we do not, we cannot make the 
                     * compiling successful.
                     */
                    ptr_desc_node = fold_convert(
                            const_char_restrict_ptr_type_node, 
                            ptr_desc_node);

                    /*
                     * If is_gimple_min_invariant(ptr_desc_node)
                     * is true, we build a corrent argument, otherwise
                     * the argument is not suitable for gimple call
                     */
                    if(!is_gimple_min_invariant(ptr_desc_node))
                    {
                        printf("Something wrong with is_gimple_min_invariant\n");
                        return ;
                    }

                    /*
                     * This applies for a temporary variable
                     */
                    tmp_var = make_rename_temp(
                            const_char_restrict_ptr_type_node,
                            "plugin_var");

                    /*
                     * Build a gimple statement. Still remember that?
                     * <D.XXX> = (const char * restrict) "Hello, GCC!\n"
                     */
                    tmp_gstmt = gimple_build_assign(tmp_var, 
                                                    ptr_desc_node);

                    /*
                     * Check if the gimple statment is corrent
                     */
                    if(!is_gimple_assign(tmp_gstmt))
                    {
                        printf("tmp_gstmt is invalid\n");
                    }

                    printf("Insert gimple statment:");
                    print_gimple_stmt(stdout, tmp_gstmt, 0,
                                TDF_DETAILS | TDF_VERBOSE | TDF_TREE);
                    /*
                     * Insert the gimple statment into the basic block
                     */
                    gsi_insert_after(ptrgsi, tmp_gstmt, 
                            GSI_NEW_STMT);

                    if(is_gimple_operand(tmp_var))
                    {

                        printf("begin to insert printf\n");
                        yes = 1;
                        printf("Insert gimple statment:");
                        /*
                         * Insert the gimple statment printf 
                         * into the basic block
                         */
                        new_gnode = gimple_build_call(
                                funcdecl, 1, tmp_var);
                        print_gimple_stmt(stdout, new_gnode, 0, 0);
                        gsi_insert_after(ptrgsi, new_gnode, 
                                GSI_NEW_STMT); 
                    }
                    else
                    {
                        print_generic_stmt(stdout, ptr_desc_node, 
                                TDF_DETAILS | TDF_VERBOSE | TDF_TREE);
                        printf("Not Gimple Operands\n");
                    }

                    /*
                     * Since we have more than one consecutive statements 
                     * to insert, we can actually use build a gimple 
                     * sequence, insert all statement into the sequence, 
                     * and then insert the sequence into the basic block. 
                     * This seems to be a better method.
                     */
                }
            }
            else
            {
            }
            break;
        default:
            break;
    }
}
Exemplo n.º 20
0
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple bind;
  tree t;
  gimple x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  if (gimple_seq_may_fallthru (lowered_body)
      && (data.return_statements.is_empty ()
	  || gimple_return_retval (data.return_statements.last().stmt) != NULL))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
    }

  /* If the function calls __builtin_setjmp, we need to emit the computed
     goto that will serve as the unique dispatcher for all the receivers.  */
  if (data.calls_builtin_setjmp)
    {
      tree disp_label, disp_var, arg;

      /* Build 'DISP_LABEL:' and insert.  */
      disp_label = create_artificial_label (cfun->function_end_locus);
      /* This mark will create forward edges from every call site.  */
      DECL_NONLOCAL (disp_label) = 1;
      cfun->has_nonlocal_label = 1;
      x = gimple_build_label (disp_label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);

      /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);'
	 and insert.  */
      disp_var = create_tmp_var (ptr_type_node, "setjmpvar");
      arg = build_addr (disp_label, current_function_decl);
      t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER);
      x = gimple_build_call (t, 1, arg);
      gimple_call_set_lhs (x, disp_var);

      /* Build 'goto DISP_VAR;' and insert.  */
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      x = gimple_build_goto (disp_var);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}
Exemplo n.º 21
0
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple *bind;
  gimple *x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If we had begin stmt markers from e.g. PCH, but this compilation
     doesn't want them, lower_stmt will have cleaned them up; we can
     now clear the flag that indicates we had them.  */
  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
    {
      /* This counter needs not be exact, but before lowering it will
	 most certainly be.  */
      gcc_assert (cfun->debug_marker_count == 0);
      cfun->debug_nonbind_markers = false;
    }

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  bool may_fallthru = gimple_seq_may_fallthru (lowered_body);
  if (may_fallthru
      && (data.return_statements.is_empty ()
	  || (gimple_return_retval (data.return_statements.last().stmt)
	      != NULL)))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      may_fallthru = false;
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
      if (may_fallthru)
	{
	  /* Remove the line number from the representative return statement.
	     It now fills in for the fallthru too.  Failure to remove this
	     will result in incorrect results for coverage analysis.  */
	  gimple_set_location (t.stmt, UNKNOWN_LOCATION);
	  may_fallthru = false;
	}
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}
Exemplo n.º 22
0
static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple bind;
  gimple x;

  /* The gimplifier should've left a body of exactly one statement,
     namely a GIMPLE_BIND.  */
  gcc_assert (gimple_seq_first (body) == gimple_seq_last (body)
	      && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND);

  memset (&data, 0, sizeof (data));
  data.block = DECL_INITIAL (current_function_decl);
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
  BLOCK_CHAIN (data.block) = NULL_TREE;
  TREE_ASM_WRITTEN (data.block) = 1;
  data.return_statements.create (8);

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);

  i = gsi_last (lowered_body);

  /* If the function falls off the end, we need a null return statement.
     If we've already got one in the return_statements vector, we don't
     need to do anything special.  Otherwise build one by hand.  */
  if (gimple_seq_may_fallthru (lowered_body)
      && (data.return_statements.is_empty ()
	  || (gimple_return_retval (data.return_statements.last().stmt)
	      != NULL)))
    {
      x = gimple_build_return (NULL);
      gimple_set_location (x, cfun->function_end_locus);
      gimple_set_block (x, DECL_INITIAL (current_function_decl));
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
    }

  /* If we lowered any return statements, emit the representative
     at the end of the function.  */
  while (!data.return_statements.is_empty ())
    {
      return_statements_t t = data.return_statements.pop ();
      x = gimple_build_label (t.label);
      gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
      gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
    }

  /* Once the old body has been lowered, replace it with the new
     lowered sequence.  */
  gimple_set_body (current_function_decl, lowered_body);

  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
  BLOCK_SUBBLOCKS (data.block)
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));

  clear_block_marks (data.block);
  data.return_statements.release ();
  return 0;
}
Exemplo n.º 23
0
unsigned int
execute_fixup_cfg (void)
{
  basic_block bb;
  gimple_stmt_iterator gsi;
  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
  gcov_type count_scale;
  edge e;
  edge_iterator ei;

  count_scale
      = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count,
                            ENTRY_BLOCK_PTR->count);

  ENTRY_BLOCK_PTR->count = cgraph_get_node (current_function_decl)->count;
  EXIT_BLOCK_PTR->count = apply_scale (EXIT_BLOCK_PTR->count,
                                       count_scale);

  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
    e->count = apply_scale (e->count, count_scale);

  FOR_EACH_BB (bb)
    {
      bb->count = apply_scale (bb->count, count_scale);
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree decl = is_gimple_call (stmt)
		      ? gimple_call_fndecl (stmt)
		      : NULL;
	  if (decl)
	    {
	      int flags = gimple_call_flags (stmt);
	      if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE))
		{
		  if (gimple_purge_dead_abnormal_call_edges (bb))
		    todo |= TODO_cleanup_cfg;

		  if (gimple_in_ssa_p (cfun))
		    {
		      todo |= TODO_update_ssa | TODO_cleanup_cfg;
		      update_stmt (stmt);
		    }
		}

	      if (flags & ECF_NORETURN
		  && fixup_noreturn_call (stmt))
		todo |= TODO_cleanup_cfg;
	     }

	  if (maybe_clean_eh_stmt (stmt)
	      && gimple_purge_dead_eh_edges (bb))
	    todo |= TODO_cleanup_cfg;
	}

      FOR_EACH_EDGE (e, ei, bb->succs)
        e->count = apply_scale (e->count, count_scale);

      /* If we have a basic block with no successors that does not
	 end with a control statement or a noreturn call end it with
	 a call to __builtin_unreachable.  This situation can occur
	 when inlining a noreturn call that does in fact return.  */
      if (EDGE_COUNT (bb->succs) == 0)
	{
	  gimple stmt = last_stmt (bb);
	  if (!stmt
	      || (!is_ctrl_stmt (stmt)
		  && (!is_gimple_call (stmt)
		      || (gimple_call_flags (stmt) & ECF_NORETURN) == 0)))
	    {
	      stmt = gimple_build_call
		  (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
	      gimple_stmt_iterator gsi = gsi_last_bb (bb);
	      gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
	    }
	}
    }
  if (count_scale != REG_BR_PROB_BASE)
    compute_function_frequency ();

  /* We just processed all calls.  */
  if (cfun->gimple_df)
    vec_free (MODIFIED_NORETURN_CALLS (cfun));

  /* Dump a textual representation of the flowgraph.  */
  if (dump_file)
    gimple_dump_cfg (dump_file, dump_flags);

  if (current_loops
      && (todo & TODO_cleanup_cfg))
    loops_state_set (LOOPS_NEED_FIXUP);

  return todo;
}
Exemplo n.º 24
0
static void gen_alloca_stmts(gimple_seq* stmts_, tree* sp_)
{
    /* doc: tree-complex.c, c-common.c, omp-low.c */

    /* create the stmt sequence so that:
       *sp = alloca(sizeof(type));
       type: the type to be stacked
       stmts: the allocation sequence
       sp: the allocated area ptr
     */

    gimple call;
    gimple_seq stmts;
    tree binop;
    tree mul;
    tree val;
    tree count;
    tree sizeuf;
    tree sp;
    tree ref;
    gimple assign;
    gimple_stmt_iterator gsi;

    /* build an empty sequence */
    stmts = gimple_seq_alloc();
    gsi = gsi_last(stmts);

#if 0 /* fixme */
    sp = create_tmp_var(ptr_type_node, NULL);
#else
    /* from varpool.c */
    sp = add_new_static_var(ptr_type_node);
#endif

    /* sp = __builtin_alloca(count * sizeof(uintptr_t)); */
    count = build_int_cst(integer_type_node, 2);
    sizeuf = build_int_cst(integer_type_node, sizeof(uintptr_t));
    mul = build2(MULT_EXPR, integer_type_node, count, sizeuf);
    /* call = gimple_build_call(built_in_decls[BUILT_IN_ALLOCA], 1, mul); */
    call = gimple_build_call(kaapi_pushdata_aligned_decl, 1, mul);
    gimple_call_set_lhs(call, sp);
    gsi_insert_after(&gsi, call, GSI_CONTINUE_LINKING);

    /* *(sp + 0) = 42; */
    ref = build1(INDIRECT_REF, TREE_TYPE(sp), sp);
    val = build_int_cst(ptr_type_node, 0xdeadc0d3);
    assign = gimple_build_assign(ref, val);
    gsi_insert_after(&gsi, assign, GSI_CONTINUE_LINKING);

    /* *(sp + 8) = 24 */
    binop = build_binary_op
            (0, PLUS_EXPR, convert(integer_type_node, sp), sizeuf, 0);
    ref = build1(INDIRECT_REF, TREE_TYPE(binop), binop);
    val = build_int_cst(ptr_type_node, 0xdeadc003);
    assign = gimple_build_assign(ref, val);
    gsi_insert_after(&gsi, assign, GSI_CONTINUE_LINKING);

    /* affect results */
    *sp_ = sp;
    *stmts_ = stmts;
}