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 #ifndef GCC_ANALYZER_PROGRAM_POINT_H 22*4c3eb207Smrg #define GCC_ANALYZER_PROGRAM_POINT_H 23*4c3eb207Smrg 24*4c3eb207Smrg namespace ana { 25*4c3eb207Smrg 26*4c3eb207Smrg class exploded_graph; 27*4c3eb207Smrg 28*4c3eb207Smrg /* An enum for distinguishing the various kinds of program_point. */ 29*4c3eb207Smrg 30*4c3eb207Smrg enum point_kind { 31*4c3eb207Smrg /* A "fake" node which has edges to all entrypoints. */ 32*4c3eb207Smrg PK_ORIGIN, 33*4c3eb207Smrg 34*4c3eb207Smrg PK_BEFORE_SUPERNODE, 35*4c3eb207Smrg PK_BEFORE_STMT, 36*4c3eb207Smrg PK_AFTER_SUPERNODE, 37*4c3eb207Smrg 38*4c3eb207Smrg /* Special values used for hash_map: */ 39*4c3eb207Smrg PK_EMPTY, 40*4c3eb207Smrg PK_DELETED, 41*4c3eb207Smrg 42*4c3eb207Smrg NUM_POINT_KINDS 43*4c3eb207Smrg }; 44*4c3eb207Smrg 45*4c3eb207Smrg extern const char *point_kind_to_string (enum point_kind pk); 46*4c3eb207Smrg 47*4c3eb207Smrg class format 48*4c3eb207Smrg { 49*4c3eb207Smrg public: format(bool newlines)50*4c3eb207Smrg format (bool newlines) : m_newlines (newlines) {} 51*4c3eb207Smrg spacer(pretty_printer * pp)52*4c3eb207Smrg void spacer (pretty_printer *pp) const 53*4c3eb207Smrg { 54*4c3eb207Smrg if (m_newlines) 55*4c3eb207Smrg pp_newline (pp); 56*4c3eb207Smrg else 57*4c3eb207Smrg pp_space (pp); 58*4c3eb207Smrg } 59*4c3eb207Smrg 60*4c3eb207Smrg bool m_newlines; 61*4c3eb207Smrg }; 62*4c3eb207Smrg 63*4c3eb207Smrg /* A class for representing a location within the program, without 64*4c3eb207Smrg interprocedural information. 65*4c3eb207Smrg 66*4c3eb207Smrg This represents a fine-grained location within the supergraph (or 67*4c3eb207Smrg within one of its nodes). */ 68*4c3eb207Smrg 69*4c3eb207Smrg class function_point 70*4c3eb207Smrg { 71*4c3eb207Smrg public: function_point(const supernode * supernode,const superedge * from_edge,unsigned stmt_idx,enum point_kind kind)72*4c3eb207Smrg function_point (const supernode *supernode, 73*4c3eb207Smrg const superedge *from_edge, 74*4c3eb207Smrg unsigned stmt_idx, 75*4c3eb207Smrg enum point_kind kind) 76*4c3eb207Smrg : m_supernode (supernode), m_from_edge (from_edge), 77*4c3eb207Smrg m_stmt_idx (stmt_idx), m_kind (kind) 78*4c3eb207Smrg { 79*4c3eb207Smrg if (from_edge) 80*4c3eb207Smrg { 81*4c3eb207Smrg gcc_checking_assert (m_kind == PK_BEFORE_SUPERNODE); 82*4c3eb207Smrg gcc_checking_assert (from_edge->get_kind () == SUPEREDGE_CFG_EDGE); 83*4c3eb207Smrg } 84*4c3eb207Smrg if (stmt_idx) 85*4c3eb207Smrg gcc_checking_assert (m_kind == PK_BEFORE_STMT); 86*4c3eb207Smrg } 87*4c3eb207Smrg 88*4c3eb207Smrg void print (pretty_printer *pp, const format &f) const; 89*4c3eb207Smrg void print_source_line (pretty_printer *pp) const; 90*4c3eb207Smrg void dump () const; 91*4c3eb207Smrg 92*4c3eb207Smrg hashval_t hash () const; 93*4c3eb207Smrg bool operator== (const function_point &other) const 94*4c3eb207Smrg { 95*4c3eb207Smrg return (m_supernode == other.m_supernode 96*4c3eb207Smrg && m_from_edge == other.m_from_edge 97*4c3eb207Smrg && m_stmt_idx == other.m_stmt_idx 98*4c3eb207Smrg && m_kind == other.m_kind); 99*4c3eb207Smrg } 100*4c3eb207Smrg 101*4c3eb207Smrg /* Accessors. */ 102*4c3eb207Smrg get_supernode()103*4c3eb207Smrg const supernode *get_supernode () const { return m_supernode; } get_function()104*4c3eb207Smrg function *get_function () const 105*4c3eb207Smrg { 106*4c3eb207Smrg if (m_supernode) 107*4c3eb207Smrg return m_supernode->m_fun; 108*4c3eb207Smrg else 109*4c3eb207Smrg return NULL; 110*4c3eb207Smrg } 111*4c3eb207Smrg const gimple *get_stmt () const; 112*4c3eb207Smrg location_t get_location () const; get_kind()113*4c3eb207Smrg enum point_kind get_kind () const { return m_kind; } get_from_edge()114*4c3eb207Smrg const superedge *get_from_edge () const 115*4c3eb207Smrg { 116*4c3eb207Smrg return m_from_edge; 117*4c3eb207Smrg } get_stmt_idx()118*4c3eb207Smrg unsigned get_stmt_idx () const 119*4c3eb207Smrg { 120*4c3eb207Smrg gcc_assert (m_kind == PK_BEFORE_STMT); 121*4c3eb207Smrg return m_stmt_idx; 122*4c3eb207Smrg } 123*4c3eb207Smrg 124*4c3eb207Smrg /* Factory functions for making various kinds of program_point. */ 125*4c3eb207Smrg from_function_entry(const supergraph & sg,function * fun)126*4c3eb207Smrg static function_point from_function_entry (const supergraph &sg, 127*4c3eb207Smrg function *fun) 128*4c3eb207Smrg { 129*4c3eb207Smrg return before_supernode (sg.get_node_for_function_entry (fun), 130*4c3eb207Smrg NULL); 131*4c3eb207Smrg } 132*4c3eb207Smrg before_supernode(const supernode * supernode,const superedge * from_edge)133*4c3eb207Smrg static function_point before_supernode (const supernode *supernode, 134*4c3eb207Smrg const superedge *from_edge) 135*4c3eb207Smrg { 136*4c3eb207Smrg if (from_edge && from_edge->get_kind () != SUPEREDGE_CFG_EDGE) 137*4c3eb207Smrg from_edge = NULL; 138*4c3eb207Smrg return function_point (supernode, from_edge, 0, PK_BEFORE_SUPERNODE); 139*4c3eb207Smrg } 140*4c3eb207Smrg before_stmt(const supernode * supernode,unsigned stmt_idx)141*4c3eb207Smrg static function_point before_stmt (const supernode *supernode, 142*4c3eb207Smrg unsigned stmt_idx) 143*4c3eb207Smrg { 144*4c3eb207Smrg return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); 145*4c3eb207Smrg } 146*4c3eb207Smrg after_supernode(const supernode * supernode)147*4c3eb207Smrg static function_point after_supernode (const supernode *supernode) 148*4c3eb207Smrg { 149*4c3eb207Smrg return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); 150*4c3eb207Smrg } 151*4c3eb207Smrg 152*4c3eb207Smrg /* Support for hash_map. */ 153*4c3eb207Smrg empty()154*4c3eb207Smrg static function_point empty () 155*4c3eb207Smrg { 156*4c3eb207Smrg return function_point (NULL, NULL, 0, PK_EMPTY); 157*4c3eb207Smrg } deleted()158*4c3eb207Smrg static function_point deleted () 159*4c3eb207Smrg { 160*4c3eb207Smrg return function_point (NULL, NULL, 0, PK_DELETED); 161*4c3eb207Smrg } 162*4c3eb207Smrg 163*4c3eb207Smrg static int cmp_within_supernode_1 (const function_point &point_a, 164*4c3eb207Smrg const function_point &point_b); 165*4c3eb207Smrg static int cmp_within_supernode (const function_point &point_a, 166*4c3eb207Smrg const function_point &point_b); 167*4c3eb207Smrg 168*4c3eb207Smrg private: 169*4c3eb207Smrg const supernode *m_supernode; 170*4c3eb207Smrg 171*4c3eb207Smrg /* For PK_BEFORE_SUPERNODE, and only for CFG edges. */ 172*4c3eb207Smrg const superedge *m_from_edge; 173*4c3eb207Smrg 174*4c3eb207Smrg /* Only for PK_BEFORE_STMT. */ 175*4c3eb207Smrg unsigned m_stmt_idx; 176*4c3eb207Smrg 177*4c3eb207Smrg enum point_kind m_kind; 178*4c3eb207Smrg }; 179*4c3eb207Smrg 180*4c3eb207Smrg /* A class for representing a location within the program, including 181*4c3eb207Smrg interprocedural information. 182*4c3eb207Smrg 183*4c3eb207Smrg This represents a fine-grained location within the supergraph (or 184*4c3eb207Smrg within one of its nodes), along with a call string giving the 185*4c3eb207Smrg interprocedural context. */ 186*4c3eb207Smrg 187*4c3eb207Smrg class program_point 188*4c3eb207Smrg { 189*4c3eb207Smrg public: program_point(const function_point & fn_point,const call_string & call_string)190*4c3eb207Smrg program_point (const function_point &fn_point, 191*4c3eb207Smrg const call_string &call_string) 192*4c3eb207Smrg : m_function_point (fn_point), 193*4c3eb207Smrg m_call_string (call_string) 194*4c3eb207Smrg { 195*4c3eb207Smrg } 196*4c3eb207Smrg 197*4c3eb207Smrg void print (pretty_printer *pp, const format &f) const; 198*4c3eb207Smrg void print_source_line (pretty_printer *pp) const; 199*4c3eb207Smrg void dump () const; 200*4c3eb207Smrg 201*4c3eb207Smrg hashval_t hash () const; 202*4c3eb207Smrg bool operator== (const program_point &other) const 203*4c3eb207Smrg { 204*4c3eb207Smrg return (m_function_point == other.m_function_point 205*4c3eb207Smrg && m_call_string == other.m_call_string); 206*4c3eb207Smrg } 207*4c3eb207Smrg 208*4c3eb207Smrg /* Accessors. */ 209*4c3eb207Smrg get_function_point()210*4c3eb207Smrg const function_point &get_function_point () const { return m_function_point; } get_call_string()211*4c3eb207Smrg const call_string &get_call_string () const { return m_call_string; } 212*4c3eb207Smrg get_supernode()213*4c3eb207Smrg const supernode *get_supernode () const 214*4c3eb207Smrg { 215*4c3eb207Smrg return m_function_point.get_supernode (); 216*4c3eb207Smrg } get_function()217*4c3eb207Smrg function *get_function () const 218*4c3eb207Smrg { 219*4c3eb207Smrg return m_function_point.get_function (); 220*4c3eb207Smrg } 221*4c3eb207Smrg function *get_function_at_depth (unsigned depth) const; get_fndecl()222*4c3eb207Smrg tree get_fndecl () const 223*4c3eb207Smrg { 224*4c3eb207Smrg gcc_assert (get_kind () != PK_ORIGIN); 225*4c3eb207Smrg return get_function ()->decl; 226*4c3eb207Smrg } get_stmt()227*4c3eb207Smrg const gimple *get_stmt () const 228*4c3eb207Smrg { 229*4c3eb207Smrg return m_function_point.get_stmt (); 230*4c3eb207Smrg } get_location()231*4c3eb207Smrg location_t get_location () const 232*4c3eb207Smrg { 233*4c3eb207Smrg return m_function_point.get_location (); 234*4c3eb207Smrg } get_kind()235*4c3eb207Smrg enum point_kind get_kind () const 236*4c3eb207Smrg { 237*4c3eb207Smrg return m_function_point.get_kind (); 238*4c3eb207Smrg } get_from_edge()239*4c3eb207Smrg const superedge *get_from_edge () const 240*4c3eb207Smrg { 241*4c3eb207Smrg return m_function_point.get_from_edge (); 242*4c3eb207Smrg } get_stmt_idx()243*4c3eb207Smrg unsigned get_stmt_idx () const 244*4c3eb207Smrg { 245*4c3eb207Smrg return m_function_point.get_stmt_idx (); 246*4c3eb207Smrg } 247*4c3eb207Smrg 248*4c3eb207Smrg /* Get the number of frames we expect at this program point. 249*4c3eb207Smrg This will be one more than the length of the call_string 250*4c3eb207Smrg (which stores the parent callsites), apart from the origin 251*4c3eb207Smrg node, which doesn't have any frames. */ get_stack_depth()252*4c3eb207Smrg int get_stack_depth () const 253*4c3eb207Smrg { 254*4c3eb207Smrg if (get_kind () == PK_ORIGIN) 255*4c3eb207Smrg return 0; 256*4c3eb207Smrg return m_call_string.length () + 1; 257*4c3eb207Smrg } 258*4c3eb207Smrg 259*4c3eb207Smrg /* Factory functions for making various kinds of program_point. */ 260*4c3eb207Smrg from_function_entry(const supergraph & sg,function * fun)261*4c3eb207Smrg static program_point from_function_entry (const supergraph &sg, 262*4c3eb207Smrg function *fun) 263*4c3eb207Smrg { 264*4c3eb207Smrg return program_point (function_point::from_function_entry (sg, fun), 265*4c3eb207Smrg call_string ()); 266*4c3eb207Smrg } 267*4c3eb207Smrg before_supernode(const supernode * supernode,const superedge * from_edge,const call_string & call_string)268*4c3eb207Smrg static program_point before_supernode (const supernode *supernode, 269*4c3eb207Smrg const superedge *from_edge, 270*4c3eb207Smrg const call_string &call_string) 271*4c3eb207Smrg { 272*4c3eb207Smrg return program_point (function_point::before_supernode (supernode, 273*4c3eb207Smrg from_edge), 274*4c3eb207Smrg call_string); 275*4c3eb207Smrg } 276*4c3eb207Smrg before_stmt(const supernode * supernode,unsigned stmt_idx,const call_string & call_string)277*4c3eb207Smrg static program_point before_stmt (const supernode *supernode, 278*4c3eb207Smrg unsigned stmt_idx, 279*4c3eb207Smrg const call_string &call_string) 280*4c3eb207Smrg { 281*4c3eb207Smrg return program_point (function_point::before_stmt (supernode, stmt_idx), 282*4c3eb207Smrg call_string); 283*4c3eb207Smrg } 284*4c3eb207Smrg after_supernode(const supernode * supernode,const call_string & call_string)285*4c3eb207Smrg static program_point after_supernode (const supernode *supernode, 286*4c3eb207Smrg const call_string &call_string) 287*4c3eb207Smrg { 288*4c3eb207Smrg return program_point (function_point::after_supernode (supernode), 289*4c3eb207Smrg call_string); 290*4c3eb207Smrg } 291*4c3eb207Smrg 292*4c3eb207Smrg /* Support for hash_map. */ 293*4c3eb207Smrg empty()294*4c3eb207Smrg static program_point empty () 295*4c3eb207Smrg { 296*4c3eb207Smrg return program_point (function_point::empty (), call_string ()); 297*4c3eb207Smrg } deleted()298*4c3eb207Smrg static program_point deleted () 299*4c3eb207Smrg { 300*4c3eb207Smrg return program_point (function_point::deleted (), call_string ()); 301*4c3eb207Smrg } 302*4c3eb207Smrg 303*4c3eb207Smrg bool on_edge (exploded_graph &eg, const superedge *succ); 304*4c3eb207Smrg 305*4c3eb207Smrg void validate () const; 306*4c3eb207Smrg 307*4c3eb207Smrg private: 308*4c3eb207Smrg const function_point m_function_point; 309*4c3eb207Smrg call_string m_call_string; 310*4c3eb207Smrg }; 311*4c3eb207Smrg 312*4c3eb207Smrg } // namespace ana 313*4c3eb207Smrg 314*4c3eb207Smrg #endif /* GCC_ANALYZER_PROGRAM_POINT_H */ 315