Project stage-3 (testing & reflection)

Introduction

In this blog, we will test and validate the prune-clones I made last time. In this process, I will explain how I modified the files passes.cc and passes.def, and why I made prune_clones.h separately because prune_clones.cc was not enough.

passes.cc and passes.def modification process
1. Modify passes.cc

The passes.cc file defines and implements several optimization passes for GCC, where you might want to add a prune-clones pass:

  • Define and implement prune_clones related classes and functions.
  • Clearly define what role this path plays in the overall optimization process of the compiler.
For example, passes.cc needs to declare a prune_clones class and add code to register it with pass_manager. passes.cc 's main task is to initialize and manage each optimization pass.


// passes.cc


#include "gcc.h"

    ...

#include "prune_clones.h"


// function generating prune_clones pass

gimple_opt_pass * make_pass_prune_clones(gcc::context *ctxt)

 {

   return new pass_prune_clones(ctxt);

 }


2.Modifying passes.def

The passes.def file defines the optimization passes used by GCC. You can modify this file to add a prune_clones pass. Passes.def usually defines the name and order of the passes.

// passes.def


#include "gcc.h"

    ...

NEXT_PASS(pass_prune_clones);

    ...



Why I added prune_clones.h 


prune_clones.cc is usually a file that contains the implementation of the pass. However, it may be desirable to separate the definition and implementation of the pass, as prune_clones passes may be required in other parts as well. This helps to increase the modularity and reusability of the code. In this project, prune_clones feature needs to be added in Makefile and passes files.


 - prune_clones.cc

In the last project, I supplemented the function of the prune-clone function a little more. 'prune_clones' iterates through the cloned versions of a function represented by nodes, compares each clone to the default version, and removes any duplicates it finds. 


unsigned int prune_clones(cgraph_node *node);


// Constructor definition for pass_prune_clones

pass_prune_clones::pass_prune_clones(gcc::context *ctxt)

    : gimple_opt_pass(pass_data_prune_clones, ctxt) {}


unsigned int pass_prune_clones::execute(function *fun) {

    for (cgraph_node *node = cgraph_nodes; node; node = node->next) {

        if (node->simd_clone) {

            printf("Found SIMD clones for function: %s\n", cgraph_node_name(node));

            prune_clones(node);

        }

    }

    return 0;

}


namespace {

// Define the pass data structure

const pass_data pass_data_prune_clones = {

    GIMPLE_PASS,         // type

    "prune_clones", // name

    OPTGROUP_NONE, // optinfo_flags

    TV_NONE,             // tv_id

    PROP_gimple_any,     // PROP_gimple

    0,                   // properties_provided

    0,                   // properties_destroyed

    0,                   // todo_flags_start

    0                    // todo_flags_finish

};


gimple_opt_pass *make_pass_prune_clones(gcc::context *ctxt) {

    return new pass_prune_clones(ctxt);

}

} // namespace


// Function to prune duplicate clones

unsigned int prune_clones(cgraph_node *node) {

    printf("Pruning clones for function: %s\n", cgraph_node_name(node));

    cgraph_function_version_info *default_fvi = node->function_version();

    cgraph_function_version_info *curr_fvi = node->function_version();

    cgraph_function_version_info *prev_fvi = nullptr;


  • default_fvi is initialized to point to the default version of the function associated with node.
  • curr_fvi is also initialized to the default version initially.
  • prev_fvi is set to nullptr to keep track of the previous version as we iterate through the list of versions.
  •     while (curr_fvi->next) {

            prev_fvi = curr_fvi;

            // Get the next clone

            curr_fvi = curr_fvi->next;

            // Compare to the default node

            // Prune if duplicate

            if(curr_fvi->clone_of == default_fvi->clone_of) {

                printf("Removing duplicate clone: %s\n", cgraph_node_name(curr_fvi->clone_of));

                prev_fvi->next = curr_fvi->next;

                delete curr_fvi;

            }

        }


        return 0;

    }

    - This while loop iterates through the list of function versions (curr_fvi) starting from the default version (default_fvi). It stops when there are no more clones (curr_fvi->next is nullptr).


    - Inside the loop, it checks if the current function version (curr_fvi) is a duplicate clone of the default version (default_fvi). If they are clones of the same function (clone_of refers to the original function node):

    • It adjusts the linked list to skip over curr_fvi (prev_fvi-> next = curr_fvi-> next).
    • It deletes the current function version (delete curr_fvi), freeing memory associated with the duplicate clone.


     - prune_clones.h


    #ifndef PRUNE_CLONES_H

    #define PRUNE_CLONES_H


    #include "context.h"

    #include "tree-pass.h"

    #include "cgraph.h"


    class pass_prune_clones : public gimaple_opt_pass {

    public:

        pass_prune_clones(gcc::context *ctxt);


        unsigned int execute(function *fun) final override;

    };


    gimple_opt_pass *make_pass_prune_clones(gcc::context *ctxt);

    unsigned int prune_clones(cgraph_node *node);


    #endif // PRUNE_CLONES_H


    Reflection
    Although I failed to build the prune-clone functionality above after numerous trials and errors. I think the error is probably due to multiple dependencies on pass files and makefile, but it was my lack of ability to know how each file relates one by one. 
    I encountered many difficulties while learning this subject, but I was able to learn and grow a lot along the way. As I went through the process of analyzing and modifying the structure of the code, I was able to gain a deep understanding of the internal behavior of the GCC. In addition, the experience of adding and managing optimization passes helped me hone important skills in software development.

    댓글

    이 블로그의 인기 게시물

    Lab 1 - Calculate performance & memory usage

    Project Stage - 1 GCC for AArch64