Project Stage 1
Introduction
This project focuses on creating a custom pass for the GCC compiler, which will analyze functions during compilation. The pass will iterate through functions in the compiled code, print their names, count the number of basic blocks, and count the number of GIMPLE statements.
Step 1: Creating the GCC Pass
Creating the Pass File
I navigated to the gcc/
directory inside the GCC source tree and created a new file:
[ayoung54@aarch64-002 ~]$ cd ~/git/gcc/gcc
[ayoung54@aarch64-002 gcc]$ nano a_pass.cc
Implementing the Pass
I added the following code to define my custom GCC pass in a_pass.cc:
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree-pass.h"
#include "pass_manager.h"
#include "context.h"
#include "diagnostic-core.h"
#include "tree.h"
#include "tree-core.h"
#include "basic-block.h"
#include "gimple.h"
#include "gimple-iterator.h"
namespace {
// Define pass metadata
const pass_data a_pass_data = {
GIMPLE_PASS, // Pass operates on GIMPLE representation
"a_pass", // Pass name
OPTGROUP_NONE, // No optimization group
TV_TREE_OPS, // Tree operations category
0, 0, 0, 0 // Default settings
};
// Custom GIMPLE optimization pass class
class a_pass : public gimple_opt_pass {
public:
// Constructor initializing pass with metadata
a_pass(gcc::context *ctxt) : gimple_opt_pass(a_pass_data, ctxt) {}
// Gate function (always true)
bool gate(function *fun) override { return true; }
// Main execution function for the pass
unsigned int execute(function *fun) override {
fprintf(stderr, "Processing function: %s\n", function_name(fun));
int basic_block_count = 0, gimple_stmt_count = 0;
// Single loop to count both basic blocks and GIMPLE statements
for (auto bb : fun->cfg->x_basic_block_info) {
if (!bb) continue; // Skip null blocks (safety check)
basic_block_count++;
for (auto gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
gimple_stmt_count++;
}
}
// Print results in a single operation to minimize I/O overhead
fprintf(stderr, "Number of basic blocks: %d\nNumber of GIMPLE statements: %d\n",
basic_block_count, gimple_stmt_count);
return 0; // Indicate successful execution
}
};
// Factory function to create an instance of the pass
gimple_opt_pass *make_a_pass(gcc::context *ctxt) {
return new a_pass(ctxt);
}
} // namespace
Step 2: Registering the Pass in GCC
Modifying tree-pass.h
I put added a line before the IPA passes for the pass manager to find my pass.
[ayoung54@aarch64-002 gcc]$ nano tree-pass.h
extern gimple_opt_pass *make_pass_coroutine_early_expand_ifns (gcc::context *ct>
extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
extern gimple_opt_pass *make_a_pass (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc>
extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (
Modifying passes.def
[ayoung54@aarch64-002 gcc]$ nano passes.def
I added my pass to passes.defafter
pass_clean_state
:
POP_INSERT_PASSES ()
NEXT_PASS (pass_df_finish);
POP_INSERT_PASSES ()
NEXT_PASS (pass_clean_state);
NEXT_PASS (a_pass);
TERMINATE_PASS_LIST (all_passes)
Step 3: Adding the Pass to GCC's Build System
Configure the build using the command:
[ayoung54@aarch64-002 gcc]$ ./configure --prefix=$HOME/gcc-test-001
I added a_pass.o
to Makefile.in:
warning-control.o \
web.o \
wide-int.o \
wide-int-print.o \
a_pass.o \
$(out_object_file) \
$(ANALYZER_OBJS) \
$(EXTRA_OBJS) \
$(host_hook_obj)
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
Step 4: Rebuilding GCC
Since Makefile.in
was modified, I generated a new Makefile that includes my custom pass. The easiest way is to remove the Makefile in the build folder and re-generate the Makefile by the configuration script.
[ayoung54@aarch64-002 gcc]$ rm Makefile
[ayoung54@aarch64-002 gcc]$ ./configure --prefix=$HOME/gcc-test-001
Rebuild the gcc
[ayoung54@aarch64-002 gcc]$ time make -j$(nproc) |& tee build.log
The build took:
Step 5: Running and Testing the Pass
Compiling a Test Program
#include <stdio.h>
int main(){
printf("Alyssa here!\n");
return 0;
}
PASSED!!!
Conclusion
Through this project, I have gained a deeper understanding of compiler internals and how passes interact with the code during the compilation process. However, I have identified a gap in my knowledge regarding how GCC optimizes code at various stages. To address this, I plan to study GCC’s other optimization passes and experiment with modifying them.
In terms of further exploration, I am interested in extending my pass to perform more advanced analysis and possibly integrate it into the broader optimization workflow of GCC.
Stay tuned for the next stage of the project!
Comments
Post a Comment