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

Clone-Prune Analysis Code Pass On Both Architectures 

Pass Works On x86_64 and aarch64 Architectures


In this post, I’ll be sharing screenshots of the pass running on the x86_64 architecture. Previously, I focused only on the results from the aarch64 architecture in earlier blog entries. To start, you see a screenshot of my pass successfully built without fatal errors:


The steps I took to implement pass on architecture:

1. Created a Clone-Prune Analysis Code Pass on x86_64 architecture.
2. Declared pass factory under tree-pass.h by adding this: opt_pass *make_count_pass(gcc::context *);
3. Registered the pass in passes.def by including this: NEXT_PASS (make_count_pass(g));
4. Rebuilt the gcc by using make command: time make -j $(($(nproc)*3/2)) |& tee build.log

Final Code Used:

#include "config.h"

#include "system.h"

#include "coretypes.h"

#include "backend.h"

#include "tree.h"

#include "basic-block.h"

#include "function.h"

#include "gimple.h"

#include "gimple-iterator.h"

#include "tree-pass.h"

#include "context.h"


#include <string.h>       

#include <unordered_map>  

#include <string>         

#include <cstdio>        


namespace {


const pass_data count_pass_data = {

    GIMPLE_PASS,

    "count",             

    OPTGROUP_NONE,

    TV_NONE,

    PROP_gimple_any,     

    0, 0, 0, 0

};


struct clone_signature {

    int bb_count;

    int gimple_count;

};


static std::unordered_map<std::string, clone_signature> clone_map;


bool is_internal_function(const char *name) {

    return (strstr(name, "<anonymous>") || strstr(name, "tree_") ||

            strstr(name, "va_gc::") || strstr(name, "pass_") ||

            strstr(name, "optimize_") || strstr(name, "dump_"));

}


bool is_user_function(const char *name) {

    return (strstr(name, "scale_samples") || strstr(name, "prune") || strstr(name, "noprune"));

}


class count_pass : public gimple_opt_pass {

public:

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


    bool gate(function *fun) override {

        (void)fun;

        return true;

    }


    unsigned int execute(function *fun) override {

        const char *full_name = function_name(fun);

        if (!full_name) return 0;


        if (is_internal_function(full_name)) return 0;

        if (!is_user_function(full_name)) return 0;


        char base_name[256] = "";

        const char *dot = strchr(full_name, '.');

        if (dot) {

            size_t len = dot - full_name;

            if (len >= sizeof(base_name)) len = sizeof(base_name) - 1;

            strncpy(base_name, full_name, len);

            base_name[len] = '\0';

        } else {

            strncpy(base_name, full_name, sizeof(base_name) - 1);

            base_name[sizeof(base_name) - 1] = '\0';

        }


        int bb_count = 0, gimple_count = 0;

        basic_block bb;

        FOR_ALL_BB_FN(bb, fun) {

            gimple_stmt_iterator gsi;

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

                gimple_count++;

            bb_count++;

        }

        bool is_resolver = strstr(full_name, "resolver") != nullptr;

        if (!is_resolver) {

            std::string base_str(base_name);

            auto it = clone_map.find(base_str);

            if (it == clone_map.end()) {

                clone_map[base_str] = {bb_count, gimple_count};

            } else {

                const clone_signature &stored = it->second;

                const char *result = (stored.bb_count == bb_count && stored.gimple_count == gimple_count)

                    ? "PRUNE" : "NOPRUNE";


                if (dump_file)

                    fprintf(dump_file, "%s: %s\n", result, base_name);

                else

                    fprintf(stderr, "%s: %s\n", result, base_name);


                clone_map.erase(it);

            }

        }


        char filename[256];

        snprintf(filename, sizeof(filename), "%s.count", full_name);

        FILE *f = fopen(filename, "w");

        if (f) {

            fprintf(f, "Function: %s\n", full_name);

            fprintf(f, "Basic Blocks: %d\n", bb_count);

            fprintf(f, "GIMPLE Statements: %d\n", gimple_count);

            fclose(f);

        } else {

            if (dump_file)

                fprintf(dump_file, "Failed to write to %s\n", filename);

            else

                fprintf(stderr, "Failed to write to %s\n", filename);

        }


        if (dump_file)

            fprintf(dump_file, "Function %s: %d BBs, %d GIMPLE stmts\n",

                    full_name, bb_count, gimple_count);

        else

            fprintf(stderr, "Function %s: %d BBs, %d GIMPLE stmts\n",

                    full_name, bb_count, gimple_count);

        return 0;

    }

};



opt_pass *make_count_pass(gcc::context *ctxt) {

    return new count_pass(ctxt);

}


Comments

Popular posts from this blog

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

Lab 01 - Experiments, Calculating Performance and Modifying Code

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