SPO600 2025 Winter Project - Stage 2: Updating tree-skim.cc and Verifying Dump File Output (part2)

To begin Stage 2 of my project, I started by updating my tree-skim.cc file to support scanning all functions in the compiled file. Here’s a summary of what I changed and how I tested it.


Original Version of tree-skim.cc

Initially, my execute() method only analyzed one function at a time and printed the number of basic blocks and GIMPLE statements per function. It didn’t iterate over all functions in the file.


Updated Version of tree-skim.cc

To scan all functions, I made the following updates:

Added #include "cgraph.h" to access the function graph

Used FOR_EACH_FUNCTION(node) inside the execute() method to list all functions in the program

Printed the function names to the dump_file for output


#include "config.h"


#include "system.h"

#include "coretypes.h"

#include "backend.h"

#include "tree-pass.h"

#include "pass_manager.h"

#include "context.h"

#include "diagnostic-core.h"

#include "tree.h"

#include "tree-core.h"

#include "basic-block.h"

#include "gimple.h"

#include "gimple-iterator.h"

#include "cgraph.h" 


namespace {


// Define pass metadata

const pass_data pass_data_skim = {

    GIMPLE_PASS,      /* type */

    "skim",           /* 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 */

};


// Custom GIMPLE pass class

class pass_skim : public gimple_opt_pass {

public:

    pass_skim(gcc::context *ctxt)

        : gimple_opt_pass(pass_data_skim, ctxt) {}


    bool gate(function *fun) final override {

        return fun != nullptr;

    }


    unsigned int execute(function *fun) final override;

};


// Execute function implementation

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

    const char* fname = function_name(fun);


    // Print current function info (just like before)

    printf("Function: %s\n", fname);


    int bb_count = 0;

    int gimple_stmt_count = 0;


    // Count BBs and GIMPLE statements for this function

    basic_block bb;

    FOR_EACH_BB_FN(bb, fun) {

        if (!bb) continue;

        bb_count++;


        int bb_gimple_count = 0;

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

            bb_gimple_count++;

        }


        gimple_stmt_count += bb_gimple_count;

    }


    printf("Basic blocks: %d\n", bb_count);

    printf("GIMPLE statements: %d\n\n", gimple_stmt_count);


    // Now scan ALL functions (Step 1)

    if (dump_file) {

        fprintf(dump_file, "=== Scanning all functions ===\n");


        struct cgraph_node *node;

        FOR_EACH_FUNCTION(node) {

            const char *fn_name = IDENTIFIER_POINTER(DECL_NAME(node->decl));

            fprintf(dump_file, "Function found: %s\n", fn_name);

        }


        fprintf(dump_file, "=== End of function scan ===\n\n");

    }


    return 0;

}


} // namespace


// Register pass

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

    return new pass_skim(ctxt);

}



Building the Pass

After updating the code, I recompiled the project from my build directory using:

cd ~/gcc-build-001 time make -j20 |& tee rebuild.log


Test Case Setup

1. Moved to the home directory:

cd ~

2. Created a simple test file named test.c:

int foo(int a) { return a * 2; } int main() { int x = foo(5); return x; }

3. Moved to the GCC build directory and compiled the test file with my custom pass:

cd ~/gcc-build-001/gcc ./xgcc -B. ~/test.c -O2 -fdump-tree-skimv


Issue: No .skim File Found

After compilation, I tried to locate the dump file with:

ls ~/test.c.*.skim cat ~/test.c.*.skim

But the system responded with:

No such file or directory


Fix Attempt: Set OPTGROUP_ALL

I suspected that the issue was due to the dump file not being activated. So, I updated the pass_data declaration like this:

const pass_data pass_data_skim = { GIMPLE_PASS, "skim", OPTGROUP_ALL, // previously OPTGROUP_NONE TV_NONE, PROP_cfg, 0, 0, 0, 0 };

After rebuilding, I still didn’t see the .skim file.


Debugging dump_file

To verify whether the dump_file was being activated, I added this snippet at the top of the execute() function:

if (dump_file == nullptr) { printf("dump_file is null — dump output not activated.\n"); } else { printf("dump_file is active.\n"); }

Then I rebuilt and recompiled again:

cd ~/gcc-build-001 make -j20 cd ~/gcc-build-001/gcc ./xgcc -B. ~/test.c -O2 -fdump-tree-skim

This time, I got the following terminal output:

So, the dump_file was active, meaning the pass was working!


Finding the Actual .skim File

I used this command to search for the actual location of the .skim file:

find ~ -name "*.skim"

That led me to this file:

/home/skim499/gcc-build-001/gcc/a-test.c.264t.skim

When I opened the file, it contained:


This confirmed that:

✅ The -fdump-tree-skim option worked

✅ My custom pass pass_skim was executed

dump_file was active

✅ The output was correctly saved into the .skim file


Notes on the Dump File Name

The prefix a- seems to be automatically generated by GCC in some builds

The number 264t indicates the internal pass number where my pass is located

The .skim extension matches my pass name, so the file was successfully generated


Conclusion

After going through this debugging process, I successfully confirmed that my GIMPLE pass scans all functions and outputs results to both the terminal and the .skim file. This sets the stage for Step 2, where I’ll group and compare cloned functions like foo.default and foo.resolver.


Comments

Popular posts from this blog

SPO600 2025 Winter Project - Stage 1: Create a Basic GCC Pass (part1)

SPO600 2025 Winter Project - Stage 2: GIMPLE Level Clone Analysis and Pruning (part4)

Lab 1 - 6502 Assembly Language