Advertisement
prat3492

Untitled

Sep 16th, 2015
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 16.37 KB | None | 0 0
  1. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
  2. index fa4e083..27511bc 100644
  3. --- a/gcc/config/arm/arm.c
  4. +++ b/gcc/config/arm/arm.c
  5. @@ -309,6 +309,9 @@ static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
  6.  static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void);
  7.  
  8.  static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*);
  9. +
  10. +static bool arm_combine_divmod(enum machine_mode mode);
  11. +
  12.  
  13.  /* Table of machine attributes.  */
  14.  static const struct attribute_spec arm_attribute_table[] =
  15. @@ -735,6 +738,9 @@ static const struct attribute_spec arm_attribute_table[] =
  16.  #undef TARGET_SCHED_FUSION_PRIORITY
  17.  #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority
  18.  
  19. +#undef TARGET_COMBINE_DIVMOD
  20. +#define TARGET_COMBINE_DIVMOD arm_combine_divmod
  21. +
  22.  struct gcc_target targetm = TARGET_INITIALIZER;
  23.  
  24.  /* Obstack for minipool constant handling.  */
  25. @@ -29781,4 +29787,14 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri,
  26.    *pri = tmp;
  27.    return;
  28.  }
  29. +
  30. +/* Implement TARGET_COMBINE_DIVMOD hook.  */
  31. +
  32. +static bool
  33. +arm_combine_divmod (enum machine_mode mode ATTRIBUTE_UNUSED)
  34. +{
  35. +  /// ??? return true for all modes ?
  36. +  return true;
  37. +}
  38. +
  39.  #include "gt-arm.h"
  40. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
  41. index d548d96..8cd0500 100644
  42. --- a/gcc/doc/tm.texi
  43. +++ b/gcc/doc/tm.texi
  44. @@ -11541,6 +11541,10 @@ The support includes the assembler, linker and dynamic linker.
  45.  The default value of this hook is based on target's libc.
  46.  @end deftypefn
  47.  
  48. +@deftypefn {Target Hook} bool TARGET_COMBINE_DIVMOD (enum machine_mode @var{mode})
  49. +This target hook returns @code{true} if the target provides divmod libcall operation for the machine mode @var{mode} and must be used to combine integer division and modulus operations. Return @code{false} otherwise.
  50. +@end deftypefn
  51. +
  52.  @deftypefn {Target Hook} {unsigned int} TARGET_ATOMIC_ALIGN_FOR_MODE (machine_mode @var{mode})
  53.  If defined, this function returns an appropriate alignment in bits for an atomic object of machine_mode @var{mode}.  If 0 is returned then the default alignment for the specified mode is used.
  54.  @end deftypefn
  55. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
  56. index 9bef4a5..ea207ef 100644
  57. --- a/gcc/doc/tm.texi.in
  58. +++ b/gcc/doc/tm.texi.in
  59. @@ -8193,6 +8193,8 @@ and the associated definitions of those functions.
  60.  
  61.  @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
  62.  
  63. +@hook TARGET_COMBINE_DIVMOD
  64. +
  65.  @hook TARGET_HAS_IFUNC_P
  66.  
  67.  @hook TARGET_ATOMIC_ALIGN_FOR_MODE
  68. diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
  69. index e785946..cf28011 100644
  70. --- a/gcc/internal-fn.c
  71. +++ b/gcc/internal-fn.c
  72. @@ -1942,6 +1942,56 @@ expand_VA_ARG (gcall *stmt ATTRIBUTE_UNUSED)
  73.    gcc_unreachable ();
  74.  }
  75.  
  76. +static void
  77. +expand_DIVMOD (gcall *stmt)
  78. +{
  79. +  tree type, lhs, arg0, arg1;
  80. +  rtx op0, op1, res0, res1, target;
  81. +  enum machine_mode mode, compute_mode;
  82. +  rtx libval;
  83. +  rtx libfunc = NULL_RTX;
  84. +  bool is_unsigned;
  85. +
  86. +  lhs = gimple_call_lhs (stmt);
  87. +  arg0 = gimple_call_arg (stmt, 0);
  88. +  arg1 = gimple_call_arg (stmt, 1);
  89. +  mode = TYPE_MODE (TREE_TYPE (arg0));
  90. +  is_unsigned = TYPE_UNSIGNED (TREE_TYPE (arg0));
  91. +
  92. +  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
  93. +  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
  94. +  target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  95. +
  96. +  for (compute_mode = mode; compute_mode != VOIDmode; compute_mode = GET_MODE_WIDER_MODE (compute_mode))
  97. +    if (optab_libfunc (is_unsigned ? udivmod_optab : sdivmod_optab, compute_mode))
  98. +      break;
  99. +
  100. +  if (compute_mode != mode)
  101. +    {
  102. +      op0 = convert_modes (compute_mode, mode, op0, is_unsigned);
  103. +      op1 = convert_modes (compute_mode, mode, op1, is_unsigned);
  104. +    }
  105. +
  106. +  /* Get the libcall */
  107. +  libfunc = optab_libfunc (is_unsigned ? udivmod_optab : sdivmod_optab, compute_mode);
  108. +  gcc_assert (libfunc);
  109. +
  110. +  machine_mode libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (compute_mode), MODE_INT);
  111. +  libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, libval_mode, 2,
  112. +                   op0, compute_mode, op1, compute_mode);
  113. +
  114. +  /* Get quotient and remainder into two registers.  */
  115. +  res0 = simplify_gen_subreg (mode, libval, libval_mode, 0);
  116. +  res1 = simplify_gen_subreg (mode, libval, libval_mode, GET_MODE_SIZE (compute_mode));
  117. +
  118. +  /* Now build the complex integer target.  */
  119. +  expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
  120. +                       make_tree (TREE_TYPE (arg0), res0),
  121. +                       make_tree (TREE_TYPE (arg1), res1)),
  122. +               target, VOIDmode, EXPAND_NORMAL);
  123. +}
  124. +
  125. +
  126.  /* Routines to expand each internal function, indexed by function number.
  127.     Each routine has the prototype:
  128.  
  129. diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
  130. index ba5c2c1..c9363cc 100644
  131. --- a/gcc/internal-fn.def
  132. +++ b/gcc/internal-fn.def
  133. @@ -63,3 +63,4 @@ DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
  134.  DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
  135.  DEF_INTERNAL_FN (TSAN_FUNC_EXIT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
  136.  DEF_INTERNAL_FN (VA_ARG, ECF_NOTHROW | ECF_LEAF, NULL)
  137. +DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL)
  138. diff --git a/gcc/passes.def b/gcc/passes.def
  139. index 64fc4d9..315484d 100644
  140. --- a/gcc/passes.def
  141. +++ b/gcc/passes.def
  142. @@ -271,6 +271,7 @@ along with GCC; see the file COPYING3.  If not see
  143.        NEXT_PASS (pass_simduid_cleanup);
  144.        NEXT_PASS (pass_lower_vector_ssa);
  145.        NEXT_PASS (pass_cse_reciprocals);
  146. +      NEXT_PASS (pass_cse_divmod);
  147.        NEXT_PASS (pass_reassoc);
  148.        NEXT_PASS (pass_strength_reduction);
  149.        NEXT_PASS (pass_tracer);
  150. diff --git a/gcc/target.def b/gcc/target.def
  151. index aa5a1f1..ead638d 100644
  152. --- a/gcc/target.def
  153. +++ b/gcc/target.def
  154. @@ -4875,6 +4875,16 @@ Normally, this is not needed.",
  155.   bool, (const_tree field, machine_mode mode),
  156.   default_member_type_forces_blk)
  157.  
  158. +/* True if div and mod operations for MODE should be combined.  */
  159. +DEFHOOK
  160. +(combine_divmod,
  161. + "This target hook returns @code{true} if the target provides divmod libcall\
  162. + operation for the machine mode @var{mode} and must be used to combine\
  163. + integer division and modulus operations. Return @code{false} otherwise.",
  164. + bool, (enum machine_mode mode),
  165. + default_combine_divmod)
  166. +
  167. +
  168.  /* Return the class for a secondary reload, and fill in extra information.  */
  169.  DEFHOOK
  170.  (secondary_reload,
  171. diff --git a/gcc/targhooks.c b/gcc/targhooks.c
  172. index 7238c8f..907338e 100644
  173. --- a/gcc/targhooks.c
  174. +++ b/gcc/targhooks.c
  175. @@ -1922,4 +1922,9 @@ can_use_doloop_if_innermost (const widest_int &, const widest_int &,
  176.    return loop_depth == 1;
  177.  }
  178.  
  179. +bool default_combine_divmod (enum machine_mode mode ATTRIBUTE_UNUSED)
  180. +{
  181. +  return false;
  182. +}
  183. +
  184.  #include "gt-targhooks.h"
  185. diff --git a/gcc/targhooks.h b/gcc/targhooks.h
  186. index 5ae991d..8275e0e 100644
  187. --- a/gcc/targhooks.h
  188. +++ b/gcc/targhooks.h
  189. @@ -240,4 +240,7 @@ extern void default_setup_incoming_vararg_bounds (cumulative_args_t ca ATTRIBUTE
  190.                           tree type ATTRIBUTE_UNUSED,
  191.                           int *pretend_arg_size ATTRIBUTE_UNUSED,
  192.                           int second_time ATTRIBUTE_UNUSED);
  193. +
  194. +extern bool default_combine_divmod (enum machine_mode);
  195. +
  196.  #endif /* GCC_TARGHOOKS_H */
  197. diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
  198. index 7b66a1c..8e14950 100644
  199. --- a/gcc/tree-pass.h
  200. +++ b/gcc/tree-pass.h
  201. @@ -414,6 +414,7 @@ extern gimple_opt_pass *make_pass_early_warn_uninitialized (gcc::context *ctxt);
  202.  extern gimple_opt_pass *make_pass_late_warn_uninitialized (gcc::context *ctxt);
  203.  extern gimple_opt_pass *make_pass_cse_reciprocals (gcc::context *ctxt);
  204.  extern gimple_opt_pass *make_pass_cse_sincos (gcc::context *ctxt);
  205. +extern gimple_opt_pass *make_pass_cse_divmod (gcc::context *ctxt);
  206.  extern gimple_opt_pass *make_pass_optimize_bswap (gcc::context *ctxt);
  207.  extern gimple_opt_pass *make_pass_optimize_widening_mul (gcc::context *ctxt);
  208.  extern gimple_opt_pass *make_pass_warn_function_return (gcc::context *ctxt);
  209. diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
  210. index eae5358..095b836 100644
  211. --- a/gcc/tree-ssa-math-opts.c
  212. +++ b/gcc/tree-ssa-math-opts.c
  213. @@ -3643,3 +3643,254 @@ make_pass_optimize_widening_mul (gcc::context *ctxt)
  214.  {
  215.    return new pass_optimize_widening_mul (ctxt);
  216.  }
  217. +
  218. +namespace {
  219. +
  220. +static struct
  221. +{
  222. +  int divmod_calls_inserted;
  223. +  int divmod_result_used;
  224. +} divmod_stats;
  225. +
  226. +
  227. +const pass_data pass_data_combine_divmod =
  228. +{
  229. +  GIMPLE_PASS, /* type */
  230. +  "divmod", /* name */
  231. +  OPTGROUP_NONE, /* optinfo_flags */
  232. +  TV_NONE, /* tv_id */
  233. +  PROP_ssa, /* properties_required */
  234. +  0, /* properties_provided */
  235. +  0, /* properties_destroyed */
  236. +  0, /* todo_flags_start */
  237. +  TODO_update_ssa, /* todo_flags_finish */
  238. +};
  239. +
  240. +class pass_cse_divmod : public gimple_opt_pass
  241. +{
  242. +public:
  243. +  pass_cse_divmod (gcc::context *ctxt)
  244. +    : gimple_opt_pass (pass_data_combine_divmod, ctxt)
  245. +  {}
  246. +
  247. +  /* opt_pass methods: */
  248. +  virtual bool gate (function *)
  249. +    {
  250. +      return optimize;
  251. +    }
  252. +
  253. +  virtual unsigned int execute (function *);
  254. +
  255. +private:
  256. +  static bool execute_cse_divmod_1 (gimple);
  257. +  static bool maybe_record_stmt (vec<gimple> *stmts, basic_block *top_bb, gimple use_stmt)
  258. +    {
  259. +      stmts->safe_push (use_stmt);
  260. +      basic_block use_bb = gimple_bb (use_stmt);
  261. +      return true;
  262. +    }
  263. +
  264. +}; // class pass_cse_divmod
  265. +
  266. +/* Look for div and mod statements with the same operands and
  267. +   create a library call if needed.  We first walk over all
  268. +   immediate uses of one of the operand looking for matched statement
  269. +   that we can combine.  In a second pass replace the statement with
  270. +   a library calls and statements with the results from library call.  */
  271. +
  272. +bool
  273. +pass_cse_divmod::execute_cse_divmod_1 (gimple stmt)
  274. +{
  275. +  gimple_stmt_iterator gsi;
  276. +  imm_use_iterator use_iter;
  277. +  gimple use_stmt;
  278. +  bool found = false;
  279. +  vec<gimple> stmts = vNULL;
  280. +  basic_block top_bb = NULL;
  281. +  bool cfg_changed = false;
  282. +  int i;
  283. +  tree type, op1, op2;
  284. +
  285. +  op1 = gimple_assign_rhs1 (stmt);
  286. +  op2 = gimple_assign_rhs2 (stmt);
  287. +  type = TREE_TYPE (op1);
  288. +
  289. +  /* Skip if both the operands and constant. */
  290. +  if (TREE_CODE (op1) == INTEGER_CST && TREE_CODE (op2) == INTEGER_CST)
  291. +    return false;
  292. +
  293. +  /* Skip if the target doesnt support or require it.  */
  294. +  if (!targetm.combine_divmod (TYPE_MODE (type)))
  295. +    return false;
  296. +
  297. +  stmts.safe_push (stmt);
  298. +  top_bb = gimple_bb (stmt);
  299. +
  300. +  /* look fpr a TRUNC_MOD_EXPR coresponding to stmt
  301. +     TRUNC_DIV_EXPR s to combine.  */
  302. +  FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, (TREE_CODE (op2) == SSA_NAME) ? op2 : op1)
  303. +    {
  304. +      if (is_gimple_assign (use_stmt)
  305. +          && (gimple_assign_rhs_code (use_stmt) == TRUNC_MOD_EXPR))
  306. +        {
  307. +          tree rhs1 = gimple_assign_rhs1 (use_stmt);
  308. +          tree rhs2 = gimple_assign_rhs2 (use_stmt);
  309. +
  310. +          if ((rhs1 == op1 && rhs2 == op2)
  311. +              ||(rhs1 == op1 && rhs2 == op2))
  312. +            found |= maybe_record_stmt (&stmts, &top_bb, use_stmt);
  313. +        }
  314. +    }
  315. +
  316. +  /* If we have matched instructions to combine, try creatiing Library
  317. +     call and use the results.  */
  318. +  if (found)
  319. +    {
  320. +      gimple def_stmt1 = NULL, def_stmt2 = NULL;
  321. +      bool insert_after_op1_def, insert_after_op2_def;
  322. +      tree res, rhs;
  323. +      gimple assign_stmt, call_stmt;
  324. +      tree return_type = build_complex_type (type);
  325. +
  326. +      if (TREE_CODE (op1) == SSA_NAME)
  327. +        def_stmt1 = SSA_NAME_DEF_STMT (op1);
  328. +      if (TREE_CODE (op2) == SSA_NAME)
  329. +        def_stmt2 = SSA_NAME_DEF_STMT (op2);
  330. +
  331. +      /* Is the call to be insterted adter op1 define stmt.  */
  332. +      insert_after_op1_def = TREE_CODE (op1) == SSA_NAME
  333. +                            && !SSA_NAME_IS_DEFAULT_DEF (op1)
  334. +                            && gimple_code (def_stmt1) != GIMPLE_PHI
  335. +                            && gimple_bb (def_stmt1) == top_bb;
  336. +
  337. +      /* Is the call to be insterted adter op2 define stmt.  */
  338. +      insert_after_op2_def = TREE_CODE (op2) == SSA_NAME
  339. +                            && !SSA_NAME_IS_DEFAULT_DEF (op2)
  340. +                            && gimple_code (def_stmt2) != GIMPLE_PHI
  341. +                            && gimple_bb (def_stmt2) == top_bb;
  342. +
  343. +      /* Create a library call and instert it at the place idenified.  */
  344. +      call_stmt = gimple_build_call_internal (IFN_DIVMOD, 2, op1, op2);
  345. +      res = make_temp_ssa_name (return_type,
  346. +                                call_stmt, "divmod");
  347. +      gimple_call_set_lhs (call_stmt, res);
  348. +      divmod_stats.divmod_calls_inserted++;
  349. +
  350. +      /* Insert call at the beginning of top_bb but not earlier
  351. +         than the name def statement.  */
  352. +      if (insert_after_op1_def || insert_after_op2_def)
  353. +        {
  354. +          if (insert_after_op1_def && insert_after_op2_def)
  355. +            {
  356. +              for (gsi = gsi_start_bb (top_bb);
  357. +                   !gsi_end_p (gsi); gsi_next (&gsi))
  358. +                {
  359. +                  gimple g = gsi_stmt (gsi);
  360. +                  if (g == def_stmt1)
  361. +                    {
  362. +                      gsi = gsi_for_stmt (def_stmt2);
  363. +                      break;
  364. +                    }
  365. +                  else if (g == def_stmt2)
  366. +                    {
  367. +                      gsi = gsi_for_stmt (def_stmt1);
  368. +                      break;
  369. +                    }
  370. +                }
  371. +            }
  372. +
  373. +          /* Only one of the definition is in the basic block, place after
  374. +             that.  */
  375. +          else if (insert_after_op1_def)
  376. +            gsi = gsi_for_stmt (def_stmt1);
  377. +          else
  378. +            gsi = gsi_for_stmt (def_stmt2);
  379. +
  380. +          gsi_insert_after (&gsi, call_stmt, GSI_SAME_STMT);
  381. +        }
  382. +      else
  383. +        {
  384. +          /* op1 and op2 are defined before the top_bb.  Insert as first
  385. +             non label instruction.  */
  386. +          gsi = gsi_after_labels (top_bb);
  387. +          gsi_insert_before (&gsi, call_stmt, GSI_SAME_STMT);
  388. +        }
  389. +
  390. +      /* Adjust the recorded old statements to use the results.  */
  391. +      for (i = 0; stmts.iterate (i, &use_stmt); ++i)
  392. +        {
  393. +          gsi = gsi_for_stmt (use_stmt);
  394. +          divmod_stats.divmod_result_used++;
  395. +
  396. +          switch (gimple_assign_rhs_code (use_stmt))
  397. +            {
  398. +            case TRUNC_MOD_EXPR:
  399. +              /* Get the top 32 bit from result and assign it.  */
  400. +              rhs = fold_build1 (IMAGPART_EXPR, type, res);
  401. +              break;
  402. +
  403. +            case TRUNC_DIV_EXPR:
  404. +              /* Get the bottom 32 bit from result and assign it.  */
  405. +              rhs = fold_build1 (REALPART_EXPR, type, res);
  406. +              break;
  407. +
  408. +            default:
  409. +              gcc_unreachable ();
  410. +            }
  411. +
  412. +          /* Replace the statement with a copy.  */
  413. +          assign_stmt = gimple_build_assign (gimple_assign_lhs (use_stmt), rhs);
  414. +          gsi_replace (&gsi, assign_stmt, true);
  415. +
  416. +          if (gimple_purge_dead_eh_edges (gimple_bb (assign_stmt)))
  417. +            cfg_changed = true;
  418. +        }
  419. +    }
  420. +
  421. +  stmts.release ();
  422. +  return cfg_changed;
  423. +}
  424. +
  425. +/* Go through all the floating-point SSA_NAMEs, and call
  426. +   execute_cse_reciprocals_1 on each of them.  */
  427. +unsigned
  428. +pass_cse_divmod::execute (function *fun)
  429. +{
  430. +  basic_block bb;
  431. +
  432. +  memset (&divmod_stats, 0, sizeof (divmod_stats));
  433. +  calculate_dominance_info (CDI_DOMINATORS);
  434. +  calculate_dominance_info (CDI_POST_DOMINATORS);
  435. +  FOR_EACH_BB_FN (bb, fun)
  436. +    {
  437. +      gimple_stmt_iterator gsi;
  438. +      for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
  439. +        {
  440. +          gimple stmt = gsi_stmt (gsi);
  441. +
  442. +          if (is_gimple_assign (stmt)
  443. +              && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_binary)
  444. +              && (gimple_assign_rhs_code (stmt) ==  TRUNC_DIV_EXPR))
  445. +            {
  446. +              pass_cse_divmod::execute_cse_divmod_1 (stmt);
  447. +            }
  448. +        }
  449. +    }
  450. +
  451. +  statistics_counter_event (cfun, "number of combined divmod calls inserted",
  452. +                            divmod_stats.divmod_calls_inserted);
  453. +  statistics_counter_event (cfun, "number of instructions uses divmod result",
  454. +                            divmod_stats.divmod_result_used);
  455. +
  456. +  free_dominance_info (CDI_DOMINATORS);
  457. +  free_dominance_info (CDI_POST_DOMINATORS);
  458. +  return 0;
  459. +}
  460. +
  461. +} // anon namespace
  462. +
  463. +gimple_opt_pass *
  464. +make_pass_cse_divmod (gcc::context *ctxt)
  465. +{
  466. +  return new pass_cse_divmod (ctxt);
  467. +}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement