Advertisement
prat3492

Untitled

Nov 3rd, 2015
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 13.66 KB | None | 0 0
  1. diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
  2. index a7da373..1fda966 100644
  3. --- a/gcc/internal-fn.c
  4. +++ b/gcc/internal-fn.c
  5. @@ -2045,6 +2045,75 @@ expand_GOACC_LOOP (gcall *stmt ATTRIBUTE_UNUSED)
  6.    gcc_unreachable ();
  7.  }
  8.  
  9. +/* Expand DIVMOD() using:
  10. + a) optab handler for udivmod/sdivmod if it is available
  11. + b) If optab_handler doesn't exist, Generate call to optab_libfunc for udivmod/sdivmod.  */
  12. +
  13. +static void
  14. +expand_DIVMOD (gcall *stmt)
  15. +{
  16. +  tree lhs = gimple_call_lhs (stmt);
  17. +  tree arg0 = gimple_call_arg (stmt, 0);
  18. +  tree arg1 = gimple_call_arg (stmt, 1);
  19. +  
  20. +  gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
  21. +  tree type = TREE_TYPE (TREE_TYPE (lhs));
  22. +  machine_mode mode = TYPE_MODE (type);
  23. +  optab tab = (TYPE_UNSIGNED (type)) ? udivmod_optab : sdivmod_optab;
  24. +
  25. +  rtx op0 = expand_normal (arg0);
  26. +  rtx op1 = expand_normal (arg1);
  27. +  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  28. +
  29. +  /* Check if optab handler exists for udivmod/sdivmod.  */
  30. +  if (optab_handler (tab, mode) != CODE_FOR_nothing)
  31. +    {
  32. +      rtx quotient = gen_reg_rtx (mode);
  33. +      rtx remainder = gen_reg_rtx (mode);
  34. +      expand_twoval_binop (tab, op0, op1, quotient, remainder, TYPE_UNSIGNED (type));
  35. +  
  36. +      /* Wrap the return value (quotient, remaineder) within COMPLEX_EXPR */
  37. +      expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
  38. +                  make_tree (TREE_TYPE (arg0), quotient),
  39. +                  make_tree (TREE_TYPE (arg1), remainder)),
  40. +                  target, VOIDmode, EXPAND_NORMAL);
  41. +
  42. +      return;
  43. +    }
  44. +
  45. +  rtx libfunc = NULL_RTX;
  46. +  machine_mode compute_mode;
  47. +  for (compute_mode = mode;
  48. +       compute_mode != VOIDmode;
  49. +       compute_mode = GET_MODE_WIDER_MODE (compute_mode))
  50. +    {
  51. +      libfunc = optab_libfunc (tab, compute_mode);
  52. +      if (libfunc != NULL_RTX)
  53. +       break;
  54. +    }
  55. +
  56. +  gcc_assert (libfunc != NULL_RTX);
  57. +  
  58. +  if (compute_mode != mode)
  59. +    {
  60. +      op0 = convert_modes (compute_mode, GET_MODE (op0), op0, tab);
  61. +      op1 = convert_modes (compute_mode, GET_MODE (op1), op1, tab);
  62. +    }
  63. +
  64. +  machine_mode libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (compute_mode), MODE_INT);
  65. +  rtx libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
  66. +                                       libval_mode, 2, op0, compute_mode, op1, compute_mode);  
  67. +
  68. +  rtx quotient = simplify_gen_subreg (mode, libval, libval_mode, 0);
  69. +  rtx remainder = simplify_gen_subreg (mode, libval, libval_mode, GET_MODE_SIZE (compute_mode));
  70. +
  71. +  /* Wrap the return value (quotient, remaineder) within COMPLEX_EXPR */
  72. +  expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
  73. +                      make_tree (TREE_TYPE (arg0), quotient),
  74. +                      make_tree (TREE_TYPE (arg1), remainder)),
  75. +             target, VOIDmode, EXPAND_NORMAL);
  76. +}
  77. +
  78.  /* Routines to expand each internal function, indexed by function number.
  79.     Each routine has the prototype:
  80.  
  81. diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
  82. index 78266d9..f28579b 100644
  83. --- a/gcc/internal-fn.def
  84. +++ b/gcc/internal-fn.def
  85. @@ -83,3 +83,5 @@ DEF_INTERNAL_FN (GOACC_DIM_POS, ECF_PURE | ECF_NOTHROW | ECF_LEAF, ".")
  86.  
  87.  /* OpenACC looping abstraction.  See internal-fn.h for usage.  */
  88.  DEF_INTERNAL_FN (GOACC_LOOP, ECF_PURE | ECF_NOTHROW, NULL)
  89. +
  90. +DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL)
  91. diff --git a/gcc/testsuite/gcc.dg/pr43721-1.c b/gcc/testsuite/gcc.dg/pr43721-1.c
  92. new file mode 100644
  93. index 0000000..8873d9f
  94. --- /dev/null
  95. +++ b/gcc/testsuite/gcc.dg/pr43721-1.c
  96. @@ -0,0 +1,10 @@
  97. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  98. +
  99. +int f(int x, int y)
  100. +{
  101. +  int quotient = x / y;
  102. +  int remainder = x % y;
  103. +  return quotient + remainder;
  104. +}
  105. +
  106. +/* { dg-final { scan-tree-dump-times "DIVMOD" 1 "widening_mul" } } */
  107. diff --git a/gcc/testsuite/gcc.dg/pr43721-2.c b/gcc/testsuite/gcc.dg/pr43721-2.c
  108. new file mode 100644
  109. index 0000000..62d73af
  110. --- /dev/null
  111. +++ b/gcc/testsuite/gcc.dg/pr43721-2.c
  112. @@ -0,0 +1,16 @@
  113. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  114. +
  115. +int f(int x, int y)
  116. +{
  117. +  extern int early_exit;
  118. +
  119. +  int quot = x / y;
  120. +
  121. +  if (early_exit)
  122. +    return 0;
  123. +
  124. +  int rem = x % y;
  125. +  return quot + rem;
  126. +}
  127. +
  128. +/* { dg-final { scan-tree-dump-times "DIVMOD" 1 "widening_mul" } } */
  129. diff --git a/gcc/testsuite/gcc.dg/pr43721-3.c b/gcc/testsuite/gcc.dg/pr43721-3.c
  130. new file mode 100644
  131. index 0000000..74816a0
  132. --- /dev/null
  133. +++ b/gcc/testsuite/gcc.dg/pr43721-3.c
  134. @@ -0,0 +1,17 @@
  135. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  136. +
  137. +int f(int x, int y)
  138. +{
  139. +  extern int flag;
  140. +  int quot;
  141. +
  142. +  if (flag)
  143. +    quot = x / y;
  144. +  else
  145. +    quot = 0;
  146. +
  147. +  int rem = x % y;
  148. +  return quot + rem;
  149. +}
  150. +
  151. +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */
  152. diff --git a/gcc/testsuite/gcc.dg/pr43721-4.c b/gcc/testsuite/gcc.dg/pr43721-4.c
  153. new file mode 100644
  154. index 0000000..fd82ad8
  155. --- /dev/null
  156. +++ b/gcc/testsuite/gcc.dg/pr43721-4.c
  157. @@ -0,0 +1,18 @@
  158. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  159. +
  160. +int f(int x, int y)
  161. +{
  162. +  int quot = 0;
  163. +  int rem = 0;
  164. +
  165. +  extern int flag;
  166. +
  167. +  if (flag)
  168. +    quot = x / y;
  169. +  else
  170. +    rem = x % y;
  171. +
  172. +  return quot + rem;
  173. +}
  174. +
  175. +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */
  176. diff --git a/gcc/testsuite/gcc.dg/pr43721-5.c b/gcc/testsuite/gcc.dg/pr43721-5.c
  177. new file mode 100644
  178. index 0000000..f57761f
  179. --- /dev/null
  180. +++ b/gcc/testsuite/gcc.dg/pr43721-5.c
  181. @@ -0,0 +1,19 @@
  182. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  183. +
  184. +int f1(int x)
  185. +{
  186. +  int quot = x / 3;
  187. +  int rem = x % 3;
  188. +
  189. +  return quot + rem;
  190. +}
  191. +
  192. +int f2(int x)
  193. +{
  194. +  int quot = 3 / x;
  195. +  int rem = 3 % x;
  196. +
  197. +  return quot + rem;
  198. +}
  199. +
  200. +/* { dg-final { scan-tree-dump-times "DIVMOD" 2 "widening_mul" } } */
  201. diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
  202. index 41fcabf..ba3fcb7 100644
  203. --- a/gcc/tree-ssa-math-opts.c
  204. +++ b/gcc/tree-ssa-math-opts.c
  205. @@ -110,6 +110,7 @@ along with GCC; see the file COPYING3.  If not see
  206.  #include "tree-ssa.h"
  207.  #include "builtins.h"
  208.  #include "params.h"
  209. +#include "optabs-libfuncs.h"
  210.  
  211.  /* This structure represents one basic block that either computes a
  212.     division, or is a common dominator for basic block that compute a
  213. @@ -182,6 +183,9 @@ static struct
  214.  
  215.    /* Number of fp fused multiply-add ops inserted.  */
  216.    int fmas_inserted;
  217. +
  218. +  /* Number of divmod calls inserted.  */
  219. +  int divmod_calls_inserted;
  220.  } widen_mul_stats;
  221.  
  222.  /* The instance of "struct occurrence" representing the highest
  223. @@ -3493,6 +3497,186 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2)
  224.    return true;
  225.  }
  226.  
  227. +/* Add use_stmt to stmts if either top_bb or gimple_bb(use_stmt) dominate each other.
  228. +   If gimple_bb (use_stmt) dominates top_bb, then set top_bb to gimple_bb (use_stmt).  */
  229. +
  230. +static bool
  231. +maybe_record_divmod (vec<gimple *>& stmts, basic_block& top_bb, gimple *use_stmt)
  232. +{
  233. +  basic_block bb = gimple_bb (use_stmt);
  234. +
  235. +  if (dominated_by_p (CDI_DOMINATORS, top_bb, bb))
  236. +    ;
  237. +  else if (dominated_by_p (CDI_DOMINATORS, bb, top_bb))
  238. +    top_bb = bb;
  239. +  else
  240. +    return false;
  241. +
  242. +  stmts.safe_push (use_stmt);
  243. +  return true;
  244. +}  
  245. +
  246. +/* This function looks for:
  247. +   t1 = a TRUNC_DIV_EXPR b;
  248. +   t2 = a TRUNC_MOD_EXPR b;
  249. +   and transforms it to the following sequence:
  250. +   complex_tmp = DIVMOD (a, b);
  251. +   t1 = REALPART_EXPR(a);
  252. +   t2 = IMAGPART_EXPR(b);
  253. +   This change is done only if the target has support for divmod.
  254. +
  255. +   The pass works in two phases:
  256. +   1) Walk through all immediate uses of stmt's operand and find a TRUNC_DIV_EXPR with matching operands
  257. +      and if such a stmt is found add it to stmts vector.
  258. +   2) Insert DIVMOD() internal function in the basic block that dominates all statements in stmts
  259. +      vector (top_bb) and upates statements in stmts vector to use return value of DIVMOD.  */
  260. +
  261. +static bool
  262. +convert_to_divmod (gassign *stmt)
  263. +{
  264. +  /* Check if divmod is available for the target.  */
  265. +  enum machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
  266. +  const_tree type = TREE_TYPE (gimple_assign_lhs (stmt));
  267. +  optab tab = (TYPE_UNSIGNED (type)) ? udivmod_optab : sdivmod_optab;
  268. +
  269. +  if (!(optab_handler (tab, mode) || optab_libfunc (tab, mode)))
  270. +    return false;
  271. +
  272. +  vec<gimple *> stmts = vNULL;
  273. +  stmts.safe_push (stmt);
  274. +  basic_block top_bb = gimple_bb (stmt);
  275. +
  276. +  tree op1 = gimple_assign_rhs1 (stmt);
  277. +  tree op2 = gimple_assign_rhs2 (stmt);
  278. +
  279. +  use_operand_p use_p;
  280. +  imm_use_iterator use_iter;
  281. +
  282. +  /* FIXME: Is it safe to assume both operands cannot be constant since constant folding would have taken place ?  */
  283. +  gcc_assert (! (TREE_CONSTANT (op1) && TREE_CONSTANT (op2)));
  284. +  
  285. +  tree op = (TREE_CONSTANT (op2)) ? op1 : op2;
  286. +
  287. +  FOR_EACH_IMM_USE_FAST (use_p, use_iter, op)
  288. +    {
  289. +      gimple *use_stmt = USE_STMT (use_p);
  290. +      if (is_gimple_assign (use_stmt)
  291. +         && gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
  292. +    && !TYPE_OVERFLOW_TRAPS (TREE_TYPE (gimple_assign_lhs (use_stmt))))
  293. +       {
  294. +         tree u_op1 = gimple_assign_rhs1 (use_stmt);
  295. +         tree u_op2 = gimple_assign_rhs2 (use_stmt);
  296. +
  297. +         if ((operand_equal_p (op1, u_op1, 0)) && operand_equal_p (op2, u_op2, 0))
  298. +      maybe_record_divmod (stmts, top_bb, use_stmt);
  299. +       }
  300. +    }
  301. +
  302. +  if (stmts.length () == 1)
  303. +    return false;
  304. +
  305. +  /* Create the library call.  */
  306. +  gcall *call_stmt = gimple_build_call_internal (IFN_DIVMOD, 2, op1, op2);
  307. +  tree res = make_temp_ssa_name (build_complex_type (TREE_TYPE (gimple_assign_lhs (stmt))), call_stmt, "divmod_tmp");
  308. +  gimple_call_set_lhs (call_stmt, res);
  309. +
  310. +  widen_mul_stats.divmod_calls_inserted++;
  311. +
  312. +  /* Insert the call-stmt.  */
  313. +  gimple *def_stmt_op1 = 0;
  314. +  gimple *def_stmt_op2 = 0;
  315. +  bool op1_def_in_bb = false;
  316. +  bool op2_def_in_bb = false;
  317. +
  318. +  /* Check if either operand is a constant. If it is a constant then treat it's def as outside basic block.  */
  319. +
  320. +  if (!TREE_CONSTANT (op1))
  321. +    {
  322. +      def_stmt_op1 = SSA_NAME_DEF_STMT (op1);
  323. +      op1_def_in_bb =
  324. +   (!SSA_NAME_IS_DEFAULT_DEF (op1)
  325. +   && gimple_code (def_stmt_op1) != GIMPLE_PHI
  326. +   && gimple_bb (def_stmt_op1) == top_bb);
  327. +    }
  328. +
  329. +  if (!TREE_CONSTANT (op2))
  330. +    {
  331. +      def_stmt_op2 = SSA_NAME_DEF_STMT (op2);
  332. +      op2_def_in_bb =
  333. +   (!SSA_NAME_IS_DEFAULT_DEF (op2)
  334. +   && gimple_code (def_stmt_op2) != GIMPLE_PHI
  335. +   && gimple_bb (def_stmt_op2) == top_bb);
  336. +    }
  337. +
  338. +  /* 3 cases arise where to insert the call to divmod depending upon where op1 and op2 are defined wrt top_bb:
  339. +   * Case 1: When both def are outside top_bb, simply insert after labels */
  340. +  if (!op1_def_in_bb && !op2_def_in_bb)
  341. +    {
  342. +      gcc_assert (top_bb != 0);
  343. +      gimple_stmt_iterator gsi = gsi_after_labels (top_bb);
  344. +      gsi_insert_before (&gsi, call_stmt, GSI_SAME_STMT);
  345. +    }
  346. +
  347. +  /* Case 2: When both def are in top_bb.  */
  348. +  else if (op1_def_in_bb && op2_def_in_bb)
  349. +    {
  350. +      gimple_stmt_iterator gsi;
  351. +
  352. +      if (gimple_uid (def_stmt_op1) < gimple_uid (def_stmt_op2))
  353. +   gsi = gsi_for_stmt (def_stmt_op2);
  354. +      else
  355. +   gsi = gsi_for_stmt (def_stmt_op1);
  356. +
  357. +      gsi_insert_after (&gsi, call_stmt, GSI_SAME_STMT);
  358. +    }
  359. +
  360. +  /* Case 3: When one def is inside top_bb and one is outside.  */
  361. +  else
  362. +    {
  363. +      gimple_stmt_iterator gsi;
  364. +      if (op1_def_in_bb)
  365. +   gsi = gsi_for_stmt (def_stmt_op1);
  366. +      else if (op2_def_in_bb)
  367. +   gsi = gsi_for_stmt (def_stmt_op2);
  368. +      else
  369. +   gcc_unreachable ();
  370. +
  371. +      gsi_insert_after (&gsi, call_stmt, GSI_SAME_STMT);
  372. +    }
  373. +
  374. +  /* Update stmts. */
  375. +  bool cfg_changed = false;
  376. +  gimple *use_stmt;
  377. +  for (unsigned i = 0; i < stmts.length (); ++i)
  378. +    {
  379. +      tree rhs;
  380. +      use_stmt = stmts[i];
  381. +
  382. +      switch (gimple_assign_rhs_code (use_stmt))
  383. +       {
  384. +         case TRUNC_DIV_EXPR:
  385. +           rhs = fold_build1 (REALPART_EXPR, TREE_TYPE (op1), res);
  386. +           break;
  387. +
  388. +         case TRUNC_MOD_EXPR:
  389. +           rhs = fold_build1 (IMAGPART_EXPR, TREE_TYPE (op1), res);
  390. +           break;
  391. +
  392. +         default:
  393. +           gcc_unreachable ();
  394. +       }
  395. +
  396. +        gassign *assign_stmt = gimple_build_assign (gimple_assign_lhs (use_stmt), rhs);
  397. +        gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
  398. +        gsi_replace (&gsi, assign_stmt, true);
  399. +        if (gimple_purge_dead_eh_edges (gimple_bb (assign_stmt)))
  400. +         cfg_changed = true;
  401. +    }
  402. +
  403. +  stmts.release ();
  404. +  return cfg_changed;
  405. +}
  406. +
  407.  /* Find integer multiplications where the operands are extended from
  408.     smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR
  409.     where appropriate.  */
  410. @@ -3535,7 +3719,10 @@ pass_optimize_widening_mul::execute (function *fun)
  411.    basic_block bb;
  412.    bool cfg_changed = false;
  413.  
  414. +  calculate_dominance_info (CDI_DOMINATORS);
  415. +
  416.    memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
  417. +  renumber_gimple_stmt_uids ();
  418.  
  419.    FOR_EACH_BB_FN (bb, fun)
  420.      {
  421. @@ -3563,6 +3750,10 @@ pass_optimize_widening_mul::execute (function *fun)
  422.             }
  423.           break;
  424.  
  425. +       case TRUNC_MOD_EXPR:
  426. +         convert_to_divmod (as_a<gassign *> (stmt));
  427. +         break;
  428. +
  429.         case PLUS_EXPR:
  430.         case MINUS_EXPR:
  431.           convert_plusminus_to_widen (&gsi, stmt, code);
  432. @@ -3614,6 +3805,10 @@ pass_optimize_widening_mul::execute (function *fun)
  433.                 widen_mul_stats.maccs_inserted);
  434.    statistics_counter_event (fun, "fused multiply-adds inserted",
  435.                 widen_mul_stats.fmas_inserted);
  436. +  statistics_counter_event (fun, "divmod calls inserted",
  437. +               widen_mul_stats.divmod_calls_inserted);
  438. +
  439. +  free_dominance_info (CDI_DOMINATORS);
  440.  
  441.    return cfg_changed ? TODO_cleanup_cfg : 0;
  442.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement