SPO600 2025 Winter Project: Stage 1 - Creating a Basic GCC Pass

Project Overview

In this project, I enhanced the GNU Compiler Collection (GCC) by adding a custom compiler pass to analyze functions during compilation. The pass performs three key tasks:

  1. Prints the name of every function being compiled.
  2. Counts the number of basic blocks in each function.
  3. Counts the number of GIMPLE statements within each basic block.

This pass helps developers understand code structure and optimization impacts. Below, I detail my implementation journey, including challenges and solutions.


Environment Setup

To avoid conflicts with the system compiler, I used three isolated directories:

  • Source Directory: ~/git/gcc (GCC source code).
  • Build Directory: ~/gcc-build-001 (compilation artifacts).
  • Install Directory: ~/gcc-test-001 (custom GCC installation).

Why This Matters: Separating source, build, and install directories ensures a clean workflow and simplifies debugging.


Step 1: Creating the Custom Pass

File: tree_tpatel103_pass.cc

I created a new file in gcc/gcc to house the pass logic. Key components include:




1. Headers: Included essential GCC headers for GIMPLE, basic blocks, and function analysis:

#include "config.h"

#include "system.h"

#include "coretypes.h"

#include "backend.h"

#include "tree.h"

#include "gimple.h"

#include "pass_manager.h"

#include "context.h"

#include "diagnostic-core.h"

#include "tree-pass.h"

#include "ssa.h"

#include "tree-pretty-print.h"

#include "internal-fn.h"

#include "gimple-iterator.h"

#include "gimple-walk.h"

#include "internal-fn.h"

#include "tree-core.h"

#include "basic-block.h"

#include "gimple-ssa.h"

#include "cgraph.h"

#include "attribs.h"

#include "pretty-print.h"

#include "tree-inline.h"

#include "intl.h"

#include "dumpfile.h"

#include "builtins.h"


2. Pass Data Structure: Defined pass metadata:

const pass_data pass_data_tpatel103 = {  

    GIMPLE_PASS,        // Works on GIMPLE IR  

    "tpatel103",        // Pass name  

    OPTGROUP_NONE,      // No optimization group  

    TV_NONE,            // No timevar (profiling)  

    PROP_cfg,           // Requires CFG  

    0, 0, 0, 0         // Flags (see GCC docs)  

};  


3. Execute Method: Core logic to iterate functions and count blocks/statements:

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

    int bb_count = 0, gimple_count = 0;  


    // Print function name  

    if (dump_file)  

        fprintf(dump_file, "=== Function: %s ===\n", function_name(fun));  


    // Iterate basic blocks  

    basic_block bb;  

    FOR_EACH_BB_FN(bb, fun) {  

        bb_count++;  

        int stmt_count = 0;  


        // Count GIMPLE statements in the block  

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

            stmt_count++;  


        gimple_count += stmt_count;  


        if (dump_file)  

            fprintf(dump_file, "BB %d: %d statements\n", bb_count, stmt_count);  

    }  


    // Final summary  

    if (dump_file) {  

        fprintf(dump_file, "Total BBs: %d\n", bb_count);  

        fprintf(dump_file, "Total GIMPLE: %d\n", gimple_count);  

    }  

    return 0;  

}  


Step 2: Integrating the Pass into GCC

1. Registering the Pass

  • passes.def: Inserted the pass after pass_nrw to analyze post-optimization GIMPLE
    NEXT_PASS (pass_nrw); 
    NEXT_PASS (pass_tpatel103);  // Added here  


  • tree-pass.h: Declared the pass to make it visible to GCC:
    extern gimple_opt_pass *make_pass_tpatel103 (gcc::context *ctxt); 

  •  

2. Updating the Build System
  • Makefile.in: Added tree-tpatel103.o to the OBJS list to compile the pass.



Step 3: Rebuilding GCC

After modifying source files:

1. Delete old Makefile:
cd ~/gcc-build-001/gcc  
rm Makefile  

2. Rebuild with 20 threads:
time make -j20 |& tee rebuild.log  

3. Install:
make install  


Step 4: Testing the Pass

Test Program: hello.c

#include <stdio.h>  
int main() {  
    printf("Hello World!\n");  
    return 0;  



Compilation Command

PATH=~/gcc-test-001/bin:$PATH  
gcc -g -O0 -fno-builtin -fdump-tree-tpatel103 -o hello hello.c  

Output: hello.c.265t.tpatel103

=== Function: main ===  
BB 1: 2 GIMPLE statements 
BB 2: 2 GIMPLE statements  
Total BBs: 2  
Total GIMPLE: 4  



Challenges & Solutions

1. Build Error: CC/CXX Version Mismatch
  • Cause: Stale build files from previous configurations.
  • Fix: Clean the build directory with make distclean and reconfigure.

2. Missing Dump File
  • Cause: Incorrect pass name in -fdump-tree-*.
  • Fix: Verified pass registration in passes.def and tree-pass.h.

Capabilities & Limitations
  • Strengths:

    • Works on both x86_64 and AArch64 architectures.
    • Compatible with GCC’s latest development version.
  • Limitations:

    • Only counts GIMPLE statements, not RTL or machine code.
    • Requires rebuilding GCC for changes.

Reflections
  • Learned: GCC’s pass manager, GIMPLE IR, and build process intricacies.
  • Challenging: Debugging build errors due to incomplete cleanups.
  • Next Steps: Extend the pass to analyze loops or memory operations.
By documenting this process, I aim to help others navigate GCC internals and contribute to compiler development!

Comments

Popular posts from this blog

Lab-1: Exploring 6502 Assembly

Project Stage III: Multi-Clone Analysis in GCC Pass

Lab 2 - 6502 Math Lab