xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/analyzer/program-point.cc (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Classes for representing locations within the program.
2*4c3eb207Smrg    Copyright (C) 2019-2020 Free Software Foundation, Inc.
3*4c3eb207Smrg    Contributed by David Malcolm <dmalcolm@redhat.com>.
4*4c3eb207Smrg 
5*4c3eb207Smrg This file is part of GCC.
6*4c3eb207Smrg 
7*4c3eb207Smrg GCC is free software; you can redistribute it and/or modify it
8*4c3eb207Smrg under the terms of the GNU General Public License as published by
9*4c3eb207Smrg the Free Software Foundation; either version 3, or (at your option)
10*4c3eb207Smrg any later version.
11*4c3eb207Smrg 
12*4c3eb207Smrg GCC is distributed in the hope that it will be useful, but
13*4c3eb207Smrg WITHOUT ANY WARRANTY; without even the implied warranty of
14*4c3eb207Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*4c3eb207Smrg General Public License for more details.
16*4c3eb207Smrg 
17*4c3eb207Smrg You should have received a copy of the GNU General Public License
18*4c3eb207Smrg along with GCC; see the file COPYING3.  If not see
19*4c3eb207Smrg <http://www.gnu.org/licenses/>.  */
20*4c3eb207Smrg 
21*4c3eb207Smrg #include "config.h"
22*4c3eb207Smrg #include "system.h"
23*4c3eb207Smrg #include "coretypes.h"
24*4c3eb207Smrg #include "tree.h"
25*4c3eb207Smrg #include "gimple-pretty-print.h"
26*4c3eb207Smrg #include "gcc-rich-location.h"
27*4c3eb207Smrg #include "analyzer/call-string.h"
28*4c3eb207Smrg #include "ordered-hash-map.h"
29*4c3eb207Smrg #include "options.h"
30*4c3eb207Smrg #include "cgraph.h"
31*4c3eb207Smrg #include "function.h"
32*4c3eb207Smrg #include "cfg.h"
33*4c3eb207Smrg #include "basic-block.h"
34*4c3eb207Smrg #include "gimple.h"
35*4c3eb207Smrg #include "gimple-iterator.h"
36*4c3eb207Smrg #include "digraph.h"
37*4c3eb207Smrg #include "analyzer/analyzer.h"
38*4c3eb207Smrg #include "analyzer/analyzer-logging.h"
39*4c3eb207Smrg #include "analyzer/supergraph.h"
40*4c3eb207Smrg #include "analyzer/program-point.h"
41*4c3eb207Smrg #include "sbitmap.h"
42*4c3eb207Smrg #include "bitmap.h"
43*4c3eb207Smrg #include "tristate.h"
44*4c3eb207Smrg #include "selftest.h"
45*4c3eb207Smrg #include "analyzer/region-model.h"
46*4c3eb207Smrg #include "analyzer/sm.h"
47*4c3eb207Smrg #include "analyzer/program-state.h"
48*4c3eb207Smrg #include "alloc-pool.h"
49*4c3eb207Smrg #include "fibonacci_heap.h"
50*4c3eb207Smrg #include "diagnostic-event-id.h"
51*4c3eb207Smrg #include "analyzer/pending-diagnostic.h"
52*4c3eb207Smrg #include "analyzer/diagnostic-manager.h"
53*4c3eb207Smrg #include "shortest-paths.h"
54*4c3eb207Smrg #include "analyzer/exploded-graph.h"
55*4c3eb207Smrg #include "analyzer/analysis-plan.h"
56*4c3eb207Smrg 
57*4c3eb207Smrg #if ENABLE_ANALYZER
58*4c3eb207Smrg 
59*4c3eb207Smrg namespace ana {
60*4c3eb207Smrg 
61*4c3eb207Smrg /* Get a string for PK.  */
62*4c3eb207Smrg 
63*4c3eb207Smrg const char *
point_kind_to_string(enum point_kind pk)64*4c3eb207Smrg point_kind_to_string (enum point_kind pk)
65*4c3eb207Smrg {
66*4c3eb207Smrg   switch (pk)
67*4c3eb207Smrg     {
68*4c3eb207Smrg     default:
69*4c3eb207Smrg       gcc_unreachable ();
70*4c3eb207Smrg     case PK_ORIGIN:
71*4c3eb207Smrg       return "PK_ORIGIN";
72*4c3eb207Smrg     case PK_BEFORE_SUPERNODE:
73*4c3eb207Smrg       return "PK_BEFORE_SUPERNODE";
74*4c3eb207Smrg     case PK_BEFORE_STMT:
75*4c3eb207Smrg       return "PK_BEFORE_STMT";
76*4c3eb207Smrg     case PK_AFTER_SUPERNODE:
77*4c3eb207Smrg       return "PK_AFTER_SUPERNODE";
78*4c3eb207Smrg     case PK_EMPTY:
79*4c3eb207Smrg       return "PK_EMPTY";
80*4c3eb207Smrg     case PK_DELETED:
81*4c3eb207Smrg       return "PK_DELETED";
82*4c3eb207Smrg     }
83*4c3eb207Smrg }
84*4c3eb207Smrg 
85*4c3eb207Smrg /* class function_point.  */
86*4c3eb207Smrg 
87*4c3eb207Smrg /* Print this function_point to PP.  */
88*4c3eb207Smrg 
89*4c3eb207Smrg void
print(pretty_printer * pp,const format & f) const90*4c3eb207Smrg function_point::print (pretty_printer *pp, const format &f) const
91*4c3eb207Smrg {
92*4c3eb207Smrg   switch (get_kind ())
93*4c3eb207Smrg     {
94*4c3eb207Smrg     default:
95*4c3eb207Smrg       gcc_unreachable ();
96*4c3eb207Smrg 
97*4c3eb207Smrg     case PK_ORIGIN:
98*4c3eb207Smrg       pp_printf (pp, "origin");
99*4c3eb207Smrg       break;
100*4c3eb207Smrg 
101*4c3eb207Smrg     case PK_BEFORE_SUPERNODE:
102*4c3eb207Smrg       {
103*4c3eb207Smrg 	if (m_from_edge)
104*4c3eb207Smrg 	  pp_printf (pp, "before SN: %i (from SN: %i)",
105*4c3eb207Smrg 		     m_supernode->m_index, m_from_edge->m_src->m_index);
106*4c3eb207Smrg 	else
107*4c3eb207Smrg 	  pp_printf (pp, "before SN: %i (NULL from-edge)",
108*4c3eb207Smrg 		     m_supernode->m_index);
109*4c3eb207Smrg 	f.spacer (pp);
110*4c3eb207Smrg 	for (gphi_iterator gpi
111*4c3eb207Smrg 	       = const_cast<supernode *>(get_supernode ())->start_phis ();
112*4c3eb207Smrg 	     !gsi_end_p (gpi); gsi_next (&gpi))
113*4c3eb207Smrg 	  {
114*4c3eb207Smrg 	    const gphi *phi = gpi.phi ();
115*4c3eb207Smrg 	    pp_gimple_stmt_1 (pp, phi, 0, (dump_flags_t)0);
116*4c3eb207Smrg 	  }
117*4c3eb207Smrg       }
118*4c3eb207Smrg       break;
119*4c3eb207Smrg 
120*4c3eb207Smrg     case PK_BEFORE_STMT:
121*4c3eb207Smrg       pp_printf (pp, "before (SN: %i stmt: %i): ", m_supernode->m_index,
122*4c3eb207Smrg 		 m_stmt_idx);
123*4c3eb207Smrg       f.spacer (pp);
124*4c3eb207Smrg       pp_gimple_stmt_1 (pp, get_stmt (), 0, (dump_flags_t)0);
125*4c3eb207Smrg       if (f.m_newlines)
126*4c3eb207Smrg 	{
127*4c3eb207Smrg 	  pp_newline (pp);
128*4c3eb207Smrg 	  print_source_line (pp);
129*4c3eb207Smrg 	}
130*4c3eb207Smrg       break;
131*4c3eb207Smrg 
132*4c3eb207Smrg     case PK_AFTER_SUPERNODE:
133*4c3eb207Smrg       pp_printf (pp, "after SN: %i", m_supernode->m_index);
134*4c3eb207Smrg       break;
135*4c3eb207Smrg     }
136*4c3eb207Smrg }
137*4c3eb207Smrg 
138*4c3eb207Smrg /* Generate a hash value for this function_point.  */
139*4c3eb207Smrg 
140*4c3eb207Smrg hashval_t
hash() const141*4c3eb207Smrg function_point::hash () const
142*4c3eb207Smrg {
143*4c3eb207Smrg   inchash::hash hstate;
144*4c3eb207Smrg   if (m_supernode)
145*4c3eb207Smrg     hstate.add_int (m_supernode->m_index);
146*4c3eb207Smrg   hstate.add_ptr (m_from_edge);
147*4c3eb207Smrg   hstate.add_int (m_stmt_idx);
148*4c3eb207Smrg   hstate.add_int (m_kind);
149*4c3eb207Smrg   return hstate.end ();
150*4c3eb207Smrg }
151*4c3eb207Smrg 
152*4c3eb207Smrg /* Get the gimple stmt for this function_point, if any.  */
153*4c3eb207Smrg 
154*4c3eb207Smrg const gimple *
get_stmt() const155*4c3eb207Smrg function_point::get_stmt () const
156*4c3eb207Smrg {
157*4c3eb207Smrg   if (m_kind == PK_BEFORE_STMT)
158*4c3eb207Smrg     return m_supernode->m_stmts[m_stmt_idx];
159*4c3eb207Smrg   else if (m_kind == PK_AFTER_SUPERNODE)
160*4c3eb207Smrg     return m_supernode->get_last_stmt ();
161*4c3eb207Smrg   else
162*4c3eb207Smrg     return NULL;
163*4c3eb207Smrg }
164*4c3eb207Smrg 
165*4c3eb207Smrg /* Get a location for this function_point, if any.  */
166*4c3eb207Smrg 
167*4c3eb207Smrg location_t
get_location() const168*4c3eb207Smrg function_point::get_location () const
169*4c3eb207Smrg {
170*4c3eb207Smrg   const gimple *stmt = get_stmt ();
171*4c3eb207Smrg   if (stmt)
172*4c3eb207Smrg     return stmt->location;
173*4c3eb207Smrg 
174*4c3eb207Smrg   return UNKNOWN_LOCATION;
175*4c3eb207Smrg }
176*4c3eb207Smrg 
177*4c3eb207Smrg /* A subclass of diagnostic_context for use by
178*4c3eb207Smrg    program_point::print_source_line.  */
179*4c3eb207Smrg 
180*4c3eb207Smrg class debug_diagnostic_context : public diagnostic_context
181*4c3eb207Smrg {
182*4c3eb207Smrg public:
debug_diagnostic_context()183*4c3eb207Smrg   debug_diagnostic_context ()
184*4c3eb207Smrg   {
185*4c3eb207Smrg     diagnostic_initialize (this, 0);
186*4c3eb207Smrg     show_line_numbers_p = true;
187*4c3eb207Smrg     show_caret = true;
188*4c3eb207Smrg   }
~debug_diagnostic_context()189*4c3eb207Smrg   ~debug_diagnostic_context ()
190*4c3eb207Smrg   {
191*4c3eb207Smrg     diagnostic_finish (this);
192*4c3eb207Smrg   }
193*4c3eb207Smrg };
194*4c3eb207Smrg 
195*4c3eb207Smrg /* Print the source line (if any) for this function_point to PP.  */
196*4c3eb207Smrg 
197*4c3eb207Smrg void
print_source_line(pretty_printer * pp) const198*4c3eb207Smrg function_point::print_source_line (pretty_printer *pp) const
199*4c3eb207Smrg {
200*4c3eb207Smrg   const gimple *stmt = get_stmt ();
201*4c3eb207Smrg   if (!stmt)
202*4c3eb207Smrg     return;
203*4c3eb207Smrg   // TODO: monospace font
204*4c3eb207Smrg   debug_diagnostic_context tmp_dc;
205*4c3eb207Smrg   gcc_rich_location richloc (stmt->location);
206*4c3eb207Smrg   diagnostic_show_locus (&tmp_dc, &richloc, DK_ERROR);
207*4c3eb207Smrg   pp_string (pp, pp_formatted_text (tmp_dc.printer));
208*4c3eb207Smrg }
209*4c3eb207Smrg 
210*4c3eb207Smrg /* class program_point.  */
211*4c3eb207Smrg 
212*4c3eb207Smrg /* Print this program_point to PP.  */
213*4c3eb207Smrg 
214*4c3eb207Smrg void
print(pretty_printer * pp,const format & f) const215*4c3eb207Smrg program_point::print (pretty_printer *pp, const format &f) const
216*4c3eb207Smrg {
217*4c3eb207Smrg   pp_string (pp, "callstring: ");
218*4c3eb207Smrg   m_call_string.print (pp);
219*4c3eb207Smrg   f.spacer (pp);
220*4c3eb207Smrg 
221*4c3eb207Smrg   m_function_point.print (pp, f);
222*4c3eb207Smrg }
223*4c3eb207Smrg 
224*4c3eb207Smrg /* Dump this point to stderr.  */
225*4c3eb207Smrg 
226*4c3eb207Smrg DEBUG_FUNCTION void
dump() const227*4c3eb207Smrg program_point::dump () const
228*4c3eb207Smrg {
229*4c3eb207Smrg   pretty_printer pp;
230*4c3eb207Smrg   pp_show_color (&pp) = pp_show_color (global_dc->printer);
231*4c3eb207Smrg   pp.buffer->stream = stderr;
232*4c3eb207Smrg   print (&pp, format (true));
233*4c3eb207Smrg   pp_flush (&pp);
234*4c3eb207Smrg }
235*4c3eb207Smrg 
236*4c3eb207Smrg /* Generate a hash value for this program_point.  */
237*4c3eb207Smrg 
238*4c3eb207Smrg hashval_t
hash() const239*4c3eb207Smrg program_point::hash () const
240*4c3eb207Smrg {
241*4c3eb207Smrg   inchash::hash hstate;
242*4c3eb207Smrg   hstate.merge_hash (m_function_point.hash ());
243*4c3eb207Smrg   hstate.merge_hash (m_call_string.hash ());
244*4c3eb207Smrg   return hstate.end ();
245*4c3eb207Smrg }
246*4c3eb207Smrg 
247*4c3eb207Smrg /* Get the function * at DEPTH within the call stack.  */
248*4c3eb207Smrg 
249*4c3eb207Smrg function *
get_function_at_depth(unsigned depth) const250*4c3eb207Smrg program_point::get_function_at_depth (unsigned depth) const
251*4c3eb207Smrg {
252*4c3eb207Smrg   gcc_assert (depth <= m_call_string.length ());
253*4c3eb207Smrg   if (depth == m_call_string.length ())
254*4c3eb207Smrg     return m_function_point.get_function ();
255*4c3eb207Smrg   else
256*4c3eb207Smrg     return m_call_string[depth]->get_caller_function ();
257*4c3eb207Smrg }
258*4c3eb207Smrg 
259*4c3eb207Smrg /* Assert that this object is sane.  */
260*4c3eb207Smrg 
261*4c3eb207Smrg void
validate() const262*4c3eb207Smrg program_point::validate () const
263*4c3eb207Smrg {
264*4c3eb207Smrg   /* Skip this in a release build.  */
265*4c3eb207Smrg #if !CHECKING_P
266*4c3eb207Smrg   return;
267*4c3eb207Smrg #endif
268*4c3eb207Smrg 
269*4c3eb207Smrg   m_call_string.validate ();
270*4c3eb207Smrg   /* The "callee" of the final entry in the callstring should be the
271*4c3eb207Smrg      function of the m_function_point.  */
272*4c3eb207Smrg   if (m_call_string.length () > 0)
273*4c3eb207Smrg     gcc_assert (m_call_string[m_call_string.length () - 1]->get_callee_function ()
274*4c3eb207Smrg 		== get_function ());
275*4c3eb207Smrg }
276*4c3eb207Smrg 
277*4c3eb207Smrg /* Check to see if SUCC is a valid edge to take (ensuring that we have
278*4c3eb207Smrg    interprocedurally valid paths in the exploded graph, and enforcing
279*4c3eb207Smrg    recursion limits).
280*4c3eb207Smrg 
281*4c3eb207Smrg    Update the call string if SUCC is a call or a return.
282*4c3eb207Smrg 
283*4c3eb207Smrg    Return true if SUCC can be taken, or false otherwise.
284*4c3eb207Smrg 
285*4c3eb207Smrg    This is the "point" half of exploded_node::on_edge.  */
286*4c3eb207Smrg 
287*4c3eb207Smrg bool
on_edge(exploded_graph & eg,const superedge * succ)288*4c3eb207Smrg program_point::on_edge (exploded_graph &eg,
289*4c3eb207Smrg 			const superedge *succ)
290*4c3eb207Smrg {
291*4c3eb207Smrg   logger * const logger = eg.get_logger ();
292*4c3eb207Smrg   LOG_FUNC (logger);
293*4c3eb207Smrg   switch (succ->m_kind)
294*4c3eb207Smrg     {
295*4c3eb207Smrg     case SUPEREDGE_CFG_EDGE:
296*4c3eb207Smrg       {
297*4c3eb207Smrg 	const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (succ);
298*4c3eb207Smrg 
299*4c3eb207Smrg 	/* Reject abnormal edges; we special-case setjmp/longjmp.  */
300*4c3eb207Smrg 	if (cfg_sedge->get_flags () & EDGE_ABNORMAL)
301*4c3eb207Smrg 	  return false;
302*4c3eb207Smrg       }
303*4c3eb207Smrg       break;
304*4c3eb207Smrg 
305*4c3eb207Smrg     case SUPEREDGE_CALL:
306*4c3eb207Smrg       {
307*4c3eb207Smrg 	const call_superedge *call_sedge = as_a <const call_superedge *> (succ);
308*4c3eb207Smrg 
309*4c3eb207Smrg 	if (eg.get_analysis_plan ().use_summary_p (call_sedge->m_cedge))
310*4c3eb207Smrg 	  {
311*4c3eb207Smrg 	    if (logger)
312*4c3eb207Smrg 	      logger->log ("rejecting call edge: using summary instead");
313*4c3eb207Smrg 	    return false;
314*4c3eb207Smrg 	  }
315*4c3eb207Smrg 
316*4c3eb207Smrg 	/* Add the callsite to the call string.  */
317*4c3eb207Smrg 	m_call_string.push_call (eg.get_supergraph (), call_sedge);
318*4c3eb207Smrg 
319*4c3eb207Smrg 	/* Impose a maximum recursion depth and don't analyze paths
320*4c3eb207Smrg 	   that exceed it further.
321*4c3eb207Smrg 	   This is something of a blunt workaround, but it only
322*4c3eb207Smrg 	   applies to recursion (and mutual recursion), not to
323*4c3eb207Smrg 	   general call stacks.  */
324*4c3eb207Smrg 	if (m_call_string.calc_recursion_depth ()
325*4c3eb207Smrg 	    > param_analyzer_max_recursion_depth)
326*4c3eb207Smrg 	  {
327*4c3eb207Smrg 	    if (logger)
328*4c3eb207Smrg 	      logger->log ("rejecting call edge: recursion limit exceeded");
329*4c3eb207Smrg 	    // TODO: issue a sorry for this?
330*4c3eb207Smrg 	    return false;
331*4c3eb207Smrg 	  }
332*4c3eb207Smrg       }
333*4c3eb207Smrg       break;
334*4c3eb207Smrg 
335*4c3eb207Smrg     case SUPEREDGE_RETURN:
336*4c3eb207Smrg       {
337*4c3eb207Smrg 	/* Require that we return to the call site in the call string.  */
338*4c3eb207Smrg 	if (m_call_string.empty_p ())
339*4c3eb207Smrg 	  {
340*4c3eb207Smrg 	    if (logger)
341*4c3eb207Smrg 	      logger->log ("rejecting return edge: empty call string");
342*4c3eb207Smrg 	    return false;
343*4c3eb207Smrg 	  }
344*4c3eb207Smrg 	const return_superedge *top_of_stack = m_call_string.pop ();
345*4c3eb207Smrg 	if (top_of_stack != succ)
346*4c3eb207Smrg 	  {
347*4c3eb207Smrg 	    if (logger)
348*4c3eb207Smrg 	      logger->log ("rejecting return edge: return to wrong callsite");
349*4c3eb207Smrg 	    return false;
350*4c3eb207Smrg 	  }
351*4c3eb207Smrg       }
352*4c3eb207Smrg       break;
353*4c3eb207Smrg 
354*4c3eb207Smrg     case SUPEREDGE_INTRAPROCEDURAL_CALL:
355*4c3eb207Smrg       {
356*4c3eb207Smrg 	const callgraph_superedge *cg_sedge
357*4c3eb207Smrg 	  = as_a <const callgraph_superedge *> (succ);
358*4c3eb207Smrg 	/* Consider turning this edge into a use of an
359*4c3eb207Smrg 	   interprocedural summary.  */
360*4c3eb207Smrg 	if (eg.get_analysis_plan ().use_summary_p (cg_sedge->m_cedge))
361*4c3eb207Smrg 	  {
362*4c3eb207Smrg 	    if (logger)
363*4c3eb207Smrg 	      logger->log ("using function summary for %qE in %qE",
364*4c3eb207Smrg 			   cg_sedge->get_callee_decl (),
365*4c3eb207Smrg 			   cg_sedge->get_caller_decl ());
366*4c3eb207Smrg 	    return true;
367*4c3eb207Smrg 	  }
368*4c3eb207Smrg 	else
369*4c3eb207Smrg 	  {
370*4c3eb207Smrg 	    /* Otherwise, we ignore these edges  */
371*4c3eb207Smrg 	    if (logger)
372*4c3eb207Smrg 	      logger->log ("rejecting interprocedural edge");
373*4c3eb207Smrg 	    return false;
374*4c3eb207Smrg 	  }
375*4c3eb207Smrg       }
376*4c3eb207Smrg     }
377*4c3eb207Smrg 
378*4c3eb207Smrg   return true;
379*4c3eb207Smrg }
380*4c3eb207Smrg 
381*4c3eb207Smrg /* Comparator for program points within the same supernode,
382*4c3eb207Smrg    for implementing worklist::key_t comparison operators.
383*4c3eb207Smrg    Return negative if POINT_A is before POINT_B
384*4c3eb207Smrg    Return positive if POINT_A is after POINT_B
385*4c3eb207Smrg    Return 0 if they are equal.  */
386*4c3eb207Smrg 
387*4c3eb207Smrg int
cmp_within_supernode_1(const function_point & point_a,const function_point & point_b)388*4c3eb207Smrg function_point::cmp_within_supernode_1 (const function_point &point_a,
389*4c3eb207Smrg 					const function_point &point_b)
390*4c3eb207Smrg {
391*4c3eb207Smrg   gcc_assert (point_a.get_supernode () == point_b.get_supernode ());
392*4c3eb207Smrg 
393*4c3eb207Smrg   switch (point_a.m_kind)
394*4c3eb207Smrg     {
395*4c3eb207Smrg     default:
396*4c3eb207Smrg       gcc_unreachable ();
397*4c3eb207Smrg     case PK_BEFORE_SUPERNODE:
398*4c3eb207Smrg       switch (point_b.m_kind)
399*4c3eb207Smrg 	{
400*4c3eb207Smrg 	default:
401*4c3eb207Smrg 	  gcc_unreachable ();
402*4c3eb207Smrg 	case PK_BEFORE_SUPERNODE:
403*4c3eb207Smrg 	  {
404*4c3eb207Smrg 	    int a_src_idx = -1;
405*4c3eb207Smrg 	    int b_src_idx = -1;
406*4c3eb207Smrg 	    if (point_a.m_from_edge)
407*4c3eb207Smrg 	      a_src_idx = point_a.m_from_edge->m_src->m_index;
408*4c3eb207Smrg 	    if (point_b.m_from_edge)
409*4c3eb207Smrg 	      b_src_idx = point_b.m_from_edge->m_src->m_index;
410*4c3eb207Smrg 	    return a_src_idx - b_src_idx;
411*4c3eb207Smrg 	  }
412*4c3eb207Smrg 	  break;
413*4c3eb207Smrg 
414*4c3eb207Smrg 	case PK_BEFORE_STMT:
415*4c3eb207Smrg 	case PK_AFTER_SUPERNODE:
416*4c3eb207Smrg 	  return -1;
417*4c3eb207Smrg 	}
418*4c3eb207Smrg       break;
419*4c3eb207Smrg     case PK_BEFORE_STMT:
420*4c3eb207Smrg       switch (point_b.m_kind)
421*4c3eb207Smrg 	{
422*4c3eb207Smrg 	default:
423*4c3eb207Smrg 	  gcc_unreachable ();
424*4c3eb207Smrg 	case PK_BEFORE_SUPERNODE:
425*4c3eb207Smrg 	  return 1;
426*4c3eb207Smrg 
427*4c3eb207Smrg 	case PK_BEFORE_STMT:
428*4c3eb207Smrg 	  return point_a.m_stmt_idx - point_b.m_stmt_idx;
429*4c3eb207Smrg 
430*4c3eb207Smrg 	case PK_AFTER_SUPERNODE:
431*4c3eb207Smrg 	  return -1;
432*4c3eb207Smrg 	}
433*4c3eb207Smrg       break;
434*4c3eb207Smrg     case PK_AFTER_SUPERNODE:
435*4c3eb207Smrg       switch (point_b.m_kind)
436*4c3eb207Smrg 	{
437*4c3eb207Smrg 	default:
438*4c3eb207Smrg 	  gcc_unreachable ();
439*4c3eb207Smrg 	case PK_BEFORE_SUPERNODE:
440*4c3eb207Smrg 	case PK_BEFORE_STMT:
441*4c3eb207Smrg 	  return 1;
442*4c3eb207Smrg 
443*4c3eb207Smrg 	case PK_AFTER_SUPERNODE:
444*4c3eb207Smrg 	  return 0;
445*4c3eb207Smrg 	}
446*4c3eb207Smrg       break;
447*4c3eb207Smrg     }
448*4c3eb207Smrg }
449*4c3eb207Smrg 
450*4c3eb207Smrg /* Comparator for program points within the same supernode,
451*4c3eb207Smrg    for implementing worklist::key_t comparison operators.
452*4c3eb207Smrg    Return negative if POINT_A is before POINT_B
453*4c3eb207Smrg    Return positive if POINT_A is after POINT_B
454*4c3eb207Smrg    Return 0 if they are equal.  */
455*4c3eb207Smrg 
456*4c3eb207Smrg int
cmp_within_supernode(const function_point & point_a,const function_point & point_b)457*4c3eb207Smrg function_point::cmp_within_supernode (const function_point &point_a,
458*4c3eb207Smrg 				      const function_point &point_b)
459*4c3eb207Smrg {
460*4c3eb207Smrg   int result = cmp_within_supernode_1 (point_a, point_b);
461*4c3eb207Smrg 
462*4c3eb207Smrg   /* Check that the ordering is symmetric  */
463*4c3eb207Smrg #if CHECKING_P
464*4c3eb207Smrg   int reversed = cmp_within_supernode_1 (point_b, point_a);
465*4c3eb207Smrg   gcc_assert (reversed == -result);
466*4c3eb207Smrg #endif
467*4c3eb207Smrg 
468*4c3eb207Smrg   return result;
469*4c3eb207Smrg }
470*4c3eb207Smrg 
471*4c3eb207Smrg #if CHECKING_P
472*4c3eb207Smrg 
473*4c3eb207Smrg namespace selftest {
474*4c3eb207Smrg 
475*4c3eb207Smrg /* Verify that function_point::operator== works as expected.  */
476*4c3eb207Smrg 
477*4c3eb207Smrg static void
test_function_point_equality()478*4c3eb207Smrg test_function_point_equality ()
479*4c3eb207Smrg {
480*4c3eb207Smrg   const supernode *snode = NULL;
481*4c3eb207Smrg 
482*4c3eb207Smrg   function_point a = function_point (snode, NULL, 0,
483*4c3eb207Smrg 				     PK_BEFORE_SUPERNODE);
484*4c3eb207Smrg   function_point b = function_point::before_supernode (snode, NULL);
485*4c3eb207Smrg   ASSERT_EQ (a, b);
486*4c3eb207Smrg }
487*4c3eb207Smrg 
488*4c3eb207Smrg /* Verify that function_point::cmp_within_supernode works as expected.  */
489*4c3eb207Smrg 
490*4c3eb207Smrg static void
test_function_point_ordering()491*4c3eb207Smrg test_function_point_ordering ()
492*4c3eb207Smrg {
493*4c3eb207Smrg   const supernode *snode = NULL;
494*4c3eb207Smrg   const call_string call_string;
495*4c3eb207Smrg 
496*4c3eb207Smrg   /* Populate an array with various points within the same
497*4c3eb207Smrg      snode, in order.  */
498*4c3eb207Smrg   auto_vec<function_point> points;
499*4c3eb207Smrg   points.safe_push (function_point::before_supernode (snode, NULL));
500*4c3eb207Smrg   points.safe_push (function_point::before_stmt (snode, 0));
501*4c3eb207Smrg   points.safe_push (function_point::before_stmt (snode, 1));
502*4c3eb207Smrg   points.safe_push (function_point::after_supernode (snode));
503*4c3eb207Smrg 
504*4c3eb207Smrg   /* Check all pairs.  */
505*4c3eb207Smrg   unsigned i;
506*4c3eb207Smrg   function_point *point_a;
507*4c3eb207Smrg   FOR_EACH_VEC_ELT (points, i, point_a)
508*4c3eb207Smrg     {
509*4c3eb207Smrg       unsigned j;
510*4c3eb207Smrg       function_point *point_b;
511*4c3eb207Smrg       FOR_EACH_VEC_ELT (points, j, point_b)
512*4c3eb207Smrg 	{
513*4c3eb207Smrg 	  int cmp = function_point::cmp_within_supernode (*point_a, *point_b);
514*4c3eb207Smrg 	  if (i == j)
515*4c3eb207Smrg 	    ASSERT_EQ (cmp, 0);
516*4c3eb207Smrg 	  if (i < j)
517*4c3eb207Smrg 	    ASSERT_TRUE (cmp < 0);
518*4c3eb207Smrg 	  if (i > j)
519*4c3eb207Smrg 	    ASSERT_TRUE (cmp > 0);
520*4c3eb207Smrg 	}
521*4c3eb207Smrg     }
522*4c3eb207Smrg }
523*4c3eb207Smrg 
524*4c3eb207Smrg /* Verify that program_point::operator== works as expected.  */
525*4c3eb207Smrg 
526*4c3eb207Smrg static void
test_program_point_equality()527*4c3eb207Smrg test_program_point_equality ()
528*4c3eb207Smrg {
529*4c3eb207Smrg   const supernode *snode = NULL;
530*4c3eb207Smrg 
531*4c3eb207Smrg   const call_string cs;
532*4c3eb207Smrg 
533*4c3eb207Smrg   program_point a = program_point::before_supernode (snode, NULL,
534*4c3eb207Smrg 						     cs);
535*4c3eb207Smrg 
536*4c3eb207Smrg   program_point b = program_point::before_supernode (snode, NULL,
537*4c3eb207Smrg 						     cs);
538*4c3eb207Smrg 
539*4c3eb207Smrg   ASSERT_EQ (a, b);
540*4c3eb207Smrg   // TODO: verify with non-empty callstrings, with different edges
541*4c3eb207Smrg }
542*4c3eb207Smrg 
543*4c3eb207Smrg /* Run all of the selftests within this file.  */
544*4c3eb207Smrg 
545*4c3eb207Smrg void
analyzer_program_point_cc_tests()546*4c3eb207Smrg analyzer_program_point_cc_tests ()
547*4c3eb207Smrg {
548*4c3eb207Smrg   test_function_point_equality ();
549*4c3eb207Smrg   test_function_point_ordering ();
550*4c3eb207Smrg   test_program_point_equality ();
551*4c3eb207Smrg }
552*4c3eb207Smrg 
553*4c3eb207Smrg } // namespace selftest
554*4c3eb207Smrg 
555*4c3eb207Smrg #endif /* CHECKING_P */
556*4c3eb207Smrg 
557*4c3eb207Smrg } // namespace ana
558*4c3eb207Smrg 
559*4c3eb207Smrg #endif /* #if ENABLE_ANALYZER */
560