Week 7 - GCC Passes & Project Stage 1

Hamza TeliHamza Teli
12 min read

Welcome everyone! As the weeks go by, the material I will cover may be more advanced or difficult to grasp. But we are in this together and I hope that my article explains it effectively. In this article, I will briefly discuss GCC passes and also dive right into the Project Stage 1!

What are GCC Passes?

Think of GCC passes as stages that transform your source code into machine code. We know that the gcc compiler enables our code in C or C++ to be transformed into machine code so that it may be understood and executed. So while this process contains several steps, GCC passes are key as these are the driving forces in transforming our C/C++ code into machine code.

To learn more about these passes, please open your gcc directory and go to the gcc subdirectory. In here, you will see many files that perform GCC passes. The different types you’ll see include:

  • Tree

  • IPA

  • LTO

  • RTL

What if you wanted to create your own GCC pass? (We will be doing this for the project). There are six main steps.

Creating a GCC Pass

  1. Create your pass file

  2. Edit the passes.def file

  3. Add the pass to tree-pass.h

  4. Edit the Makefile.in

  5. Rebuild the Makefile

  6. Test out the gcc pass on a function

I will first start off by showing my code, explaining it, and then going through each step. So lets get started with the first step, creating the pass file. I created my pass file as follows:

Step 1. Creating .cc pass file

  • Navigate to the gcc subdirectory → cd ~/git/gcc/gcc

  • Create a new file, I named mine hamza_gcc_pass.cc → touch tree-hteli1.cc

  • I used vi to edit it → vi tree-hteli1.cc

  • And finally I pasted my pass in here as follows:

/* This pass was creatd by Hamza Teli with the help of
Professor Chris Tyler's SPO600 wiki and lecture. 

This pass accomplishes the following:


*/
// These headers were taken from Professor Chris Tyler's Week 7 Lecture
// These headers were taken from Professor Chris Tyler's Week 7 Lecture
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "tree-pass.h"
#include "ssa.h"
#include "tree-pretty-print.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "internal-fn.h"
#include "gimple-pretty-print.h"
#include "cgraph.h"

// Added headers
#include "gimple-ssa.h"
#include "attribs.h"
#include "pretty-print.h"
#include "tree-inline.h"
#include "intl.h"
#include "function.h"
#include "basic-block.h"



// Namespace <--- This section I learned from SPO600 Week 7 - Class 1 Lecture from Professor Chris Tyler
namespace{
    const pass_data pass_data_hteli1 = {
            GIMPLE_PASS, /* type */
            "hteli1", /* name of my pass [We will use this inside passes.def as pass_hteli1_pass]*/ 
            OPTGROUP_NONE, /* optinfo_ flags */
            TV_NONE, /* tv_id */
            PROP_cfg, /* specify that we need properties */
            0, /* the properties provided */
            0, /* the properties destroyed */
            0, /* todo_flags_start */
            0, /* todo_flags_finish */
    };

    /*
        Please refer to the instructions below from Professor CHris Tyler that helped me build the class:
        Pass Code
            Each pass provides a C++ source file which provides:
            -   A pass_data structure which defines the pass details (defined in tree-pass.h);
            -   A class which defines a gimple_opt_pass and includes the public methods gate and execute.
            -   The gate method controls whether the pass is active. It can consider multiple factors, including command-line arguments, source language, and target. This method returns a boolean.
            -   The execute method executes the pass. It accepts a pointer to a function object and will be called once for each function in the unit being compiled (which is not always what you want!).
            -   A method in the anon namespace named make_pass_name which returns a pointer to the gimple_opt_pass described above.
    */


    // This is where you identify the class
    class pass_hteli1 : public gimple_opt_pass {
        public:
            // Constructor
            pass_hteli1(gcc::context *ctxt) : gimple_opt_pass(pass_data_hteli1, ctxt) {

            }

            // The gate function 
            bool gate(function *) final override {
                // return 
                return true;

            }

            // The execute function: this is where the magic happens
            unsigned int execute (function *func) override {

                // Declarations
                // Count the number of basic blocks
                unsigned int number_of_basic_blocks = 0;

                // Count the number of Gimple statements
                unsigned int number_of_gimple_statements = 0;

                // Instantiate function name
                /* 
                    Inside function.cc, there's a function_name method that returns
                    the name of a function. Check out line 6454:
                    https://github.com/gcc-mirror/gcc/blob/master/gcc/function.cc

                */
                const char* functionName = function_name(func);

                // Print the name of each function being compiled
                if (dump_file) {
                    fprintf(dump_file, "Function: %s\n", functionName);
                }


                // Now we use the macro FOR_EACH_FUNCTION to get the number of basic blocks
                // and print the number of gimple statements in each function
                basic_block BB;
                FOR_EACH_BB_FN(BB, func) {
                    // Increment
                    number_of_basic_blocks++;

                    // Now for each basic block, iterate using the gimple iterator in the wiki
                    // Credit: http://spo600.cdot.systems/doku.php?id=spo600:creating_a_gcc_pass

                    for (gimple_stmt_iterator gsi = gsi_start_bb (BB); !gsi_end_p (gsi); gsi_next(&gsi)) {
                        number_of_gimple_statements++;
                    }
                }

                // Now we can print the basic blocks
                if (dump_file) {
                    fprintf(dump_file, "---- Function: %s | Basic Blocks: %u, | Gimple Statements: %u\n", functionName, number_of_basic_blocks,  number_of_gimple_statements);
                }                
                // Return value
                return 0;


            }
    };
}

// This is used inside the tree-pass.h file
gimple_opt_pass* make_pass_hteli1(gcc::context *ctxt) {
    return new pass_hteli1(ctxt);
}
  • To save → Press ESC and type :wq and press enter

NOTE: I have also uploaded my code to a git repository which can be accessed here: https://github.com/Hamza-Teli/spo600-gcc-project/blob/main/hamza_gcc_pass.cc

Please feel free to look at the revisions I made to see how I came to the final code. It took me quite a bit of trial and error (13 commits). But again thats how you learn best.

Breaking the code down

When I first seen this code, I too got scared. There’s a lot going on but I will explain it how I understand and hopefully you can learn as well.

  1. First thing first, there is a section for the header whereby we have to include the necessary ones in order for our pass to execute. This is actually where I had initially run into problems.

  2. const pass_data structure: Inside here we’re just defining the type of pass it is, the name, and other properties. This is needed for the gcc to add our pass in and identify it.

  3. class declaration: Inside here we have a gate function and execute:

    • gate function: Just specifies if the pass should run on every function. Because I returned true, this means it will.

    • execute function: This function does a few things.

      1. Gets the functions name using func_name

      2. Uses the FOR_EACH_BB_FN macro to iterate over the basic blocks

      3. Inside each block we increment the total GIMPLE statements

      4. Print the function name, total basic blocks, and gimple statements

Step 2. Edit the passes.def file

The passes.def file contains a list of passes, all we have to do here is add our pass. To do this, follow the steps below:

  • Navigate to the source directory → cd ~/git/gcc/gcc

  • Open passes.def → vi passes.def

  • Add the following near the end of the file: NEXT_PASS (pass_hteli1);

    • Heres an image:

  • To save → Press ESC and type :wq and press enter

Step 3. Add the pass to tree-pass.h

Now we add the pass to tree-pass.h, this step is simple as well. Please do the following:

  • Navigate to the source directory → cd ~/git/gcc/gcc

  • Open tree-pass.h → vi tree-pass.h

  • Add the following near the end of the file:
    extern gimple_opt_pass *make_pass_hteli1 (gcc::context *ctxt);

  • To save → Press ESC and type :wq and press enter

Step 4. Edit the Makefile.in

  • Navigate to the gcc source directory → cd ~/git/gcc/gcc

  • Open Makefile.in → vi Makefile.in

  • Locate the OBJS = section → Should look like this:

  • Add the following inside the section → tree-hteli1.o \

  • To save → Press ESC and type :wq and press enter

Step 5. Rebuild the Makefile

Initially, I rebuilt the makefile however, it did not work. Therefore, I thought about the previous lab I completed (Lab 4) and started the build from scratch. This is what I realized. Firstly, to setup the pass we strictly use gcc source directory. Therefore, all I have to do is create my pass file there, setup the tree-pas.h, passes.def, and Makefile.in. Once thats done, I delete the old build folder and test folder as well. I perform the exact steps I did in Lab 4 and run make install at the end. Here’s a quick overview:

  • Delete any existing builds along with the test folder using rm → rm ~/gcc-build-001

  • Create a new gcc-build directory → mkdir ~/gcc-build-001

  • Go into this directory → cd ~/gcc-build-001

  • Set the configure → ~/git/gcc/configure —prefix=$HOME/gcc-test-001

  • Create a screen session → screen -S project1

  • Execute make command → time make -j$(nproc) |& tee rebuild_log.log

  • Execute make install → make install

On the x86 machine, this is the output I received after running the make -j command:

---- Function: process_bb | Basic Blocks: 306, | Gimple Statements: 763
Function: find_func_aliases
---- Function: find_func_aliases | Basic Blocks: 532, | Gimple Statements: 1477
Function: maybe_optimize_range_tests
---- Function: maybe_optimize_range_tests | Basic Blocks: 392, | Gimple Statements: 1040
Function: hash_table<shared_bitmap_hasher>::expand
---- Function: hash_table<shared_bitmap_hasher>::expand | Basic Blocks: 37, | Gimple Statements: 110
Function: do_rpo_vn_1
---- Function: do_rpo_vn_1 | Basic Blocks: 365, | Gimple Statements: 1189
Function: hash_table<shared_bitmap_hasher>::find_slot_with_hash
---- Function: hash_table<shared_bitmap_hasher>::find_slot_with_hash | Basic Blocks: 49, | Gimple Statements: 141
Function: hash_table<hash_map<variable_info*, pt_solution*>::hash_entry, false, xcallocator>::expand
---- Function: hash_table<hash_map<variable_info*, pt_solution*>::hash_entry, false, xcallocator>::expand | Basic Blocks: 37, | Gimple Statements: 113
Function: find_what_var_points_to.isra
---- Function: find_what_var_points_to.isra | Basic Blocks: 167, | Gimple Statements: 476
Function: find_what_p_points_to
---- Function: find_what_p_points_to | Basic Blocks: 44, | Gimple Statements: 106
Function: run_rpo_vn
---- Function: run_rpo_vn | Basic Blocks: 103, | Gimple Statements: 277
Function: do_rpo_vn
---- Function: do_rpo_vn | Basic Blocks: 4, | Gimple Statements: 12
Function: {anonymous}::pass_fre::execute
---- Function: {anonymous}::pass_fre::execute | Basic Blocks: 9, | Gimple Statements: 20
Function: compute_may_aliases
---- Function: compute_may_aliases | Basic Blocks: 190, | Gimple Statements: 590
Function: {anonymous}::pass_reassoc::execute
---- Function: {anonymous}::pass_reassoc::execute | Basic Blocks: 560, | Gimple Statements: 1590
Function: vn_reference_lookup_3
---- Function: vn_reference_lookup_3 | Basic Blocks: 654, | Gimple Statements: 1905
Function: _GLOBAL__sub_I__Z16dump_range_entryP8_IO_FILEP11range_entryb
---- Function: _GLOBAL__sub_I__Z16dump_range_entryP8_IO_FILEP11range_entryb | Basic Blocks: 1, | Gimple Statements: 20
Function: {anonymous}::pass_ipa_pta::execute
---- Function: {anonymous}::pass_ipa_pta::execute | Basic Blocks: 436, | Gimple Statements: 1245
Function: _GLOBAL__sub_I_final_solutions_obstack
---- Function: _GLOBAL__sub_I_final_solutions_obstack | Basic Blocks: 1, | Gimple Statements: 29
.........
dep.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_symbolizer_mac.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_symbolizer_markup.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_symbolizer_posix_libcdep.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_symbolizer_report.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_symbolizer_win.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_termination.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_thread_arg_retval.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_thread_history.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_thread_registry.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_tls_get_addr.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_unwind_linux_libcdep.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_unwind_win.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_win.o .libs/libubsan.lax/libsanitizer_common.a/sanitizer_win_interception.o  .libs/libubsan.lax/libinterception.a/interception_linux.o .libs/libubsan.lax/libinterception.a/interception_mac.o .libs/libubsan.lax/libinterception.a/interception_type_test.o .libs/libubsan.lax/libinterception.a/interception_win.o  .libs/libubsan.lax/libsanitizer_libbacktrace.a/atomic.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/bridge.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/cp-demangle.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/dwarf.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/elf.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/fileline.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/mmap.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/mmapio.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/posix.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/sort.o .libs/libubsan.lax/libsanitizer_libbacktrace.a/state.o 
libtool: link: ranlib --plugin /usr/libexec/gcc/x86_64-redhat-linux/14/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so .libs/libubsan.a
libtool: link: rm -fr .libs/libubsan.lax
libtool: link: ( cd ".libs" && rm -f "libubsan.la" && ln -s "../libubsan.la" "libubsan.la" )
make[8]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/32/libsanitizer/ubsan'
make[8]: Entering directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/32/libsanitizer'
true "AR_FLAGS=rc" "CC_FOR_BUILD=gcc" "CFLAGS=-g -O2  -m32" "CXXFLAGS=-g -O2 -D_GNU_SOURCE  -m32" "CFLAGS_FOR_BUILD=-g -O2" "CFLAGS_FOR_TARGET=-g -O2" "INSTALL=/usr/bin/install -c" "INSTALL_DATA=/usr/bin/install -c -m 644" "INSTALL_PROGRAM=/usr/bin/install -c" "INSTALL_SCRIPT=/usr/bin/install -c" "JC1FLAGS=" "LDFLAGS=-m32" "LIBCFLAGS=-g -O2  -m32" "LIBCFLAGS_FOR_TARGET=-g -O2" "MAKE=make" "MAKEINFO=/home/hteli1/git/gcc/missing makeinfo --split-size=5000000   " "PICFLAG=" "PICFLAG_FOR_TARGET=" "SHELL=/bin/sh" "RUNTESTFLAGS=" "exec_prefix=/home/hteli1/gcc-test-001" "infodir=/home/hteli1/gcc-test-001/share/info" "libdir=/home/hteli1/gcc-test-001/lib" "prefix=/home/hteli1/gcc-test-001" "includedir=/home/hteli1/gcc-test-001/include" "AR=ar --plugin /usr/libexec/gcc/x86_64-redhat-linux/14/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so" "AS=/home/hteli1/gcc-build-001/./gcc/as" "LD=/home/hteli1/gcc-build-001/./gcc/collect-ld -m elf_x86_64 -m elf_i386" "LIBCFLAGS=-g -O2  -m32" "NM=/home/hteli1/gcc-build-001/./gcc/nm -B -B" "PICFLAG=" "RANLIB=ranlib --plugin /usr/libexec/gcc/x86_64-redhat-linux/14/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so --plugin /home/hteli1/gcc-build-001/./gcc/liblto_plugin.so" "DESTDIR=" DO=all multi-do # make
make[8]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/32/libsanitizer'
make[7]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/32/libsanitizer'
make[6]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/32/libsanitizer'
make[5]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/libsanitizer'
make[4]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/libsanitizer'
make[3]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/libsanitizer'
make[2]: Leaving directory '/home/hteli1/gcc-build-001/x86_64-pc-linux-gnu/libsanitizer'
make[1]: Leaving directory '/home/hteli1/gcc-build-001'

Looking at the output, you can see that my pass is doing its job :) Although I don’t have the time which I am not sure why as I did run the entire command with time and re-directed the output to a file, this part did take about 30-40 minutes long. After that make install didn’t take that long.

Testing it out with a file

I decided to test my pass by using the spo600 directory from our Lab 4 experiment. However I did make a small change to the makefile to output the dump files. Here are the steps I took:

  • Navigate to the directory → cd ~/spo600/examples/hello/c

  • Edit the Makefile → vi Makefile

  •   BINARIES=hello hello-static hello-opt hello2 hello3
      CCFLAGS=-g -O0 -fno-builtin -fdump-tree-all
    
      all:            ${BINARIES}
    
      hello:          hello.c
                      ~/gcc-test-001/bin/gcc  ${CCFLAGS}      -o hello                        hello.c
    
      # Statically-linked version
      hello-static:   hello.c
                      gcc     ${CCFLAGS}      -o hello-static -static         hello.c
    
      # Optimized version
      hello-opt:      hello.c
                      gcc     -O3 -g          -o hello-opt                    hello.c
    
      hello2:         hello2.c
                      gcc     ${CCFLAGS}      -o hello2                       hello2.c
    
      hello3:         hello3.c
                      gcc     ${CCFLAGS}      -o hello3                       hello3.c
    
      clean:  
                      rm ${BINARIES} *.o || true
    

After making this change, I made sure to check which gcc my machine was using just to be safe:

NOTE: If it shows a different gcc, please execute the following command: PATH=”$HOME/gcc-test-001/bin:$PATH”

I then executed the make commands as follows:

  • make clean

  • make

This outputted the following files:

hteli1@x86-001:~/spo600/examples/hello/c$ ls
hello                           hello2.c.254t.cplxlower0      hello3.c.014t.eh                hello3.c.269t.optimized   hello.c.032t.local-fnsummary1  hello.c.368t.debug                          hello-static-hello.c.253t.veclower
hello2                          hello2.c.255t.bitintlower0    hello3.c.016t.cfg               hello3.c.269t.waccess3    hello.c.033t.einline           hello-opt                                   hello-static-hello.c.254t.cplxlower0
hello2.c                        hello2.c.257t.switchlower_O0  hello3.c.018t.ompexp            hello3.c.270t.optimized   hello.c.053t.profile_estimate  hello.s                                     hello-static-hello.c.255t.bitintlower0
hello2.c.006t.original          hello2.c.265t.hteli1          hello3.c.022t.fixup_cfg1        hello3.c.365t.statistics  hello.c.057t.release_ssa       hello-static                                hello-static-hello.c.257t.switchlower_O0
hello2.c.007t.gimple            hello2.c.265t.isel            hello3.c.023t.ssa               hello3.c.366t.earlydebug  hello.c.058t.local-fnsummary2  hello-static-hello.c.006t.original          hello-static-hello.c.265t.hteli1
hello2.c.010t.omplower          hello2.c.266t.isel            hello3.c.024t.walloca1          hello3.c.366t.statistics  hello.c.099t.fixup_cfg3        hello-static-hello.c.007t.gimple            hello-static-hello.c.265t.isel
hello2.c.011t.lower             hello2.c.268t.waccess3        hello3.c.027t.waccess1          hello3.c.367t.debug       hello.c.106t.adjust_alignment  hello-static-hello.c.010t.omplower          hello-static-hello.c.266t.isel
hello2.c.014t.eh                hello2.c.269t.optimized       hello3.c.031t.fixup_cfg2        hello3.c.367t.earlydebug  hello.c.253t.veclower          hello-static-hello.c.011t.lower             hello-static-hello.c.268t.waccess3
hello2.c.016t.cfg               hello2.c.269t.waccess3        hello3.c.032t.local-fnsummary1  hello3.c.368t.debug       hello.c.254t.cplxlower0        hello-static-hello.c.014t.eh                hello-static-hello.c.269t.optimized
hello2.c.018t.ompexp            hello2.c.270t.optimized       hello3.c.033t.einline           hello3.s                  hello.c.255t.bitintlower0      hello-static-hello.c.016t.cfg               hello-static-hello.c.269t.waccess3
hello2.c.022t.fixup_cfg1        hello2.c.365t.statistics      hello3.c.053t.profile_estimate  hello.c                   hello.c.257t.switchlower_O0    hello-static-hello.c.018t.ompexp            hello-static-hello.c.270t.optimized
hello2.c.023t.ssa               hello2.c.366t.earlydebug      hello3.c.057t.release_ssa       hello.c.006t.original     hello.c.265t.hteli1            hello-static-hello.c.022t.fixup_cfg1        hello-static-hello.c.365t.statistics
hello2.c.024t.walloca1          hello2.c.366t.statistics      hello3.c.058t.local-fnsummary2  hello.c.007t.gimple       hello.c.265t.isel              hello-static-hello.c.023t.ssa               hello-static-hello.c.366t.earlydebug
hello2.c.027t.waccess1          hello2.c.367t.debug           hello3.c.099t.fixup_cfg3        hello.c.010t.omplower     hello.c.266t.isel              hello-static-hello.c.024t.walloca1          hello-static-hello.c.366t.statistics
hello2.c.031t.fixup_cfg2        hello2.c.367t.earlydebug      hello3.c.106t.adjust_alignment  hello.c.011t.lower        hello.c.268t.waccess3          hello-static-hello.c.027t.waccess1          hello-static-hello.c.367t.debug
hello2.c.032t.local-fnsummary1  hello2.c.368t.debug           hello3.c.253t.veclower          hello.c.014t.eh           hello.c.269t.optimized         hello-static-hello.c.031t.fixup_cfg2        hello-static-hello.c.367t.earlydebug
hello2.c.033t.einline           hello2.s                      hello3.c.254t.cplxlower0        hello.c.016t.cfg          hello.c.269t.waccess3          hello-static-hello.c.032t.local-fnsummary1  hello-static-hello.c.368t.debug
hello2.c.053t.profile_estimate  hello3                        hello3.c.255t.bitintlower0      hello.c.018t.ompexp       hello.c.270t.optimized         hello-static-hello.c.033t.einline           Makefile
hello2.c.057t.release_ssa       hello3.c                      hello3.c.257t.switchlower_O0    hello.c.022t.fixup_cfg1   hello.c.365t.statistics        hello-static-hello.c.053t.profile_estimate
hello2.c.058t.local-fnsummary2  hello3.c.006t.original        hello3.c.265t.hteli1            hello.c.023t.ssa          hello.c.366t.earlydebug        hello-static-hello.c.057t.release_ssa
hello2.c.099t.fixup_cfg3        hello3.c.007t.gimple          hello3.c.265t.isel              hello.c.024t.walloca1     hello.c.366t.statistics        hello-static-hello.c.058t.local-fnsummary2
hello2.c.106t.adjust_alignment  hello3.c.010t.omplower        hello3.c.266t.isel              hello.c.027t.waccess1     hello.c.367t.debug             hello-static-hello.c.099t.fixup_cfg3
hello2.c.253t.veclower          hello3.c.011t.lower           hello3.c.268t.waccess3          hello.c.031t.fixup_cfg2   hello.c.367t.earlydebug        hello-static-hello.c.106t.adjust_alignment

At this point there were too many dump files, so I changed my Makefile to only include my dump file: -fdump-tree-hteli1:

BINARIES=hello hello-static hello-opt hello2 hello3
CCFLAGS=-g -O0 -fno-builtin -fdump-tree-hteli1

all:            ${BINARIES}

hello:          hello.c
                ~/gcc-test-001/bin/gcc  ${CCFLAGS}      -o hello                        hello.c

# Statically-linked version
hello-static:   hello.c
                gcc     ${CCFLAGS}      -o hello-static -static         hello.c

# Optimized version
hello-opt:      hello.c
                gcc     -O3 -g          -o hello-opt                    hello.c

hello2:         hello2.c
                gcc     ${CCFLAGS}      -o hello2                       hello2.c

hello3:         hello3.c
                gcc     ${CCFLAGS}      -o hello3                       hello3.c

clean:  
                rm ${BINARIES} *.o || true

Output from dump file:

x86:

The output on the x86 is below:

hteli1@x86-001:~/spo600/examples/hello/c$ cat hello.c.265t.hteli1 

;; Function main (main, funcdef_no=0, decl_uid=2335, cgraph_uid=1, symbol_order=0)

Function: main
---- Function: main | Basic Blocks: 2, | Gimple Statements: 4
int main ()
{
  int D.2338;
  int _3;

  <bb 2> :
  printf ("Hello World!\n");
  _3 = 0;

  <bb 3> :
<L0>:
  return _3;

}

Here is an image:

AArch64:

The output for AArch64 is as follows:

[hteli1@aarch64-002 c]$ cat hello.c.265t.hteli1 

;; Function main (main, funcdef_no=0, decl_uid=3927, cgraph_uid=1, symbol_order=0)

Function: main
---- Function: main | Basic Blocks: 2, | Gimple Statements: 4
int main ()
{
  int D.3930;
  int _3;

  <bb 2> :
  printf ("Hello World!\n");
  _3 = 0;

  <bb 3> :
<L0>:
  return _3;

}

Reflection

Thank you very much for following along for my project stage 1. This project did take me a while but it reinforced my understanding the role GCC plays as well as gcc passes. In addition, I ran into several bottlenecks like incorrect headers in the gcc pass, incorrect naming, etc. I also made an incorrect build of my gcc-test-001 which was not picking up my pass. I took the time to diagnose the issue and was finally successful. Overall, I found it hard at first but now I feel like I can add more passes.

References

  • Credit goes to Professor Chris Tyler’s lecture and SPO600 wiki
0
Subscribe to my newsletter

Read articles from Hamza Teli directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hamza Teli
Hamza Teli