Line 17... |
Line 17... |
typedef struct or1k_32_instruction_properties instruction_properties ;
|
typedef struct or1k_32_instruction_properties instruction_properties ;
|
|
|
#include "insn-lists.h"
|
#include "insn-lists.h"
|
|
|
|
|
|
// Variable to keep track of unique instructions we have
|
|
int num_setup_insns;
|
|
int num_seen_insns;
|
|
|
|
struct or1k_insn_info * or1k_32_insns[OR1K_32_MAX_INSNS];
|
|
|
|
// Keep enough instructions required to do the maximum n-tuple set
|
|
// analysis.
|
|
int or1k_32_recent_insns[OR1K_MAX_GROUPINGS_ANALYSIS];
|
|
|
int or1k_32_analyse_insn(uint32_t insn,
|
int or1k_32_analyse_insn(uint32_t insn,
|
struct or1k_32_instruction_properties * insn_props)
|
struct or1k_32_instruction_properties * insn_props)
|
{
|
{
|
|
|
switch(insn_or1k_opcode(insn))
|
switch(insn_or1k_opcode(insn))
|
Line 978... |
Line 988... |
struct or1k_32_instruction_properties * insn_props)
|
struct or1k_32_instruction_properties * insn_props)
|
{
|
{
|
// Add this instruction's occurance to our data
|
// Add this instruction's occurance to our data
|
insn_lists_add(insn, insn_props);
|
insn_lists_add(insn, insn_props);
|
|
|
|
// n-tuple groupings stats recording here!
|
|
// only if we've seen enough to do all the sequence analysis
|
|
if (num_seen_insns > OR1K_MAX_GROUPINGS_ANALYSIS+1)
|
|
{
|
|
int n;
|
|
for(n=2;n<OR1K_MAX_GROUPINGS_ANALYSIS+1;n++)
|
|
insn_lists_group_add(n, insn_props);
|
}
|
}
|
|
|
|
// Finished adding to stats for this instruction
|
|
|
|
|
struct or1k_value_list
|
}
|
{
|
|
|
|
#define OR1K_VALUE_MAX_ENTRIES 64
|
|
int count;
|
|
// [value][occurances_of_value]
|
|
int32_t values[OR1K_VALUE_MAX_ENTRIES][2];
|
|
|
|
};
|
|
|
|
|
|
// Function to add entry to, or increment incidences of, value in the value list
|
// Function to add entry to, or increment incidences of, value in the value list
|
void or1k_add_in_list(struct or1k_value_list * list, int32_t value)
|
void or1k_add_in_list(struct or1k_value_list * list, int32_t value)
|
{
|
{
|
int i;
|
int i;
|
Line 1017... |
Line 1026... |
// Not found, add it to the list
|
// Not found, add it to the list
|
list->values[(list->count)][0] = value;
|
list->values[(list->count)][0] = value;
|
list->values[(list->count)][1] = 1;
|
list->values[(list->count)][1] = 1;
|
list->count++;
|
list->count++;
|
}
|
}
|
|
|
}
|
}
|
|
|
struct or1k_insn_info
|
|
{
|
|
char* insn_string;
|
|
|
|
int count;
|
|
|
|
int has_branchtarg;
|
|
struct or1k_value_list branch_info;
|
|
|
|
int has_imm;
|
|
struct or1k_value_list imm_info;
|
|
|
|
int has_rD;
|
|
int rD_use_freq[32];
|
|
int has_rA;
|
|
int rA_use_freq[32];
|
|
int has_rB;
|
|
int rB_use_freq[32];
|
|
|
|
// Set maximum instructions in a row we'll keep track of, starting at pairs
|
|
#define OR1K_MAX_GROUPINGS_ANALYSIS 4
|
|
#define OR1K_MAX_ENTRIES_PER_GROUP 1000
|
|
// Format of grouping data:
|
|
//
|
|
// 1st dimension: A list for each n-tuple group we're keeping track of
|
|
// (starting at pairs of instructions)
|
|
//
|
|
// 2nd dimension: Stores the list entries for the 1st dimension-tuple
|
|
// grouping. The number in [x][0][0] is the number of entries in the list so
|
|
// far, beginning at 0. The actual entries with data for grouping x start at
|
|
// [x][1][], where that entry holds the 1st x+2-tuple grouping information
|
|
// (eg. at x=0, [0][1][] is the first entry for/ pair instruction
|
|
// information, x=1, is for triples, x=2 quadruples, etc)
|
|
//
|
|
// 3rd dimension: Store up to x+2 instruction indexes (where x is the first
|
|
// dimension index, meaning this particular data is for a (x+2)-tuple set)
|
|
// and then a frequency count for this set (in index (x+2) of the third
|
|
// dimension array). Note we will have the index for the instruction this
|
|
// struct corresponds to in [x][n][(x+2)-1], which seems redundant, but can
|
|
// help processing later on.
|
|
//
|
|
// Note that we will have empty entries in the third dimension arrays for all
|
|
// but the last in the list of n-tuples. This is to save doing tricky naming
|
|
// defines and, in the future, if we would like to analyse sets that are
|
|
// bigger or smaller, hopefully all we need to do is change a single define.
|
|
//
|
|
int groupings[OR1K_MAX_GROUPINGS_ANALYSIS][OR1K_MAX_ENTRIES_PER_GROUP+1][OR1K_MAX_GROUPINGS_ANALYSIS+1];
|
|
|
|
};
|
|
|
|
// This number should correspond to the maximum insn_index we assign in the
|
|
// analyse function
|
|
#define OR1K_32_MAX_INSNS 117
|
|
struct or1k_insn_info * or1k_32_insns[OR1K_32_MAX_INSNS];
|
|
|
|
|
|
// List management/analysis functions - accessed through insn_lists() set of
|
// List management/analysis functions - accessed through insn_lists() set of
|
// functions
|
// functions
|
|
|
// Variable to keep track of unique instructions we have
|
|
int num_setup_insns;
|
|
int num_seen_insns;
|
|
|
|
|
|
void or1k_32_insn_lists_init(void)
|
void or1k_32_insn_lists_init(void)
|
{
|
{
|
num_setup_insns = 0;
|
num_setup_insns = 0;
|
num_seen_insns = 0;
|
num_seen_insns = 0;
|
// Clear the pointer array so we can tell if things are used or not
|
// Clear the pointer array so we can tell if things are used or not
|
Line 1109... |
Line 1056... |
|
|
// Install the pointer for this newly allocated struct in its corresponding
|
// Install the pointer for this newly allocated struct in its corresponding
|
// index, as set when we decode the instruction
|
// index, as set when we decode the instruction
|
or1k_32_insns[insn_props->insn_index] = new_insn;
|
or1k_32_insns[insn_props->insn_index] = new_insn;
|
|
|
|
// Clear the set statistics counters
|
|
int set_itr;
|
|
for(set_itr=0;set_itr<OR1K_MAX_GROUPINGS_ANALYSIS;set_itr++)
|
|
or1k_32_insns[insn_props->insn_index]->groupings[set_itr][0][0] = 0;
|
|
|
// Increment number of instructions we have set up
|
// Increment number of instructions we have set up
|
num_setup_insns++;
|
num_setup_insns++;
|
|
|
// Debugging:
|
// Debugging:
|
//printf("Adding %dth instruction - %s\n",
|
//printf("Adding %dth instruction - %s\n",
|
Line 1180... |
Line 1132... |
{
|
{
|
(or1k_32_insns[insn_props->insn_index])->has_rB = 1;
|
(or1k_32_insns[insn_props->insn_index])->has_rB = 1;
|
((or1k_32_insns[insn_props->insn_index])->rB_use_freq[insn_or1k_32_rB(insn)])++;
|
((or1k_32_insns[insn_props->insn_index])->rB_use_freq[insn_or1k_32_rB(insn)])++;
|
}
|
}
|
|
|
|
// Increment overall instructions "seen" counter
|
|
num_seen_insns++;
|
|
|
// TODO: n-tuple groupings stats recording here!
|
// Shift along the recently seen instructions
|
|
int i;
|
|
for(i=OR1K_MAX_GROUPINGS_ANALYSIS-1;i>0;i--)
|
|
or1k_32_recent_insns[i] = or1k_32_recent_insns[i-1];
|
|
or1k_32_recent_insns[0] = insn_props->insn_index;
|
|
|
// Finished adding to stats for this instruction
|
}
|
|
|
// Increment overall instructions "seen" counter
|
|
num_seen_insns++;
|
|
|
|
|
|
|
|
|
// Do the n-tuple set analysis for the most recently added instruction
|
|
void or1k_32_ntuple_add(int n,
|
|
struct or1k_32_instruction_properties *insn_props)
|
|
{
|
|
|
|
if (n<2)
|
|
{
|
|
fprintf(stderr,"or1k_32_ntuple_add: tuple number < 2 (%d)",n);
|
|
return;
|
}
|
}
|
|
|
|
struct or1k_insn_info * insn_info = or1k_32_insns[insn_props->insn_index];
|
|
|
// Free up all added instruction statistic tracking structs
|
// Get the number of sets for these n-tuple groups we've seen so far.
|
void or1k_32_insn_lists_free(void)
|
int sets_for_ntuple = insn_info->groupings[n-1][0][0];
|
|
|
|
int set_match_index; int tuple_set_itr, tuple_set_match;
|
|
|
|
|
|
// now find if the current n instructions in or1k_32_recent_insns[] matches
|
|
// any set of n instructions we're keeping track of in groupings[][][].
|
|
for (set_match_index=0; set_match_index<sets_for_ntuple; set_match_index++)
|
{
|
{
|
// Free all entries we m/calloc()'d
|
// Check this set for a match with our existing trace
|
int insn_index;
|
// Example:
|
for(insn_index=0;insn_index<OR1K_32_MAX_INSNS;insn_index++)
|
// In case of a triple (n=3), 1st set, [3][1][0] corresponds to the third
|
|
// instruction in the trace (or1k_32_recent_insns[2]), [3][1][1] should
|
|
// be the second in the trace, and [3][1][2] should be the first in the
|
|
// trace (same index as insn_props->insn_index)
|
|
|
|
// Presuppose a match, de-assert and break out of the loop as soon as we
|
|
// detect a mismatch.
|
|
tuple_set_match = 1;
|
|
for(tuple_set_itr=0;tuple_set_itr<n;tuple_set_itr++)
|
{
|
{
|
if (or1k_32_insns[insn_index] != NULL)
|
if (insn_info->groupings[n-1][set_match_index+1][tuple_set_itr]
|
free(or1k_32_insns[insn_index]);
|
!= or1k_32_recent_insns[n-1 - tuple_set_itr])
|
|
{
|
|
tuple_set_match = 0;
|
|
break; // No match, so break out of this for() loop
|
|
}
|
|
}
|
|
|
|
if (!tuple_set_match)
|
|
continue; // go again...
|
|
}
|
|
|
|
if (tuple_set_match)
|
|
// Found a match - just increment the counter (set_match_index should
|
|
// be pointing at the right set)
|
|
(insn_info->groupings[n-1][set_match_index+1][n])++;
|
|
else
|
|
{
|
|
// If we can record a new set
|
|
if (sets_for_ntuple < OR1K_MAX_ENTRIES_PER_GROUP)
|
|
{
|
|
// Increment the number of sets we have for this n-tuple starting
|
|
// on the current instruction
|
|
sets_for_ntuple++;
|
|
// Add new set to the end (all n instructions, copy in)
|
|
for(tuple_set_itr=0;tuple_set_itr<n;tuple_set_itr++)
|
|
insn_info->groupings[n-1][sets_for_ntuple][tuple_set_itr]
|
|
= or1k_32_recent_insns[n-1 - tuple_set_itr];
|
|
// Set the count for this set to 1
|
|
insn_info->groupings[n-1][sets_for_ntuple][n] = 1;
|
|
// Increment the counter of these n-tuple sets
|
|
(insn_info->groupings[n-1][0][0])++;
|
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
#define DISPLAY_STRING
|
#define DISPLAY_STRING
|
Line 1387... |
Line 1401... |
i++;
|
i++;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
#define MAX_NTUPLE_LISTING 5
|
|
// Print out the most common n-tuple groupings for an instruction
|
|
void or1k_32_generate_ntuple_stats(int n, struct or1k_insn_info *insn_info,
|
|
FILE * stream)
|
|
{
|
|
|
|
// If n=2 (pairs) then groupings[1] is where our list is
|
|
int total_sets_for_ntuple = insn_info->groupings[n-1][0][0];
|
|
|
|
if (total_sets_for_ntuple == 0)
|
|
return;
|
|
|
|
fprintf(stream, "%d-tuple groupings ending with this instruction\n",n);
|
|
|
|
// This is actually a pointer to a 2-dimensional integer array, looking like:
|
|
// [OR1K_MAX_ENTRIES_PER_GROUP+1][OR1K_MAX_GROUPINGS_ANALYSIS+1;]
|
|
int *ntuplelist = (int*)&(insn_info->groupings[n-1]);
|
|
int *set;
|
|
int set_count, set_count2;
|
|
|
|
// Let's make a copy of the counts for each... so we don't trash them
|
|
int set_count_copy[OR1K_MAX_ENTRIES_PER_GROUP+1];
|
|
|
|
// Go through the list, copy the counts for each
|
|
for (set_count = 0;set_count <total_sets_for_ntuple;set_count++)
|
|
{
|
|
set = (int*)ntuplelist[set_count+1];
|
|
set_count_copy[set_count+1]=set[n];
|
|
}
|
|
|
|
// Now go through, finding the most frequent n-tuple of instructions and
|
|
// print it out
|
|
int largest_indx = 0;
|
|
set_count=0;
|
|
while(set_count < total_sets_for_ntuple && set_count < MAX_NTUPLE_LISTING)
|
|
{
|
|
largest_indx = 0;
|
|
for(set_count2=0;set_count2<total_sets_for_ntuple;set_count2++)
|
|
largest_indx = (set_count_copy[set_count2 + 1] >
|
|
set_count_copy[largest_indx + 1]) ?
|
|
set_count2 : largest_indx;
|
|
// largest_indx is the index of the set with the highest occurance, so
|
|
// let's print it out, but first get a pointer to the set's data
|
|
set = (int*)ntuplelist[largest_indx+1];
|
|
|
|
// Print out the sequence of prior isntructions
|
|
fprintf(stream,"Seq:\t");
|
|
// Go through the indexes of the previous instructions, get their
|
|
// strings, and print them out
|
|
for(set_count2=0;set_count2<n;set_count2++)
|
|
fprintf(stream, "%s\t", or1k_32_insns[(set[set_count2])]->insn_string);
|
|
|
|
// now print out the occurances
|
|
fprintf(stream, "%d\ttimes\n", set_count_copy[largest_indx + 1]);
|
|
|
|
// done printing this one out.. let's clear its count
|
|
set_count_copy[largest_indx + 1] = -1;
|
|
|
|
set_count++;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
// Print out the stats relating to the sequences of instructions most
|
|
// common before seeing this instruction
|
|
void or1k_32_generate_groupings_stats(struct or1k_insn_info *insn_info,
|
|
FILE * stream)
|
|
{
|
|
int n;
|
|
for(n=2;n<OR1K_MAX_GROUPINGS_ANALYSIS+1;n++)
|
|
or1k_32_generate_ntuple_stats(n, insn_info, stream);
|
|
|
|
}
|
|
|
void or1k_32_generate_stats(FILE * stream)
|
void or1k_32_generate_stats(FILE * stream)
|
{
|
{
|
// Generate some useful things
|
// Generate some useful things
|
fprintf(stream, "Analysis output:\n");
|
fprintf(stream, "Analysis output:\n");
|
|
|
Line 1399... |
Line 1490... |
// Print out all stats for every instruction we saw!
|
// Print out all stats for every instruction we saw!
|
int insn_index;
|
int insn_index;
|
for(insn_index=0;insn_index<OR1K_32_MAX_INSNS;insn_index++)
|
for(insn_index=0;insn_index<OR1K_32_MAX_INSNS;insn_index++)
|
{
|
{
|
if (or1k_32_insns[insn_index] != NULL)
|
if (or1k_32_insns[insn_index] != NULL)
|
|
{
|
or1k_32_insn_top_x(or1k_32_insns[insn_index],stream,10);
|
or1k_32_insn_top_x(or1k_32_insns[insn_index],stream,10);
|
|
or1k_32_generate_groupings_stats(or1k_32_insns[insn_index],stream);
|
|
}
|
}
|
}
|
|
|
|
|
|
|
// Do most frequent instruction analysis -- note this trashes instruction
|
// Do most frequent instruction analysis -- note this trashes instruction
|
// frequency count - should be fixed
|
// frequency count - should be fixed
|
or1k_32_most_freq_insn(stream);
|
or1k_32_most_freq_insn(stream);
|
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
|
|
|
|
|
|
// Free up all added instruction statistic tracking structs
|
|
void or1k_32_insn_lists_free(void)
|
|
{
|
|
// Free all entries we m/calloc()'d
|
|
int insn_index;
|
|
for(insn_index=0;insn_index<OR1K_32_MAX_INSNS;insn_index++)
|
|
{
|
|
if (or1k_32_insns[insn_index] != NULL)
|
|
free(or1k_32_insns[insn_index]);
|
|
}
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|