Project Stage 3: Tidy & Wrap

Introduction

In this stage, I aimed to address the feedback provided by the professor and resolve the errors encountered in the previous stages of the GCC pass project. However, despite my efforts, I have faced significant challenges that have hindered my progress.


Process and Steps Taken

Building and Testing the Demo Pass

- I started by building and testing the provided demo pass to understand its functionality.

- However, I encountered several issues during this process, which are detailed below.


Modifying the Pass


1. Adding Diagnostic Dumps:

   - I attempted to modify the pass to include diagnostic dumps to demonstrate its execution.

   - Example code snippet:

     ```cpp

     if (dump_file)

       {

         fprintf (dump_file, "===== Dummy Pass Diagnostic Dump =====\n");

       }

     ```


2. Iterating Through Code Being Compiled:

   - I updated the pass to iterate through basic blocks and statements, printing their counts and details.

   - Example code snippet:

     ```cpp

     basic_block bb;

     int bb_cnt = 0, stmt_cnt = 0;

     FOR_EACH_BB_FN (bb, fun)

       {

         // ...

       }

     ```


3. Identifying Cloned Functions:

   - I tried to implement code to check for function names with a `_clone` suffix and store them in a map.

   - Example code snippet:

     ```cpp

     std::map<tree, std::vector<function*> > cloned_functions;

     for (function *f = fun; f; f = f->next)

       {

         const char *name = IDENTIFIER_POINTER (f->decl.name);

         if (strstr (name, "_clone") != NULL)

           {

             tree base_name = get_base_name (name);

             cloned_functions[base_name].push_back (f);

           }

       }

     ```


4. Comparing GIMPLE Representations:

   - I attempted to compare the GIMPLE representations of cloned functions to determine if they are substantially the same.

   - Example code snippet:

     ```cpp

     for (auto &pair : cloned_functions)

       {

         if (pair.second.size() > 1)

           {

             bool should_prune = true;

             function *base_func = pair.second;

             for (size_t i = 1; i < pair.second.size(); i++)

               {

                 function *clone_func = pair.second[i];

                 if (!are_functions_equivalent (base_func, clone_func))

                   {

                     should_prune = false;

                     break;

                   }

               }


             // Make a decision on pruning

             if (should_prune)

               {

                 if (dump_file)

                   {

                     fprintf (dump_file, "PRUNE: %s\n", IDENTIFIER_POINTER (base_func->decl.name));

                   }

               }

             else

               {

                 if (dump_file)

                   {

                     fprintf (dump_file, "NOPRUNE: %s\n", IDENTIFIER_POINTER (base_func->decl.name));

                   }

               }

           }

       }

     ```


Encountered Errors

Despite my efforts to implement the necessary components, I encountered several errors that have hindered my progress:


1. Type Mismatch Errors:

   - Errors related to type mismatches when using `DECL_NAME` macro with `function*` instead of `tree`.

     ```sh

     /home/hsingh902/spo600/gcc/gcc/tree-ctyler.cc: In function ‘unsigned int tree_clone_pruning(function*)’:

     /home/hsingh902/spo600/gcc/gcc/tree.h:375:24: error: no matching function for call to ‘contains_struct_check(function*&, tree_node_structure_enum, const char , int, const char )’

     ```


2. Scope and Type Specifier Errors:

   - Errors related to the scope and type specifiers in function declarations and definitions.

     ```sh

     /home/hsingh902/spo600/gcc/gcc/tree-ctyler.cc:101:24: error: use of local variable with automatic storage from containing function

     ```


3. Qualified-id in Declaration Before :

   - Errors related to incorrect syntax in function declarations.

     ```sh

     /home/hsingh902/spo600/gcc/gcc/tree-ctyler.cc:113:22: error: qualified-id in declaration before ‘(’ token

     ```


4. Expected Type-Specifier Before ‘pass_ctyler’:

   - Errors related to missing type specifiers in the `make_pass_ctyler` function.

     ```sh

     /home/hsingh902/spo600/gcc/gcc/tree-ctyler.cc:154:14: error: expected type-specifier before ‘pass_ctyler’

     ```

 Attempts to Resolve Errors


I have tried resolving these errors by:


- Correcting the type mismatches by using the correct type and ensuring proper casting.

- Ensuring that `pass_data_ctyler` is defined at the correct scope.

- Correcting the syntax in function declarations.

- Adding the correct type specifiers in the `make_pass_ctyler` function.


However, despite these attempts, I have not been able to resolve all the issues, and my progress on the project has been significantly hindered.


 Next Steps

Given the current state of my project, the next steps would involve:


-Refine Comparison Logic:

  - Further work is needed to refine the comparison logic to handle more complex cases.

  - This could involve more sophisticated methods to standardize the representation of functions.

- Handle More Complex Cloning Scenarios:

  - Extend the pass to handle more complex function cloning scenarios, including multiple clones and different optimization levels.


 Recommendations for the GCC Project


- Integrate AFMV into Mainline GCC:

  - Based on this project, it would be beneficial to integrate automatic function multi-versioning and pruning into the mainline GCC compiler.

  - This could involve adding more advanced comparison methods and handling more complex function cloning scenarios.


- Improve Documentation and Testing:

  - Enhance documentation and testing frameworks to support the new AFMV capabilities.

  - Provide clear guidelines and examples for developers to use and extend these features.



Git Workflow To manage the source code of the GCC pass project, I used Git for version control. Here are the key steps involved: Initial Setup

git init

git remote add origin https://github.com/HarleenSingh2604/SPO600-project.git


Test Cases

The following test cases were planned for validating the functionality of the GCC pass project. The associated code snippets or commands illustrate how these tests were intended to be executed. However, due to unresolved code errors, I was unable to complete these tests.


  1. Diagnostic Dumps Validation:
    • Objective: Verify that diagnostic messages are correctly written to the dump file.
    • Code to Execute:
      if (dump_file) { fprintf(dump_file, "===== Dummy Pass Diagnostic Dump =====\n"); }
    • Execution Command:
      gcc -fdump-tree-all -o test_program test_program.c
    • Expected Outcome: Diagnostic messages appear in the dump files generated during compilation.

  1. Basic Block and Statement Count:
    • Objective: Ensure that the pass iterates through basic blocks and statements, logging counts in the dump file.
    • Code to Execute:
      basic_block bb; int bb_cnt = 0, stmt_cnt = 0; FOR_EACH_BB_FN(bb, fun) { bb_cnt++; stmt_cnt += gimple_bb_stmt_count(bb); if (dump_file) { fprintf(dump_file, "BB %d: Statements %d\n", bb_cnt, gimple_bb_stmt_count(bb)); } }
    • Execution Command:
      gcc -fdump-tree-all -o test_program test_program.c
    • Expected Outcome: A dump file logs the counts of basic blocks and statements for the given test program.

  1. Function Cloning Detection:
    • Objective: Identify cloned functions with a _clone suffix and store them in data structures.
    • Code to Execute:
      std::map<tree, std::vector<function*>> cloned_functions; for (function *f = fun; f; f = f->next) { const char *name = IDENTIFIER_POINTER(f->decl.name); if (strstr(name, "_clone") != NULL) { tree base_name = get_base_name(name); cloned_functions[base_name].push_back(f); } }
    • Execution Command:
      gcc -fdump-tree-all -o test_program test_program.c
    • Expected Outcome: Dump file entries show detected cloned functions grouped under their base names.

  1. GIMPLE Representation Comparison:
    • Objective: Compare GIMPLE representations of cloned functions and log pruning decisions.
    • Code to Execute:
      for (auto &pair : cloned_functions) { if (pair.second.size() > 1) { bool should_prune = true; function *base_func = pair.second[0]; for (size_t i = 1; i < pair.second.size(); i++) { function *clone_func = pair.second[i]; if (!are_functions_equivalent(base_func, clone_func)) { should_prune = false; break; } } if (dump_file) { fprintf(dump_file, "%s: %s\n", should_prune ? "PRUNE" : "NOPRUNE", IDENTIFIER_POINTER(base_func->decl.name)); } } }
    • Execution Command:
      gcc -fdump-tree-all -o test_program test_program.c
    • Expected Outcome: The dump file logs "PRUNE" or "NOPRUNE" for each function based on the comparison results.

  1. Edge Case Handling:
    • Objective: Validate handling of functions with no clones, multiple clones, or varying optimization levels.
    • Code to Execute: The same as above, with diverse test programs to cover edge cases.
    • Execution Command:
      gcc -O0 -fdump-tree-all -o test_program test_program.c gcc -O2 -fdump-tree-all -o test_program test_program.c
    • Expected Outcome: Dump files show consistent handling and decision-making across edge cases.

Note: These tests could not be executed due to unresolved errors in the code. Addressing the errors remains essential to proceed with proper testing.



 Conclusion


While I have attempted to address the professor's feedback and resolve the encountered errors, my progress on the project has been stalled due to these issues. Further assistance and guidance are needed to overcome these challenges and complete the project successfully.

Comments

Popular posts from this blog

Project Stage 1- GCC Build & Dump on AArch64

SPO600 LAB 1