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:



It works fine. Both main function, testfunciton1 and testfunciton2's diagnosis are shown. It counted number of basic blocks and gimple statement correctly.
--------------------------------------------------------------------------------------------------------

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

Popular posts from this blog

SPO600 Project Stage 1 (Pt.1) - Create a GCC Pass

SPO600 Project Stage 2 (Pt.1) - GCC pass locating clone function

SPO600 Project Stage 2 (Pt.2) - GCC pass locating clone function -modified version