Project Stage 1 Diving In!
Project Stage 1 – Understanding GCC Passes and Setting things UP
Alright, time to dive into the SPO600 course project! In Stage 1, our goal is to create a basic GCC pass that can analyze a program during compilation and print out some useful info. This is my first time working this closely with the GCC compiler, and let me just say, it’s a deep rabbit hole. But it’s also been really interesting figuring things out.
In this post, I’ll talk about:
What the project is about
How I approached it
Some of the issues I ran into and how I fixed them
What’s This Project About?
GCC processes code in multiple steps called passes. These passes can analyze and transform code at various intermediate stages before turning it into machine code.
For this project, I had to:
Iterate through each function being compiled
Print the name of each function
Count how many basic blocks are in each function
Count how many GIMPLE statements are in each function
These details come from GCC's internal representation of the code, and we get access to them in a GIMPLE pass—one of GCC’s mid-level optimization passes.
Setting Things Up
Before starting the project, I made sure Lab 4 was fully done and that my GCC source and build directories were ready to go on my Linux VM running on an M2 MacBook Air.
Commands I used to verify everything was in place:
ls -l ~
cd ~/gcc
ls
Once that was confirmed, I began creating my own GCC pass by making a new file called tree-my-pass.cc inside the gcc directory.
The Plan
The goal was to:
Write a basic pass that prints some diagnostics
Gradually add functionality to count basic blocks and GIMPLE statements
Register the pass correctly so GCC actually uses it
Get it building properly (this is where things got spicy)
Troubleshooting and Fixes
This part definitely took the most time. Here are some of the main issues I hit—and how I fixed them:
Error: expected ';' at end of member declaration
This came from my passes.def file. I originally wrote:
NEXT_PASS_WITH_ARG(pass_my_pass, 1, 1)
Turns out that was wrong. After looking at examples using:
grep -r "NEXT_PASS" ~/gcc/gcc
I realized I just needed:
NEXT_PASS(pass_my_pass, 1)
Naming Conventions Matter
I initially named my factory function like this:
gimple_opt_pass *make_tree_my_pass(gcc::context *ctxt)
But GCC expects a strict pattern:
The factory function should be make_pass_my_pass
The class name should be my_pass
The pass registration should match: NEXT_PASS(pass_my_pass, 1)
I fixed this by renaming things to keep them consistent.
Makefile: Tabs vs Spaces
When adding my object file to the Makefile.in, I got an error:
missing separator (did you mean TAB instead of 8 spaces?)
Turns out Makefiles are super picky—indentation must be a real tab, not spaces. I checked it using:
cat -A Makefile.in | grep -A 3 -B 3 "tree-my-pass"
Sure enough, there were spaces where there should’ve been tabs. Fixed that and re-ran the build.
Rebuilding GCC (Over and Over Again)
Once changes were made, I rebuilt using:
cd ~/gcc-build
time make -j$(nproc) |& tee build.log
And if I wanted to check whether my file was even included:
grep "tree-my-pass.o" build.log
Lessons from This Stage (So Far)
GCC’s codebase is huge. Searching through it using grep, find, and less is your best friend.
Naming conventions and file placement matter a lot—GCC is strict.
Always use tabs in Makefiles. It’s such a small thing but can completely break your build.
Rebuilding can take time, but using make smartly (especially with -j) saves a lot of it.
That wraps up the first part of my Stage 1 journey. In the next post, I’ll walk through the actual code for my custom pass, what it prints, and how it all works together. Overall, I’m learning a lot—not just about compilers, but about how huge open-source projects are structured and maintained.
Stay tuned for Part 2 where I show the actual pass in action!
Comments
Post a Comment