SPO600 Project Stage 1 (Pt.2) - Revise the GCC Pass
In part 1, I created a GCC pass in x86-64 server to print the functions' name. Now, I would like to revise the pass and increase it's functionality.
Revised GCC pass code:
/* Test Pass
Jeff Yau, Seneca Polytechnic College
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/>. */
//#define INCLUDE_MEMORY
#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"
//added headers
#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;
int counter = 0;
FOR_EACH_FUNCTION (node){
if (dump_file)
{
function *fun = node->get_fun();
if (!fun){continue;}
fprintf(dump_file, "Function %d's Name is '%s' \n", ++counter, node->name ());
int blockCounter = 0;
int gimple_sta_count = 0;
basic_block bb;
FOR_EACH_BB_FN(bb, fun){
blockCounter++;
for (gimple_stmt_iterator it = gsi_start_bb (bb); !gsi_end_p (it); gsi_next (&it)){
gimple_sta_count++;
}
}
fprintf(dump_file, "number of Basic Block is %d\n", blockCounter);
fprintf(dump_file, "number of gimple Statement is %d\n", gimple_sta_count);
}
}
if (dump_file){
fprintf(dump_file, "\n\n End diagnostics.\n");
}
return 0;
}
} // anon namespace
gimple_opt_pass *
make_pass_jeff (gcc::context *ctxt)
{
return new pass_jeff (ctxt);
}
To prevent the pass process the functions with no body, I add "node->get_fun()" to get the function body and a check statement" if (!fun){continue;}" to ensure if the function have body.
After re-make and install the gcc. Now, I use the updated gcc to compile a c file and observe the dumpfile
the C file:
#include <stdio.h> int main(){ printf("I am Jeff\n"); return 0; }
compile the C file and look at the dumpfile:
../gcc-test-003/bin/gcc -fdump-tree-jeff ../jeff.c -o output
Output:
It works perfectly.
-----------------------------------------------------------------
Let try the same pass in aarch64 server.
the C file:
#include <stdio.h> int main(){ printf("I am Jeff\n"); return 0; }
after rebuild the gcc:
compile the C file and look at the dumpfile:
../gcc-test-003/bin/gcc -fdump-tree-jeff ../jeff.c -o output
It also works well.
-------------------------------------------------------------------------------------------------------
Test a longer program - 1
the C file:
#include <stdio.h> int testfunction(){ printf("inside test function, statment1"); printf("inside test function, statment2"); printf("inside test function, statment3"); } int main(){ printf("I am Jeff\n"); printf("I want to test\n"); { printf("in main and inner block"); } return 0; }
compile the C file and look at the dumpfile:
../gcc-test-003/bin/gcc -fdump-tree-jeff ../test2.c -o test2 cat test2.c.265t.jeff
Output:
It works fine. Both main function and testfunciton's diagnosis are shown. It counted number of basic blocks and gimple statement correctly.
------------------------------------------------------------------------------------------------------
Test a even longer program - 2
the C file:
#include <stdio.h> int testfunction2(){ printf("inside test function2, statment1"); printf("inside test function2, statment2"); printf("inside test function2, statment3"); } int testfunction(){ printf("inside test function, statment1"); printf("inside test function, statment2"); printf("inside test function, statment3"); } int main(){ printf("I am Jeff\n"); printf("I want to test\n"); { printf("in main and inner block"); } return 0; }
compile the C file and look at the dumpfile:
../gcc-test-003/bin/gcc -fdump-tree-jeff ../test3.c -o test3 cat test3.c.265t.jeff
Output:
--------------------------------------------------------------------------------------------------------
Reflection:
Pass limitation:
First, my pass only works with GIMPLE intermediate representation. As a result, I must be placed in suitable position for GIMPLE (not too early/too late). This pass only observe the C program. Obviously, it does not modify or optimize the program. As mentioned above, it only describe the function which have function body. Also, it do not distinguish whether the function is called or not, but just proceed with every functions.
What I have learn:
In the project Stage 1, I have learnt the processes to modify the gcc. First, I learnt the structure of a pass so that I can create one. I learnt what are the critical files(passes.def, tree-pass.h, Makefile.in, Makefile, etc) and how to revise them if I want to add a new pass. I learn about GLIMPSE, GIMPLE and RTL. Since the documentation online is very limited, I spent so long time to make the pass work by try and error. One critical thing is that there are multiple errors when I update the Makefile.in file, remake and re-install. At first, I thought there is problem in the code of my pass. Then, I double check every critical files. I finally tried to delete the entire build and gcc-test-003 folder and it works perfectly finally. I feel great when it works.
Comments
Post a Comment