/*
 * Copyright 2006.  QLogic Corporation.  All Rights Reserved.
 */

/*
 * Copyright 2002, 2003, 2004, 2005, 2006 PathScale, Inc.  All Rights Reserved.
 */

/*

  Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.

   Path64 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 2, or (at your option)
   any later version.

   Path64 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 Path64; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

   Special thanks goes to SGI for their continued support to open source

*/

//  GRA tracing
/////////////////////////////////////
//
//  Description:
//
//      Support for tracing GRA
//
//
/////////////////////////////////////


//  $Revision: 1.5 $
//  $Date: 04/12/21 14:57:08-08:00 $
//  $Author: bos@eng-25.internal.keyresearch.com $
//  $Source: /home/bos/bk/kpro64-pending/be/cg/gra_mon/SCCS/s.gra_trace.cxx $

#ifdef USE_PCH
#include "cg_pch.h"
#endif // USE_PCH
#pragma hdrstop

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include "defs.h"
#include "tracing.h"
#include "cgir.h"
#include "register.h"
#include "gra_bb.h"
#include "gra_lrange.h"
#include "gra_region.h"
#include "gra_interfere.h"

static INT  trace_detail;
static BOOL trace_color;
static BOOL trace_split;
static BOOL trace_split_priority;
static BOOL trace_grants;
static BOOL trace_preference;
static BOOL trace_place;
static BOOL trace_stats;
static BOOL trace_neighbors;
static BOOL trace_loops;
static BOOL trace_homing;
static BOOL trace_memory;
static BOOL trace_perf_comp;
static BOOL trace_check_splits;

// Some brain death with stdarg.h and defs.h
#undef long

/////////////////////////////////////
void
GRA_Trace_Color_LRANGE( const char* str, LRANGE* lrange )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff[100];

  if (trace_color && 1 <= trace_detail)
    fprintf(TFile,"<gra> %s p %g %s\n",str,lrange->Priority(),
                                           lrange->Format(buff));
}

/////////////////////////////////////
void
GRA_Trace_Color_REGION( GRA_REGION* region )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_color ) {
    fprintf(TFile,"<gra> Coloring region ");
    RID_Fprint(TFile,region->Rid());
  }
}

/////////////////////////////////////
void
GRA_Trace_Grant( GRA_BB* gbb, ISA_REGISTER_CLASS cl, REGISTER reg )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_grants ) {
    fprintf(TFile,"<gra> Granting local register %s to BB%d\n",
                  REGISTER_name(cl,reg),BB_id(gbb->Bb()));
  }
}

/////////////////////////////////////
void
GRA_Trace_Grant_Unused_Caller_Saved(void)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_grants ) {
    fprintf(TFile,
	    "<gra> Attempting to grant unused caller saved registers.\n");
  }
}
    
/////////////////////////////////////
void
GRA_Trace(INT detail, const char *fmt, ...)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (detail <= trace_detail) {
    va_list args;
    va_start(args, fmt);
    fprintf(TFile, "<gra> ");
    vfprintf(TFile,fmt,args);
    fprintf(TFile,"\n");
    va_end(args);
  }
}

/////////////////////////////////////
void
GRA_Trace_Split(INT detail, const char *fmt, ...)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split && detail <= trace_detail) {
    va_list args;
    va_start(args, fmt);
    fprintf(TFile, "<gra> ");
    vfprintf(TFile,fmt,args);
    fprintf(TFile,"\n");
    va_end(args);
  }
}

/////////////////////////////////////
void
GRA_Trace_Split_Removing_Block(GRA_BB* gbb)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split) {
    fprintf(TFile, "<gra> Removing BB:%d from split.\n",
	    BB_id(gbb->Bb()));
  }
}

/////////////////////////////////////
void
GRA_Trace_Split_Add_Priority(GRA_BB* gbb, BOOL is_store)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split_priority) {
    fprintf(TFile, "<gra> Adding to priority for %s in BB:%d \n",
	    is_store ? "spill" : "restore",
	    BB_id(gbb->Bb()));
  }
}

/////////////////////////////////////
void
GRA_Trace_Split_Sub_Priority(GRA_BB* gbb, BOOL is_store)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split_priority) {
    fprintf(TFile, "<gra> Subtracting from priority for %s in BB:%d \n",
	    is_store ? "spill" : "restore",
	    BB_id(gbb->Bb()));
  }
}

#if defined( KEY)
/////////////////////////////////////
void
GRA_Trace_Split_Reclaim_Add_Priority(GRA_BB* gbb, BOOL is_store, float priority)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split_priority) {
    fprintf(TFile, "<gra> Adding %f to priority for reclaim %s in BB:%d \n",
	    priority,
	    is_store ? "spill" : "restore",
	    BB_id(gbb->Bb()));
  }
}

/////////////////////////////////////
void
GRA_Trace_Split_Reclaim_Sub_Priority(GRA_BB* gbb, BOOL is_store, float priority)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_split_priority) {
    fprintf(TFile, "<gra> Subtracting %f from priority for reclaim %s in BB:%d \n",
	    priority,
	    is_store ? "spill" : "restore",
	    BB_id(gbb->Bb()));
  }
}
#endif

/////////////////////////////////////
void
GRA_Trace_Split_Priority_On(const char *msg)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_check_splits) {
    trace_split_priority = TRUE;
    fprintf(TFile, "<gra> Calculate split priorities via %s:\n", msg);
  }
}

/////////////////////////////////////
void
GRA_Trace_Split_Priority_Off()
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  trace_split_priority = FALSE;
}

/////////////////////////////////////
void
GRA_Trace_Color(INT detail, const char *fmt, ...)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_color && detail <= trace_detail) {
    va_list args;
    va_start(args, fmt);
    fprintf(TFile, "<gra> ");
    vfprintf(TFile,fmt,args);
    fprintf(TFile,"\n");
    va_end(args);
  }
}

void
GRA_Trace_Place( INT detail, const char *fmt, ...)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_place && detail <= trace_detail) {
    va_list args;
    va_start(args, fmt);
    fprintf(TFile, "<gra> ");
    vfprintf(TFile,fmt,args);
    fprintf(TFile,"\n");
    va_end(args);
  }
}

/////////////////////////////////////
void
GRA_Trace_Place_LRANGE_GBB( const char* str, LRANGE* lrange,
                                             GRA_BB* gbb )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (trace_place && 1 <= trace_detail) {
    fprintf(TFile,"TN%d BB%d -- %s\n",TN_number(lrange->Tn()),
                                      BB_id(gbb->Bb()),
                                      str);
  }
}
    

/////////////////////////////////////
static void
print_lr( LRANGE *lr)
/////////////////////////////////////
//  print live range in format for
//  neighbor trace.
/////////////////////////////////////
{
  if (lr->Type() == LRANGE_TYPE_LOCAL) {
    if (lr->Has_Wired_Register()) {
      fprintf(TFile,"W%d(TN%d)",lr->Id(), lr->Reg());
    } else {
      fprintf(TFile,"L%d",lr->Id());
    }
  } else {
    fprintf(TFile,"C%d(TN%d)",lr->Id(), TN_number(lr->Tn()));
  }
}

/////////////////////////////////////
void
GRA_Trace_Preference_Attempt(LRANGE* lrange0, LRANGE* lrange1,
			     GRA_REGION* region, BOOL outcome )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    GRA_Trace(0,"Preference %s with %s [%s]",
                lrange0->Format(buff0),
                lrange1->Format(buff1),
                outcome ? "yes" : "no");
    if (!outcome && lrange1->Allocated()) {
      //
      // Print any neighbors that have the color.  Assumes that lrange1
      // is the one that we are attempting to preference *from*.
      //
      fprintf(TFile,"<gra> LRANGES preventing preference: ");
      LRANGE_NEIGHBOR_ITER iter;
      REGISTER reg = lrange1->Reg();
      for (iter.Init(lrange0,region); ! iter.Done(); iter.Step()) {
	LRANGE* nlr = iter.Current();
	if (nlr->Allocated() &&
	    nlr->Reg() == reg) {
	  print_lr(nlr);
	  fprintf(TFile," ");	  
	}
      }
      fprintf(TFile,"\n");

      if (lrange0->Type() ==  LRANGE_TYPE_COMPLEMENT) {
	fprintf(TFile,"<gra> BBs preventing preference: ");
	LRANGE_LIVE_GBB_ITER gbb_iter;
	ISA_REGISTER_CLASS rc = lrange0->Rc();
	for (gbb_iter.Init(lrange0); ! gbb_iter.Done(); gbb_iter.Step()) {
	  GRA_BB* gbb = gbb_iter.Current();
	  if (REGISTER_SET_MemberP(gbb->Registers_Used(rc), reg)) {
	    fprintf(TFile," BB%d", BB_id(gbb->Bb()));
	  }
	}
	fprintf(TFile,"\n");
      }
    }
  }
}

/////////////////////////////////////
void
GRA_Trace_Preference_Copy(LRANGE* lrange0, LRANGE* lrange1, GRA_BB* gbb )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    const char *str;
    if (lrange0->Type() == LRANGE_TYPE_REGION ||
	lrange1->Type() == LRANGE_TYPE_REGION) {
      str = "Glue";
    } else if (lrange0->Type() == LRANGE_TYPE_LOCAL ||
	       lrange1->Type() == LRANGE_TYPE_LOCAL) {
      str = "Dedicated";
    } else {
      str = "Global";
    }
    GRA_Trace(0,"%s preference copy allowed in BB:%d %s with %s",
	      str,
	      BB_id(gbb->Bb()),
	      lrange0->Format(buff0),
	      lrange1->Format(buff1));

  }
}

/////////////////////////////////////
void
GRA_Trace_Preference_Conflict(LRANGE* lrange0, LRANGE* lrange1, GRA_BB* gbb )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    GRA_Trace(0,"Preference: conflict for copy in BB:%d %s with %s",
                BB_id(gbb->Bb()), 
		lrange0->Format(buff0),
                lrange1->Format(buff1));

  }
}


/////////////////////////////////////
void
GRA_Trace_Possible_Preference_Copy(LRANGE* lrange0, LRANGE* lrange1, GRA_BB* gbb)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    const char *str;
    if (lrange0->Type() == LRANGE_TYPE_REGION ||
	lrange1->Type() == LRANGE_TYPE_REGION) {
      str = "Glue";
    } else if (lrange0->Type() == LRANGE_TYPE_LOCAL ||
	       lrange1->Type() == LRANGE_TYPE_LOCAL) {
      str = "Dedicated";
    } else {
      str = "Global";
    }
    GRA_Trace(0,"%s TN preference copy possible in BB:%d %s with %s",
	      str,
	      BB_id(gbb->Bb()),
	      lrange0->Format(buff0),
	      lrange1->Format(buff1));
  }
}

/////////////////////////////////////
void
GRA_Trace_Global_Preference_Failure(LRANGE* lrange0, LRANGE* lrange1, GRA_BB* gbb)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    GRA_Trace(0,"Global TN preference conflict found in BB:%d %s with %s",
                BB_id(gbb->Bb()),
                lrange0->Format(buff0),
                lrange1->Format(buff1));

  }
}

/////////////////////////////////////
void
GRA_Trace_Global_Preference_Success(LRANGE* lrange0, LRANGE* lrange1)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80], buff1[80];

  if ( trace_preference ) {
    GRA_Trace(0,"Global TN preference successful for %s with %s",
                lrange0->Format(buff0),
                lrange1->Format(buff1));
  }
}


/////////////////////////////////////
void GRA_Trace_Spill_Stats(float freq_restore_count, INT restore_count,
			   float freq_spill_count, INT spill_count,
			   float priority_count)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_stats ) {
    GRA_Trace(0,"freq weighted restores %g spills %g allocated priority %g",
                freq_restore_count,freq_spill_count, priority_count);
    GRA_Trace(0,"absolute restores %d spills %d",restore_count,spill_count);
  } else if ( trace_perf_comp ) {
    GRA_Trace(0,"%s %g %g %d %d %g\n", ST_name(Get_Current_PU_ST()),
	      freq_restore_count, freq_spill_count, restore_count,
	      spill_count, priority_count);
  }
}

/////////////////////////////////////
void GRA_Trace_LRANGE_Stats( INT32 complement_count,
                             INT32 region_count,
                             INT32 local_count,
                             INT32 split_count )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_stats ) {
    GRA_Trace(0,"LRANGE counts complement %d region %d local %d split %d",
              complement_count,
              region_count,
              local_count,
              split_count);
  }
}

/////////////////////////////////////
void GRA_Trace_Regs_Stats( ISA_REGISTER_CLASS rc,
			   REGISTER_SET regs_all, 
			   REGISTER_SET &regs_used)
// Trace how many regs used by GRA out of how many available regs
{
  if ( trace_stats ) 
    GRA_Trace(0,"rc %d: used %d regs out of %d", rc, 
	      REGISTER_SET_Size(regs_used), REGISTER_SET_Size(regs_all));
}

/////////////////////////////////////
void
GRA_Trace_Wired_Local_Count( INT32 count )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if ( trace_stats ) {
    GRA_Trace(0,"wired local LRANGE count %d\n",count);
  }
}
  
/////////////////////////////////////
void
GRA_Trace_Complement_LRANGE_Neighbors( LRANGE *lr, GRA_REGION* region )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  LRANGE_NEIGHBOR_ITER iter;
  if ( trace_neighbors ) {
    fprintf(TFile,"<gra> Neighbors for ");
    print_lr(lr);
    fprintf(TFile,": ");
    for (iter.Init(lr,region); ! iter.Done(); iter.Step()) {
      LRANGE* nlr = iter.Current();
      print_lr(nlr);
      fprintf(TFile," ");
    }
    fprintf(TFile,"\n");
    if (lr->Type() == LRANGE_TYPE_COMPLEMENT) {
      fprintf(TFile, "live_bb_set: ");
      BB_SET_Print(lr->Live_BB_Set(), TFile); fprintf(TFile, "\n");
    }
  }
}

/////////////////////////////////////
BOOL 
GRA_Trace_Loops(void)
/////////////////////////////////////
//
// See interface description.
/////////////////////////////////////
{
  return trace_loops;
}

/////////////////////////////////////
void
GRA_Trace_Homing(TN *tn, BB* bb)
/////////////////////////////////////
{
  if (trace_homing) {
    fprintf(TFile,"<gra> Homing TN%d in BB:%d\n", TN_number(tn), BB_id(bb));
  }
}

/////////////////////////////////////
void
GRA_Trace_Home_Removal(TN *tn, GRA_BB* gbb, OP* op)
/////////////////////////////////////
//
// See interface description.
/////////////////////////////////////
{
  if (trace_homing) {
    fprintf(TFile,"<gra> Homing TN%d in BB:%d Delete op ",
	    TN_number(tn), BB_id(gbb->Bb()));
    Print_OP_No_SrcLine(op);
  }
}

static void *last_brk;

/////////////////////////////////////
void
GRA_Init_Trace_Memory(void)
/////////////////////////////////////
{
  if (trace_memory) {
    last_brk = sbrk(0);
  }
}

/////////////////////////////////////
void
GRA_Trace_Memory(const char *string)
/////////////////////////////////////
{
  if (trace_memory) {
    unsigned usage = ((INTPTR) sbrk(0)) - (INTPTR) last_brk;
    fprintf(TFile,"<gra> Memory use %s: %d\n", string, usage);
  }
}

/////////////////////////////////////
void
GRA_Trace_Memory_Realloc(const char *string)
/////////////////////////////////////
{
  if (trace_memory) {
    fprintf(TFile,"<gra> Memory realloc in %s\n", string);
  }
}

/////////////////////////////////////
void
GRA_Trace_Memory_Counts()
/////////////////////////////////////
{
  if (trace_memory) {
    fprintf(TFile,
#ifdef KEY /* Mac port */
    	    "<gra> Memory use for GRA_BBs: %ld\n",
	    (long) (gbb_mgr.Alloc_Count()*sizeof(GRA_BB))
#else /* KEY Mac port */
    	    "<gra> Memory use for GRA_BBs: %d\n",
	    gbb_mgr.Alloc_Count()*sizeof(GRA_BB)
#endif /* KEY Mac port */
	    );
    fprintf(TFile,"<gra> Memory count of GRA_BBs: %d\n",
	    gbb_mgr.Alloc_Count());
    fprintf(TFile,
#ifdef KEY /* Mac port */
	    "<gra> Memory use for GRA_REGIONs: %ld\n",
	    (long) (gra_region_mgr.Alloc_Count()*sizeof(GRA_REGION))
#else /* KEY Mac port */
	    "<gra> Memory use for GRA_REGIONs: %d\n",
	    gra_region_mgr.Alloc_Count()*sizeof(GRA_REGION));
#endif /* KEY Mac port */
	    );
    fprintf(TFile,"<gra> Memory count of GRA_REGIONs: %d\n",
	    gra_region_mgr.Alloc_Count());
  }
}

void 
GRA_Trace_Split_LUNIT_Spill(LUNIT *lunit)
{
  GRA_BB* gbb = lunit->Gbb();

  if (trace_split && gbb->Freq() > 1.0 && lunit->Split_Lunit()) {
    LRANGE* lrange  = lunit->Lrange();
    TN*     tn      = lrange->Tn();    
    fprintf(TFile,"<gra> Split spill in high frequency block BB:%d ",
	    BB_id(gbb->Bb()));
    fprintf(TFile,"for TN%d\n",TN_number(tn));
  }
}

/////////////////////////////////////
BOOL
GRA_Trace_Check_Splits()
{
  return trace_check_splits;
}

/////////////////////////////////////
void
GRA_Trace_LRANGE_Allocate(LRANGE* lrange )
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  char buff0[80];

  if ( trace_color ) {
    GRA_Trace(0,"Allocated: %s", lrange->Format(buff0));
  }
}

#ifdef KEY
/////////////////////////////////////
void
GRA_Trace_LRANGE_Choose(LRANGE* lrange, REGISTER_SET allowed)
{
  if ( trace_color && lrange->Type() != LRANGE_TYPE_LOCAL) {
    fprintf(TFile, "<gra> choose from allowed ");
    REGISTER_SET_Print(allowed, TFile);
    fprintf(TFile, " for GTN%d\n", TN_number(lrange->Tn()));
  }
}

/////////////////////////////////////
void
GRA_Trace_LRANGE_Choose_Reclaimable(LRANGE* lrange, REGISTER_SET reclaimable)
{
  if ( trace_color && lrange->Type() != LRANGE_TYPE_LOCAL) {
    fprintf(TFile, "<gra> choose from reclaimable ");
    REGISTER_SET_Print(reclaimable, TFile);
    fprintf(TFile, " for GTN%d\n", TN_number(lrange->Tn()));
  }
}
#endif

/////////////////////////////////////
void
GRA_Trace_Initialize(void)
/////////////////////////////////////
//  See interface description.
/////////////////////////////////////
{
  if (Get_Trace(TP_GRA, 0xffffffff))
    fprintf(TFile, "<gra> start gra trace for %s\n", 
	    ST_name(Get_Current_PU_ST()));
  trace_detail         = Get_Trace(TP_GRA,    0x1) ? 1 : 0;
  trace_color          = Get_Trace(TP_GRA,    0x2);
  trace_split          = Get_Trace(TP_GRA,    0x4);
  trace_split_priority = FALSE;
  trace_grants         = Get_Trace(TP_GRA,    0x8);
  trace_preference     = Get_Trace(TP_GRA,   0x10);
  trace_place          = Get_Trace(TP_GRA,   0x20);
  trace_stats          = Get_Trace(TP_GRA,   0x40);
  trace_neighbors      = Get_Trace(TP_GRA,   0x80);
  trace_loops	       = Get_Trace(TP_GRA,  0x100);
  trace_homing	       = Get_Trace(TP_GRA,  0x200);
  trace_memory         = Get_Trace(TP_GRA,  0x400);
  trace_perf_comp      = Get_Trace(TP_GRA,  0x800);
  trace_check_splits   = Get_Trace(TP_GRA, 0x1000);
  // 0x2000 used by cg_spill.cxx trace
}
