xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-call-cdce.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino /* Conditional Dead Call Elimination pass for the GNU compiler.
2*e4b17023SJohn Marino    Copyright (C) 2008, 2009, 2010
3*e4b17023SJohn Marino    Free Software Foundation, Inc.
4*e4b17023SJohn Marino    Contributed by Xinliang David Li <davidxl@google.com>
5*e4b17023SJohn Marino 
6*e4b17023SJohn Marino This file is part of GCC.
7*e4b17023SJohn Marino 
8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
9*e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
10*e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
11*e4b17023SJohn Marino later version.
12*e4b17023SJohn Marino 
13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
14*e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16*e4b17023SJohn Marino for more details.
17*e4b17023SJohn Marino 
18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19*e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
21*e4b17023SJohn Marino 
22*e4b17023SJohn Marino #include "config.h"
23*e4b17023SJohn Marino #include "system.h"
24*e4b17023SJohn Marino #include "coretypes.h"
25*e4b17023SJohn Marino #include "tm.h"
26*e4b17023SJohn Marino #include "basic-block.h"
27*e4b17023SJohn Marino #include "tree.h"
28*e4b17023SJohn Marino #include "gimple-pretty-print.h"
29*e4b17023SJohn Marino #include "tree-flow.h"
30*e4b17023SJohn Marino #include "gimple.h"
31*e4b17023SJohn Marino #include "tree-dump.h"
32*e4b17023SJohn Marino #include "tree-pass.h"
33*e4b17023SJohn Marino #include "timevar.h"
34*e4b17023SJohn Marino #include "flags.h"
35*e4b17023SJohn Marino 
36*e4b17023SJohn Marino 
37*e4b17023SJohn Marino /* Conditional dead call elimination
38*e4b17023SJohn Marino 
39*e4b17023SJohn Marino    Some builtin functions can set errno on error conditions, but they
40*e4b17023SJohn Marino    are otherwise pure.  If the result of a call to such a function is
41*e4b17023SJohn Marino    not used, the compiler can still not eliminate the call without
42*e4b17023SJohn Marino    powerful interprocedural analysis to prove that the errno is not
43*e4b17023SJohn Marino    checked.  However, if the conditions under which the error occurs
44*e4b17023SJohn Marino    are known, the compiler can conditionally dead code eliminate the
45*e4b17023SJohn Marino    calls by shrink-wrapping the semi-dead calls into the error condition:
46*e4b17023SJohn Marino 
47*e4b17023SJohn Marino         built_in_call (args)
48*e4b17023SJohn Marino           ==>
49*e4b17023SJohn Marino         if (error_cond (args))
50*e4b17023SJohn Marino              built_in_call (args)
51*e4b17023SJohn Marino 
52*e4b17023SJohn Marino     An actual simple example is :
53*e4b17023SJohn Marino          log (x);   // Mostly dead call
54*e4b17023SJohn Marino      ==>
55*e4b17023SJohn Marino          if (x < 0)
56*e4b17023SJohn Marino              log (x);
57*e4b17023SJohn Marino      With this change, call to log (x) is effectively eliminated, as
58*e4b17023SJohn Marino      in majority of the cases, log won't be called with x out of
59*e4b17023SJohn Marino      range.  The branch is totally predictable, so the branch cost
60*e4b17023SJohn Marino      is low.
61*e4b17023SJohn Marino 
62*e4b17023SJohn Marino    Note that library functions are not supposed to clear errno to zero without
63*e4b17023SJohn Marino    error.  See IEEE Std 1003.1, section 2.3 Error Numbers, and section 7.5:3 of
64*e4b17023SJohn Marino    ISO/IEC 9899 (C99).
65*e4b17023SJohn Marino 
66*e4b17023SJohn Marino    The condition wrapping the builtin call is conservatively set to avoid too
67*e4b17023SJohn Marino    aggressive (wrong) shrink wrapping.  The optimization is called conditional
68*e4b17023SJohn Marino    dead call elimination because the call is eliminated under the condition
69*e4b17023SJohn Marino    that the input arguments would not lead to domain or range error (for
70*e4b17023SJohn Marino    instance when x <= 0 for a log (x) call), however the chances that the error
71*e4b17023SJohn Marino    condition is hit is very low (those builtin calls which are conditionally
72*e4b17023SJohn Marino    dead are usually part of the C++ abstraction penalty exposed after
73*e4b17023SJohn Marino    inlining).  */
74*e4b17023SJohn Marino 
75*e4b17023SJohn Marino 
76*e4b17023SJohn Marino /* A structure for representing input domain of
77*e4b17023SJohn Marino    a function argument in integer.  If the lower
78*e4b17023SJohn Marino    bound is -inf, has_lb is set to false.  If the
79*e4b17023SJohn Marino    upper bound is +inf, has_ub is false.
80*e4b17023SJohn Marino    is_lb_inclusive and is_ub_inclusive are flags
81*e4b17023SJohn Marino    to indicate if lb and ub value are inclusive
82*e4b17023SJohn Marino    respectively.  */
83*e4b17023SJohn Marino 
84*e4b17023SJohn Marino typedef struct input_domain
85*e4b17023SJohn Marino {
86*e4b17023SJohn Marino   int lb;
87*e4b17023SJohn Marino   int ub;
88*e4b17023SJohn Marino   bool has_lb;
89*e4b17023SJohn Marino   bool has_ub;
90*e4b17023SJohn Marino   bool is_lb_inclusive;
91*e4b17023SJohn Marino   bool is_ub_inclusive;
92*e4b17023SJohn Marino } inp_domain;
93*e4b17023SJohn Marino 
94*e4b17023SJohn Marino /* A helper function to construct and return an input
95*e4b17023SJohn Marino    domain object.  LB is the lower bound, HAS_LB is
96*e4b17023SJohn Marino    a boolean flag indicating if the lower bound exists,
97*e4b17023SJohn Marino    and LB_INCLUSIVE is a boolean flag indicating if the
98*e4b17023SJohn Marino    lower bound is inclusive or not.  UB, HAS_UB, and
99*e4b17023SJohn Marino    UB_INCLUSIVE have the same meaning, but for upper
100*e4b17023SJohn Marino    bound of the domain.  */
101*e4b17023SJohn Marino 
102*e4b17023SJohn Marino static inp_domain
get_domain(int lb,bool has_lb,bool lb_inclusive,int ub,bool has_ub,bool ub_inclusive)103*e4b17023SJohn Marino get_domain (int lb, bool has_lb, bool lb_inclusive,
104*e4b17023SJohn Marino             int ub, bool has_ub, bool ub_inclusive)
105*e4b17023SJohn Marino {
106*e4b17023SJohn Marino   inp_domain domain;
107*e4b17023SJohn Marino   domain.lb = lb;
108*e4b17023SJohn Marino   domain.has_lb = has_lb;
109*e4b17023SJohn Marino   domain.is_lb_inclusive = lb_inclusive;
110*e4b17023SJohn Marino   domain.ub = ub;
111*e4b17023SJohn Marino   domain.has_ub = has_ub;
112*e4b17023SJohn Marino   domain.is_ub_inclusive = ub_inclusive;
113*e4b17023SJohn Marino   return domain;
114*e4b17023SJohn Marino }
115*e4b17023SJohn Marino 
116*e4b17023SJohn Marino /* A helper function to check the target format for the
117*e4b17023SJohn Marino    argument type. In this implementation, only IEEE formats
118*e4b17023SJohn Marino    are supported.  ARG is the call argument to be checked.
119*e4b17023SJohn Marino    Returns true if the format is supported.  To support other
120*e4b17023SJohn Marino    target formats,  function get_no_error_domain needs to be
121*e4b17023SJohn Marino    enhanced to have range bounds properly computed. Since
122*e4b17023SJohn Marino    the check is cheap (very small number of candidates
123*e4b17023SJohn Marino    to be checked), the result is not cached for each float type.  */
124*e4b17023SJohn Marino 
125*e4b17023SJohn Marino static bool
check_target_format(tree arg)126*e4b17023SJohn Marino check_target_format (tree arg)
127*e4b17023SJohn Marino {
128*e4b17023SJohn Marino   tree type;
129*e4b17023SJohn Marino   enum machine_mode mode;
130*e4b17023SJohn Marino   const struct real_format *rfmt;
131*e4b17023SJohn Marino 
132*e4b17023SJohn Marino   type = TREE_TYPE (arg);
133*e4b17023SJohn Marino   mode = TYPE_MODE (type);
134*e4b17023SJohn Marino   rfmt = REAL_MODE_FORMAT (mode);
135*e4b17023SJohn Marino   if ((mode == SFmode
136*e4b17023SJohn Marino        && (rfmt == &ieee_single_format || rfmt == &mips_single_format
137*e4b17023SJohn Marino 	   || rfmt == &motorola_single_format))
138*e4b17023SJohn Marino       || (mode == DFmode
139*e4b17023SJohn Marino 	  && (rfmt == &ieee_double_format || rfmt == &mips_double_format
140*e4b17023SJohn Marino 	      || rfmt == &motorola_double_format))
141*e4b17023SJohn Marino       /* For long double, we can not really check XFmode
142*e4b17023SJohn Marino          which is only defined on intel platforms.
143*e4b17023SJohn Marino          Candidate pre-selection using builtin function
144*e4b17023SJohn Marino          code guarantees that we are checking formats
145*e4b17023SJohn Marino          for long double modes: double, quad, and extended.  */
146*e4b17023SJohn Marino       || (mode != SFmode && mode != DFmode
147*e4b17023SJohn Marino           && (rfmt == &ieee_quad_format
148*e4b17023SJohn Marino 	      || rfmt == &mips_quad_format
149*e4b17023SJohn Marino 	      || rfmt == &ieee_extended_motorola_format
150*e4b17023SJohn Marino               || rfmt == &ieee_extended_intel_96_format
151*e4b17023SJohn Marino               || rfmt == &ieee_extended_intel_128_format
152*e4b17023SJohn Marino               || rfmt == &ieee_extended_intel_96_round_53_format)))
153*e4b17023SJohn Marino     return true;
154*e4b17023SJohn Marino 
155*e4b17023SJohn Marino   return false;
156*e4b17023SJohn Marino }
157*e4b17023SJohn Marino 
158*e4b17023SJohn Marino 
159*e4b17023SJohn Marino /* A helper function to help select calls to pow that are suitable for
160*e4b17023SJohn Marino    conditional DCE transformation.  It looks for pow calls that can be
161*e4b17023SJohn Marino    guided with simple conditions.  Such calls either have constant base
162*e4b17023SJohn Marino    values or base values converted from integers.  Returns true if
163*e4b17023SJohn Marino    the pow call POW_CALL is a candidate.  */
164*e4b17023SJohn Marino 
165*e4b17023SJohn Marino /* The maximum integer bit size for base argument of a pow call
166*e4b17023SJohn Marino    that is suitable for shrink-wrapping transformation.  */
167*e4b17023SJohn Marino #define MAX_BASE_INT_BIT_SIZE 32
168*e4b17023SJohn Marino 
169*e4b17023SJohn Marino static bool
check_pow(gimple pow_call)170*e4b17023SJohn Marino check_pow (gimple pow_call)
171*e4b17023SJohn Marino {
172*e4b17023SJohn Marino   tree base, expn;
173*e4b17023SJohn Marino   enum tree_code bc, ec;
174*e4b17023SJohn Marino 
175*e4b17023SJohn Marino   if (gimple_call_num_args (pow_call) != 2)
176*e4b17023SJohn Marino     return false;
177*e4b17023SJohn Marino 
178*e4b17023SJohn Marino   base = gimple_call_arg (pow_call, 0);
179*e4b17023SJohn Marino   expn = gimple_call_arg (pow_call, 1);
180*e4b17023SJohn Marino 
181*e4b17023SJohn Marino   if (!check_target_format (expn))
182*e4b17023SJohn Marino     return false;
183*e4b17023SJohn Marino 
184*e4b17023SJohn Marino   bc = TREE_CODE (base);
185*e4b17023SJohn Marino   ec = TREE_CODE (expn);
186*e4b17023SJohn Marino 
187*e4b17023SJohn Marino   /* Folding candidates are not interesting.
188*e4b17023SJohn Marino      Can actually assert that it is already folded.  */
189*e4b17023SJohn Marino   if (ec == REAL_CST && bc == REAL_CST)
190*e4b17023SJohn Marino     return false;
191*e4b17023SJohn Marino 
192*e4b17023SJohn Marino   if (bc == REAL_CST)
193*e4b17023SJohn Marino     {
194*e4b17023SJohn Marino       /* Only handle a fixed range of constant.  */
195*e4b17023SJohn Marino       REAL_VALUE_TYPE mv;
196*e4b17023SJohn Marino       REAL_VALUE_TYPE bcv = TREE_REAL_CST (base);
197*e4b17023SJohn Marino       if (REAL_VALUES_EQUAL (bcv, dconst1))
198*e4b17023SJohn Marino         return false;
199*e4b17023SJohn Marino       if (REAL_VALUES_LESS (bcv, dconst1))
200*e4b17023SJohn Marino         return false;
201*e4b17023SJohn Marino       real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, 0, 1);
202*e4b17023SJohn Marino       if (REAL_VALUES_LESS (mv, bcv))
203*e4b17023SJohn Marino         return false;
204*e4b17023SJohn Marino       return true;
205*e4b17023SJohn Marino     }
206*e4b17023SJohn Marino   else if (bc == SSA_NAME)
207*e4b17023SJohn Marino     {
208*e4b17023SJohn Marino       tree base_val0, base_var, type;
209*e4b17023SJohn Marino       gimple base_def;
210*e4b17023SJohn Marino       int bit_sz;
211*e4b17023SJohn Marino 
212*e4b17023SJohn Marino       /* Only handles cases where base value is converted
213*e4b17023SJohn Marino          from integer values.  */
214*e4b17023SJohn Marino       base_def = SSA_NAME_DEF_STMT (base);
215*e4b17023SJohn Marino       if (gimple_code (base_def) != GIMPLE_ASSIGN)
216*e4b17023SJohn Marino         return false;
217*e4b17023SJohn Marino 
218*e4b17023SJohn Marino       if (gimple_assign_rhs_code (base_def) != FLOAT_EXPR)
219*e4b17023SJohn Marino         return false;
220*e4b17023SJohn Marino       base_val0 = gimple_assign_rhs1 (base_def);
221*e4b17023SJohn Marino 
222*e4b17023SJohn Marino       base_var = SSA_NAME_VAR (base_val0);
223*e4b17023SJohn Marino       if (!DECL_P  (base_var))
224*e4b17023SJohn Marino         return false;
225*e4b17023SJohn Marino 
226*e4b17023SJohn Marino       type = TREE_TYPE (base_var);
227*e4b17023SJohn Marino       if (TREE_CODE (type) != INTEGER_TYPE)
228*e4b17023SJohn Marino         return false;
229*e4b17023SJohn Marino       bit_sz = TYPE_PRECISION (type);
230*e4b17023SJohn Marino       /* If the type of the base is too wide,
231*e4b17023SJohn Marino          the resulting shrink wrapping condition
232*e4b17023SJohn Marino 	 will be too conservative.  */
233*e4b17023SJohn Marino       if (bit_sz > MAX_BASE_INT_BIT_SIZE)
234*e4b17023SJohn Marino         return false;
235*e4b17023SJohn Marino 
236*e4b17023SJohn Marino       return true;
237*e4b17023SJohn Marino     }
238*e4b17023SJohn Marino   else
239*e4b17023SJohn Marino     return false;
240*e4b17023SJohn Marino }
241*e4b17023SJohn Marino 
242*e4b17023SJohn Marino /* A helper function to help select candidate function calls that are
243*e4b17023SJohn Marino    suitable for conditional DCE.  Candidate functions must have single
244*e4b17023SJohn Marino    valid input domain in this implementation except for pow (see check_pow).
245*e4b17023SJohn Marino    Returns true if the function call is a candidate.  */
246*e4b17023SJohn Marino 
247*e4b17023SJohn Marino static bool
check_builtin_call(gimple bcall)248*e4b17023SJohn Marino check_builtin_call (gimple bcall)
249*e4b17023SJohn Marino {
250*e4b17023SJohn Marino   tree arg;
251*e4b17023SJohn Marino 
252*e4b17023SJohn Marino   arg = gimple_call_arg (bcall, 0);
253*e4b17023SJohn Marino   return check_target_format (arg);
254*e4b17023SJohn Marino }
255*e4b17023SJohn Marino 
256*e4b17023SJohn Marino /* A helper function to determine if a builtin function call is a
257*e4b17023SJohn Marino    candidate for conditional DCE.  Returns true if the builtin call
258*e4b17023SJohn Marino    is a candidate.  */
259*e4b17023SJohn Marino 
260*e4b17023SJohn Marino static bool
is_call_dce_candidate(gimple call)261*e4b17023SJohn Marino is_call_dce_candidate (gimple call)
262*e4b17023SJohn Marino {
263*e4b17023SJohn Marino   tree fn;
264*e4b17023SJohn Marino   enum built_in_function fnc;
265*e4b17023SJohn Marino 
266*e4b17023SJohn Marino   /* Only potentially dead calls are considered.  */
267*e4b17023SJohn Marino   if (gimple_call_lhs (call))
268*e4b17023SJohn Marino     return false;
269*e4b17023SJohn Marino 
270*e4b17023SJohn Marino   fn = gimple_call_fndecl (call);
271*e4b17023SJohn Marino   if (!fn
272*e4b17023SJohn Marino       || !DECL_BUILT_IN (fn)
273*e4b17023SJohn Marino       || (DECL_BUILT_IN_CLASS (fn) != BUILT_IN_NORMAL))
274*e4b17023SJohn Marino     return false;
275*e4b17023SJohn Marino 
276*e4b17023SJohn Marino   fnc = DECL_FUNCTION_CODE (fn);
277*e4b17023SJohn Marino   switch (fnc)
278*e4b17023SJohn Marino     {
279*e4b17023SJohn Marino     /* Trig functions.  */
280*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ACOS):
281*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ASIN):
282*e4b17023SJohn Marino     /* Hyperbolic functions.  */
283*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ACOSH):
284*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ATANH):
285*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_COSH):
286*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_SINH):
287*e4b17023SJohn Marino     /* Log functions.  */
288*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG):
289*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG2):
290*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG10):
291*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG1P):
292*e4b17023SJohn Marino     /* Exp functions.  */
293*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_EXP):
294*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_EXP2):
295*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_EXP10):
296*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_EXPM1):
297*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_POW10):
298*e4b17023SJohn Marino     /* Sqrt.  */
299*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_SQRT):
300*e4b17023SJohn Marino       return check_builtin_call (call);
301*e4b17023SJohn Marino     /* Special one: two argument pow.  */
302*e4b17023SJohn Marino     case BUILT_IN_POW:
303*e4b17023SJohn Marino       return check_pow (call);
304*e4b17023SJohn Marino     default:
305*e4b17023SJohn Marino       break;
306*e4b17023SJohn Marino     }
307*e4b17023SJohn Marino 
308*e4b17023SJohn Marino   return false;
309*e4b17023SJohn Marino }
310*e4b17023SJohn Marino 
311*e4b17023SJohn Marino 
312*e4b17023SJohn Marino /* A helper function to generate gimple statements for
313*e4b17023SJohn Marino    one bound comparison.  ARG is the call argument to
314*e4b17023SJohn Marino    be compared with the bound, LBUB is the bound value
315*e4b17023SJohn Marino    in integer, TCODE is the tree_code of the comparison,
316*e4b17023SJohn Marino    TEMP_NAME1/TEMP_NAME2 are names of the temporaries,
317*e4b17023SJohn Marino    CONDS is a vector holding the produced GIMPLE statements,
318*e4b17023SJohn Marino    and NCONDS points to the variable holding the number
319*e4b17023SJohn Marino    of logical comparisons.  CONDS is either empty or
320*e4b17023SJohn Marino    a list ended with a null tree.  */
321*e4b17023SJohn Marino 
322*e4b17023SJohn Marino static void
gen_one_condition(tree arg,int lbub,enum tree_code tcode,const char * temp_name1,const char * temp_name2,VEC (gimple,heap)* conds,unsigned * nconds)323*e4b17023SJohn Marino gen_one_condition (tree arg, int lbub,
324*e4b17023SJohn Marino                    enum tree_code tcode,
325*e4b17023SJohn Marino                    const char *temp_name1,
326*e4b17023SJohn Marino 		   const char *temp_name2,
327*e4b17023SJohn Marino                    VEC (gimple, heap) *conds,
328*e4b17023SJohn Marino                    unsigned *nconds)
329*e4b17023SJohn Marino {
330*e4b17023SJohn Marino   tree lbub_real_cst, lbub_cst, float_type;
331*e4b17023SJohn Marino   tree temp, tempn, tempc, tempcn;
332*e4b17023SJohn Marino   gimple stmt1, stmt2, stmt3;
333*e4b17023SJohn Marino 
334*e4b17023SJohn Marino   float_type = TREE_TYPE (arg);
335*e4b17023SJohn Marino   lbub_cst = build_int_cst (integer_type_node, lbub);
336*e4b17023SJohn Marino   lbub_real_cst = build_real_from_int_cst (float_type, lbub_cst);
337*e4b17023SJohn Marino 
338*e4b17023SJohn Marino   temp = create_tmp_var (float_type, temp_name1);
339*e4b17023SJohn Marino   stmt1 = gimple_build_assign (temp, arg);
340*e4b17023SJohn Marino   tempn = make_ssa_name (temp, stmt1);
341*e4b17023SJohn Marino   gimple_assign_set_lhs (stmt1, tempn);
342*e4b17023SJohn Marino 
343*e4b17023SJohn Marino   tempc = create_tmp_var (boolean_type_node, temp_name2);
344*e4b17023SJohn Marino   stmt2 = gimple_build_assign (tempc,
345*e4b17023SJohn Marino                                fold_build2 (tcode,
346*e4b17023SJohn Marino 					    boolean_type_node,
347*e4b17023SJohn Marino 					    tempn, lbub_real_cst));
348*e4b17023SJohn Marino   tempcn = make_ssa_name (tempc, stmt2);
349*e4b17023SJohn Marino   gimple_assign_set_lhs (stmt2, tempcn);
350*e4b17023SJohn Marino 
351*e4b17023SJohn Marino   stmt3 = gimple_build_cond_from_tree (tempcn, NULL_TREE, NULL_TREE);
352*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, stmt1);
353*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, stmt2);
354*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, stmt3);
355*e4b17023SJohn Marino   (*nconds)++;
356*e4b17023SJohn Marino }
357*e4b17023SJohn Marino 
358*e4b17023SJohn Marino /* A helper function to generate GIMPLE statements for
359*e4b17023SJohn Marino    out of input domain check.  ARG is the call argument
360*e4b17023SJohn Marino    to be runtime checked, DOMAIN holds the valid domain
361*e4b17023SJohn Marino    for the given function, CONDS points to the vector
362*e4b17023SJohn Marino    holding the result GIMPLE statements.  *NCONDS is
363*e4b17023SJohn Marino    the number of logical comparisons.  This function
364*e4b17023SJohn Marino    produces no more than two logical comparisons, one
365*e4b17023SJohn Marino    for lower bound check, one for upper bound check.  */
366*e4b17023SJohn Marino 
367*e4b17023SJohn Marino static void
gen_conditions_for_domain(tree arg,inp_domain domain,VEC (gimple,heap)* conds,unsigned * nconds)368*e4b17023SJohn Marino gen_conditions_for_domain (tree arg, inp_domain domain,
369*e4b17023SJohn Marino                            VEC (gimple, heap) *conds,
370*e4b17023SJohn Marino                            unsigned *nconds)
371*e4b17023SJohn Marino {
372*e4b17023SJohn Marino   if (domain.has_lb)
373*e4b17023SJohn Marino     gen_one_condition (arg, domain.lb,
374*e4b17023SJohn Marino                        (domain.is_lb_inclusive
375*e4b17023SJohn Marino                         ? LT_EXPR : LE_EXPR),
376*e4b17023SJohn Marino                        "DCE_COND_LB", "DCE_COND_LB_TEST",
377*e4b17023SJohn Marino                        conds, nconds);
378*e4b17023SJohn Marino 
379*e4b17023SJohn Marino   if (domain.has_ub)
380*e4b17023SJohn Marino     {
381*e4b17023SJohn Marino       /* Now push a separator.  */
382*e4b17023SJohn Marino       if (domain.has_lb)
383*e4b17023SJohn Marino         VEC_quick_push (gimple, conds, NULL);
384*e4b17023SJohn Marino 
385*e4b17023SJohn Marino       gen_one_condition (arg, domain.ub,
386*e4b17023SJohn Marino                          (domain.is_ub_inclusive
387*e4b17023SJohn Marino                           ? GT_EXPR : GE_EXPR),
388*e4b17023SJohn Marino                          "DCE_COND_UB", "DCE_COND_UB_TEST",
389*e4b17023SJohn Marino                          conds, nconds);
390*e4b17023SJohn Marino     }
391*e4b17023SJohn Marino }
392*e4b17023SJohn Marino 
393*e4b17023SJohn Marino 
394*e4b17023SJohn Marino /* A helper function to generate condition
395*e4b17023SJohn Marino    code for the y argument in call pow (some_const, y).
396*e4b17023SJohn Marino    See candidate selection in check_pow.  Since the
397*e4b17023SJohn Marino    candidates' base values have a limited range,
398*e4b17023SJohn Marino    the guarded code generated for y are simple:
399*e4b17023SJohn Marino    if (y > max_y)
400*e4b17023SJohn Marino      pow (const, y);
401*e4b17023SJohn Marino    Note max_y can be computed separately for each
402*e4b17023SJohn Marino    const base, but in this implementation, we
403*e4b17023SJohn Marino    choose to compute it using the max base
404*e4b17023SJohn Marino    in the allowed range for the purpose of
405*e4b17023SJohn Marino    simplicity.  BASE is the constant base value,
406*e4b17023SJohn Marino    EXPN is the expression for the exponent argument,
407*e4b17023SJohn Marino    *CONDS is the vector to hold resulting statements,
408*e4b17023SJohn Marino    and *NCONDS is the number of logical conditions.  */
409*e4b17023SJohn Marino 
410*e4b17023SJohn Marino static void
gen_conditions_for_pow_cst_base(tree base,tree expn,VEC (gimple,heap)* conds,unsigned * nconds)411*e4b17023SJohn Marino gen_conditions_for_pow_cst_base (tree base, tree expn,
412*e4b17023SJohn Marino                                  VEC (gimple, heap) *conds,
413*e4b17023SJohn Marino                                  unsigned *nconds)
414*e4b17023SJohn Marino {
415*e4b17023SJohn Marino   inp_domain exp_domain;
416*e4b17023SJohn Marino   /* Validate the range of the base constant to make
417*e4b17023SJohn Marino      sure it is consistent with check_pow.  */
418*e4b17023SJohn Marino   REAL_VALUE_TYPE mv;
419*e4b17023SJohn Marino   REAL_VALUE_TYPE bcv = TREE_REAL_CST (base);
420*e4b17023SJohn Marino   gcc_assert (!REAL_VALUES_EQUAL (bcv, dconst1)
421*e4b17023SJohn Marino               && !REAL_VALUES_LESS (bcv, dconst1));
422*e4b17023SJohn Marino   real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, 0, 1);
423*e4b17023SJohn Marino   gcc_assert (!REAL_VALUES_LESS (mv, bcv));
424*e4b17023SJohn Marino 
425*e4b17023SJohn Marino   exp_domain = get_domain (0, false, false,
426*e4b17023SJohn Marino                            127, true, false);
427*e4b17023SJohn Marino 
428*e4b17023SJohn Marino   gen_conditions_for_domain (expn, exp_domain,
429*e4b17023SJohn Marino                              conds, nconds);
430*e4b17023SJohn Marino }
431*e4b17023SJohn Marino 
432*e4b17023SJohn Marino /* Generate error condition code for pow calls with
433*e4b17023SJohn Marino    non constant base values.  The candidates selected
434*e4b17023SJohn Marino    have their base argument value converted from
435*e4b17023SJohn Marino    integer (see check_pow) value (1, 2, 4 bytes), and
436*e4b17023SJohn Marino    the max exp value is computed based on the size
437*e4b17023SJohn Marino    of the integer type (i.e. max possible base value).
438*e4b17023SJohn Marino    The resulting input domain for exp argument is thus
439*e4b17023SJohn Marino    conservative (smaller than the max value allowed by
440*e4b17023SJohn Marino    the runtime value of the base).  BASE is the integer
441*e4b17023SJohn Marino    base value, EXPN is the expression for the exponent
442*e4b17023SJohn Marino    argument, *CONDS is the vector to hold resulting
443*e4b17023SJohn Marino    statements, and *NCONDS is the number of logical
444*e4b17023SJohn Marino    conditions.  */
445*e4b17023SJohn Marino 
446*e4b17023SJohn Marino static void
gen_conditions_for_pow_int_base(tree base,tree expn,VEC (gimple,heap)* conds,unsigned * nconds)447*e4b17023SJohn Marino gen_conditions_for_pow_int_base (tree base, tree expn,
448*e4b17023SJohn Marino                                  VEC (gimple, heap) *conds,
449*e4b17023SJohn Marino                                  unsigned *nconds)
450*e4b17023SJohn Marino {
451*e4b17023SJohn Marino   gimple base_def;
452*e4b17023SJohn Marino   tree base_val0;
453*e4b17023SJohn Marino   tree base_var, int_type;
454*e4b17023SJohn Marino   tree temp, tempn;
455*e4b17023SJohn Marino   tree cst0;
456*e4b17023SJohn Marino   gimple stmt1, stmt2;
457*e4b17023SJohn Marino   int bit_sz, max_exp;
458*e4b17023SJohn Marino   inp_domain exp_domain;
459*e4b17023SJohn Marino 
460*e4b17023SJohn Marino   base_def = SSA_NAME_DEF_STMT (base);
461*e4b17023SJohn Marino   base_val0 = gimple_assign_rhs1 (base_def);
462*e4b17023SJohn Marino   base_var = SSA_NAME_VAR (base_val0);
463*e4b17023SJohn Marino   int_type = TREE_TYPE (base_var);
464*e4b17023SJohn Marino   bit_sz = TYPE_PRECISION (int_type);
465*e4b17023SJohn Marino   gcc_assert (bit_sz > 0
466*e4b17023SJohn Marino               && bit_sz <= MAX_BASE_INT_BIT_SIZE);
467*e4b17023SJohn Marino 
468*e4b17023SJohn Marino   /* Determine the max exp argument value according to
469*e4b17023SJohn Marino      the size of the base integer.  The max exp value
470*e4b17023SJohn Marino      is conservatively estimated assuming IEEE754 double
471*e4b17023SJohn Marino      precision format.  */
472*e4b17023SJohn Marino   if (bit_sz == 8)
473*e4b17023SJohn Marino     max_exp = 128;
474*e4b17023SJohn Marino   else if (bit_sz == 16)
475*e4b17023SJohn Marino     max_exp = 64;
476*e4b17023SJohn Marino   else
477*e4b17023SJohn Marino     {
478*e4b17023SJohn Marino       gcc_assert (bit_sz == MAX_BASE_INT_BIT_SIZE);
479*e4b17023SJohn Marino       max_exp = 32;
480*e4b17023SJohn Marino     }
481*e4b17023SJohn Marino 
482*e4b17023SJohn Marino   /* For pow ((double)x, y), generate the following conditions:
483*e4b17023SJohn Marino      cond 1:
484*e4b17023SJohn Marino      temp1 = x;
485*e4b17023SJohn Marino      if (temp1 <= 0)
486*e4b17023SJohn Marino 
487*e4b17023SJohn Marino      cond 2:
488*e4b17023SJohn Marino      temp2 = y;
489*e4b17023SJohn Marino      if (temp2 > max_exp_real_cst)  */
490*e4b17023SJohn Marino 
491*e4b17023SJohn Marino   /* Generate condition in reverse order -- first
492*e4b17023SJohn Marino      the condition for the exp argument.  */
493*e4b17023SJohn Marino 
494*e4b17023SJohn Marino   exp_domain = get_domain (0, false, false,
495*e4b17023SJohn Marino                            max_exp, true, true);
496*e4b17023SJohn Marino 
497*e4b17023SJohn Marino   gen_conditions_for_domain (expn, exp_domain,
498*e4b17023SJohn Marino                              conds, nconds);
499*e4b17023SJohn Marino 
500*e4b17023SJohn Marino   /* Now generate condition for the base argument.
501*e4b17023SJohn Marino      Note it does not use the helper function
502*e4b17023SJohn Marino      gen_conditions_for_domain because the base
503*e4b17023SJohn Marino      type is integer.  */
504*e4b17023SJohn Marino 
505*e4b17023SJohn Marino   /* Push a separator.  */
506*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, NULL);
507*e4b17023SJohn Marino 
508*e4b17023SJohn Marino   temp = create_tmp_var (int_type, "DCE_COND1");
509*e4b17023SJohn Marino   cst0 = build_int_cst (int_type, 0);
510*e4b17023SJohn Marino   stmt1 = gimple_build_assign (temp, base_val0);
511*e4b17023SJohn Marino   tempn = make_ssa_name (temp, stmt1);
512*e4b17023SJohn Marino   gimple_assign_set_lhs (stmt1, tempn);
513*e4b17023SJohn Marino   stmt2 = gimple_build_cond (LE_EXPR, tempn, cst0, NULL_TREE, NULL_TREE);
514*e4b17023SJohn Marino 
515*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, stmt1);
516*e4b17023SJohn Marino   VEC_quick_push (gimple, conds, stmt2);
517*e4b17023SJohn Marino   (*nconds)++;
518*e4b17023SJohn Marino }
519*e4b17023SJohn Marino 
520*e4b17023SJohn Marino /* Method to generate conditional statements for guarding conditionally
521*e4b17023SJohn Marino    dead calls to pow.  One or more statements can be generated for
522*e4b17023SJohn Marino    each logical condition.  Statement groups of different conditions
523*e4b17023SJohn Marino    are separated by a NULL tree and they are stored in the VEC
524*e4b17023SJohn Marino    conds.  The number of logical conditions are stored in *nconds.
525*e4b17023SJohn Marino 
526*e4b17023SJohn Marino    See C99 standard, 7.12.7.4:2, for description of pow (x, y).
527*e4b17023SJohn Marino    The precise condition for domain errors are complex.  In this
528*e4b17023SJohn Marino    implementation, a simplified (but conservative) valid domain
529*e4b17023SJohn Marino    for x and y are used: x is positive to avoid dom errors, while
530*e4b17023SJohn Marino    y is smaller than a upper bound (depending on x) to avoid range
531*e4b17023SJohn Marino    errors.  Runtime code is generated to check x (if not constant)
532*e4b17023SJohn Marino    and y against the valid domain.  If it is out, jump to the call,
533*e4b17023SJohn Marino    otherwise the call is bypassed.  POW_CALL is the call statement,
534*e4b17023SJohn Marino    *CONDS is a vector holding the resulting condition statements,
535*e4b17023SJohn Marino    and *NCONDS is the number of logical conditions.  */
536*e4b17023SJohn Marino 
537*e4b17023SJohn Marino static void
gen_conditions_for_pow(gimple pow_call,VEC (gimple,heap)* conds,unsigned * nconds)538*e4b17023SJohn Marino gen_conditions_for_pow (gimple pow_call, VEC (gimple, heap) *conds,
539*e4b17023SJohn Marino                         unsigned *nconds)
540*e4b17023SJohn Marino {
541*e4b17023SJohn Marino   tree base, expn;
542*e4b17023SJohn Marino   enum tree_code bc;
543*e4b17023SJohn Marino 
544*e4b17023SJohn Marino   gcc_checking_assert (check_pow (pow_call));
545*e4b17023SJohn Marino 
546*e4b17023SJohn Marino   *nconds = 0;
547*e4b17023SJohn Marino 
548*e4b17023SJohn Marino   base = gimple_call_arg (pow_call, 0);
549*e4b17023SJohn Marino   expn = gimple_call_arg (pow_call, 1);
550*e4b17023SJohn Marino 
551*e4b17023SJohn Marino   bc = TREE_CODE (base);
552*e4b17023SJohn Marino 
553*e4b17023SJohn Marino   if (bc == REAL_CST)
554*e4b17023SJohn Marino     gen_conditions_for_pow_cst_base (base, expn, conds, nconds);
555*e4b17023SJohn Marino   else if (bc == SSA_NAME)
556*e4b17023SJohn Marino     gen_conditions_for_pow_int_base (base, expn, conds, nconds);
557*e4b17023SJohn Marino   else
558*e4b17023SJohn Marino     gcc_unreachable ();
559*e4b17023SJohn Marino }
560*e4b17023SJohn Marino 
561*e4b17023SJohn Marino /* A helper routine to help computing the valid input domain
562*e4b17023SJohn Marino    for a builtin function.  See C99 7.12.7 for details.  In this
563*e4b17023SJohn Marino    implementation, we only handle single region domain.  The
564*e4b17023SJohn Marino    resulting region can be conservative (smaller) than the actual
565*e4b17023SJohn Marino    one and rounded to integers.  Some of the bounds are documented
566*e4b17023SJohn Marino    in the standard, while other limit constants are computed
567*e4b17023SJohn Marino    assuming IEEE floating point format (for SF and DF modes).
568*e4b17023SJohn Marino    Since IEEE only sets minimum requirements for long double format,
569*e4b17023SJohn Marino    different long double formats exist under different implementations
570*e4b17023SJohn Marino    (e.g, 64 bit double precision (DF), 80 bit double-extended
571*e4b17023SJohn Marino    precision (XF), and 128 bit quad precision (QF) ).  For simplicity,
572*e4b17023SJohn Marino    in this implementation, the computed bounds for long double assume
573*e4b17023SJohn Marino    64 bit format (DF), and are therefore conservative.  Another
574*e4b17023SJohn Marino    assumption is that single precision float type is always SF mode,
575*e4b17023SJohn Marino    and double type is DF mode.  This function is quite
576*e4b17023SJohn Marino    implementation specific, so it may not be suitable to be part of
577*e4b17023SJohn Marino    builtins.c.  This needs to be revisited later to see if it can
578*e4b17023SJohn Marino    be leveraged in x87 assembly expansion.  */
579*e4b17023SJohn Marino 
580*e4b17023SJohn Marino static inp_domain
get_no_error_domain(enum built_in_function fnc)581*e4b17023SJohn Marino get_no_error_domain (enum built_in_function fnc)
582*e4b17023SJohn Marino {
583*e4b17023SJohn Marino   switch (fnc)
584*e4b17023SJohn Marino     {
585*e4b17023SJohn Marino     /* Trig functions: return [-1, +1]  */
586*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ACOS):
587*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ASIN):
588*e4b17023SJohn Marino       return get_domain (-1, true, true,
589*e4b17023SJohn Marino                          1, true, true);
590*e4b17023SJohn Marino     /* Hyperbolic functions.  */
591*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ACOSH):
592*e4b17023SJohn Marino       /* acosh: [1, +inf)  */
593*e4b17023SJohn Marino       return get_domain (1, true, true,
594*e4b17023SJohn Marino                          1, false, false);
595*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_ATANH):
596*e4b17023SJohn Marino       /* atanh: (-1, +1)  */
597*e4b17023SJohn Marino       return get_domain (-1, true, false,
598*e4b17023SJohn Marino                          1, true, false);
599*e4b17023SJohn Marino     case BUILT_IN_COSHF:
600*e4b17023SJohn Marino     case BUILT_IN_SINHF:
601*e4b17023SJohn Marino       /* coshf: (-89, +89)  */
602*e4b17023SJohn Marino       return get_domain (-89, true, false,
603*e4b17023SJohn Marino                          89, true, false);
604*e4b17023SJohn Marino     case BUILT_IN_COSH:
605*e4b17023SJohn Marino     case BUILT_IN_SINH:
606*e4b17023SJohn Marino     case BUILT_IN_COSHL:
607*e4b17023SJohn Marino     case BUILT_IN_SINHL:
608*e4b17023SJohn Marino       /* cosh: (-710, +710)  */
609*e4b17023SJohn Marino       return get_domain (-710, true, false,
610*e4b17023SJohn Marino                          710, true, false);
611*e4b17023SJohn Marino     /* Log functions: (0, +inf)  */
612*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG):
613*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG2):
614*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG10):
615*e4b17023SJohn Marino       return get_domain (0, true, false,
616*e4b17023SJohn Marino                          0, false, false);
617*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_LOG1P):
618*e4b17023SJohn Marino       return get_domain (-1, true, false,
619*e4b17023SJohn Marino                          0, false, false);
620*e4b17023SJohn Marino     /* Exp functions.  */
621*e4b17023SJohn Marino     case BUILT_IN_EXPF:
622*e4b17023SJohn Marino     case BUILT_IN_EXPM1F:
623*e4b17023SJohn Marino       /* expf: (-inf, 88)  */
624*e4b17023SJohn Marino       return get_domain (-1, false, false,
625*e4b17023SJohn Marino                          88, true, false);
626*e4b17023SJohn Marino     case BUILT_IN_EXP:
627*e4b17023SJohn Marino     case BUILT_IN_EXPM1:
628*e4b17023SJohn Marino     case BUILT_IN_EXPL:
629*e4b17023SJohn Marino     case BUILT_IN_EXPM1L:
630*e4b17023SJohn Marino       /* exp: (-inf, 709)  */
631*e4b17023SJohn Marino       return get_domain (-1, false, false,
632*e4b17023SJohn Marino                          709, true, false);
633*e4b17023SJohn Marino     case BUILT_IN_EXP2F:
634*e4b17023SJohn Marino       /* exp2f: (-inf, 128)  */
635*e4b17023SJohn Marino       return get_domain (-1, false, false,
636*e4b17023SJohn Marino                          128, true, false);
637*e4b17023SJohn Marino     case BUILT_IN_EXP2:
638*e4b17023SJohn Marino     case BUILT_IN_EXP2L:
639*e4b17023SJohn Marino       /* exp2: (-inf, 1024)  */
640*e4b17023SJohn Marino       return get_domain (-1, false, false,
641*e4b17023SJohn Marino                          1024, true, false);
642*e4b17023SJohn Marino     case BUILT_IN_EXP10F:
643*e4b17023SJohn Marino     case BUILT_IN_POW10F:
644*e4b17023SJohn Marino       /* exp10f: (-inf, 38)  */
645*e4b17023SJohn Marino       return get_domain (-1, false, false,
646*e4b17023SJohn Marino                          38, true, false);
647*e4b17023SJohn Marino     case BUILT_IN_EXP10:
648*e4b17023SJohn Marino     case BUILT_IN_POW10:
649*e4b17023SJohn Marino     case BUILT_IN_EXP10L:
650*e4b17023SJohn Marino     case BUILT_IN_POW10L:
651*e4b17023SJohn Marino       /* exp10: (-inf, 308)  */
652*e4b17023SJohn Marino       return get_domain (-1, false, false,
653*e4b17023SJohn Marino                          308, true, false);
654*e4b17023SJohn Marino     /* sqrt: [0, +inf)  */
655*e4b17023SJohn Marino     CASE_FLT_FN (BUILT_IN_SQRT):
656*e4b17023SJohn Marino       return get_domain (0, true, true,
657*e4b17023SJohn Marino                          0, false, false);
658*e4b17023SJohn Marino     default:
659*e4b17023SJohn Marino       gcc_unreachable ();
660*e4b17023SJohn Marino     }
661*e4b17023SJohn Marino 
662*e4b17023SJohn Marino   gcc_unreachable ();
663*e4b17023SJohn Marino }
664*e4b17023SJohn Marino 
665*e4b17023SJohn Marino /* The function to generate shrink wrap conditions for a partially
666*e4b17023SJohn Marino    dead builtin call whose return value is not used anywhere,
667*e4b17023SJohn Marino    but has to be kept live due to potential error condition.
668*e4b17023SJohn Marino    BI_CALL is the builtin call, CONDS is the vector of statements
669*e4b17023SJohn Marino    for condition code, NCODES is the pointer to the number of
670*e4b17023SJohn Marino    logical conditions.  Statements belonging to different logical
671*e4b17023SJohn Marino    condition are separated by NULL tree in the vector.  */
672*e4b17023SJohn Marino 
673*e4b17023SJohn Marino static void
gen_shrink_wrap_conditions(gimple bi_call,VEC (gimple,heap)* conds,unsigned int * nconds)674*e4b17023SJohn Marino gen_shrink_wrap_conditions (gimple bi_call, VEC (gimple, heap) *conds,
675*e4b17023SJohn Marino                             unsigned int *nconds)
676*e4b17023SJohn Marino {
677*e4b17023SJohn Marino   gimple call;
678*e4b17023SJohn Marino   tree fn;
679*e4b17023SJohn Marino   enum built_in_function fnc;
680*e4b17023SJohn Marino 
681*e4b17023SJohn Marino   gcc_assert (nconds && conds);
682*e4b17023SJohn Marino   gcc_assert (VEC_length (gimple, conds) == 0);
683*e4b17023SJohn Marino   gcc_assert (is_gimple_call (bi_call));
684*e4b17023SJohn Marino 
685*e4b17023SJohn Marino   call = bi_call;
686*e4b17023SJohn Marino   fn = gimple_call_fndecl (call);
687*e4b17023SJohn Marino   gcc_assert (fn && DECL_BUILT_IN (fn));
688*e4b17023SJohn Marino   fnc = DECL_FUNCTION_CODE (fn);
689*e4b17023SJohn Marino   *nconds = 0;
690*e4b17023SJohn Marino 
691*e4b17023SJohn Marino   if (fnc == BUILT_IN_POW)
692*e4b17023SJohn Marino     gen_conditions_for_pow (call, conds, nconds);
693*e4b17023SJohn Marino   else
694*e4b17023SJohn Marino     {
695*e4b17023SJohn Marino       tree arg;
696*e4b17023SJohn Marino       inp_domain domain = get_no_error_domain (fnc);
697*e4b17023SJohn Marino       *nconds = 0;
698*e4b17023SJohn Marino       arg = gimple_call_arg (bi_call, 0);
699*e4b17023SJohn Marino       gen_conditions_for_domain (arg, domain, conds, nconds);
700*e4b17023SJohn Marino     }
701*e4b17023SJohn Marino 
702*e4b17023SJohn Marino   return;
703*e4b17023SJohn Marino }
704*e4b17023SJohn Marino 
705*e4b17023SJohn Marino 
706*e4b17023SJohn Marino /* Probability of the branch (to the call) is taken.  */
707*e4b17023SJohn Marino #define ERR_PROB 0.01
708*e4b17023SJohn Marino 
709*e4b17023SJohn Marino /* The function to shrink wrap a partially dead builtin call
710*e4b17023SJohn Marino    whose return value is not used anywhere, but has to be kept
711*e4b17023SJohn Marino    live due to potential error condition.  Returns true if the
712*e4b17023SJohn Marino    transformation actually happens.  */
713*e4b17023SJohn Marino 
714*e4b17023SJohn Marino static bool
shrink_wrap_one_built_in_call(gimple bi_call)715*e4b17023SJohn Marino shrink_wrap_one_built_in_call (gimple bi_call)
716*e4b17023SJohn Marino {
717*e4b17023SJohn Marino   gimple_stmt_iterator bi_call_bsi;
718*e4b17023SJohn Marino   basic_block bi_call_bb, join_tgt_bb, guard_bb, guard_bb0;
719*e4b17023SJohn Marino   edge join_tgt_in_edge_from_call, join_tgt_in_edge_fall_thru;
720*e4b17023SJohn Marino   edge bi_call_in_edge0, guard_bb_in_edge;
721*e4b17023SJohn Marino   VEC (gimple, heap) *conds;
722*e4b17023SJohn Marino   unsigned tn_cond_stmts, nconds;
723*e4b17023SJohn Marino   unsigned ci;
724*e4b17023SJohn Marino   gimple cond_expr = NULL;
725*e4b17023SJohn Marino   gimple cond_expr_start;
726*e4b17023SJohn Marino   tree bi_call_label_decl;
727*e4b17023SJohn Marino   gimple bi_call_label;
728*e4b17023SJohn Marino 
729*e4b17023SJohn Marino   conds = VEC_alloc (gimple, heap, 12);
730*e4b17023SJohn Marino   gen_shrink_wrap_conditions (bi_call, conds, &nconds);
731*e4b17023SJohn Marino 
732*e4b17023SJohn Marino   /* This can happen if the condition generator decides
733*e4b17023SJohn Marino      it is not beneficial to do the transformation.  Just
734*e4b17023SJohn Marino      return false and do not do any transformation for
735*e4b17023SJohn Marino      the call.  */
736*e4b17023SJohn Marino   if (nconds == 0)
737*e4b17023SJohn Marino     return false;
738*e4b17023SJohn Marino 
739*e4b17023SJohn Marino   bi_call_bb = gimple_bb (bi_call);
740*e4b17023SJohn Marino 
741*e4b17023SJohn Marino   /* Now find the join target bb -- split
742*e4b17023SJohn Marino      bi_call_bb if needed.  */
743*e4b17023SJohn Marino   bi_call_bsi = gsi_for_stmt (bi_call);
744*e4b17023SJohn Marino 
745*e4b17023SJohn Marino   join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
746*e4b17023SJohn Marino   bi_call_bsi = gsi_for_stmt (bi_call);
747*e4b17023SJohn Marino 
748*e4b17023SJohn Marino   join_tgt_bb = join_tgt_in_edge_from_call->dest;
749*e4b17023SJohn Marino 
750*e4b17023SJohn Marino   /* Now it is time to insert the first conditional expression
751*e4b17023SJohn Marino      into bi_call_bb and split this bb so that bi_call is
752*e4b17023SJohn Marino      shrink-wrapped.  */
753*e4b17023SJohn Marino   tn_cond_stmts = VEC_length (gimple, conds);
754*e4b17023SJohn Marino   cond_expr = NULL;
755*e4b17023SJohn Marino   cond_expr_start = VEC_index (gimple, conds, 0);
756*e4b17023SJohn Marino   for (ci = 0; ci < tn_cond_stmts; ci++)
757*e4b17023SJohn Marino     {
758*e4b17023SJohn Marino       gimple c = VEC_index (gimple, conds, ci);
759*e4b17023SJohn Marino       gcc_assert (c || ci != 0);
760*e4b17023SJohn Marino       if (!c)
761*e4b17023SJohn Marino         break;
762*e4b17023SJohn Marino       gsi_insert_before (&bi_call_bsi, c, GSI_SAME_STMT);
763*e4b17023SJohn Marino       cond_expr = c;
764*e4b17023SJohn Marino     }
765*e4b17023SJohn Marino   nconds--;
766*e4b17023SJohn Marino   ci++;
767*e4b17023SJohn Marino   gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);
768*e4b17023SJohn Marino 
769*e4b17023SJohn Marino   /* Now the label.  */
770*e4b17023SJohn Marino   bi_call_label_decl = create_artificial_label (gimple_location (bi_call));
771*e4b17023SJohn Marino   bi_call_label = gimple_build_label (bi_call_label_decl);
772*e4b17023SJohn Marino   gsi_insert_before (&bi_call_bsi, bi_call_label, GSI_SAME_STMT);
773*e4b17023SJohn Marino 
774*e4b17023SJohn Marino   bi_call_in_edge0 = split_block (bi_call_bb, cond_expr);
775*e4b17023SJohn Marino   bi_call_in_edge0->flags &= ~EDGE_FALLTHRU;
776*e4b17023SJohn Marino   bi_call_in_edge0->flags |= EDGE_TRUE_VALUE;
777*e4b17023SJohn Marino   guard_bb0 = bi_call_bb;
778*e4b17023SJohn Marino   bi_call_bb = bi_call_in_edge0->dest;
779*e4b17023SJohn Marino   join_tgt_in_edge_fall_thru = make_edge (guard_bb0, join_tgt_bb,
780*e4b17023SJohn Marino                                           EDGE_FALSE_VALUE);
781*e4b17023SJohn Marino 
782*e4b17023SJohn Marino   bi_call_in_edge0->probability = REG_BR_PROB_BASE * ERR_PROB;
783*e4b17023SJohn Marino   join_tgt_in_edge_fall_thru->probability =
784*e4b17023SJohn Marino       REG_BR_PROB_BASE - bi_call_in_edge0->probability;
785*e4b17023SJohn Marino 
786*e4b17023SJohn Marino   /* Code generation for the rest of the conditions  */
787*e4b17023SJohn Marino   guard_bb = guard_bb0;
788*e4b17023SJohn Marino   while (nconds > 0)
789*e4b17023SJohn Marino     {
790*e4b17023SJohn Marino       unsigned ci0;
791*e4b17023SJohn Marino       edge bi_call_in_edge;
792*e4b17023SJohn Marino       gimple_stmt_iterator guard_bsi = gsi_for_stmt (cond_expr_start);
793*e4b17023SJohn Marino       ci0 = ci;
794*e4b17023SJohn Marino       cond_expr_start = VEC_index (gimple, conds, ci0);
795*e4b17023SJohn Marino       for (; ci < tn_cond_stmts; ci++)
796*e4b17023SJohn Marino         {
797*e4b17023SJohn Marino           gimple c = VEC_index (gimple, conds, ci);
798*e4b17023SJohn Marino           gcc_assert (c || ci != ci0);
799*e4b17023SJohn Marino           if (!c)
800*e4b17023SJohn Marino             break;
801*e4b17023SJohn Marino           gsi_insert_before (&guard_bsi, c, GSI_SAME_STMT);
802*e4b17023SJohn Marino           cond_expr = c;
803*e4b17023SJohn Marino         }
804*e4b17023SJohn Marino       nconds--;
805*e4b17023SJohn Marino       ci++;
806*e4b17023SJohn Marino       gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);
807*e4b17023SJohn Marino       guard_bb_in_edge = split_block (guard_bb, cond_expr);
808*e4b17023SJohn Marino       guard_bb_in_edge->flags &= ~EDGE_FALLTHRU;
809*e4b17023SJohn Marino       guard_bb_in_edge->flags |= EDGE_FALSE_VALUE;
810*e4b17023SJohn Marino 
811*e4b17023SJohn Marino       bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_TRUE_VALUE);
812*e4b17023SJohn Marino 
813*e4b17023SJohn Marino       bi_call_in_edge->probability = REG_BR_PROB_BASE * ERR_PROB;
814*e4b17023SJohn Marino       guard_bb_in_edge->probability =
815*e4b17023SJohn Marino           REG_BR_PROB_BASE - bi_call_in_edge->probability;
816*e4b17023SJohn Marino     }
817*e4b17023SJohn Marino 
818*e4b17023SJohn Marino   VEC_free (gimple, heap, conds);
819*e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
820*e4b17023SJohn Marino     {
821*e4b17023SJohn Marino       location_t loc;
822*e4b17023SJohn Marino       loc = gimple_location (bi_call);
823*e4b17023SJohn Marino       fprintf (dump_file,
824*e4b17023SJohn Marino                "%s:%d: note: function call is shrink-wrapped"
825*e4b17023SJohn Marino                " into error conditions.\n",
826*e4b17023SJohn Marino                LOCATION_FILE (loc), LOCATION_LINE (loc));
827*e4b17023SJohn Marino     }
828*e4b17023SJohn Marino 
829*e4b17023SJohn Marino   return true;
830*e4b17023SJohn Marino }
831*e4b17023SJohn Marino 
832*e4b17023SJohn Marino /* The top level function for conditional dead code shrink
833*e4b17023SJohn Marino    wrapping transformation.  */
834*e4b17023SJohn Marino 
835*e4b17023SJohn Marino static bool
shrink_wrap_conditional_dead_built_in_calls(VEC (gimple,heap)* calls)836*e4b17023SJohn Marino shrink_wrap_conditional_dead_built_in_calls (VEC (gimple, heap) *calls)
837*e4b17023SJohn Marino {
838*e4b17023SJohn Marino   bool changed = false;
839*e4b17023SJohn Marino   unsigned i = 0;
840*e4b17023SJohn Marino 
841*e4b17023SJohn Marino   unsigned n = VEC_length (gimple, calls);
842*e4b17023SJohn Marino   if (n == 0)
843*e4b17023SJohn Marino     return false;
844*e4b17023SJohn Marino 
845*e4b17023SJohn Marino   for (; i < n ; i++)
846*e4b17023SJohn Marino     {
847*e4b17023SJohn Marino       gimple bi_call = VEC_index (gimple, calls, i);
848*e4b17023SJohn Marino       changed |= shrink_wrap_one_built_in_call (bi_call);
849*e4b17023SJohn Marino     }
850*e4b17023SJohn Marino 
851*e4b17023SJohn Marino   return changed;
852*e4b17023SJohn Marino }
853*e4b17023SJohn Marino 
854*e4b17023SJohn Marino /* Pass entry points.  */
855*e4b17023SJohn Marino 
856*e4b17023SJohn Marino static unsigned int
tree_call_cdce(void)857*e4b17023SJohn Marino tree_call_cdce (void)
858*e4b17023SJohn Marino {
859*e4b17023SJohn Marino   basic_block bb;
860*e4b17023SJohn Marino   gimple_stmt_iterator i;
861*e4b17023SJohn Marino   bool something_changed = false;
862*e4b17023SJohn Marino   VEC (gimple, heap) *cond_dead_built_in_calls = NULL;
863*e4b17023SJohn Marino   FOR_EACH_BB (bb)
864*e4b17023SJohn Marino     {
865*e4b17023SJohn Marino       /* Collect dead call candidates.  */
866*e4b17023SJohn Marino       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
867*e4b17023SJohn Marino         {
868*e4b17023SJohn Marino 	  gimple stmt = gsi_stmt (i);
869*e4b17023SJohn Marino           if (is_gimple_call (stmt)
870*e4b17023SJohn Marino               && is_call_dce_candidate (stmt))
871*e4b17023SJohn Marino             {
872*e4b17023SJohn Marino               if (dump_file && (dump_flags & TDF_DETAILS))
873*e4b17023SJohn Marino                 {
874*e4b17023SJohn Marino                   fprintf (dump_file, "Found conditional dead call: ");
875*e4b17023SJohn Marino                   print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
876*e4b17023SJohn Marino                   fprintf (dump_file, "\n");
877*e4b17023SJohn Marino                 }
878*e4b17023SJohn Marino 	      if (cond_dead_built_in_calls == NULL)
879*e4b17023SJohn Marino 		cond_dead_built_in_calls = VEC_alloc (gimple, heap, 64);
880*e4b17023SJohn Marino 	      VEC_safe_push (gimple, heap, cond_dead_built_in_calls, stmt);
881*e4b17023SJohn Marino             }
882*e4b17023SJohn Marino 	}
883*e4b17023SJohn Marino     }
884*e4b17023SJohn Marino 
885*e4b17023SJohn Marino   if (cond_dead_built_in_calls == NULL)
886*e4b17023SJohn Marino     return 0;
887*e4b17023SJohn Marino 
888*e4b17023SJohn Marino   something_changed
889*e4b17023SJohn Marino     = shrink_wrap_conditional_dead_built_in_calls (cond_dead_built_in_calls);
890*e4b17023SJohn Marino 
891*e4b17023SJohn Marino   VEC_free (gimple, heap, cond_dead_built_in_calls);
892*e4b17023SJohn Marino 
893*e4b17023SJohn Marino   if (something_changed)
894*e4b17023SJohn Marino     {
895*e4b17023SJohn Marino       free_dominance_info (CDI_DOMINATORS);
896*e4b17023SJohn Marino       free_dominance_info (CDI_POST_DOMINATORS);
897*e4b17023SJohn Marino       /* As we introduced new control-flow we need to insert PHI-nodes
898*e4b17023SJohn Marino          for the call-clobbers of the remaining call.  */
899*e4b17023SJohn Marino       mark_sym_for_renaming (gimple_vop (cfun));
900*e4b17023SJohn Marino       return (TODO_update_ssa | TODO_cleanup_cfg | TODO_ggc_collect
901*e4b17023SJohn Marino               | TODO_remove_unused_locals);
902*e4b17023SJohn Marino     }
903*e4b17023SJohn Marino   else
904*e4b17023SJohn Marino     return 0;
905*e4b17023SJohn Marino }
906*e4b17023SJohn Marino 
907*e4b17023SJohn Marino static bool
gate_call_cdce(void)908*e4b17023SJohn Marino gate_call_cdce (void)
909*e4b17023SJohn Marino {
910*e4b17023SJohn Marino   /* The limit constants used in the implementation
911*e4b17023SJohn Marino      assume IEEE floating point format.  Other formats
912*e4b17023SJohn Marino      can be supported in the future if needed.  */
913*e4b17023SJohn Marino   return flag_tree_builtin_call_dce != 0 && optimize_function_for_speed_p (cfun);
914*e4b17023SJohn Marino }
915*e4b17023SJohn Marino 
916*e4b17023SJohn Marino struct gimple_opt_pass pass_call_cdce =
917*e4b17023SJohn Marino {
918*e4b17023SJohn Marino  {
919*e4b17023SJohn Marino   GIMPLE_PASS,
920*e4b17023SJohn Marino   "cdce",                               /* name */
921*e4b17023SJohn Marino   gate_call_cdce,                       /* gate */
922*e4b17023SJohn Marino   tree_call_cdce,                       /* execute */
923*e4b17023SJohn Marino   NULL,                                 /* sub */
924*e4b17023SJohn Marino   NULL,                                 /* next */
925*e4b17023SJohn Marino   0,                                    /* static_pass_number */
926*e4b17023SJohn Marino   TV_TREE_CALL_CDCE,                    /* tv_id */
927*e4b17023SJohn Marino   PROP_cfg | PROP_ssa,                  /* properties_required */
928*e4b17023SJohn Marino   0,                                    /* properties_provided */
929*e4b17023SJohn Marino   0,                                    /* properties_destroyed */
930*e4b17023SJohn Marino   0,                                    /* todo_flags_start */
931*e4b17023SJohn Marino   TODO_verify_ssa                       /* todo_flags_finish */
932*e4b17023SJohn Marino  }
933*e4b17023SJohn Marino };
934