<commit_before>/*
 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * @file
 * @brief       Provides several statistic functions for the backend.
 * @author      <NAME>
 * @version     $Id$
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <time.h>

#include "irnode_t.h"
#include "irprintf.h"
#include "irgwalk.h"
#include "irhooks.h"
#include "execfreq.h"
#include "dbginfo_t.h"
#include "firmstat_t.h"
#include "irtools.h"
#include "pset.h"
#include "statev.h"

#include "bearch_t.h"
#include "bestat.h"
#include "belive_t.h"
#include "besched.h"
#include "benode_t.h"

#ifdef FIRM_STATISTICS

typedef struct _be_stat_irg_t {
	ir_graph         *irg;       /**< the irg, the statistic is about */
	pset             *phases;    /**< node statistics for each phase  */
	struct obstack   obst;       /**< the obstack containing the information */
	const arch_env_t *arch_env;  /**< the current arch env */
} be_stat_irg_t;

typedef struct _be_stat_phase_t {
	const arch_env_t *arch_env;  /**< the current arch env */
	const char       *phase;     /**< the name of the phase the statistic is about */
	unsigned long    num_nodes;  /**< overall number of reachable nodes in the irg */
	unsigned long    num_data;   /**< number of data nodes ((mode_datab && ! Proj && ! Phi)  || mode_T) */
	unsigned long    num_proj;   /**< number of Projs */
	unsigned long    num_phi;    /**< number of Phis */
	unsigned long    num_load;   /**< number of Loads */
	unsigned long    num_store;  /**< number of Stores */
	unsigned long    num_spill;  /**< number of Spills */
	unsigned long    num_reload; /**< number of Reloads */
} be_stat_phase_t;

static set *be_stat_data = NULL;

static int cmp_stat_phase(const void *a, const void *b) {
	const be_stat_phase_t *p1 = a;
	const be_stat_phase_t *p2 = b;

	return p1->phase != p2->phase;
}

static int cmp_stat_data(const void *a, const void *b, size_t len) {
	const be_stat_irg_t *p1 = a;
	const be_stat_irg_t *p2 = b;
	(void) len;

	return p1->irg != p2->irg;
}

static be_stat_irg_t *find_stat_irg_entry(ir_graph *irg) {
	be_stat_irg_t *entry, key;

	if (! be_stat_data)
		return NULL;

	key.irg = irg;
	entry   = set_find(be_stat_data, &key, sizeof(key), HASH_PTR(irg));

	return entry;
}

static be_stat_irg_t *get_stat_irg_entry(ir_graph *irg) {
	be_stat_irg_t *entry, key;

	if (! be_stat_data)
		return NULL;

	entry = find_stat_irg_entry(irg);

	if (! entry) {
		key.irg = irg;
		entry   = set_insert(be_stat_data, &key, sizeof(key), HASH_PTR(irg));
	}

	return entry;
}

struct a_pressure_walker {
	be_irg_t *birg;
	be_lv_t *lv;
};

/**
 * Collect reg pressure statistics per block and per class.
 */
static void stat_reg_pressure_block(ir_node *block, void *data) {
	struct a_pressure_walker *env = data;
	be_irg_t         *birg = env->birg;
	ir_graph         *irg  = be_get_birg_irg(birg);
	const arch_env_t *aenv = be_get_birg_arch_env(birg);
	int i, n = arch_isa_get_n_reg_class(aenv->isa);

	for (i = 0; i < n; i++) {
		const arch_register_class_t *cls = arch_isa_get_reg_class(aenv->isa, i);
		ir_node      *irn;
		ir_nodeset_t  live_nodes;
		int           max_live;

		ir_nodeset_init(&live_nodes);
		be_liveness_end_of_block(env->lv, aenv, cls, block, &live_nodes);
		max_live = ir_nodeset_size(&live_nodes);

		sched_foreach_reverse(block, irn) {
			int cnt;

			if(is_Phi(irn))
				break;

			be_liveness_transfer(aenv, cls, irn, &live_nodes);
			cnt        = ir_nodeset_size(&live_nodes);
			max_live   = cnt < max_live ? max_live : cnt;
		}

		stat_be_block_regpressure(irg, block, max_live, cls->name);
		ir_nodeset_destroy(&live_nodes);
	}
}

void be_do_stat_reg_pressure(be_irg_t *birg) {
	ir_graph *irg = be_get_birg_irg(birg);

	if (stat_is_active()) {
		struct a_pressure_walker w;

		w.birg = birg;
		w.lv   = be_liveness(birg);
		/* Collect register pressure information for each block */
		irg_block_walk_graph(irg, stat_reg_pressure_block, NULL, &w);
		be_liveness_free(w.lv);
	}
}

/**
 * Notify statistic module about amount of ready nodes.
 */
void be_do_stat_sched_ready(ir_node *block, const ir_nodeset_t *ready_set) {
	if (stat_is_active()) {
		stat_be_block_sched_ready(get_irn_irg(block), block, MIN(ir_nodeset_size(ready_set), 5));
	}
}

/**
 * Pass information about a perm to the statistic module.<commit_msg>improve register pressure statistics<commit_after>/*
 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * @file
 * @brief       Provides several statistic functions for the backend.
 * @author      <NAME>
 * @version     $Id$
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <time.h>

#include "irnode_t.h"
#include "irprintf.h"
#include "irgwalk.h"
#include "irhooks.h"
#include "execfreq.h"
#include "dbginfo_t.h"
#include "firmstat_t.h"
#include "irtools.h"
#include "pset.h"
#include "statev.h"

#include "bearch_t.h"
#include "bestat.h"
#include "belive_t.h"
#include "besched.h"
#include "benode_t.h"

#ifdef FIRM_STATISTICS

typedef struct _be_stat_irg_t {
	ir_graph         *irg;       /**< the irg, the statistic is about */
	pset             *phases;    /**< node statistics for each phase  */
	struct obstack   obst;       /**< the obstack containing the information */
	const arch_env_t *arch_env;  /**< the current arch env */
} be_stat_irg_t;

typedef struct _be_stat_phase_t {
	const arch_env_t *arch_env;  /**< the current arch env */
	const char       *phase;     /**< the name of the phase the statistic is about */
	unsigned long    num_nodes;  /**< overall number of reachable nodes in the irg */
	unsigned long    num_data;   /**< number of data nodes ((mode_datab && ! Proj && ! Phi)  || mode_T) */
	unsigned long    num_proj;   /**< number of Projs */
	unsigned long    num_phi;    /**< number of Phis */
	unsigned long    num_load;   /**< number of Loads */
	unsigned long    num_store;  /**< number of Stores */
	unsigned long    num_spill;  /**< number of Spills */
	unsigned long    num_reload; /**< number of Reloads */
} be_stat_phase_t;

static set *be_stat_data = NULL;

static int cmp_stat_phase(const void *a, const void *b) {
	const be_stat_phase_t *p1 = a;
	const be_stat_phase_t *p2 = b;

	return p1->phase != p2->phase;
}

static int cmp_stat_data(const void *a, const void *b, size_t len) {
	const be_stat_irg_t *p1 = a;
	const be_stat_irg_t *p2 = b;
	(void) len;

	return p1->irg != p2->irg;
}

static be_stat_irg_t *find_stat_irg_entry(ir_graph *irg) {
	be_stat_irg_t *entry, key;

	if (! be_stat_data)
		return NULL;

	key.irg = irg;
	entry   = set_find(be_stat_data, &key, sizeof(key), HASH_PTR(irg));

	return entry;
}

static be_stat_irg_t *get_stat_irg_entry(ir_graph *irg) {
	be_stat_irg_t *entry, key;

	if (! be_stat_data)
		return NULL;

	entry = find_stat_irg_entry(irg);

	if (! entry) {
		key.irg = irg;
		entry   = set_insert(be_stat_data, &key, sizeof(key), HASH_PTR(irg));
	}

	return entry;
}

typedef struct pressure_walker_env_t pressure_walker_env_t;
struct pressure_walker_env_t {
	be_irg_t *birg;
	be_lv_t  *lv;
	double    insn_count;
	double    regpressure;
	int       max_pressure;
	const arch_register_class_t *cls;
};

static void check_reg_pressure_class(pressure_walker_env_t *env,
                                     ir_node *block,
                                     const arch_register_class_t *cls)
{
	be_irg_t         *birg = env->birg;
	ir_graph         *irg  = be_get_birg_irg(birg);
	const arch_env_t *aenv = be_get_birg_arch_env(birg);
	ir_node          *irn;
	ir_nodeset_t      live_nodes;
	int               max_live;

	ir_nodeset_init(&live_nodes);
	be_liveness_end_of_block(env->lv, aenv, cls, block, &live_nodes);
	max_live = ir_nodeset_size(&live_nodes);
	env->regpressure += max_live;

	sched_foreach_reverse(block, irn) {
		int cnt;

		if(is_Phi(irn))
			break;

		be_liveness_transfer(aenv, cls, irn, &live_nodes);
		cnt      = ir_nodeset_size(&live_nodes);
		max_live = cnt < max_live ? max_live : cnt;
		env->regpressure += cnt;
		env->insn_count++;
	}

	if(max_live > env->max_pressure)
		env->max_pressure = max_live;

	stat_be_block_regpressure(irg, block, max_live, cls->name);
	ir_nodeset_destroy(&live_nodes);
}

/**
 * Collect reg pressure statistics per block and per class.
 */
static void stat_reg_pressure_block(ir_node *block, void *data) {
	pressure_walker_env_t *env = data;

	if(env->cls != NULL) {
		check_reg_pressure_class(env, block, env->cls);
	} else {
		const arch_env_t *arch_env = be_get_birg_arch_env(env->birg);
		int i, n;

		n = arch_isa_get_n_reg_class(arch_env->isa);
		for (i = 0; i < n; i++) {
			const arch_register_class_t *cls
				= arch_isa_get_reg_class(arch_env->isa, i);

			check_reg_pressure_class(env, block, cls);
		}
	}
}

void be_do_stat_reg_pressure(be_irg_t *birg) {
	pressure_walker_env_t  env;
	ir_graph              *irg = be_get_birg_irg(birg);
	double                 average_pressure;

	env.birg         = birg;
	env.insn_count   = 0;
	env.max_pressure = 0;
	env.regpressure  = 0;
	be_liveness_assure_sets(be_assure_liveness(birg));
	env.lv           = be_get_birg_liveness(birg);

	// hack for now, TODO: remove me later
#if 0
	env.cls          = NULL;
#else
	env.cls          = arch_isa_get_reg_class(
			be_get_birg_arch_env(birg)->isa, 2);
#endif

	/* Collect register pressure information for each block */
	irg_block_walk_graph(irg, stat_reg_pressure_block, NULL, &env);

	average_pressure = env.regpressure / env.insn_count;
	stat_ev_emit("average_register_pressure", average_pressure);
	stat_ev_emit("maximum_register_pressure", env.max_pressure);
}

/**
 * Notify statistic module about amount of ready nodes.
 */
void be_do_stat_sched_ready(ir_node *block, const ir_nodeset_t *ready_set) {
	if (stat_is_active()) {
		stat_be_block_sched_ready(get_irn_irg(block), block, MIN(ir_nodeset_size(ready_set), 5));
	}
}

/**
 * Pass information about a perm to the statistic module.
{'fraction_non_alphanumeric': 0.11167968399317713, 'fraction_numerical': 0.0038603106203429394, 'mean_word_length': 3.706379383185467, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3340311', 'n_tokens_mistral': 4358, 'n_tokens_neox': 4167, 'n_words': 1075}