Project Stage 1 - Creating GCC Pass

 Project Stage 1 

Creating GCC Pass and Building GCC


In this blog, I will walk you through the steps I followed to create a simple GCC pass. 

STEP 0: I accessed a SPO600 Server.
STEP 1: I used the command ls to show successful build from files created in Lab 4. I have three directories, each serving a different purpose. File called gcc was cloned from a git repository, file called gcc-build-001 is a directory dedicated for building and gcc-test-001 is a directory to test.

gcc  gcc-build-001  gcc-test-001  password.txt  spo600



STEP 2: I changed directory to ~/gcc/gcc to create my "tree-count-pass.cc". My gcc pass analyzes the compiled program by iterating through functions, counting their basic blocks and GIMPLE statements, and logging this data for debugging and analysis. Although this code can be improved to be functional, this has displayed logic that could be useful for a dummy pass. Down below is the code for my pass:


    #include "gcc-plugin.h"

    #include "plugin-version.h"

    #include "pass_manager.h"

    #include "tree-pass.h"

    #include "context.h"

    #include "diagnostic.h"

    #include "gimple.h"

    #include "gimple-iterator.h"

    #include "basic-block.h"

    #include "config.h"

    #include "system.h"

    #include "coretypes.h"

    #include "tree.h"

    #include "context.h"


    int plugin_is_GPL_compatible;


    namespace {


    const pass_data count_pass_data = {

        GIMPLE_PASS,      

        "count_pass",    

        OPTGROUP_NONE,    

        TV_NONE,          

        PROP_gimple_any,  

        0,                

        0,                

        0,               

    };


    class count_pass : public simple_ipa_opt_pass {

    public:

        count_pass(gcc::context *ctxt) : simple_ipa_opt_pass(count_pass_data, ctxt)     {}


        bool gate(function *fun) override {

            return true; 

        }


        unsigned int execute(function *fun) override {

            if (dump_file) {

                fprintf(dump_file, "\nAnalyzing function: %s\n", function_name(fun));

            

                int basic_block_count = 0;

                int gimple_stmt_count = 0;

            

                basic_block bb;

                FOR_EACH_BB_FN(bb, fun) {

                    basic_block_count++;

                

                    for (gimple_stmt_iterator gsi = gsi_start_bb(bb);     !gsi_end_p(gsi); gsi_next(&gsi)) { 

                        gimple_stmt_count++;

                    }

                }

            

                fprintf(dump_file, "Basic Blocks: %d\n", basic_block_count);

                fprintf(dump_file, "GIMPLE Statements: %d\n", gimple_stmt_count);

            }

            return 0;

        }

    };


    


    extern "C" {


    gcc::context *global_context;


    static struct plugin_info count_plugin_info = {

        .version = "1.0",

        .help = "Counts functions, basic blocks, and GIMPLE statements."

    };


    int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version     *version) {

        if (!plugin_default_version_check(version, &gcc_version)) {

            error_at (UNKNOWN_LOCATION, "GCC version mismatch"); 

            return 1;

        }

    

        register_pass_info pass_info;

        pass_info.pass = new count_pass(global_context);

        pass_info.reference_pass_name = "gimple";

        pass_info.ref_pass_instance_number = 1;

        pass_info.pos_op = PASS_POS_INSERT_AFTER;

    

        register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr,     &pass_info);

        register_callback(plugin_info->base_name, PLUGIN_INFO, nullptr,     &count_plugin_info);

    

        return 0;

    }

       extern "C" gimple_opt_pass *make_pass_count(gcc::context *ctxt) {

         return new count_pass(ctxt);

       }

    }



STEP 3: Ensuring make_pass_count is recognized by inserting a line of code in tree-pass.h. Since I had added a line of code extern gimple_opt_pass *make_pass_count(gcc:: *);, I also needed to update passes.def by adding this line NEXT_PASS(make_pass_count); - by doing so, I registered make_pass_count as a pass.


NOTE: I had to create an instance of my pass to properly link into GCC's pass manager by having function added in tree-count-pass. 


extern "C" gimple_opt_pass *make_pass_count(gcc::context *ctxt) { 

    return new count_pass(ctxt); 

}


STEP 4: Building system changes by adding tree-count-pass under the OBJS list in the Makefile.in. I also ensured to include my pass as a header file into tree-pass.h.

STEP 5: I ran the command make -j to compile efficiently by utilizing CPU cores. By running this, I found several issues that helped me understand what went wrong with my pass and how I made it recognizable to other files. 

ISSUES & INVESTIGATION:


1. Missing config.h: I realized that creating my pass in the gcc/gcc directory, I was not able to link it to "config.h" which was found in gcc-build-001. I navigated through all directories to manually find "config.h". After realizing "config.h" is not in the same directory as "plugin.h", I had to modify compilation command to include the path to "config.h". 

2. NEXT_PASS();: NEXT_PASS was not properly declared in "tree-pass.h" and could be in the wrong place. I was presented by this issue after using make command. There were two errors related to this, which required me to add a function that returns gcc::context *ctxt. I also needed to find an appropriate location in passes.def that aligned with this logic. 

Even though these two issues have resulted in my pass to fail or be unsuccessful,I have not given up on my investigation and am still working on a fix by analyzing the different directories and exploring how the files are interconnected.






Comments

Popular posts from this blog

BATCH 3 | Project Stage 2, Part 3 - Cloned Functions Comparison and Reflection

BATCH 4 | Clone-Prune Analysis Code Pass On Both Architectures

BATCH 3 | Project Stage 2, Part 1 - Clone-Pruning Analysis Pass