Stage 1 Completed
Project Stage 1 Completed!
For the first stage of my SPO600 project, I created a custom GCC pass that prints out the name of each function being compiled, along with the number of basic blocks and GIMPLE statements in that function. This gave me a deeper look into how the compiler breaks down high-level code during the compilation process.
Setting Up My Environment
I used the recommended three-directory setup:
~/git/gcc/ # GCC source directory
~/gcc-build-001/ # Build directory
~/gcc-test-001/ # Install/test directory
I followed the official GCC documentation to configure the build:
../git/gcc/configure --prefix=$HOME/gcc-test-001 --enable-languages=c --disable-bootstrap --disable-multilib
time make -j$(nproc) |& tee build.log
The build process took a while at first, but using make for incremental rebuilds really saved time later. I made sure to always build inside a screen session so I wouldn't lose progress if my SSH connection dropped.
Implementing My Pass
I added a new file called tree-my-pass.cc in the GCC source directory, and this is where all the logic lives. My pass is a GIMPLE pass and runs once per function. Here's what it does:
Prints the name of the function being compiled.
Counts how many basic blocks exist in that function.
Counts all the GIMPLE statements in those basic blocks.
These results are printed into the dump file when the compiler is run with -fdump-tree-my-pass.
To register the pass, I updated:
passes.def to register the pass.
tree-pass.h to declare the factory function.
Makefile.in to include the new .o file.
Here’s an example of what the output looks like:
Processing function: add
Number of basic blocks: 1
Number of GIMPLE statements: 1
Processing function: main
Number of basic blocks: 2
Number of GIMPLE statements: 4
Pretty cool to see how even a simple C function expands into multiple compiler-level operations!
Challenges and Troubleshooting
One of the trickiest parts was navigating the GCC source code and figuring out where to plug things in. The file structure can be intimidating at first, and there’s a bit of trial and error involved. I also ran into a few compiler errors when I forgot to include certain headers or mismatched function names.
To deal with this, I took notes on what changes went where, and I rebuilt often using make -j$(nproc) to get fast feedback. I also made sure to keep build.log files from every session for debugging and tracking progress.
What I Learned and How I Can Improve for Stage 2
This stage helped me understand the basic flow of how a GCC pass works and where it fits into the compiler pipeline. I now have a better grasp of concepts like basic blocks and GIMPLE, which felt pretty abstract before I saw them in action.
I also learned how powerful and complex GCC really is—it’s not just compiling code, it’s analyzing, optimizing, transforming, and then finally translating code into machine instructions. The level of abstraction in a GIMPLE pass gave me a cool behind-the-scenes view.
For Stage 2, I want to focus on improving a few things:
Formatting: I could improve how my pass outputs data, maybe organize the dump with indentation or function separators.
Extra data: I might try extracting more insights from the GIMPLE or CFG (control flow graph) representations, just to see what else is possible.
Automation: I’d like to write a small script to compile and test sample C files more efficiently, especially for testing across both architectures.
Documentation: I'm planning to better comment my code and maybe include usage instructions in a README so it's more shareable and maintainable.
Developing the Custom Pass
Step 1: Creating the Pass Source File
First, I created a new file tree-my-pass.cc in the GCC source code directory with the following implementation:
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "tree-pass.h"
#include "gimple-iterator.h"
#include "pass_manager.h"
#include "basic-block.h"
namespace {
const pass_data my_pass_data = {
GIMPLE_PASS, // Pass type: operates on GIMPLE
"my-pass", // Name of the pass
OPTGROUP_NONE, // No optimization group
TV_NONE, // No TV id
0, // No properties required
0, // No properties provided
0, // No properties destroyed
0 // No specific flags
};
class my_pass : public gimple_opt_pass {
public:
my_pass(gcc::context *ctxt)
: gimple_opt_pass(my_pass_data, ctxt) { }
// The gate method: always run this pass
bool gate(function *) override {
return true;
}
// The execute method: called for every function
unsigned int execute(function *fun) override {
if (dump_file) {
fprintf(dump_file, "Processing function: %s\n", function_name(fun));
// Count basic blocks
int basic_block_count = 0;
basic_block bb;
FOR_EACH_BB_FN(bb, fun) {
basic_block_count++;
}
fprintf(dump_file, "Number of basic blocks: %d\n", basic_block_count);
// Count GIMPLE statements
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(dump_file, "Number of GIMPLE statements: %d\n", gimple_stmt_count);
}
return 0;
}
};
}
// Factory function to create an instance of the pass
gimple_opt_pass *
make_pass_my_pass(gcc::context *ctxt)
{
return new my_pass(ctxt);
}
This implementation:
Defines a GIMPLE pass that runs on each function.
Counts basic blocks in each function.
Counts GIMPLE statements in each function.
Outputs the results to the dump file.
Step 2: Registering the Pass in passes.def
To register my pass in the GCC pipeline, I added the following line to passes.def:
NEXT_PASS (pass_my_pass, 1)
This registers my pass with a unique name and indicates it should be executed in the compiler's pass pipeline.
Step 3: Declaring the Pass in tree-pass.h
To make my pass's factory function available, I added this declaration to tree-pass.h:
extern gimple_opt_pass *make_pass_my_pass (gcc::context *ctxt);
Step 4: Updating Makefile.in
To include my pass in the build, I added it to the list of object files in Makefile.in:
tree-my-pass.o \
Stay tuned for Project Stage 2!
Comments
Post a Comment