Commit 4af99ad0 authored by Cédric VALENSI's avatar Cédric VALENSI

Sync

parent ea99fa9f
......@@ -441,7 +441,7 @@ INSTALL( PROGRAMS maqao
SET(server_path "${CMAKE_CURRENT_SOURCE_DIR}/src/plugins/built_in")
ADD_CUSTOM_TARGET(distclean DEPENDS
# MAQAO core
distclean_maqao distclean_madras distclean_madrasAPI distclean_libdwarf
distclean_maqao distclean_madras distclean_libtroll distclean_libdwarf
# MAQAO Lua API
${DISTCLEAN_LUA} distclean_builtin distclean_abstractobjects distclean_crosscompil
# MAQAO doc
......
......@@ -601,7 +601,7 @@ WARN_LOGFILE = @CMAKE_SOURCE_DIR@/doc/internals/doxygen.errors
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = @CMAKE_SOURCE_DIR@/doc/internals/CoreDevGuide @CMAKE_SOURCE_DIR@/src/common/libmcommon.h @CMAKE_SOURCE_DIR@/src/common/libmasm.h @CMAKE_SOURCE_DIR@/src/analyze/libmcore.h @CMAKE_SOURCE_DIR@/src/madras/libmtroll.h @CMAKE_SOURCE_DIR@/src/madras/libmdisass.h @CMAKE_SOURCE_DIR@/src/madras/libmpatch.h @CMAKE_SOURCE_DIR@/src/madras/fsmutils.h @CMAKE_SOURCE_DIR@/src/madrasAPI/libmadras.h @CMAKE_SOURCE_DIR@/src/maqao/libmmaqao.h
INPUT = @CMAKE_SOURCE_DIR@/doc/internals/CoreDevGuide @CMAKE_SOURCE_DIR@/src/common/libmcommon.h @CMAKE_SOURCE_DIR@/src/asm/libmasm.h @CMAKE_SOURCE_DIR@/src/analyze/libmcore.h @CMAKE_SOURCE_DIR@/src/madras/libtroll/libmtroll.h @CMAKE_SOURCE_DIR@/src/madras/disass/libmdisass.h @CMAKE_SOURCE_DIR@/src/madras/patch/libmpatch.h @CMAKE_SOURCE_DIR@/src/madras/disass/fsmutils.h @CMAKE_SOURCE_DIR@/src/madras/libmadras.h @CMAKE_SOURCE_DIR@/src/maqao/libmmaqao.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
......@@ -34,8 +34,8 @@ FILE(GLOB
# ---- Specify paths to sub-directories
ADD_SUBDIRECTORY(${LUA_DIR})
ADD_SUBDIRECTORY(common)
ADD_SUBDIRECTORY(asm)
ADD_SUBDIRECTORY(madras)
ADD_SUBDIRECTORY(madrasAPI)
ADD_SUBDIRECTORY(analyze)
ADD_SUBDIRECTORY(plugins)
ADD_SUBDIRECTORY(maqao)
......@@ -135,6 +135,10 @@ typedef struct cntxt_s {
queue_t* current_CC; //queue of block. Each block is an entry of current CC
queue_t** bflags; //array of queue, one per block
queue_t* CC_to_remove; //array of queue to remove, one per CC
// Index on CCs to speedup lookup
hashtable_t* current_CC_ht; //hashtable of block. Each block is an entry of current CC
hashtable_t** bflags_ht; //array of hashtable, one per block
} cntxt_t;
/**
......@@ -196,13 +200,16 @@ static void _DFS_func(graph_t* node, void* context)
if (cntxt->bflags[b->id] == NULL) {
cntxt->bflags[b->id] = cntxt->current_CC;
cntxt->bflags_ht[b->id] = cntxt->current_CC_ht;
} else {
block_t *CC_entry = queue_peek_head(cntxt->current_CC);
//Means current block has been traversed twice
//Add current CC entry into the CC saved in cntxt->bflags[b->id]
if (queue_lookup(cntxt->bflags[b->id], &direct_equal,
queue_peek_head(cntxt->current_CC)) == NULL)
queue_add_tail(cntxt->bflags[b->id],
queue_peek_head(cntxt->current_CC));
if (hashtable_lookup(cntxt->bflags_ht[b->id], CC_entry) == NULL) {
queue_add_tail(cntxt->bflags[b->id], CC_entry);
hashtable_insert (cntxt->bflags_ht[b->id], CC_entry, CC_entry);
}
if (queue_lookup(cntxt->CC_to_remove, &direct_equal,
cntxt->current_CC) == NULL)
queue_add_head(cntxt->CC_to_remove, cntxt->current_CC);
......@@ -220,6 +227,7 @@ static void _DFS_main(graph_t* node, void* context)
cntxt_t* cntxt = (cntxt_t*) context;
block_t* b = node->data;
cntxt->bflags[b->id] = cntxt->current_CC;
cntxt->bflags_ht[b->id] = cntxt->current_CC_ht;
}
/**
......@@ -276,6 +284,9 @@ void lcore_analyze_connected_components(asmfile_t *asmfile)
// and add each traversed block in the CC. If a block belongs to several CC,
// these CC are merged into a single one with multiple entries
// Recycled structures
hashtable_t* marks = hashtable_new(&direct_hash, &direct_equal);
// Iterate over asmfile functions
FOREACH_INQUEUE(asmfile->functions, it_func) {
fct_t* func = GET_DATA_T(fct_t*, it_func);
......@@ -306,26 +317,33 @@ void lcore_analyze_connected_components(asmfile_t *asmfile)
cntxt_t cntxt;
cntxt.f = func;
cntxt.current_CC = NULL;
cntxt.current_CC_ht = NULL;
cntxt.bflags = lc_malloc0(
queue_length(func->blocks) * sizeof(queue_t*));
cntxt.bflags_ht = lc_malloc0(
queue_length(func->blocks) * sizeof(hashtable_t*));
cntxt.CC_to_remove = queue_new();
queue_t *CC_ht_to_remove = queue_new();
FOREACH_INQUEUE(func->components, it_cc) {
queue_t* cc = GET_DATA_T(queue_t*, it_cc);
block_t* b = queue_peek_head(cc);
cntxt.current_CC = cc;
cntxt.current_CC_ht = hashtable_new (&direct_hash, &direct_equal);
queue_add_tail (CC_ht_to_remove, cntxt.current_CC_ht);
FOREACH_INQUEUE(cc, it_bl) {
block_t *block = GET_DATA_T(block_t*, it_bl);
hashtable_insert (cntxt.current_CC_ht, block, block);
}
if (pos == 0) { // If first CC (the main one), just marks blocks
hashtable_t* marks = hashtable_new(&direct_hash, &direct_equal);
__traverse_CFG(b->cfg_node, &cntxt, marks, &_DFS_main);
hashtable_free(marks, NULL, NULL);
} else { // Else, check for if traversed block if it has already been traversed
// (during another CC analysis)
// If yes, merge current CC with the CC containing the block
hashtable_t* marks = hashtable_new(&direct_hash, &direct_equal);
__traverse_CFG(b->cfg_node, &cntxt, marks, &_DFS_func);
hashtable_free(marks, NULL, NULL);
}
hashtable_flush (marks, NULL, NULL);
pos++;
}
......@@ -336,8 +354,20 @@ void lcore_analyze_connected_components(asmfile_t *asmfile)
queue_free(cc, NULL);
}
queue_free(cntxt.CC_to_remove, NULL);
FOREACH_INQUEUE(CC_ht_to_remove, it_cc2) {
hashtable_t* cc_ht = GET_DATA_T(hashtable_t*, it_cc2);
hashtable_free(cc_ht, NULL, NULL);
}
queue_free(CC_ht_to_remove, NULL);
lc_free(cntxt.bflags);
lc_free(cntxt.bflags_ht);
}
}
// recycled structures
hashtable_free (marks, NULL, NULL);
asmfile->analyze_flag |= COM_ANALYZE;
}
......@@ -246,7 +246,7 @@ static void connect_nodes(graph_t *src, graph_t *dst, char *kind, int distance,
/* Fills data_dep fields */
data_dep->distance = distance;
insnext_t *ext = insn_get_ext(src->data);
intel_ooo_t *ext = insn_get_ext(src->data);
if (ext != NULL) {
data_dep->latency = min_latency ? ext->latency.min : ext->latency.max;
} else
......
......@@ -433,6 +433,67 @@ static void lcore_loop_find_orphan_CC(asmfile_t *asmfile)
}
}
int _fix_loop_entries (asmfile_t *asmfile)
{
int nb_added_entries = 0;
DBGMSG0("Fixing loops entries\n");
// Analyze all functions
FOREACH_INQUEUE(asmfile->functions, funciter)
{
fct_t* f = GET_DATA_T(fct_t*, funciter);
// Analyse all loops
FOREACH_INQUEUE(f->loops, loopiter)
{
loop_t* l = GET_DATA_T(loop_t*, loopiter);
// Analyze all blocks in the loop
FOREACH_INQUEUE(l->blocks, blockiter)
{
block_t* b = GET_DATA_T (block_t*, blockiter);
graph_t* cfg_b = block_get_CFG_node (b);
// For each predecessor in the CFG, check if it is in the loop
FOREACH_INLIST (cfg_b->in, initer)
{
edge_t* edge = GET_DATA_T (edge_t*, initer);
graph_t* cfg_pred = edge->from;
block_t* pred = cfg_pred->data;
char is_in_loop = FALSE;
FOREACH_INQUEUE(l->blocks, blockiter2)
{
block_t* b = GET_DATA_T (block_t*, blockiter2);
if (block_get_id (pred) == block_get_id (b))
{
is_in_loop = TRUE;
break;
}
}
// If yes, continue
if (is_in_loop == TRUE)
continue;
// Check if it is in the entry list
if (list_lookup(loop_get_entries (l), b) == NULL)
{
// If not, add it in the entry list
l->entries = list_add_before(l->entries, b);
nb_added_entries = nb_added_entries + 1;
}
}
}
}
}
return (nb_added_entries);
}
/*
* Launches the loop detection analysis for all functions
* \param asmfile a valid asmfile
......@@ -459,4 +520,10 @@ void lcore_analyze_loops(asmfile_t *asmfile)
asmfile->analyze_flag |= LOO_ANALYZE;
//Special case where an independent loop is not recognized as a CC
lcore_loop_find_orphan_CC(asmfile);
// fix loop entries
// In some cases, some loop entries are not detected.
// As some of our analysis require loops have only one entry, it is
// necessary than loop entries are corrects
_fix_loop_entries (asmfile);
}
......@@ -18,32 +18,31 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
##
CONFIGURE_FILE(madras_help.c.in ${CMAKE_CURRENT_SOURCE_DIR}/madras_help.c @ONLY)
FILE(GLOB_RECURSE
files_asm
la*.c
la*.cpp
)
foreach(ARCH ${ARCHS})
ADD_SUBDIRECTORY(${ARCH})
add_subdirectory(${ARCH})
endforeach(ARCH)
FILE(GLOB_RECURSE
file_libmdrs
libmadras.c
)
### --- Create the madras objects --- ###
# Create the madras object for static libraries/binaries #
ADD_LIBRARY(madras-obj-static OBJECT ${file_libmdrs})
SET_TARGET_PROPERTIES(madras-obj-static PROPERTIES COMPILE_FLAGS "${C_STATIC_FLAGS}")
### --- Create the masm objects --- ###
# Create the masm object for STATIC libraries/binaries #
ADD_LIBRARY(masm-obj-static OBJECT ${files_asm})
SET_TARGET_PROPERTIES(masm-obj-static PROPERTIES COMPILE_FLAGS "${C_STATIC_FLAGS}")
# Create the madras object for dynamic libraries/binaries #
ADD_LIBRARY(madras-obj-dyn OBJECT ${file_libmdrs})
SET_TARGET_PROPERTIES(madras-obj-dyn PROPERTIES COMPILE_FLAGS "${C_DYNAMIC_FLAGS}")
# Create the masm object for DYNAMIC libraries/binaries #
ADD_LIBRARY(masm-obj-dyn OBJECT ${files_asm})
SET_TARGET_PROPERTIES(masm-obj-dyn PROPERTIES COMPILE_FLAGS "${C_DYNAMIC_FLAGS}")
IF (IS_STDCXX)
SET_TARGET_PROPERTIES (masm-obj-static PROPERTIES COMPILE_DEFINITIONS "IS_STDCXX")
SET_TARGET_PROPERTIES (masm-obj-dyn PROPERTIES COMPILE_DEFINITIONS "IS_STDCXX")
MESSAGE ("-- stdc++ available")
ENDIF (IS_STDCXX)
### --- Install headers --- ###
FILE(COPY libmadras.h DESTINATION ${INCLUDE_OUTPUT_PATH})
### --- Install the headers --- ###
FILE(COPY libmasm.h DESTINATION ${INCLUDE_OUTPUT_PATH})
### --- For cleaning files generated by cmake --- ###
ADD_CUSTOM_TARGET(distclean_madrasAPI
COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_SOURCE_DIR}/madras_help.c
)
##
# Copyright (C) 2004 - 2016 Université de Versailles Saint-Quentin-en-Yvelines (UVSQ)
#
# This file is part of MAQAO.
#
# MAQAO is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
##
SET (SELECTED_ARCH k1om)
### ===========================================================================
### --- Create the march objects --- ###
# List the source files #
SET (file_arch ${CMAKE_CURRENT_SOURCE_DIR}/${SELECTED_ARCH}_arch.c
${CMAKE_CURRENT_SOURCE_DIR}/${SELECTED_ARCH}_implicit_reg.c)
# Create the march object for STATIC libraries/binaries #
ADD_LIBRARY(march${SELECTED_ARCH}-obj-static OBJECT ${file_arch})
SET_TARGET_PROPERTIES(march${SELECTED_ARCH}-obj-static PROPERTIES COMPILE_FLAGS "${C_STATIC_FLAGS}")
IF (is_WINDOWS)
# Create the march object for DYNAMIC libraries/binaries #
ADD_LIBRARY(march${SELECTED_ARCH}-obj-dyn OBJECT ${file_arch})
SET_TARGET_PROPERTIES(march${SELECTED_ARCH}-obj-dyn PROPERTIES COMPILE_FLAGS "${C_DYNAMIC_FLAGS}")
ENDIF ()
### ===========================================================================
### --- Create the mext objects --- ###
# List the source files #
SET (file_ext ${CMAKE_CURRENT_SOURCE_DIR}/${SELECTED_ARCH}_ext.c)
# Create the mext object for STATIC libraries/binaries #
ADD_LIBRARY(mext${SELECTED_ARCH}-obj-static OBJECT ${file_ext})
SET_TARGET_PROPERTIES(mext${SELECTED_ARCH}-obj-static PROPERTIES COMPILE_FLAGS "${C_STATIC_FLAGS}")
IF (is_WINDOWS)
# Create the mext object for DYNAMIC libraries/binaries #
ADD_LIBRARY(mext${SELECTED_ARCH}-obj-dyn OBJECT ${file_ext})
SET_TARGET_PROPERTIES(mext${SELECTED_ARCH}-obj-dyn PROPERTIES COMPILE_FLAGS "${C_DYNAMIC_FLAGS}")
ENDIF ()
### --- Install the headers --- ###
FILE(COPY ${SELECTED_ARCH}_arch.h DESTINATION ${INCLUDE_OUTPUT_PATH})
......@@ -455,7 +455,27 @@ extern insn_t* k1om_insn_parse(char* strinsn);
* */
extern queue_t* k1om_insnlist_parse(char* insn_list);
enum k1om_flag { F_OF, F_CF, F_PF, F_SF, F_ZF, F_AF};
///////////////////////////////////////////////////////////////////////////////
// Operand //
///////////////////////////////////////////////////////////////////////////////
/*
* Parses an operand from a string representation of an instruction, based on a given architecture
* \param strinsn The string containing the representation of the instruction.
* \param pos Pointer to the index into the string at which the parsing starts. Will be updated to contain the
* index at which the operand ends (operand separator or end of string)
* \return The parsed operand, or NULL if the parsing failed
* */
extern oprnd_t* k1om_oprnd_parse(char* strinsn, int *pos);
enum k1om_flag {
F_OF,
F_CF,
F_PF,
F_SF,
F_ZF,
F_AF
};
int k1om_insn_altered_flags(insn_t *in, uint8_t *read, uint8_t *set, uint8_t *cleared, uint8_t * def, uint8_t *undef);
......
......@@ -220,6 +220,46 @@ graph_t* block_get_CFG_node(block_t* b)
return (b != NULL) ? b->cfg_node : PTR_ERROR;
}
/*
* Returns predecessors (in the CFG) of a block
* \param b a block
* \return queue of blocks or PTR_ERROR if no CFG node
*/
queue_t * block_get_predecessors(block_t* b)
{
graph_t *CFG_node = block_get_CFG_node (b);
if (CFG_node == NULL) return PTR_ERROR;
queue_t *new = queue_new();
FOREACH_INLIST(CFG_node->in, iter) {
block_t *block = GET_DATA_T (edge_t *, iter)->from->data;
queue_add_tail (new, block);
}
return new;
}
/*
* Returns successors (in the CFG) of a block
* \param b a block
* \return queue of blocks or PTR_ERROR if no CFG node
*/
queue_t * block_get_successors(block_t* b)
{
graph_t *CFG_node = block_get_CFG_node (b);
if (CFG_node == NULL) return PTR_ERROR;
queue_t *new = queue_new();
FOREACH_INLIST(CFG_node->out, iter) {
block_t *block = GET_DATA_T (edge_t *, iter)->to->data;
queue_add_tail (new, block);
}
return new;
}
/*
* Retrieves the block domination node
* \param b a block
......@@ -638,6 +678,75 @@ void block_get_src_lines (block_t *block, unsigned *min, unsigned *max)
}
}
/*
* Returns source regions for a set of blocks as a queue of strings.
* Source regions are formatted as "<file>: <start_line>-<end_line>"
* \param blocks queue of blocks
* \return queue of strings
*/
queue_t *blocks_get_src_regions (queue_t *blocks) {
queue_t *ret = queue_new();
hashtable_t *index = hashtable_new (&str_hash, &str_equal);
FOREACH_INQUEUE(blocks, it_b) {
block_t *block = GET_DATA_T(block_t *, it_b);
FOREACH_INSN_INBLOCK(block, iti) {
insn_t *insn = GET_DATA_T(insn_t*, iti);
char *file_path = insn_get_src_file (insn);
if (file_path == NULL) continue;
unsigned src_line = insn_get_src_line (insn);
if (src_line == 0) continue;
list_t *src_lines = hashtable_lookup (index, file_path);
if (src_lines == NULL) {
src_lines = list_new ((void *) (unsigned long) src_line);
hashtable_insert (index, file_path, src_lines);
} else {
src_lines = list_add_after (src_lines, (void *) (unsigned long) src_line);
}
}
}
FOREACH_INHASHTABLE(index,it_hn) {
char *src_file = GET_KEY(char *, it_hn);
list_t *src_lines = GET_DATA_T(list_t *, it_hn);
int min = -1, max = -1;
FOREACH_INLIST (src_lines, it_line) {
unsigned line = GET_DATA_T(unsigned long, it_line);
if (min == -1 || min > line) min = line;
if (max == -1 || max < line) max = line;
}
list_free (src_lines, NULL);
char *str = malloc (strlen (src_file)+20);
lc_sprintf (str, strlen (src_file)+20, "%s: %u-%u", src_file, min, max);
queue_add_tail (ret, str);
}
hashtable_free (index, NULL, NULL);
return ret;
}
/*
* Returns source regions for a block
* \see blocks_get_src_regions
*/
queue_t *block_get_src_regions (block_t *block) {
queue_t *blocks = queue_new ();
queue_add_tail (blocks, block);
queue_t *ret = blocks_get_src_regions (blocks);
queue_free (blocks, NULL);
return ret;
}
/*
* Sets a block unique id
* \param b a block
......
......@@ -314,6 +314,71 @@ int loop_get_depth(loop_t *loop)
return _rec_depth(loop, 0);
}
/*
* Returns backedges of a loop
* A backedge E for the loop L is such as E->to is an entry block for L and E->from belongs to L
* \param loop a loop
* \return queue of CFG edges
*/
queue_t *loop_get_backedges (loop_t *loop)
{
queue_t *new = queue_new();
// For each entry block
FOREACH_INLIST (loop_get_entries (loop), itb) {
block_t *block = GET_DATA_T (block_t*, itb);
// For each predecessor (incoming edge to the CFG node)
graph_t *CFG_node = block_get_CFG_node (block);
FOREACH_INLIST (CFG_node ? CFG_node->in : NULL, ite) {
edge_t *edge = GET_DATA_T (edge_t *, ite);
block_t *pred_block = edge->from->data;
loop_t *pred_loop = block_get_loop (pred_block);
if (loop_get_id (pred_loop) == loop_get_id (loop))
queue_add_tail (new, edge);
}
}
return new;
}
/*
* Returns backedge instructions of a loop (instructions branching to same loop)
* \param loop a loop
* \return queue of instructions
*/
queue_t *loop_get_backedge_insns (loop_t *loop)
{
queue_t *new = queue_new();
// For each backedge
queue_t *backedges = loop_get_backedges (loop);
FOREACH_INQUEUE (backedges, ite) {
// Insert to queue last instruction of the related predecessor block
edge_t *edge = GET_DATA_T (edge_t *, ite);
block_t *pred = edge->from->data;
queue_add_tail (new, block_get_last_insn (pred));
}
queue_free (backedges, NULL);
return new;
}
/*
* Returns the first backedge instruction of a loop
*/
static insn_t *loop_get_first_backedge_insn (loop_t *loop)
{
queue_t *backedge_insns = loop_get_backedge_insns (loop);
insn_t *first_insn = queue_peek_head (backedge_insns);
queue_free (backedge_insns, NULL);