SPO600 Project Stage 2 (Pt.2) - GCC pass locating clone function -modified version
In project stage 1, I created a GCC pass in both x86-64 server and AARCH64 server to print the functions' name and counting number of block. In stage 2 pt.1, I was trying to modify the code to locate the clone but in vain.
I sought advice from my professor, Chris Tyler and note that for the default version of the clone, the node->name() function will return function name without any .variant, i.e. without .default . That's why the previous version does not work. As a result, I revised the code accordingly and it works now.
revised code:
/* Test Pass
Jeff Yau, Seneca Polytechnic College
Student ID :142466234
Modelled on tree-nrv.cc and tree-ctyler.cc by Chris Tyler, Seneca Polytechnic College, 2024-11
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/>. */
#include <map>
#include <string>
#include <stdlib.h>
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "tree-pass.h"
#include "ssa.h"
#include "tree-pretty-print.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "internal-fn.h"
#include "gimple-pretty-print.h"
#include "cgraph.h"
#include "gimple-ssa.h"
#include "attribs.h"
#include "pretty-print.h"
#include "tree-inline.h"
#include "intl.h"
#include "function.h"
#include "basic-block.h"
namespace {
const pass_data pass_data_jeff =
{
GIMPLE_PASS, /* type */
"jeff", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_jeff : public gimple_opt_pass
{
public:
pass_jeff (gcc::context *ctxt)
: gimple_opt_pass (pass_data_jeff, ctxt)
{}
/* opt_pass methods: */
bool gate (function *) final override { return 1; }
unsigned int execute (function *) final override;
}; // class pass_jeff
unsigned int pass_jeff::execute (function *)
{
struct cgraph_node *node;
std::map<std::string, cgraph_node*> variant_map;
int counter = 0;
struct cgraph_node *variant1_node = nullptr;
struct cgraph_node *variant2_node = nullptr;
std::string base_function;
FOR_EACH_FUNCTION (node)
{
if (!dump_file)
continue;
const char *fname = node->name();
std::string name(fname);
if (name.find(".resolver") != std::string::npos)
continue;
size_t dot_pos = name.find(".");
std::string base;
if (dot_pos == std::string::npos)
base = name;
else{
base = name.substr(0, dot_pos);
}
f (variant_map.find(base) != variant_map.end())
{
variant1_node = variant_map[base];
variant2_node = node;
base_function = base;
fprintf(dump_file, "---------------------------clone found for function '%s'---------------\n",base.c_str());
fprintf(dump_file, " Variant 1: %s\n", variant1_node->name());
fprintf(dump_file, " Variant 2: %s\n", variant2_node->name());
break;
}
else
{
variant_map[base] = node;
}
function *fun = node->get_fun();
if (!fun)
{
continue;
}
}
return 0;
}
} // anon namespace
gimple_opt_pass *
make_pass_jeff (gcc::context *ctxt)
{
return new pass_jeff (ctxt);
}
It can locate the clone now. However, since the execute run the once for every function and I used FOR_EACH_FUNCTION inside the execute, it turns out run n*n time in total when there are n functions. I would like to remove the duplicate works so I re-wrote it again.
This is the modified version.
/* Test Pass
Jeff Yau, Seneca Polytechnic College
Student ID :142466234
Modelled on tree-nrv.cc and tree-ctyler.cc by Chris Tyler, Seneca Polytechnic College, 2024-11
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/>. */
#include <map>
#include <string>
#include <stdlib.h>
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "tree-pass.h"
#include "ssa.h"
#include "tree-pretty-print.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "internal-fn.h"
#include "gimple-pretty-print.h"
#include "cgraph.h"
#include "gimple-ssa.h"
#include "attribs.h"
#include "pretty-print.h"
#include "tree-inline.h"
#include "intl.h"
#include "function.h"
#include "basic-block.h"
namespace {
const pass_data pass_data_jeff =
{
GIMPLE_PASS, /* type */
"jeff", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_jeff : public gimple_opt_pass
{
public:
pass_jeff (gcc::context *ctxt)
: gimple_opt_pass (pass_data_jeff, ctxt)
{}
/* opt_pass methods: */
bool gate (function *) final override { return 1; }
unsigned int execute (function *) final override;
unsigned int execute (function *) final override;
}; // class pass_jeff
unsigned int pass_jeff::execute (function * func)
{
static std::map<std::string, cgraph_node*> variant_map;
struct cgraph_node *node = cgraph_node::get(func->decl);
struct cgraph_node *variant1_node = nullptr;
struct cgraph_node *variant2_node = nullptr;
std::string base_function;
if (!dump_file)
return 0;
const char *fname = node->name();
std::string name(fname);
if (name.find(".resolver") != std::string::npos)
return 0;
size_t dot_pos = name.find(".");
std::string base;
if (dot_pos == std::string::npos)
base = name;
else{
base = name.substr(0, dot_pos);
}
if (variant_map.find(base) != variant_map.end())
{
variant1_node = variant_map[base];
variant2_node = node;
base_function = base;
fprintf(dump_file, "---------------------------clone found for function '%s'---------------\n",base.c_str());
fprintf(dump_file, " Variant 1: %s\n", variant1_node->name());
fprintf(dump_file, " Variant 2: %s\n", variant2_node->name());
return 0;
}
else
{
variant_map[base] = node;
return 0;
}
function *fun = node->get_fun();
if (!fun)
{
return 0;
}
return 0;
}
} // anon namespace
gimple_opt_pass *
make_pass_jeff (gcc::context *ctxt)
{
return new pass_jeff (ctxt);
}
Now the output can correctly show the clone located.
In part 3, I will modify the code to compare two clone functions.
Comments
Post a Comment