target.h (globalize_decl_name): New.
[gcc.git] / gcc / tree-ssa-math-opts.c
1 /* Global, SSA-based optimizations using mathematical identities.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 /* Currently, the only mini-pass in this file tries to CSE reciprocal
22 operations. These are common in sequences such as this one:
23
24 modulus = sqrt(x*x + y*y + z*z);
25 x = x / modulus;
26 y = y / modulus;
27 z = z / modulus;
28
29 that can be optimized to
30
31 modulus = sqrt(x*x + y*y + z*z);
32 rmodulus = 1.0 / modulus;
33 x = x * rmodulus;
34 y = y * rmodulus;
35 z = z * rmodulus;
36
37 We do this for loop invariant divisors, and with this pass whenever
38 we notice that a division has the same divisor multiple times.
39
40 Of course, like in PRE, we don't insert a division if a dominator
41 already has one. However, this cannot be done as an extension of
42 PRE for several reasons.
43
44 First of all, with some experiments it was found out that the
45 transformation is not always useful if there are only two divisions
46 hy the same divisor. This is probably because modern processors
47 can pipeline the divisions; on older, in-order processors it should
48 still be effective to optimize two divisions by the same number.
49 We make this a param, and it shall be called N in the remainder of
50 this comment.
51
52 Second, if trapping math is active, we have less freedom on where
53 to insert divisions: we can only do so in basic blocks that already
54 contain one. (If divisions don't trap, instead, we can insert
55 divisions elsewhere, which will be in blocks that are common dominators
56 of those that have the division).
57
58 We really don't want to compute the reciprocal unless a division will
59 be found. To do this, we won't insert the division in a basic block
60 that has less than N divisions *post-dominating* it.
61
62 The algorithm constructs a subset of the dominator tree, holding the
63 blocks containing the divisions and the common dominators to them,
64 and walk it twice. The first walk is in post-order, and it annotates
65 each block with the number of divisions that post-dominate it: this
66 gives information on where divisions can be inserted profitably.
67 The second walk is in pre-order, and it inserts divisions as explained
68 above, and replaces divisions by multiplications.
69
70 In the best case, the cost of the pass is O(n_statements). In the
71 worst-case, the cost is due to creating the dominator tree subset,
72 with a cost of O(n_basic_blocks ^ 2); however this can only happen
73 for n_statements / n_basic_blocks statements. So, the amortized cost
74 of creating the dominator tree subset is O(n_basic_blocks) and the
75 worst-case cost of the pass is O(n_statements * n_basic_blocks).
76
77 More practically, the cost will be small because there are few
78 divisions, and they tend to be in the same basic block, so insert_bb
79 is called very few times.
80
81 If we did this using domwalk.c, an efficient implementation would have
82 to work on all the variables in a single pass, because we could not
83 work on just a subset of the dominator tree, as we do now, and the
84 cost would also be something like O(n_statements * n_basic_blocks).
85 The data structures would be more complex in order to work on all the
86 variables in a single pass. */
87
88 #include "config.h"
89 #include "system.h"
90 #include "coretypes.h"
91 #include "tm.h"
92 #include "flags.h"
93 #include "tree.h"
94 #include "tree-flow.h"
95 #include "real.h"
96 #include "timevar.h"
97 #include "tree-pass.h"
98 #include "alloc-pool.h"
99 #include "basic-block.h"
100 #include "target.h"
101
102
103 /* This structure represents one basic block that either computes a
104 division, or is a common dominator for basic block that compute a
105 division. */
106 struct occurrence {
107 /* The basic block represented by this structure. */
108 basic_block bb;
109
110 /* If non-NULL, the SSA_NAME holding the definition for a reciprocal
111 inserted in BB. */
112 tree recip_def;
113
114 /* If non-NULL, the GIMPLE_MODIFY_STMT for a reciprocal computation that
115 was inserted in BB. */
116 tree recip_def_stmt;
117
118 /* Pointer to a list of "struct occurrence"s for blocks dominated
119 by BB. */
120 struct occurrence *children;
121
122 /* Pointer to the next "struct occurrence"s in the list of blocks
123 sharing a common dominator. */
124 struct occurrence *next;
125
126 /* The number of divisions that are in BB before compute_merit. The
127 number of divisions that are in BB or post-dominate it after
128 compute_merit. */
129 int num_divisions;
130
131 /* True if the basic block has a division, false if it is a common
132 dominator for basic blocks that do. If it is false and trapping
133 math is active, BB is not a candidate for inserting a reciprocal. */
134 bool bb_has_division;
135 };
136
137
138 /* The instance of "struct occurrence" representing the highest
139 interesting block in the dominator tree. */
140 static struct occurrence *occ_head;
141
142 /* Allocation pool for getting instances of "struct occurrence". */
143 static alloc_pool occ_pool;
144
145
146
147 /* Allocate and return a new struct occurrence for basic block BB, and
148 whose children list is headed by CHILDREN. */
149 static struct occurrence *
150 occ_new (basic_block bb, struct occurrence *children)
151 {
152 struct occurrence *occ;
153
154 occ = bb->aux = pool_alloc (occ_pool);
155 memset (occ, 0, sizeof (struct occurrence));
156
157 occ->bb = bb;
158 occ->children = children;
159 return occ;
160 }
161
162
163 /* Insert NEW_OCC into our subset of the dominator tree. P_HEAD points to a
164 list of "struct occurrence"s, one per basic block, having IDOM as
165 their common dominator.
166
167 We try to insert NEW_OCC as deep as possible in the tree, and we also
168 insert any other block that is a common dominator for BB and one
169 block already in the tree. */
170
171 static void
172 insert_bb (struct occurrence *new_occ, basic_block idom,
173 struct occurrence **p_head)
174 {
175 struct occurrence *occ, **p_occ;
176
177 for (p_occ = p_head; (occ = *p_occ) != NULL; )
178 {
179 basic_block bb = new_occ->bb, occ_bb = occ->bb;
180 basic_block dom = nearest_common_dominator (CDI_DOMINATORS, occ_bb, bb);
181 if (dom == bb)
182 {
183 /* BB dominates OCC_BB. OCC becomes NEW_OCC's child: remove OCC
184 from its list. */
185 *p_occ = occ->next;
186 occ->next = new_occ->children;
187 new_occ->children = occ;
188
189 /* Try the next block (it may as well be dominated by BB). */
190 }
191
192 else if (dom == occ_bb)
193 {
194 /* OCC_BB dominates BB. Tail recurse to look deeper. */
195 insert_bb (new_occ, dom, &occ->children);
196 return;
197 }
198
199 else if (dom != idom)
200 {
201 gcc_assert (!dom->aux);
202
203 /* There is a dominator between IDOM and BB, add it and make
204 two children out of NEW_OCC and OCC. First, remove OCC from
205 its list. */
206 *p_occ = occ->next;
207 new_occ->next = occ;
208 occ->next = NULL;
209
210 /* None of the previous blocks has DOM as a dominator: if we tail
211 recursed, we would reexamine them uselessly. Just switch BB with
212 DOM, and go on looking for blocks dominated by DOM. */
213 new_occ = occ_new (dom, new_occ);
214 }
215
216 else
217 {
218 /* Nothing special, go on with the next element. */
219 p_occ = &occ->next;
220 }
221 }
222
223 /* No place was found as a child of IDOM. Make BB a sibling of IDOM. */
224 new_occ->next = *p_head;
225 *p_head = new_occ;
226 }
227
228 /* Register that we found a division in BB. */
229
230 static inline void
231 register_division_in (basic_block bb)
232 {
233 struct occurrence *occ;
234
235 occ = (struct occurrence *) bb->aux;
236 if (!occ)
237 {
238 occ = occ_new (bb, NULL);
239 insert_bb (occ, ENTRY_BLOCK_PTR, &occ_head);
240 }
241
242 occ->bb_has_division = true;
243 occ->num_divisions++;
244 }
245
246
247 /* Compute the number of divisions that postdominate each block in OCC and
248 its children. */
249
250 static void
251 compute_merit (struct occurrence *occ)
252 {
253 struct occurrence *occ_child;
254 basic_block dom = occ->bb;
255
256 for (occ_child = occ->children; occ_child; occ_child = occ_child->next)
257 {
258 basic_block bb;
259 if (occ_child->children)
260 compute_merit (occ_child);
261
262 if (flag_exceptions)
263 bb = single_noncomplex_succ (dom);
264 else
265 bb = dom;
266
267 if (dominated_by_p (CDI_POST_DOMINATORS, bb, occ_child->bb))
268 occ->num_divisions += occ_child->num_divisions;
269 }
270 }
271
272
273 /* Return whether USE_STMT is a floating-point division by DEF. */
274 static inline bool
275 is_division_by (tree use_stmt, tree def)
276 {
277 return TREE_CODE (use_stmt) == GIMPLE_MODIFY_STMT
278 && TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == RDIV_EXPR
279 && TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 1) == def;
280 }
281
282 /* Walk the subset of the dominator tree rooted at OCC, setting the
283 RECIP_DEF field to a definition of 1.0 / DEF that can be used in
284 the given basic block. The field may be left NULL, of course,
285 if it is not possible or profitable to do the optimization.
286
287 DEF_BSI is an iterator pointing at the statement defining DEF.
288 If RECIP_DEF is set, a dominator already has a computation that can
289 be used. */
290
291 static void
292 insert_reciprocals (block_stmt_iterator *def_bsi, struct occurrence *occ,
293 tree def, tree recip_def, int threshold)
294 {
295 tree type, new_stmt;
296 block_stmt_iterator bsi;
297 struct occurrence *occ_child;
298
299 if (!recip_def
300 && (occ->bb_has_division || !flag_trapping_math)
301 && occ->num_divisions >= threshold)
302 {
303 /* Make a variable with the replacement and substitute it. */
304 type = TREE_TYPE (def);
305 recip_def = make_rename_temp (type, "reciptmp");
306 new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, recip_def,
307 fold_build2 (RDIV_EXPR, type, build_one_cst (type),
308 def));
309
310
311 if (occ->bb_has_division)
312 {
313 /* Case 1: insert before an existing division. */
314 bsi = bsi_after_labels (occ->bb);
315 while (!bsi_end_p (bsi) && !is_division_by (bsi_stmt (bsi), def))
316 bsi_next (&bsi);
317
318 bsi_insert_before (&bsi, new_stmt, BSI_SAME_STMT);
319 }
320 else if (def_bsi && occ->bb == def_bsi->bb)
321 {
322 /* Case 2: insert right after the definition. Note that this will
323 never happen if the definition statement can throw, because in
324 that case the sole successor of the statement's basic block will
325 dominate all the uses as well. */
326 bsi_insert_after (def_bsi, new_stmt, BSI_NEW_STMT);
327 }
328 else
329 {
330 /* Case 3: insert in a basic block not containing defs/uses. */
331 bsi = bsi_after_labels (occ->bb);
332 bsi_insert_before (&bsi, new_stmt, BSI_SAME_STMT);
333 }
334
335 occ->recip_def_stmt = new_stmt;
336 }
337
338 occ->recip_def = recip_def;
339 for (occ_child = occ->children; occ_child; occ_child = occ_child->next)
340 insert_reciprocals (def_bsi, occ_child, def, recip_def, threshold);
341 }
342
343
344 /* Replace the division at USE_P with a multiplication by the reciprocal, if
345 possible. */
346
347 static inline void
348 replace_reciprocal (use_operand_p use_p)
349 {
350 tree use_stmt = USE_STMT (use_p);
351 basic_block bb = bb_for_stmt (use_stmt);
352 struct occurrence *occ = (struct occurrence *) bb->aux;
353
354 if (occ->recip_def && use_stmt != occ->recip_def_stmt)
355 {
356 TREE_SET_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1), MULT_EXPR);
357 SET_USE (use_p, occ->recip_def);
358 fold_stmt_inplace (use_stmt);
359 update_stmt (use_stmt);
360 }
361 }
362
363
364 /* Free OCC and return one more "struct occurrence" to be freed. */
365
366 static struct occurrence *
367 free_bb (struct occurrence *occ)
368 {
369 struct occurrence *child, *next;
370
371 /* First get the two pointers hanging off OCC. */
372 next = occ->next;
373 child = occ->children;
374 occ->bb->aux = NULL;
375 pool_free (occ_pool, occ);
376
377 /* Now ensure that we don't recurse unless it is necessary. */
378 if (!child)
379 return next;
380 else
381 {
382 while (next)
383 next = free_bb (next);
384
385 return child;
386 }
387 }
388
389
390 /* Look for floating-point divisions among DEF's uses, and try to
391 replace them by multiplications with the reciprocal. Add
392 as many statements computing the reciprocal as needed.
393
394 DEF must be a GIMPLE register of a floating-point type. */
395
396 static void
397 execute_cse_reciprocals_1 (block_stmt_iterator *def_bsi, tree def)
398 {
399 use_operand_p use_p;
400 imm_use_iterator use_iter;
401 struct occurrence *occ;
402 int count = 0, threshold;
403
404 gcc_assert (FLOAT_TYPE_P (TREE_TYPE (def)) && is_gimple_reg (def));
405
406 FOR_EACH_IMM_USE_FAST (use_p, use_iter, def)
407 {
408 tree use_stmt = USE_STMT (use_p);
409 if (is_division_by (use_stmt, def))
410 {
411 register_division_in (bb_for_stmt (use_stmt));
412 count++;
413 }
414 }
415
416 /* Do the expensive part only if we can hope to optimize something. */
417 threshold = targetm.min_divisions_for_recip_mul (TYPE_MODE (TREE_TYPE (def)));
418 if (count >= threshold)
419 {
420 tree use_stmt;
421 for (occ = occ_head; occ; occ = occ->next)
422 {
423 compute_merit (occ);
424 insert_reciprocals (def_bsi, occ, def, NULL, threshold);
425 }
426
427 FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, def)
428 {
429 if (is_division_by (use_stmt, def))
430 {
431 FOR_EACH_IMM_USE_ON_STMT (use_p, use_iter)
432 replace_reciprocal (use_p);
433 }
434 }
435 }
436
437 for (occ = occ_head; occ; )
438 occ = free_bb (occ);
439
440 occ_head = NULL;
441 }
442
443 static bool
444 gate_cse_reciprocals (void)
445 {
446 return optimize && !optimize_size && flag_unsafe_math_optimizations;
447 }
448
449 /* Go through all the floating-point SSA_NAMEs, and call
450 execute_cse_reciprocals_1 on each of them. */
451 static unsigned int
452 execute_cse_reciprocals (void)
453 {
454 basic_block bb;
455 tree arg;
456
457 occ_pool = create_alloc_pool ("dominators for recip",
458 sizeof (struct occurrence),
459 n_basic_blocks / 3 + 1);
460
461 calculate_dominance_info (CDI_DOMINATORS);
462 calculate_dominance_info (CDI_POST_DOMINATORS);
463
464 #ifdef ENABLE_CHECKING
465 FOR_EACH_BB (bb)
466 gcc_assert (!bb->aux);
467 #endif
468
469 for (arg = DECL_ARGUMENTS (cfun->decl); arg; arg = TREE_CHAIN (arg))
470 if (gimple_default_def (cfun, arg)
471 && FLOAT_TYPE_P (TREE_TYPE (arg))
472 && is_gimple_reg (arg))
473 execute_cse_reciprocals_1 (NULL, gimple_default_def (cfun, arg));
474
475 FOR_EACH_BB (bb)
476 {
477 block_stmt_iterator bsi;
478 tree phi, def;
479
480 for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
481 {
482 def = PHI_RESULT (phi);
483 if (FLOAT_TYPE_P (TREE_TYPE (def))
484 && is_gimple_reg (def))
485 execute_cse_reciprocals_1 (NULL, def);
486 }
487
488 for (bsi = bsi_after_labels (bb); !bsi_end_p (bsi); bsi_next (&bsi))
489 {
490 tree stmt = bsi_stmt (bsi);
491
492 if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
493 && (def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF)) != NULL
494 && FLOAT_TYPE_P (TREE_TYPE (def))
495 && TREE_CODE (def) == SSA_NAME)
496 execute_cse_reciprocals_1 (&bsi, def);
497 }
498 }
499
500 free_dominance_info (CDI_DOMINATORS);
501 free_dominance_info (CDI_POST_DOMINATORS);
502 free_alloc_pool (occ_pool);
503 return 0;
504 }
505
506 struct tree_opt_pass pass_cse_reciprocals =
507 {
508 "recip", /* name */
509 gate_cse_reciprocals, /* gate */
510 execute_cse_reciprocals, /* execute */
511 NULL, /* sub */
512 NULL, /* next */
513 0, /* static_pass_number */
514 0, /* tv_id */
515 PROP_ssa, /* properties_required */
516 0, /* properties_provided */
517 0, /* properties_destroyed */
518 0, /* todo_flags_start */
519 TODO_dump_func | TODO_update_ssa | TODO_verify_ssa
520 | TODO_verify_stmts, /* todo_flags_finish */
521 0 /* letter */
522 };
523
524 /* Records an occurance at statement USE_STMT in the vector of trees
525 STMTS if it is dominated by *TOP_BB or dominates it or this basic block
526 is not yet initialized. Returns true if the occurance was pushed on
527 the vector. Adjusts *TOP_BB to be the basic block dominating all
528 statements in the vector. */
529
530 static bool
531 maybe_record_sincos (VEC(tree, heap) **stmts,
532 basic_block *top_bb, tree use_stmt)
533 {
534 basic_block use_bb = bb_for_stmt (use_stmt);
535 if (*top_bb
536 && (*top_bb == use_bb
537 || dominated_by_p (CDI_DOMINATORS, use_bb, *top_bb)))
538 VEC_safe_push (tree, heap, *stmts, use_stmt);
539 else if (!*top_bb
540 || dominated_by_p (CDI_DOMINATORS, *top_bb, use_bb))
541 {
542 VEC_safe_push (tree, heap, *stmts, use_stmt);
543 *top_bb = use_bb;
544 }
545 else
546 return false;
547
548 return true;
549 }
550
551 /* Look for sin, cos and cexpi calls with the same argument NAME and
552 create a single call to cexpi CSEing the result in this case.
553 We first walk over all immediate uses of the argument collecting
554 statements that we can CSE in a vector and in a second pass replace
555 the statement rhs with a REALPART or IMAGPART expression on the
556 result of the cexpi call we insert before the use statement that
557 dominates all other candidates. */
558
559 static void
560 execute_cse_sincos_1 (tree name)
561 {
562 block_stmt_iterator bsi;
563 imm_use_iterator use_iter;
564 tree def_stmt, use_stmt, fndecl, res, call, stmt, type;
565 int seen_cos = 0, seen_sin = 0, seen_cexpi = 0;
566 VEC(tree, heap) *stmts = NULL;
567 basic_block top_bb = NULL;
568 int i;
569
570 type = TREE_TYPE (name);
571 FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, name)
572 {
573 if (TREE_CODE (use_stmt) != GIMPLE_MODIFY_STMT
574 || TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) != CALL_EXPR
575 || !(fndecl = get_callee_fndecl (GIMPLE_STMT_OPERAND (use_stmt, 1)))
576 || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
577 continue;
578
579 switch (DECL_FUNCTION_CODE (fndecl))
580 {
581 CASE_FLT_FN (BUILT_IN_COS):
582 seen_cos |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
583 break;
584
585 CASE_FLT_FN (BUILT_IN_SIN):
586 seen_sin |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
587 break;
588
589 CASE_FLT_FN (BUILT_IN_CEXPI):
590 seen_cexpi |= maybe_record_sincos (&stmts, &top_bb, use_stmt) ? 1 : 0;
591 break;
592
593 default:;
594 }
595 }
596
597 if (seen_cos + seen_sin + seen_cexpi <= 1)
598 {
599 VEC_free(tree, heap, stmts);
600 return;
601 }
602
603 /* Simply insert cexpi at the beginning of top_bb but not earlier than
604 the name def statement. */
605 fndecl = mathfn_built_in (type, BUILT_IN_CEXPI);
606 if (!fndecl)
607 return;
608 res = make_rename_temp (TREE_TYPE (TREE_TYPE (fndecl)), "sincostmp");
609 call = build_function_call_expr (fndecl, build_tree_list (NULL_TREE, name));
610 stmt = build2 (GIMPLE_MODIFY_STMT, NULL_TREE, res, call);
611 def_stmt = SSA_NAME_DEF_STMT (name);
612 if (bb_for_stmt (def_stmt) == top_bb
613 && TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT)
614 {
615 bsi = bsi_for_stmt (def_stmt);
616 bsi_insert_after (&bsi, stmt, BSI_SAME_STMT);
617 }
618 else
619 {
620 bsi = bsi_after_labels (top_bb);
621 bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
622 }
623 update_stmt (stmt);
624
625 /* And adjust the recorded old call sites. */
626 for (i = 0; VEC_iterate(tree, stmts, i, use_stmt); ++i)
627 {
628 fndecl = get_callee_fndecl (GIMPLE_STMT_OPERAND (use_stmt, 1));
629 switch (DECL_FUNCTION_CODE (fndecl))
630 {
631 CASE_FLT_FN (BUILT_IN_COS):
632 GIMPLE_STMT_OPERAND (use_stmt, 1) = fold_build1 (REALPART_EXPR,
633 type, res);
634 break;
635
636 CASE_FLT_FN (BUILT_IN_SIN):
637 GIMPLE_STMT_OPERAND (use_stmt, 1) = fold_build1 (IMAGPART_EXPR,
638 type, res);
639 break;
640
641 CASE_FLT_FN (BUILT_IN_CEXPI):
642 GIMPLE_STMT_OPERAND (use_stmt, 1) = res;
643 break;
644
645 default:;
646 gcc_unreachable ();
647 }
648
649 update_stmt (use_stmt);
650 }
651
652 VEC_free(tree, heap, stmts);
653 }
654
655 /* Go through all calls to sin, cos and cexpi and call execute_cse_sincos_1
656 on the SSA_NAME argument of each of them. */
657
658 static unsigned int
659 execute_cse_sincos (void)
660 {
661 basic_block bb;
662
663 calculate_dominance_info (CDI_DOMINATORS);
664
665 FOR_EACH_BB (bb)
666 {
667 block_stmt_iterator bsi;
668
669 for (bsi = bsi_after_labels (bb); !bsi_end_p (bsi); bsi_next (&bsi))
670 {
671 tree stmt = bsi_stmt (bsi);
672 tree fndecl;
673
674 if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
675 && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR
676 && (fndecl = get_callee_fndecl (GIMPLE_STMT_OPERAND (stmt, 1)))
677 && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
678 {
679 tree arg;
680
681 switch (DECL_FUNCTION_CODE (fndecl))
682 {
683 CASE_FLT_FN (BUILT_IN_COS):
684 CASE_FLT_FN (BUILT_IN_SIN):
685 CASE_FLT_FN (BUILT_IN_CEXPI):
686 arg = GIMPLE_STMT_OPERAND (stmt, 1);
687 arg = TREE_VALUE (TREE_OPERAND (arg, 1));
688 if (TREE_CODE (arg) == SSA_NAME)
689 execute_cse_sincos_1 (arg);
690 break;
691
692 default:;
693 }
694 }
695 }
696 }
697
698 free_dominance_info (CDI_DOMINATORS);
699 return 0;
700 }
701
702 static bool
703 gate_cse_sincos (void)
704 {
705 /* Make sure we have either sincos or cexp. */
706 return (TARGET_HAS_SINCOS
707 || TARGET_C99_FUNCTIONS)
708 && optimize;
709 }
710
711 struct tree_opt_pass pass_cse_sincos =
712 {
713 "sincos", /* name */
714 gate_cse_sincos, /* gate */
715 execute_cse_sincos, /* execute */
716 NULL, /* sub */
717 NULL, /* next */
718 0, /* static_pass_number */
719 0, /* tv_id */
720 PROP_ssa, /* properties_required */
721 0, /* properties_provided */
722 0, /* properties_destroyed */
723 0, /* todo_flags_start */
724 TODO_dump_func | TODO_update_ssa | TODO_verify_ssa
725 | TODO_verify_stmts, /* todo_flags_finish */
726 0 /* letter */
727 };