Project Stage 1
In this project, I set out to create a custom GCC pass that analyzed GIMPLE files by iterating through every function, counting the basic blocks, and tallying the number of GIMPLE statements. I successfully integrated this pass into the GCC build system and tested it on a simple C program. Here’s how I did it.
1. Writing the Pass Code
I began by writing the pass code in C++ and saved it in a file named tree-my-new-pass.cc within the gcc subdirectory of my GCC source. My pass, which I named "my_new_pass", was designed to run during the GIMPLE phase. The code looked like this:
#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" namespace { const pass_data my_new_pass_data = { GIMPLE_PASS, /* type */ "my_new_pass", /* name - determines the dump file suffix (e.g., .my_new_pass) */ OPTGROUP_NONE, /* optinfo_flags */ TV_TREE_OPS, /* tv_id */ 0, 0, 0, 0 /* properties_required, properties_provided, properties_destroyed, todo_flags */ }; class my_new_pass : public gimple_opt_pass { public: my_new_pass(gcc::context *ctxt) : gimple_opt_pass(my_new_pass_data, ctxt) {} bool gate(function *fun) override { return true; // I ensured the pass always ran. } unsigned int execute(function *fun) override { fprintf(stderr, "Processing function: %s\n", function_name(fun)); int basic_block_count = 0; basic_block bb; FOR_EACH_BB_FN(bb, fun) { basic_block_count++; } fprintf(stderr, "Number of basic blocks: %d\n", basic_block_count); int gimple_stmt_count = 0; FOR_EACH_BB_FN(bb, fun) { for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { gimple_stmt_count++; } } fprintf(stderr, "Number of GIMPLE statements: %d\n", gimple_stmt_count); return 0; } }; gimple_opt_pass *make_my_new_pass(gcc::context *ctxt) { return new my_new_pass(ctxt); } }
command:
cd ~/gcc-project/gcc-source/gcc
nano tree-my-new-pass.cc
B. Declaring the Pass in tree-pass.h
Next, I opened tree-pass.h
in the same directory and added the following extern declaration near other pass creation functions:
extern gimple_opt_pass *make_my_new_pass (gcc::context *);
C. Inserting the Pass into passes.def
I then opened passes.def to insert my pass into the pass manager’s pipeline. I found a suitable spot near other passes and added:
NEXT_PASS (my_new_pass);
D. Updating the Build System
I also edited Makefile.in in the gcc subdirectory and located the OBJS list. I appended my new pass’s object file by adding:
tree-my-new-pass.o
E. Regenerating the Makefile and Building GCC
With my modifications in place, I switched to my build directory (located at ~/gcc-project/gcc-build):
ran the configure script with my chosen installation prefix:
../gcc-source/configure --prefix=$HOME/my-gcc-install
After configuration, I built GCC using:
make -j 8
F. Testing the New Pass
Install GCC
I installed my custom GCC by running:
make install
Compile a Test Program with Dump Flags:
~/my-gcc-install/bin/gcc -O2 -fdump-tree-all test.c -o test
My custom GCC pass did not work as expected because it appears that it was not properly integrated into GCC's pass pipeline. Despite ensuring that the gate method always returned true and correctly declaring the pass in both tree-pass.h and passes.def, the pass did not trigger during compilation. This could be due to subtle issues in the macro expansion or an incorrect placement of the pass within the build system. Additionally, the dump file generation might not have been enabled with the necessary flags, so the diagnostic output was never written to disk. Ultimately, the combination of these factors prevented the pass from executing as intended during the compilation process.
Comments
Post a Comment