Project Stage 2

This blog is about my journey into learning GCC. It’s been a mix of downloading the source code, fixing directory problems, and trying to add a custom pass. Honestly, I’ve learned more about compilers in the past few days than I ever thought I would. Let me share my experience with you.


Step 1: Setting Up the Project

First, I created a project directory to keep things organized. I wanted separate folders for the GCC source code, the build files, and the final installation. Here’s what my structure looked like:

mkdir -p ~/gcc-project/{src,build,install}

Downloading the Source Code

Next, I cloned the GCC repository. This took some time because the GCC codebase is huge:

git clone git://gcc.gnu.org/git/gcc.git ~/gcc-project/src

When the cloning finished, I was ready to configure and build GCC. Or so I thought.


Step 2: It showed No Such File

When I tried to configure GCC, I hit my first big roadblock. Running ../src/configure from the build directory didn’t work:

-bash: ../src/configure: No such file or directory

After some digging, I realized that the configure script wasn’t in the src directory. Instead, the source code was nested one level deeper in a gcc-src folder. So, I moved everything up:

mv ~/gcc-project/src/gcc-src/* ~/gcc-project/src/

mv ~/gcc-project/src/gcc-src/.* ~/gcc-project/src/ 2>/dev/null

rmdir ~/gcc-project/src/gcc-src

This fixed the issue, and now the configure script was in the right place. Finally, I could move on.


Step 3: Configuring and Building GCC

Configuration

From the build directory, I ran:

../src/configure --disable-bootstrap --enable-languages=c,c++ --prefix=$HOME/gcc-project/install

  • --disable-bootstrap: This skips the multi-stage build process, making things faster.
  • --enable-languages=c,c++: I only needed C and C++ support for this project.
  • --prefix: This tells GCC where to install the final binaries.

The configuration went smoothly, and I was ready to build.

Building

I started the build with:

make -j$(nproc)

The -j$(nproc) flag lets GCC use all available CPU cores. Even then, it took a long time. (Lesson learned: patience is key when working with compilers.)

Installing

After the build finished, I installed GCC:

make install

This step moved the compiled binaries into the install directory. I verified the installation by checking the GCC version:
~/gcc-project/install/bin/gcc --version

Success! GCC was up and running.
Step 4: Adding a Custom Pass

Now came the fun (and challenging) part: adding a custom pass to GCC.

Creating the Pass

I created a new file called tree-ctyler.cc in the src directory. This file contained the logic for my pass. Here’s what it does:

  • Iterates over basic blocks and GIMPLE statements (an intermediate representation in GCC).
  • Prints diagnostic information to a dump file.

Here’s the core of the pass:

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "tree-pass.h"
#include "function.h"
#include "basic-block.h"
#include "gimple-iterator.h"

namespace {
    const pass_data pass_ctyler_data = {
        GIMPLE_PASS,
        "ctyler_pass",
        OPTGROUP_NONE,
        TV_TREE,
        PROP_gimple_any,
        PROP_trees,
        TODO_update_ssa,
        TODO_dump_func
    };

    class pass_ctyler : public gimple_opt_pass {
    public:
        pass_ctyler(gcc::context *ctxt) : gimple_opt_pass(pass_ctyler_data, ctxt) {}

        bool gate(function *) override {
            return true;
        }

        unsigned int execute(function *fun) override {
            fprintf(stderr, "=== Executing ctyler_pass for function: %s ===\n", function_name(fun));
            FOR_EACH_BB_FN(bb, cfun) {
                fprintf(stderr, "Processing Basic Block: %d\n", bb->index);
                for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
                    gimple *stmt = gsi_stmt(gsi);
                    if (gimple_code(stmt) == GIMPLE_ASSIGN) {
                        fprintf(stderr, "Assignment Statement Found:\n");
                        dump_gimple_stmt(TDF_VOPS | TDF_MEMSYMS, stmt, 0);
                    } else {
                        fprintf(stderr, "Other Statement:\n");
                        dump_gimple_stmt(TDF_NONE, stmt, 0);
                    }
                }
            }
            fprintf(stderr, "=== Finished ctyler_pass ===\n");
            return 0;
        }
    };
}

gimple_opt_pass *make_pass_ctyler(gcc::context *ctxt) {
    return new pass_ctyler(ctxt);
}

Integrating the Pass

I updated three files to integrate my pass:

  1. Makefile.in: Added tree-ctyler.o to the list of object files.
  2. passes.def: Registered the pass:
    NEXT_PASS(pass_ctyler)
  3. tree-pass.h: Declared the pass:
    extern gimple_opt_pass *make_pass_ctyler(gcc::context *ctxt);

Rebuilding GCC

After making these changes, I rebuilt GCC:

cd ~/gcc-project/build

make -j$(nproc)

make install

After rebuilding, I confirmed the installation worked by running:

~/gcc-project/install/bin/gcc --version

This confirmed the rebuilt GCC was functional and included the custom pass.




Testing the Custom Pass

To test the pass, I wrote a simple C program:

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}
I compiled it using my custom GCC with the following flag:

~/gcc-project/install/bin/gcc hello.c -fdump-tree-ctyler

The pass executed successfully, generating a dump file with diagnostic information.


Reflections

This project was both challenging and rewarding. I gained a deeper understanding of GCC’s internals, from how basic blocks are processed to how passes interact with GIMPLE statements. The most satisfying moment was seeing my custom pass work and generate meaningful diagnostics. This experience has deepened my appreciation for compiler design and development, and I’m excited to take on even more complex challenges in the future.





Comments

Popular posts from this blog

Lab1

Project Stage 1