/* Header file for gimple range phi analysis.
   Copyright (C) 2023-2024 Free Software Foundation, Inc.
   Contributed by Andrew MacLeod <amacleod@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#ifndef GCC_SSA_RANGE_PHI_H
#define GCC_SSA_RANGE_PHI_H

// -------------------------------------------------------------------------

// A PHI_GROUP consists of a set of SSA_NAMES which are all PHI_DEFS, and
// their arguemnts contain nothing but other PHI defintions, with at most
// 2 exceptions:
//  1 - An initial value.  This is either a constant, or another non-phi name
//      with a single incoming edge to the cycle group
//  2 - A modifier statement which adjusts the value.  ie, name2 = phi_name + 1
//  The initial range is used to create one bound and the modifier is examined
//  to determine the other bound.
//  All members of the PHI cycle will be given the same range.
//
// For example, given the follwoing sequences:
// qa_20 = qa_10 + 1;
// qa_9 = PHI <qa_10(3), qa_20(4)>
// qa_10 = PHI <0(2), qa_9(5)>
//
// We can determine the following group:
//
// PHI cycle members qa_9, qa_10
// Initial value : 0
// modifier stmt: qa_20 = qa_10 + 1;
// 
// Based on just this analysis, We can project that qa_9 and qa_10 will have
// a range of [0, +INF].

class phi_group
{
public:
  phi_group (bitmap bm, irange &init_range, gimple *mod, range_query *q);
  phi_group (const phi_group &g);
  const_bitmap group () const { return m_group; }
  const vrange &range () const { return m_vr; }
  gimple *modifier_stmt () const { return m_modifier; }
  void dump (FILE *);
protected:
  bool calculate_using_modifier (range_query *q);
  bool refine_using_relation (relation_kind k);
  static unsigned is_modifier_p (gimple *s, const bitmap bm);
  bitmap m_group;
  gimple *m_modifier;     // Single stmt which modifies phi group.
  unsigned m_modifier_op; // Operand of group member in modifier stmt.
  int_range_max m_vr;
  friend class phi_analyzer;
};

// The phi anlyzer will return the group that name belongs to.
// If inforamtion is not known about a name yet, analysis is conducted by
// looking at the arguments to PHIS and following them to their defs to
// determine whether the conditions are met to form a new group.

class phi_analyzer
{
public:
  phi_analyzer (range_query &);
  ~phi_analyzer ();
  phi_group *operator[] (tree name);
  void dump (FILE *f);
protected:
  phi_group *group (tree name) const;
  void process_phi (gphi *phi);
  range_query &m_global;
  vec<tree> m_work;

  bitmap m_simple;       // Processed, not part of a group.
  bitmap m_current;	 // Potential group currently being analyzed.
  vec<phi_group *> m_phi_groups;
  vec<phi_group *> m_tab;
  bitmap_obstack m_bitmaps;
};

// These are the APIs to start and stop a phi analyzerin a SCEV like manner.
// There can only be one operating at any given time.
// When initialized, a range-query if provided to do lookups of values for
// PHIs and to evaluate modifier and initial value statements.
// To avoid problems, this should be some form of constant query, like
// global_range_query or better yet a const_query from a functioning ranger.

bool phi_analysis_available_p ();
phi_analyzer &phi_analysis ();
void phi_analysis_initialize (range_query &);
void phi_analysis_finalize ();

#endif // GCC_SSA_RANGE_PHI_H
