Advertisement
prat3492

Untitled

Nov 9th, 2015
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 11.43 KB | None | 0 0
  1. diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
  2. index a7da373..c0c84d8 100644
  3. --- a/gcc/internal-fn.c
  4. +++ b/gcc/internal-fn.c
  5. @@ -2045,6 +2045,47 @@ 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
  12. +    optab_libfunc for udivmod/sdivmod.  */
  13. +
  14. +static void
  15. +expand_DIVMOD (gcall *stmt)
  16. +{
  17. +  tree lhs = gimple_call_lhs (stmt);
  18. +  tree arg0 = gimple_call_arg (stmt, 0);
  19. +  tree arg1 = gimple_call_arg (stmt, 1);
  20. +  
  21. +  gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
  22. +  tree type = TREE_TYPE (TREE_TYPE (lhs));
  23. +  machine_mode mode = TYPE_MODE (type);
  24. +  optab tab = (TYPE_UNSIGNED (type)) ? udivmod_optab : sdivmod_optab;
  25. +
  26. +  rtx op0 = expand_normal (arg0);
  27. +  rtx op1 = expand_normal (arg1);
  28. +  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
  29. +
  30. +  rtx libfunc = optab_libfunc (tab, mode);
  31. +  gcc_assert (libfunc != NULL_RTX);
  32. +  
  33. +  machine_mode libval_mode =
  34. +    smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode), MODE_INT);
  35. +
  36. +  rtx libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
  37. +                                       libval_mode, 2, op0, mode, op1, mode);
  38. +
  39. +  rtx quotient = simplify_gen_subreg (mode, libval, libval_mode, 0);
  40. +  rtx remainder = simplify_gen_subreg (mode, libval, libval_mode,
  41. +                      GET_MODE_SIZE (mode));
  42. +
  43. +  /* Wrap the return value (quotient, remaineder) within COMPLEX_EXPR */
  44. +  expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
  45. +                      make_tree (TREE_TYPE (arg0), quotient),
  46. +                      make_tree (TREE_TYPE (arg1), remainder)),
  47. +             target, VOIDmode, EXPAND_NORMAL);
  48. +}
  49. +
  50.  /* Routines to expand each internal function, indexed by function number.
  51.     Each routine has the prototype:
  52.  
  53. diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
  54. index 78266d9..f28579b 100644
  55. --- a/gcc/internal-fn.def
  56. +++ b/gcc/internal-fn.def
  57. @@ -83,3 +83,5 @@ DEF_INTERNAL_FN (GOACC_DIM_POS, ECF_PURE | ECF_NOTHROW | ECF_LEAF, ".")
  58.  
  59.  /* OpenACC looping abstraction.  See internal-fn.h for usage.  */
  60.  DEF_INTERNAL_FN (GOACC_LOOP, ECF_PURE | ECF_NOTHROW, NULL)
  61. +
  62. +DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL)
  63. diff --git a/gcc/testsuite/gcc.dg/pr43721-1.c b/gcc/testsuite/gcc.dg/pr43721-1.c
  64. new file mode 100644
  65. index 0000000..2ec1118
  66. --- /dev/null
  67. +++ b/gcc/testsuite/gcc.dg/pr43721-1.c
  68. @@ -0,0 +1,11 @@
  69. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  70. +/* { dg-require-effective-target divmod } */
  71. +
  72. +int f(int x, int y)
  73. +{
  74. +  int quotient = x / y;
  75. +  int remainder = x % y;
  76. +  return quotient + remainder;
  77. +}
  78. +
  79. +/* { dg-final { scan-tree-dump-times "DIVMOD" 1 "widening_mul" } } */
  80. diff --git a/gcc/testsuite/gcc.dg/pr43721-2.c b/gcc/testsuite/gcc.dg/pr43721-2.c
  81. new file mode 100644
  82. index 0000000..974099c
  83. --- /dev/null
  84. +++ b/gcc/testsuite/gcc.dg/pr43721-2.c
  85. @@ -0,0 +1,17 @@
  86. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  87. +/* { dg-require-effective-target divmod } */
  88. +
  89. +int f(int x, int y)
  90. +{
  91. +  extern int early_exit;
  92. +
  93. +  int quot = x / y;
  94. +
  95. +  if (early_exit)
  96. +    return 0;
  97. +
  98. +  int rem = x % y;
  99. +  return quot + rem;
  100. +}
  101. +
  102. +/* { dg-final { scan-tree-dump-times "DIVMOD" 1 "widening_mul" } } */
  103. diff --git a/gcc/testsuite/gcc.dg/pr43721-3.c b/gcc/testsuite/gcc.dg/pr43721-3.c
  104. new file mode 100644
  105. index 0000000..41cda2e
  106. --- /dev/null
  107. +++ b/gcc/testsuite/gcc.dg/pr43721-3.c
  108. @@ -0,0 +1,18 @@
  109. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  110. +/* { dg-require-effective-target divmod } */
  111. +
  112. +int f(int x, int y)
  113. +{
  114. +  extern int flag;
  115. +  int quot;
  116. +
  117. +  if (flag)
  118. +    quot = x / y;
  119. +  else
  120. +    quot = 0;
  121. +
  122. +  int rem = x % y;
  123. +  return quot + rem;
  124. +}
  125. +
  126. +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */
  127. diff --git a/gcc/testsuite/gcc.dg/pr43721-4.c b/gcc/testsuite/gcc.dg/pr43721-4.c
  128. new file mode 100644
  129. index 0000000..b4f69b0
  130. --- /dev/null
  131. +++ b/gcc/testsuite/gcc.dg/pr43721-4.c
  132. @@ -0,0 +1,19 @@
  133. +/* { dg-options "-O2 -fdump-tree-widening_mul" } */
  134. +/* { dg-require-effective-target divmod } */
  135. +
  136. +int f(int x, int y)
  137. +{
  138. +  int quot = 0;
  139. +  int rem = 0;
  140. +
  141. +  extern int flag;
  142. +
  143. +  if (flag)
  144. +    quot = x / y;
  145. +  else
  146. +    rem = x % y;
  147. +
  148. +  return quot + rem;
  149. +}
  150. +
  151. +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */
  152. diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
  153. index b543519..c3895a7 100644
  154. --- a/gcc/testsuite/lib/target-supports.exp
  155. +++ b/gcc/testsuite/lib/target-supports.exp
  156. @@ -6494,3 +6494,12 @@ proc check_effective_target_vect_max_reduc { } {
  157.      }
  158.      return 0
  159.  }
  160. +
  161. +# Return 1 if the target supports divmod
  162. +
  163. +proc check_effective_target_divmod { } {
  164. +    if { [istarget arm*-*-*] } {
  165. +   return 1
  166. +    }
  167. +    return 0
  168. +}
  169. diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
  170. index 41fcabf..ac4140d 100644
  171. --- a/gcc/tree-ssa-math-opts.c
  172. +++ b/gcc/tree-ssa-math-opts.c
  173. @@ -110,6 +110,8 @@ along with GCC; see the file COPYING3.  If not see
  174.  #include "tree-ssa.h"
  175.  #include "builtins.h"
  176.  #include "params.h"
  177. +#include "optabs-libfuncs.h"
  178. +#include "tree-eh.h"
  179.  
  180.  /* This structure represents one basic block that either computes a
  181.     division, or is a common dominator for basic block that compute a
  182. @@ -182,6 +184,9 @@ static struct
  183.  
  184.    /* Number of fp fused multiply-add ops inserted.  */
  185.    int fmas_inserted;
  186. +
  187. +  /* Number of divmod calls inserted.  */
  188. +  int divmod_calls_inserted;
  189.  } widen_mul_stats;
  190.  
  191.  /* The instance of "struct occurrence" representing the highest
  192. @@ -3493,6 +3498,151 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2)
  193.    return true;
  194.  }
  195.  
  196. +/* Add use_stmt to stmts if either top_bb or gimple_bb(use_stmt) dominate
  197. +   each other. If gimple_bb (use_stmt) dominates top_bb, then set top_bb
  198. +   to gimple_bb (use_stmt).  */
  199. +
  200. +static bool
  201. +maybe_record_divmod (vec<gimple *>& stmts, basic_block& top_bb,
  202. +            gimple *use_stmt)
  203. +{
  204. +  basic_block bb = gimple_bb (use_stmt);
  205. +
  206. +  if (dominated_by_p (CDI_DOMINATORS, top_bb, bb))
  207. +    ;
  208. +  else if (dominated_by_p (CDI_DOMINATORS, bb, top_bb))
  209. +    top_bb = bb;
  210. +  else
  211. +    return false;
  212. +
  213. +  stmts.safe_push (use_stmt);
  214. +  return true;
  215. +}  
  216. +
  217. +/* This function looks for:
  218. +   t1 = a TRUNC_DIV_EXPR b;
  219. +   t2 = a TRUNC_MOD_EXPR b;
  220. +   and transforms it to the following sequence:
  221. +   complex_tmp = DIVMOD (a, b);
  222. +   t1 = REALPART_EXPR(a);
  223. +   t2 = IMAGPART_EXPR(b);
  224. +   This change is done only if the target has support for divmod.
  225. +
  226. +   The pass works in two phases:
  227. +   1) Walk through all immediate uses of stmt's operand and find a
  228. +      TRUNC_DIV_EXPR with matching operands and if such a stmt is found add
  229. +      it to stmts vector.
  230. +   2) Insert DIVMOD call before first div/mod stmt in top_bb (basic block that
  231. +      dominates other div/mod stmts with same operands) and update entries in
  232. +      stmts vector to use return value of DIMOVD (REALEXPR_PART for div,
  233. +      IMAGPART_EXPR for mod).  */
  234. +
  235. +static bool
  236. +convert_to_divmod (gassign *stmt)
  237. +{
  238. +  enum machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
  239. +  const_tree type = TREE_TYPE (gimple_assign_lhs (stmt));
  240. +  optab divmod_optab = (TYPE_UNSIGNED (type)) ? udivmod_optab : sdivmod_optab;
  241. +
  242. +  /* FIXME: Check for divmod optab handler or libfunc.  */
  243. +
  244. +  if (optab_handler (divmod_optab, mode) != CODE_FOR_nothing
  245. +      || (optab_libfunc (divmod_optab, mode) == NULL_RTX))
  246. +    return false;
  247. +
  248. +  tree op1 = gimple_assign_rhs1 (stmt);
  249. +  tree op2 = gimple_assign_rhs2 (stmt);
  250. +  
  251. +  /* FIXME: Drop handling constants for now.  */
  252. +  if (TREE_CONSTANT (op1) || TREE_CONSTANT (op2))
  253. +    return false;
  254. +
  255. +  if (TYPE_OVERFLOW_TRAPS (type))
  256. +    return false;
  257. +
  258. +  vec<gimple *> stmts = vNULL;
  259. +  stmts.safe_push (stmt);
  260. +  basic_block top_bb = gimple_bb (stmt);
  261. +
  262. +  imm_use_iterator use_iter;
  263. +  gimple *use_stmt;
  264. +
  265. +  FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op1)
  266. +    {
  267. +      if (is_gimple_assign (use_stmt)
  268. +          && gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
  269. +     && operand_equal_p (op1, gimple_assign_rhs1 (use_stmt), 0)
  270. +     && operand_equal_p (op2, gimple_assign_rhs2 (use_stmt), 0))
  271. +   maybe_record_divmod (stmts, top_bb, use_stmt);
  272. +    }
  273. +  
  274. +  if (stmts.length () == 1)
  275. +    return false;
  276. +
  277. +  /* Create the library call.  */
  278. +  gcall *call_stmt = gimple_build_call_internal (IFN_DIVMOD, 2, op1, op2);
  279. +  tree res = make_temp_ssa_name (
  280. +       build_complex_type (TREE_TYPE (gimple_assign_lhs (stmt))),
  281. +       call_stmt, "divmod_tmp");
  282. +
  283. +  gimple_call_set_lhs (call_stmt, res);
  284. +
  285. +  widen_mul_stats.divmod_calls_inserted++;
  286. +
  287. +  /* Insert call-stmt just before the topmost div/mod stmt.
  288. +     top_bb dominates all other basic blocks containing div/mod stms
  289. +     so, the topmost stmt would be the first div/mod stmt with matching operands
  290. +     in top_bb.  */
  291. +
  292. +  gcc_assert (top_bb != 0);
  293. +  gimple_stmt_iterator gsi;
  294. +  for (gsi = gsi_after_labels (top_bb); !gsi_end_p (gsi); gsi_next (&gsi))
  295. +    {
  296. +      gimple *g = gsi_stmt (gsi);
  297. +      if (is_gimple_assign (g)
  298. +     && (gimple_assign_rhs_code (g) == TRUNC_DIV_EXPR
  299. +        || gimple_assign_rhs_code (g) == TRUNC_MOD_EXPR)
  300. +     && operand_equal_p (op1, gimple_assign_rhs1 (g), 0)
  301. +     && operand_equal_p (op2, gimple_assign_rhs2 (g), 0))
  302. +   break;
  303. +    }
  304. +
  305. +  gcc_assert (!gsi_end_p (gsi));
  306. +  gsi_insert_before (&gsi, call_stmt, GSI_SAME_STMT);
  307. +
  308. +  /* Update stmts. */
  309. +  bool cfg_changed = false;
  310. +  for (unsigned i = 0; i < stmts.length (); ++i)
  311. +    {
  312. +      tree rhs;
  313. +      use_stmt = stmts[i];
  314. +
  315. +      switch (gimple_assign_rhs_code (use_stmt))
  316. +   {
  317. +     case TRUNC_DIV_EXPR:
  318. +       rhs = fold_build1 (REALPART_EXPR, TREE_TYPE (op1), res);
  319. +       break;
  320. +
  321. +     case TRUNC_MOD_EXPR:
  322. +       rhs = fold_build1 (IMAGPART_EXPR, TREE_TYPE (op1), res);
  323. +       break;
  324. +
  325. +     default:
  326. +       gcc_unreachable ();
  327. +   }
  328. +
  329. +      gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
  330. +      gimple_assign_set_rhs_from_tree (&gsi, rhs);
  331. +      update_stmt (use_stmt);
  332. +
  333. +      if (maybe_clean_or_replace_eh_stmt (use_stmt, use_stmt))
  334. +   cfg_changed = true;
  335. +    }
  336. +
  337. +  stmts.release ();
  338. +  return cfg_changed;
  339. +}
  340. +
  341.  /* Find integer multiplications where the operands are extended from
  342.     smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR
  343.     where appropriate.  */
  344. @@ -3535,7 +3685,10 @@ pass_optimize_widening_mul::execute (function *fun)
  345.    basic_block bb;
  346.    bool cfg_changed = false;
  347.  
  348. +  calculate_dominance_info (CDI_DOMINATORS);
  349. +
  350.    memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
  351. +  renumber_gimple_stmt_uids ();
  352.  
  353.    FOR_EACH_BB_FN (bb, fun)
  354.      {
  355. @@ -3563,6 +3716,10 @@ pass_optimize_widening_mul::execute (function *fun)
  356.             }
  357.           break;
  358.  
  359. +       case TRUNC_MOD_EXPR:
  360. +         convert_to_divmod (as_a<gassign *> (stmt));
  361. +         break;
  362. +
  363.         case PLUS_EXPR:
  364.         case MINUS_EXPR:
  365.           convert_plusminus_to_widen (&gsi, stmt, code);
  366. @@ -3614,6 +3771,10 @@ pass_optimize_widening_mul::execute (function *fun)
  367.                 widen_mul_stats.maccs_inserted);
  368.    statistics_counter_event (fun, "fused multiply-adds inserted",
  369.                 widen_mul_stats.fmas_inserted);
  370. +  statistics_counter_event (fun, "divmod calls inserted",
  371. +               widen_mul_stats.divmod_calls_inserted);
  372. +
  373. +  free_dominance_info (CDI_DOMINATORS);
  374.  
  375.    return cfg_changed ? TODO_cleanup_cfg : 0;
  376.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement