Esempio n. 1
0
void
gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
{
  gimple stmt = value->hvalue.stmt;
  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
  gimple call;
  tree val;
  tree start = build_int_cst_type (integer_type_node,
				   value->hdata.intvl.int_start);
  tree steps = build_int_cst_type (unsigned_type_node,
				   value->hdata.intvl.steps);

  ref_ptr = force_gimple_operand_gsi (&gsi,
				      build_addr (ref, current_function_decl),
				      true, NULL_TREE, true, GSI_SAME_STMT);
  val = prepare_instrumented_value (&gsi, value);
  call = gimple_build_call (tree_interval_profiler_fn, 4,
			    ref_ptr, val, start, steps);
  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
Esempio n. 2
0
static void
issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
{
  HOST_WIDE_INT delta;
  tree addr, addr_base, write_p, local;
  gimple prefetch;
  gimple_stmt_iterator bsi;
  unsigned n_prefetches, ap;
  bool nontemporal = ref->reuse_distance >= L2_CACHE_SIZE_BYTES;

  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "Issued%s prefetch for %p.\n",
	     nontemporal ? " nontemporal" : "",
	     (void *) ref);

  bsi = gsi_for_stmt (ref->stmt);

  n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
		  / ref->prefetch_mod);
  addr_base = build_fold_addr_expr_with_type (ref->mem, ptr_type_node);
  addr_base = force_gimple_operand_gsi (&bsi, unshare_expr (addr_base),
					true, NULL, true, GSI_SAME_STMT);
  write_p = ref->write_p ? integer_one_node : integer_zero_node;
  local = build_int_cst (integer_type_node, nontemporal ? 0 : 3);

  for (ap = 0; ap < n_prefetches; ap++)
    {
      /* Determine the address to prefetch.  */
      delta = (ahead + ap * ref->prefetch_mod) * ref->group->step;
      addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
			  addr_base, size_int (delta));
      addr = force_gimple_operand_gsi (&bsi, unshare_expr (addr), true, NULL,
				       true, GSI_SAME_STMT);

      /* Create the prefetch instruction.  */
      prefetch = gimple_build_call (built_in_decls[BUILT_IN_PREFETCH],
				    3, addr, write_p, local);
      gsi_insert_before (&bsi, prefetch, GSI_SAME_STMT);
    }
}
Esempio n. 3
0
/* Try to compare bounds value and address value
   used in the check CI.  If we can prove that check
   always pass then remove it.  */
static void
chkp_remove_check_if_pass (struct check_info *ci)
{
    int result = 0;

    if (dump_file && (dump_flags & TDF_DETAILS))
    {
        fprintf (dump_file, "Trying to remove check: ");
        print_gimple_stmt (dump_file, ci->stmt, 0, 0);
    }

    result = chkp_get_check_result (ci, ci->bounds);

    if (result == 1)
    {
        gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);

        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  action: delete check (always pass)\n");

        gsi_remove (&i, true);
        unlink_stmt_vdef (ci->stmt);
        release_defs (ci->stmt);
        ci->stmt = NULL;
    }
    else if (result == -1)
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  action: keep check (always fail)\n");
        warning_at (gimple_location (ci->stmt), OPT_Wchkp,
                    "memory access check always fail");
    }
    else if (result == 0)
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  action: keep check (cannot compute result)\n");
    }
}
Esempio n. 4
0
static bool
remove_prop_source_from_use (tree name, gimple up_to_stmt)
{
  gimple_stmt_iterator gsi;
  gimple stmt;

  do {
    if (!has_zero_uses (name))
      return false;

    stmt = SSA_NAME_DEF_STMT (name);
    if (stmt == up_to_stmt)
      return true;

    gsi = gsi_for_stmt (stmt);
    release_defs (stmt);
    gsi_remove (&gsi, true);

    name = (gimple_assign_copy_p (stmt)) ? gimple_assign_rhs1 (stmt) : NULL;
  } while (name && TREE_CODE (name) == SSA_NAME);

  return false;
}
Esempio n. 5
0
/* Insert a call to the runtime function "__slimer_add_fn" which will add the
 * "junk" function created at compile-time to an array at runtime
 */
static void insert_add_fn(gimple stmt, int index)
{
    tree fn;
    gimple call;
    gimple_stmt_iterator gsi;
    static tree decl, proto, idx;

    if (!decl || !proto)
    {
        proto = build_function_type_list(void_type_node, ptr_type_node,
                                         integer_type_node, NULL_TREE);
        decl = build_fn_decl("__slimer_add_fn", proto);
    
        /* Add this fndecl to our list of things we do not process */
        VEC_safe_push(tree, gc, analyized_fns, decl);
    }

    /* Create a constant value and pointer to the function we are to add */
    idx = build_int_cst(integer_type_node, index);
    fn = build_addr(VEC_index(tree, fakes, index), NULL_TREE);
    call = gimple_build_call(decl, 2, fn, idx);
    gsi = gsi_for_stmt(stmt);
    gsi_insert_before(&gsi, call, GSI_NEW_STMT);
}
Esempio n. 6
0
static bool
ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
{
  gimple inner_cond, outer_cond;
  tree name1, name2, bits1, bits2;

  inner_cond = last_stmt (inner_cond_bb);
  if (!inner_cond
      || gimple_code (inner_cond) != GIMPLE_COND)
    return false;

  outer_cond = last_stmt (outer_cond_bb);
  if (!outer_cond
      || gimple_code (outer_cond) != GIMPLE_COND)
    return false;

  /* See if we have two bit tests of the same name in both tests.
     In that case remove the outer test and change the inner one to
     test for name & (bits1 | bits2) != 0.  */
  if (recognize_bits_test (inner_cond, &name1, &bits1)
      && recognize_bits_test (outer_cond, &name2, &bits2))
    {
      gimple_stmt_iterator gsi;
      tree t;

      /* Find the common name which is bit-tested.  */
      if (name1 == name2)
	;
      else if (bits1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else if (name1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	}
      else if (bits1 == name2)
	{
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else
	return false;

      /* As we strip non-widening conversions in finding a common
         name that is tested make sure to end up with an integral
	 type for building the bit operations.  */
      if (TYPE_PRECISION (TREE_TYPE (bits1))
	  >= TYPE_PRECISION (TREE_TYPE (bits2)))
	{
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  name1 = fold_convert (TREE_TYPE (bits1), name1);
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  bits2 = fold_convert (TREE_TYPE (bits1), bits2);
	}
      else
	{
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  name1 = fold_convert (TREE_TYPE (bits2), name1);
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  bits1 = fold_convert (TREE_TYPE (bits2), bits1);
	}

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (NE_EXPR, boolean_type_node, t,
		       build_int_cst (TREE_TYPE (t), 0));
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing bits or bits test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T != 0\nwith temporary T = ");
	  print_generic_expr (dump_file, bits1, 0);
	  fprintf (dump_file, " | ");
	  print_generic_expr (dump_file, bits2, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  /* See if we have two comparisons that we can merge into one.
     This happens for C++ operator overloading where for example
     GE_EXPR is implemented as GT_EXPR || EQ_EXPR.  */
  else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
	   && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison
	   && operand_equal_p (gimple_cond_lhs (inner_cond),
			       gimple_cond_lhs (outer_cond), 0)
	   && operand_equal_p (gimple_cond_rhs (inner_cond),
			       gimple_cond_rhs (outer_cond), 0))
    {
      enum tree_code code1 = gimple_cond_code (inner_cond);
      enum tree_code code2 = gimple_cond_code (outer_cond);
      enum tree_code code;
      tree t;

#define CHK(a,b) ((code1 == a ## _EXPR && code2 == b ## _EXPR) \
		  || (code2 == a ## _EXPR && code1 == b ## _EXPR))
      /* Merge the two condition codes if possible.  */
      if (code1 == code2)
	code = code1;
      else if (CHK (EQ, LT))
	code = LE_EXPR;
      else if (CHK (EQ, GT))
	code = GE_EXPR;
      else if (CHK (LT, LE))
	code = LE_EXPR;
      else if (CHK (GT, GE))
	code = GE_EXPR;
      else if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (inner_cond)))
	       || flag_unsafe_math_optimizations)
	{
	  if (CHK (LT, GT))
	    code = NE_EXPR;
	  else if (CHK (LT, NE))
	    code = NE_EXPR;
	  else if (CHK (GT, NE))
	    code = NE_EXPR;
	  else
	    return false;
	}
      /* We could check for combinations leading to trivial true/false.  */
      else
	return false;
#undef CHK

      /* Do it.  */
      t = fold_build2 (code, boolean_type_node, gimple_cond_lhs (outer_cond),
		       gimple_cond_rhs (outer_cond));
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing two comparisons to ");
	  print_generic_expr (dump_file, t, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  return false;
}
Esempio n. 7
0
static bool
ifcombine_ifandif (basic_block inner_cond_bb, basic_block outer_cond_bb)
{
  gimple_stmt_iterator gsi;
  gimple inner_cond, outer_cond;
  tree name1, name2, bit1, bit2;

  inner_cond = last_stmt (inner_cond_bb);
  if (!inner_cond
      || gimple_code (inner_cond) != GIMPLE_COND)
    return false;

  outer_cond = last_stmt (outer_cond_bb);
  if (!outer_cond
      || gimple_code (outer_cond) != GIMPLE_COND)
    return false;

  /* See if we test a single bit of the same name in both tests.  In
     that case remove the outer test, merging both else edges,
     and change the inner one to test for
     name & (bit1 | bit2) == (bit1 | bit2).  */
  if (recognize_single_bit_test (inner_cond, &name1, &bit1)
      && recognize_single_bit_test (outer_cond, &name2, &bit2)
      && name1 == name2)
    {
      tree t, t2;

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		       build_int_cst (TREE_TYPE (name1), 1), bit1);
      t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		        build_int_cst (TREE_TYPE (name1), 1), bit2);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
				     true, GSI_SAME_STMT);
      t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing double bit test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T == T\nwith temporary T = (1 << ");
	  print_generic_expr (dump_file, bit1, 0);
	  fprintf (dump_file, ") | (1 << ");
	  print_generic_expr (dump_file, bit2, 0);
	  fprintf (dump_file, ")\n");
	}

      return true;
    }

  return false;
}
Esempio n. 8
0
static bool
ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
		   basic_block outer_cond_bb, bool outer_inv, bool result_inv)
{
  gimple_stmt_iterator gsi;
  gimple inner_stmt, outer_stmt;
  gcond *inner_cond, *outer_cond;
  tree name1, name2, bit1, bit2, bits1, bits2;

  inner_stmt = last_stmt (inner_cond_bb);
  if (!inner_stmt
      || gimple_code (inner_stmt) != GIMPLE_COND)
    return false;
  inner_cond = as_a <gcond *> (inner_stmt);

  outer_stmt = last_stmt (outer_cond_bb);
  if (!outer_stmt
      || gimple_code (outer_stmt) != GIMPLE_COND)
    return false;
  outer_cond = as_a <gcond *> (outer_stmt);

  /* See if we test a single bit of the same name in both tests.  In
     that case remove the outer test, merging both else edges,
     and change the inner one to test for
     name & (bit1 | bit2) == (bit1 | bit2).  */
  if (recognize_single_bit_test (inner_cond, &name1, &bit1, inner_inv)
      && recognize_single_bit_test (outer_cond, &name2, &bit2, outer_inv)
      && name1 == name2)
    {
      tree t, t2;

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		       build_int_cst (TREE_TYPE (name1), 1), bit1);
      t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		        build_int_cst (TREE_TYPE (name1), 1), bit2);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
				     true, GSI_SAME_STMT);
      t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR,
		       boolean_type_node, t2, t);
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond,
	outer_inv ? boolean_false_node : boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing double bit test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T == T\nwith temporary T = (1 << ");
	  print_generic_expr (dump_file, bit1, 0);
	  fprintf (dump_file, ") | (1 << ");
	  print_generic_expr (dump_file, bit2, 0);
	  fprintf (dump_file, ")\n");
	}

      return true;
    }

  /* See if we have two bit tests of the same name in both tests.
     In that case remove the outer test and change the inner one to
     test for name & (bits1 | bits2) != 0.  */
  else if (recognize_bits_test (inner_cond, &name1, &bits1, !inner_inv)
      && recognize_bits_test (outer_cond, &name2, &bits2, !outer_inv))
    {
      gimple_stmt_iterator gsi;
      tree t;

      /* Find the common name which is bit-tested.  */
      if (name1 == name2)
	;
      else if (bits1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else if (name1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	}
      else if (bits1 == name2)
	{
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else
	return false;

      /* As we strip non-widening conversions in finding a common
         name that is tested make sure to end up with an integral
	 type for building the bit operations.  */
      if (TYPE_PRECISION (TREE_TYPE (bits1))
	  >= TYPE_PRECISION (TREE_TYPE (bits2)))
	{
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  name1 = fold_convert (TREE_TYPE (bits1), name1);
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  bits2 = fold_convert (TREE_TYPE (bits1), bits2);
	}
      else
	{
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  name1 = fold_convert (TREE_TYPE (bits2), name1);
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  bits1 = fold_convert (TREE_TYPE (bits2), bits1);
	}

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (result_inv ? NE_EXPR : EQ_EXPR, boolean_type_node, t,
		       build_int_cst (TREE_TYPE (t), 0));
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond,
	outer_inv ? boolean_false_node : boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing bits or bits test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T != 0\nwith temporary T = ");
	  print_generic_expr (dump_file, bits1, 0);
	  fprintf (dump_file, " | ");
	  print_generic_expr (dump_file, bits2, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  /* See if we have two comparisons that we can merge into one.  */
  else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
	   && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison)
    {
      tree t;
      enum tree_code inner_cond_code = gimple_cond_code (inner_cond);
      enum tree_code outer_cond_code = gimple_cond_code (outer_cond);

      /* Invert comparisons if necessary (and possible).  */
      if (inner_inv)
	inner_cond_code = invert_tree_comparison (inner_cond_code,
	  HONOR_NANS (gimple_cond_lhs (inner_cond)));
      if (inner_cond_code == ERROR_MARK)
	return false;
      if (outer_inv)
	outer_cond_code = invert_tree_comparison (outer_cond_code,
	  HONOR_NANS (gimple_cond_lhs (outer_cond)));
      if (outer_cond_code == ERROR_MARK)
	return false;
      /* Don't return false so fast, try maybe_fold_or_comparisons?  */

      if (!(t = maybe_fold_and_comparisons (inner_cond_code,
					    gimple_cond_lhs (inner_cond),
					    gimple_cond_rhs (inner_cond),
					    outer_cond_code,
					    gimple_cond_lhs (outer_cond),
					    gimple_cond_rhs (outer_cond))))
	{
	  tree t1, t2;
	  gimple_stmt_iterator gsi;
	  if (!LOGICAL_OP_NON_SHORT_CIRCUIT)
	    return false;
	  /* Only do this optimization if the inner bb contains only the conditional. */
	  if (!gsi_one_before_end_p (gsi_start_nondebug_after_labels_bb (inner_cond_bb)))
	    return false;
	  t1 = fold_build2_loc (gimple_location (inner_cond),
				inner_cond_code,
				boolean_type_node,
				gimple_cond_lhs (inner_cond),
				gimple_cond_rhs (inner_cond));
	  t2 = fold_build2_loc (gimple_location (outer_cond),
				outer_cond_code,
				boolean_type_node,
				gimple_cond_lhs (outer_cond),
				gimple_cond_rhs (outer_cond));
	  t = fold_build2_loc (gimple_location (inner_cond), 
			       TRUTH_AND_EXPR, boolean_type_node, t1, t2);
	  if (result_inv)
	    {
	      t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
	      result_inv = false;
	    }
	  gsi = gsi_for_stmt (inner_cond);
	  t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true,
					  GSI_SAME_STMT);
        }
      if (result_inv)
	t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond,
	outer_inv ? boolean_false_node : boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing two comparisons to ");
	  print_generic_expr (dump_file, t, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  return false;
}
Esempio n. 9
0
static bool
shrink_wrap_one_built_in_call (gimple bi_call)
{
  gimple_stmt_iterator bi_call_bsi;
  basic_block bi_call_bb, join_tgt_bb, guard_bb, guard_bb0;
  edge join_tgt_in_edge_from_call, join_tgt_in_edge_fall_thru;
  edge bi_call_in_edge0, guard_bb_in_edge;
  unsigned tn_cond_stmts, nconds;
  unsigned ci;
  gimple cond_expr = NULL;
  gimple cond_expr_start;
  tree bi_call_label_decl;
  gimple bi_call_label;

  auto_vec<gimple, 12> conds;
  gen_shrink_wrap_conditions (bi_call, conds, &nconds);

  /* This can happen if the condition generator decides
     it is not beneficial to do the transformation.  Just
     return false and do not do any transformation for
     the call.  */
  if (nconds == 0)
    return false;

  bi_call_bb = gimple_bb (bi_call);

  /* Now find the join target bb -- split bi_call_bb if needed.  */
  if (stmt_ends_bb_p (bi_call))
    {
      /* If the call must be the last in the bb, don't split the block,
	 it could e.g. have EH edges.  */
      join_tgt_in_edge_from_call = find_fallthru_edge (bi_call_bb->succs);
      if (join_tgt_in_edge_from_call == NULL)
        return false;
    }
  else
    join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);

  bi_call_bsi = gsi_for_stmt (bi_call);

  join_tgt_bb = join_tgt_in_edge_from_call->dest;

  /* Now it is time to insert the first conditional expression
     into bi_call_bb and split this bb so that bi_call is
     shrink-wrapped.  */
  tn_cond_stmts = conds.length ();
  cond_expr = NULL;
  cond_expr_start = conds[0];
  for (ci = 0; ci < tn_cond_stmts; ci++)
    {
      gimple c = conds[ci];
      gcc_assert (c || ci != 0);
      if (!c)
        break;
      gsi_insert_before (&bi_call_bsi, c, GSI_SAME_STMT);
      cond_expr = c;
    }
  nconds--;
  ci++;
  gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);

  /* Now the label.  */
  bi_call_label_decl = create_artificial_label (gimple_location (bi_call));
  bi_call_label = gimple_build_label (bi_call_label_decl);
  gsi_insert_before (&bi_call_bsi, bi_call_label, GSI_SAME_STMT);

  bi_call_in_edge0 = split_block (bi_call_bb, cond_expr);
  bi_call_in_edge0->flags &= ~EDGE_FALLTHRU;
  bi_call_in_edge0->flags |= EDGE_TRUE_VALUE;
  guard_bb0 = bi_call_bb;
  bi_call_bb = bi_call_in_edge0->dest;
  join_tgt_in_edge_fall_thru = make_edge (guard_bb0, join_tgt_bb,
                                          EDGE_FALSE_VALUE);

  bi_call_in_edge0->probability = REG_BR_PROB_BASE * ERR_PROB;
  bi_call_in_edge0->count =
      apply_probability (guard_bb0->count,
			 bi_call_in_edge0->probability);
  join_tgt_in_edge_fall_thru->probability =
      inverse_probability (bi_call_in_edge0->probability);
  join_tgt_in_edge_fall_thru->count =
      guard_bb0->count - bi_call_in_edge0->count;

  /* Code generation for the rest of the conditions  */
  guard_bb = guard_bb0;
  while (nconds > 0)
    {
      unsigned ci0;
      edge bi_call_in_edge;
      gimple_stmt_iterator guard_bsi = gsi_for_stmt (cond_expr_start);
      ci0 = ci;
      cond_expr_start = conds[ci0];
      for (; ci < tn_cond_stmts; ci++)
        {
          gimple c = conds[ci];
          gcc_assert (c || ci != ci0);
          if (!c)
            break;
          gsi_insert_before (&guard_bsi, c, GSI_SAME_STMT);
          cond_expr = c;
        }
      nconds--;
      ci++;
      gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);
      guard_bb_in_edge = split_block (guard_bb, cond_expr);
      guard_bb_in_edge->flags &= ~EDGE_FALLTHRU;
      guard_bb_in_edge->flags |= EDGE_FALSE_VALUE;

      bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_TRUE_VALUE);

      bi_call_in_edge->probability = REG_BR_PROB_BASE * ERR_PROB;
      bi_call_in_edge->count =
	  apply_probability (guard_bb->count,
			     bi_call_in_edge->probability);
      guard_bb_in_edge->probability =
          inverse_probability (bi_call_in_edge->probability);
      guard_bb_in_edge->count = guard_bb->count - bi_call_in_edge->count;
    }

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      location_t loc;
      loc = gimple_location (bi_call);
      fprintf (dump_file,
               "%s:%d: note: function call is shrink-wrapped"
               " into error conditions.\n",
               LOCATION_FILE (loc), LOCATION_LINE (loc));
    }

  return true;
}
static void
use_internal_fn (gcall *call)
{
  /* We'll be inserting another call with the same arguments after the
     lhs has been set, so prevent any possible coalescing failure from
     having both values live at once.  See PR 71020.  */
  replace_abnormal_ssa_names (call);

  unsigned nconds = 0;
  auto_vec<gimple *, 12> conds;
  if (can_test_argument_range (call))
    {
      gen_shrink_wrap_conditions (call, conds, &nconds);
      gcc_assert (nconds != 0);
    }
  else
    gcc_assert (edom_only_function (call));

  internal_fn ifn = replacement_internal_fn (call);
  gcc_assert (ifn != IFN_LAST);

  /* Construct the new call, with the same arguments as the original one.  */
  auto_vec <tree, 16> args;
  unsigned int nargs = gimple_call_num_args (call);
  for (unsigned int i = 0; i < nargs; ++i)
    args.safe_push (gimple_call_arg (call, i));
  gcall *new_call = gimple_build_call_internal_vec (ifn, args);
  gimple_set_location (new_call, gimple_location (call));
  gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call));

  /* Transfer the LHS to the new call.  */
  tree lhs = gimple_call_lhs (call);
  gimple_call_set_lhs (new_call, lhs);
  gimple_call_set_lhs (call, NULL_TREE);
  SSA_NAME_DEF_STMT (lhs) = new_call;

  /* Insert the new call.  */
  gimple_stmt_iterator gsi = gsi_for_stmt (call);
  gsi_insert_before (&gsi, new_call, GSI_SAME_STMT);

  if (nconds == 0)
    {
      /* Skip the call if LHS == LHS.  If we reach here, EDOM is the only
	 valid errno value and it is used iff the result is NaN.  */
      conds.quick_push (gimple_build_cond (EQ_EXPR, lhs, lhs,
					   NULL_TREE, NULL_TREE));
      nconds++;

      /* Try replacing the original call with a direct assignment to
	 errno, via an internal function.  */
      if (set_edom_supported_p () && !stmt_ends_bb_p (call))
	{
	  gimple_stmt_iterator gsi = gsi_for_stmt (call);
	  gcall *new_call = gimple_build_call_internal (IFN_SET_EDOM, 0);
	  gimple_set_vuse (new_call, gimple_vuse (call));
	  gimple_set_vdef (new_call, gimple_vdef (call));
	  SSA_NAME_DEF_STMT (gimple_vdef (new_call)) = new_call;
	  gimple_set_location (new_call, gimple_location (call));
	  gsi_replace (&gsi, new_call, false);
	  call = new_call;
	}
    }

  shrink_wrap_one_built_in_call_with_conds (call, conds, nconds);
}
static void
shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
					  unsigned int nconds)
{
  gimple_stmt_iterator bi_call_bsi;
  basic_block bi_call_bb, join_tgt_bb, guard_bb;
  edge join_tgt_in_edge_from_call, join_tgt_in_edge_fall_thru;
  edge bi_call_in_edge0, guard_bb_in_edge;
  unsigned tn_cond_stmts;
  unsigned ci;
  gimple *cond_expr = NULL;
  gimple *cond_expr_start;

  /* The cfg we want to create looks like this:

	   [guard n-1]         <- guard_bb (old block)
	     |    \
	     | [guard n-2]                   }
	     |    / \                        }
	     |   /  ...                      } new blocks
	     |  /  [guard 0]                 }
	     | /    /   |                    }
	    [ call ]    |     <- bi_call_bb  }
	     | \        |
	     |  \       |
	     |   [ join ]     <- join_tgt_bb (old iff call must end bb)
	     |
	 possible EH edges (only if [join] is old)

     When [join] is new, the immediate dominators for these blocks are:

     1. [guard n-1]: unchanged
     2. [call]: [guard n-1]
     3. [guard m]: [guard m+1] for 0 <= m <= n-2
     4. [join]: [guard n-1]

     We punt for the more complex case case of [join] being old and
     simply free the dominance info.  We also punt on postdominators,
     which aren't expected to be available at this point anyway.  */
  bi_call_bb = gimple_bb (bi_call);

  /* Now find the join target bb -- split bi_call_bb if needed.  */
  if (stmt_ends_bb_p (bi_call))
    {
      /* We checked that there was a fallthrough edge in
	 can_guard_call_p.  */
      join_tgt_in_edge_from_call = find_fallthru_edge (bi_call_bb->succs);
      gcc_assert (join_tgt_in_edge_from_call);
      /* We don't want to handle PHIs.  */
      if (EDGE_COUNT (join_tgt_in_edge_from_call->dest->preds) > 1)
	join_tgt_bb = split_edge (join_tgt_in_edge_from_call);
      else
	{
	  join_tgt_bb = join_tgt_in_edge_from_call->dest;
	  /* We may have degenerate PHIs in the destination.  Propagate
	     those out.  */
	  for (gphi_iterator i = gsi_start_phis (join_tgt_bb); !gsi_end_p (i);)
	    {
	      gphi *phi = i.phi ();
	      replace_uses_by (gimple_phi_result (phi),
			       gimple_phi_arg_def (phi, 0));
	      remove_phi_node (&i, true);
	    }
	}
    }
  else
    {
      join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
      join_tgt_bb = join_tgt_in_edge_from_call->dest;
    }

  bi_call_bsi = gsi_for_stmt (bi_call);

  /* Now it is time to insert the first conditional expression
     into bi_call_bb and split this bb so that bi_call is
     shrink-wrapped.  */
  tn_cond_stmts = conds.length ();
  cond_expr = NULL;
  cond_expr_start = conds[0];
  for (ci = 0; ci < tn_cond_stmts; ci++)
    {
      gimple *c = conds[ci];
      gcc_assert (c || ci != 0);
      if (!c)
        break;
      gsi_insert_before (&bi_call_bsi, c, GSI_SAME_STMT);
      cond_expr = c;
    }
  ci++;
  gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);

  typedef std::pair<edge, edge> edge_pair;
  auto_vec<edge_pair, 8> edges;

  bi_call_in_edge0 = split_block (bi_call_bb, cond_expr);
  bi_call_in_edge0->flags &= ~EDGE_FALLTHRU;
  bi_call_in_edge0->flags |= EDGE_FALSE_VALUE;
  guard_bb = bi_call_bb;
  bi_call_bb = bi_call_in_edge0->dest;
  join_tgt_in_edge_fall_thru = make_edge (guard_bb, join_tgt_bb,
                                          EDGE_TRUE_VALUE);

  edges.reserve (nconds);
  edges.quick_push (edge_pair (bi_call_in_edge0, join_tgt_in_edge_fall_thru));

  /* Code generation for the rest of the conditions  */
  for (unsigned int i = 1; i < nconds; ++i)
    {
      unsigned ci0;
      edge bi_call_in_edge;
      gimple_stmt_iterator guard_bsi = gsi_for_stmt (cond_expr_start);
      ci0 = ci;
      cond_expr_start = conds[ci0];
      for (; ci < tn_cond_stmts; ci++)
        {
	  gimple *c = conds[ci];
          gcc_assert (c || ci != ci0);
          if (!c)
            break;
          gsi_insert_before (&guard_bsi, c, GSI_SAME_STMT);
          cond_expr = c;
        }
      ci++;
      gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);
      guard_bb_in_edge = split_block (guard_bb, cond_expr);
      guard_bb_in_edge->flags &= ~EDGE_FALLTHRU;
      guard_bb_in_edge->flags |= EDGE_TRUE_VALUE;

      bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_FALSE_VALUE);
      edges.quick_push (edge_pair (bi_call_in_edge, guard_bb_in_edge));
    }

  /* Now update the probability and profile information, processing the
     guards in order of execution.

     There are two approaches we could take here.  On the one hand we
     could assign a probability of X to the call block and distribute
     that probability among its incoming edges.  On the other hand we
     could assign a probability of X to each individual call edge.

     The choice only affects calls that have more than one condition.
     In those cases, the second approach would give the call block
     a greater probability than the first.  However, the difference
     is only small, and our chosen X is a pure guess anyway.

     Here we take the second approach because it's slightly simpler
     and because it's easy to see that it doesn't lose profile counts.  */
  bi_call_bb->count = profile_count::zero ();
  while (!edges.is_empty ())
    {
      edge_pair e = edges.pop ();
      edge call_edge = e.first;
      edge nocall_edge = e.second;
      basic_block src_bb = call_edge->src;
      gcc_assert (src_bb == nocall_edge->src);

      call_edge->probability = profile_probability::very_unlikely ();
      nocall_edge->probability = profile_probability::always ()
				 - call_edge->probability;

      bi_call_bb->count += call_edge->count ();

      if (nocall_edge->dest != join_tgt_bb)
	nocall_edge->dest->count = src_bb->count - bi_call_bb->count;
    }

  if (dom_info_available_p (CDI_DOMINATORS))
    {
      /* The split_blocks leave [guard 0] as the immediate dominator
	 of [call] and [call] as the immediate dominator of [join].
	 Fix them up.  */
      set_immediate_dominator (CDI_DOMINATORS, bi_call_bb, guard_bb);
      set_immediate_dominator (CDI_DOMINATORS, join_tgt_bb, guard_bb);
    }

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      location_t loc;
      loc = gimple_location (bi_call);
      fprintf (dump_file,
               "%s:%d: note: function call is shrink-wrapped"
               " into error conditions.\n",
               LOCATION_FILE (loc), LOCATION_LINE (loc));
    }
}
static bool
conditional_replacement (basic_block cond_bb, basic_block middle_bb,
                         edge e0, edge e1, gimple phi,
                         tree arg0, tree arg1)
{
    tree result;
    gimple stmt, new_stmt;
    tree cond;
    gimple_stmt_iterator gsi;
    edge true_edge, false_edge;
    tree new_var, new_var2;

    /* FIXME: Gimplification of complex type is too hard for now.  */
    if (TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
            || TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
        return false;

    /* The PHI arguments have the constants 0 and 1, then convert
       it to the conditional.  */
    if ((integer_zerop (arg0) && integer_onep (arg1))
            || (integer_zerop (arg1) && integer_onep (arg0)))
        ;
    else
        return false;

    if (!empty_block_p (middle_bb))
        return false;

    /* At this point we know we have a GIMPLE_COND with two successors.
       One successor is BB, the other successor is an empty block which
       falls through into BB.

       There is a single PHI node at the join point (BB) and its arguments
       are constants (0, 1).

       So, given the condition COND, and the two PHI arguments, we can
       rewrite this PHI into non-branching code:

         dest = (COND) or dest = COND'

       We use the condition as-is if the argument associated with the
       true edge has the value one or the argument associated with the
       false edge as the value zero.  Note that those conditions are not
       the same since only one of the outgoing edges from the GIMPLE_COND
       will directly reach BB and thus be associated with an argument.  */

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

    /* To handle special cases like floating point comparison, it is easier and
       less error-prone to build a tree and gimplify it on the fly though it is
       less efficient.  */
    cond = fold_build2 (gimple_cond_code (stmt), boolean_type_node,
                        gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));

    /* We need to know which is the true edge and which is the false
       edge so that we know when to invert the condition below.  */
    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
    if ((e0 == true_edge && integer_zerop (arg0))
            || (e0 == false_edge && integer_onep (arg0))
            || (e1 == true_edge && integer_zerop (arg1))
            || (e1 == false_edge && integer_onep (arg1)))
        cond = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);

    /* Insert our new statements at the end of conditional block before the
       COND_STMT.  */
    gsi = gsi_for_stmt (stmt);
    new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true,
                                        GSI_SAME_STMT);

    if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var)))
    {
        new_var2 = create_tmp_var (TREE_TYPE (result), NULL);
        add_referenced_var (new_var2);
        new_stmt = gimple_build_assign_with_ops (CONVERT_EXPR, new_var2,
                   new_var, NULL);
        new_var2 = make_ssa_name (new_var2, new_stmt);
        gimple_assign_set_lhs (new_stmt, new_var2);
        gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
        new_var = new_var2;
    }

    replace_phi_edge_with_variable (cond_bb, e1, phi, new_var);

    /* Note that we optimized this PHI.  */
    return true;
}
Esempio n. 13
0
static bool
factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
				   tree arg0, tree arg1)
{
  gimple arg0_def_stmt = NULL, arg1_def_stmt = NULL, new_stmt;
  tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE;
  tree temp, result;
  gphi *newphi;
  gimple_stmt_iterator gsi, gsi_for_def;
  source_location locus = gimple_location (phi);
  enum tree_code convert_code;

  /* Handle only PHI statements with two arguments.  TODO: If all
     other arguments to PHI are INTEGER_CST or if their defining
     statement have the same unary operation, we can handle more
     than two arguments too.  */
  if (gimple_phi_num_args (phi) != 2)
    return false;

  /* First canonicalize to simplify tests.  */
  if (TREE_CODE (arg0) != SSA_NAME)
    {
      std::swap (arg0, arg1);
      std::swap (e0, e1);
    }

  if (TREE_CODE (arg0) != SSA_NAME
      || (TREE_CODE (arg1) != SSA_NAME
	  && TREE_CODE (arg1) != INTEGER_CST))
    return false;

  /* Check if arg0 is an SSA_NAME and the stmt which defines arg0 is
     a conversion.  */
  arg0_def_stmt = SSA_NAME_DEF_STMT (arg0);
  if (!is_gimple_assign (arg0_def_stmt)
      || !gimple_assign_cast_p (arg0_def_stmt))
    return false;

  /* Use the RHS as new_arg0.  */
  convert_code = gimple_assign_rhs_code (arg0_def_stmt);
  new_arg0 = gimple_assign_rhs1 (arg0_def_stmt);
  if (convert_code == VIEW_CONVERT_EXPR)
    new_arg0 = TREE_OPERAND (new_arg0, 0);

  if (TREE_CODE (arg1) == SSA_NAME)
    {
      /* Check if arg1 is an SSA_NAME and the stmt which defines arg1
	 is a conversion.  */
      arg1_def_stmt = SSA_NAME_DEF_STMT (arg1);
      if (!is_gimple_assign (arg1_def_stmt)
	  || gimple_assign_rhs_code (arg1_def_stmt) != convert_code)
	return false;

      /* Use the RHS as new_arg1.  */
      new_arg1 = gimple_assign_rhs1 (arg1_def_stmt);
      if (convert_code == VIEW_CONVERT_EXPR)
	new_arg1 = TREE_OPERAND (new_arg1, 0);
    }
  else
    {
      /* If arg1 is an INTEGER_CST, fold it to new type.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
	  && int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
	{
	  if (gimple_assign_cast_p (arg0_def_stmt))
	    new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
	  else
	    return false;
	}
      else
	return false;
    }

  /*  If arg0/arg1 have > 1 use, then this transformation actually increases
      the number of expressions evaluated at runtime.  */
  if (!has_single_use (arg0)
      || (arg1_def_stmt && !has_single_use (arg1)))
    return false;

  /* If types of new_arg0 and new_arg1 are different bailout.  */
  if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
    return false;

  /* Create a new PHI stmt.  */
  result = PHI_RESULT (phi);
  temp = make_ssa_name (TREE_TYPE (new_arg0), NULL);
  newphi = create_phi_node (temp, gimple_bb (phi));

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "PHI ");
      print_generic_expr (dump_file, gimple_phi_result (phi), 0);
      fprintf (dump_file,
	       " changed to factor conversion out from COND_EXPR.\n");
      fprintf (dump_file, "New stmt with CAST that defines ");
      print_generic_expr (dump_file, result, 0);
      fprintf (dump_file, ".\n");
    }

  /* Remove the old cast(s) that has single use.  */
  gsi_for_def = gsi_for_stmt (arg0_def_stmt);
  gsi_remove (&gsi_for_def, true);
  if (arg1_def_stmt)
    {
      gsi_for_def = gsi_for_s
static bool
ifcombine_ifandif (basic_block inner_cond_bb, basic_block outer_cond_bb)
{
  gimple_stmt_iterator gsi;
  gimple inner_cond, outer_cond;
  tree name1, name2, bit1, bit2;

  inner_cond = last_stmt (inner_cond_bb);
  if (!inner_cond
      || gimple_code (inner_cond) != GIMPLE_COND)
    return false;

  outer_cond = last_stmt (outer_cond_bb);
  if (!outer_cond
      || gimple_code (outer_cond) != GIMPLE_COND)
    return false;

  /* See if we test a single bit of the same name in both tests.  In
     that case remove the outer test, merging both else edges,
     and change the inner one to test for
     name & (bit1 | bit2) == (bit1 | bit2).  */
  if (recognize_single_bit_test (inner_cond, &name1, &bit1)
      && recognize_single_bit_test (outer_cond, &name2, &bit2)
      && name1 == name2)
    {
      tree t, t2;

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		       build_int_cst (TREE_TYPE (name1), 1), bit1);
      t2 = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1),
		        build_int_cst (TREE_TYPE (name1), 1), bit2);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), t, t2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
				     true, GSI_SAME_STMT);
      t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing double bit test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T == T\nwith temporary T = (1 << ");
	  print_generic_expr (dump_file, bit1, 0);
	  fprintf (dump_file, ") | (1 << ");
	  print_generic_expr (dump_file, bit2, 0);
	  fprintf (dump_file, ")\n");
	}

      return true;
    }

  /* See if we have two comparisons that we can merge into one.  */
  else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
	   && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison
	   && operand_equal_p (gimple_cond_lhs (inner_cond),
			       gimple_cond_lhs (outer_cond), 0)
	   && operand_equal_p (gimple_cond_rhs (inner_cond),
			       gimple_cond_rhs (outer_cond), 0))
    {
      enum tree_code code1 = gimple_cond_code (inner_cond);
      enum tree_code code2 = gimple_cond_code (outer_cond);
      tree t;

      if (!(t = combine_comparisons (UNKNOWN_LOCATION,
	      			     TRUTH_ANDIF_EXPR, code1, code2,
				     boolean_type_node,
				     gimple_cond_lhs (outer_cond),
				     gimple_cond_rhs (outer_cond))))
	return false;
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_true_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing two comparisons to ");
	  print_generic_expr (dump_file, t, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  return false;
}
Esempio n. 15
0
static void insert_call_to_junk_fn(gimple stmt)
{
    tree tv, rv, fn, rhs, tmp;
    gimple gimp;
    gimple_stmt_iterator gsi;
    static bool has_initted;
    static tree decl, proto, decl_get_funcs, proto_get_funcs, fn_ptr_type;
    
    printf("slimer: Inserting junk function call at line: %d\n",
            gimple_lineno(stmt));

    /* Get random value modulo n_funcs for index into runtime __funcs array of
     * junk functions:
     *     rv = time % n_funcs;
     *     fn = __funcs + rv;
     *     call fn
     */

    /* Build instances */
    if (!has_initted)
    {
        proto = build_function_type_list(
            uint64_type_node, ptr_type_node, NULL_TREE);
        decl = build_fn_decl("time", proto);
        DECL_EXTERNAL(decl) = 1;

        proto_get_funcs = build_function_type_list(ptr_type_node, NULL_TREE);
        decl_get_funcs = build_fn_decl("__slimer_get_funcs", proto_get_funcs);

        fn_ptr_type = build_function_type_list(
            void_type_node, void_type_node, NULL_TREE);

        has_initted = true;
    }

    /* time_tmp = time(NULL); */
    tv = create_tmp_var(uint64_type_node, "time_tmp");
    tv = make_ssa_name(tv, NULL);
    gimp = gimple_build_call(decl, 1, null_pointer_node);
    gimple_set_lhs(gimp, tv);
    gsi = gsi_for_stmt(stmt);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    /* rv_tmp = time_temp % n_funcs */
    rv = create_tmp_var(uint64_type_node, "rv_tmp");
    rv = make_ssa_name(rv, NULL);
    rhs = build_int_cst(integer_type_node, n_funcs);
    gimp = gimple_build_assign_with_ops(TRUNC_MOD_EXPR, rv, tv, rhs);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    /* tmp = __slimer_get_funcs(); TODO: Get rid of __slimer_get_funcs()
     * rv = rv * sizeof(void *)
     * fn_tmp = tmp + rv
     */
    tree pp_type = build_pointer_type(ptr_type_node);
    tmp = create_tmp_var(pp_type, "tmp");
    tmp = make_ssa_name(tmp, NULL);
    gimp = gimple_build_call(decl_get_funcs, 0);
    gimple_set_lhs(gimp, tmp);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    /* rv = rv * sizeof(void *))
     * FIXME: THIS IS NOT SUFFICIENT FOR CROSS COMPILING FOR ARCHITECTURES THAT
     * HAVE ADDRESS SIZES sizeof(void *)
     */
    tree addr_size = build_int_cst(integer_type_node, sizeof(void *));
    gimp = gimple_build_assign_with_ops(MULT_EXPR, rv, rv, addr_size);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    fn = create_tmp_var(pp_type, "fn_tmp");
    fn = make_ssa_name(fn, NULL);
    gimp = gimple_build_assign_with_ops(PLUS_EXPR, fn, tmp, rv);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    /* the_fn = *fn */
    tree f = build_pointer_type(fn_ptr_type); 
    tree the_fn = create_tmp_var(f, "the_func_ptr");
    the_fn = make_ssa_name(the_fn, NULL);
    gimp = gimple_build_assign(the_fn, build_simple_mem_ref(fn));
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

    /* call the_fn */
    gimp = gimple_build_call(the_fn, 0);
    gsi_insert_before(&gsi, gimp, GSI_SAME_STMT);

#ifdef GOAT_DEBUG
    debug_function(cfun->decl, 0);
#endif
}