DEV Community

Yukti Manoj Mulani
Yukti Manoj Mulani

Posted on

Project Stage-2 Implementation [part-2]

Welcome back peeps!! After a lot of theory about function multi versioning in the last blog we will start actually working on it in this part. So, without wasting any time lets get started.

I started with exploring files like
tree.h,tree.ccand tree-inline.h
to understand how functions are represented and cloned in GCC's gimble IR. Now the question is how do I find them. So I used the following commands and experimented with the arguments here and there and came up with the following.
Syntax
find /path -iname filename
This was the actual command I used
find ./ -iname tree.h
The file tree.his in gcc/gcc/tree.h To view thw contents of the file we can use the command cat tree.h

After taking time to investigate the file I found out that the file contains code to help around function multiversioning and deaclares those functions but does not contain the code that is used to create clones.
Now lets explore other files.This time lets use the vim editor to read the file which make it a little easy ti read.The commanf for that is :-
vi tree.cc
This file is also lacated in the /gcc/gcc/ directory.
This file does not look very useful because it contains code for the tree structure and not multi versioning.

Now explore the third file tree-inline.h. Using the same command for vim editor. To exit vim editor without saving anything, use the command.:Q!

This file contains code related to inlining, versioning, cloning, and parallelization. The presence of these keywords made me feel that I am close to the actual code where turning AFMV on and passing the target architectures array is located.

If you want to search for a keyword in vim editor, just type.
/word
I searched for the word version by using /version and found the declaration of the function called
bool tree_versionable_function_p(tree);
This function was declared under the comment
"/*function prototypes*/".
By the declaration and the name, it seems that this function determines whether the code is versionable or not. A few more commands that I tried to find the actual code were following.

grep "clon" -r
This commands grabs all the files containing the word "clon". It gace an ecdless list of files making it impossible to indentify

grep "fmv" -r
this gave me a shorter list but no results.(had a mental breakdown but I continues 😵‍💫)

git log --oneline --grep="multiversioning"
This command gives you all the past commits displayed in one line containing the word "multiversioning". I got arounf 17 commits and 3 of them were useful.

The commits are as follows.

commit logs

The ones that I founf usefule were
"[aarch64] Add function multiversioning support"
"Add support for target version attribute"
"aarch64: Fix function multi versioning mangling "

I investigated the first two commits and I could not find very useful code, but I needed to investigate these two commits to get an idea of how things work and how the function multi versioning is done. I investigated the first two and went off track forgetting that we need to update and not add FMV. Then I came to the third commit.
To investigate any commit you can use the command.
git show <commit hash>
After investigating this commit, you will see there are few lines that tell you which files were changed. And the address of the file. I tried to use the command grep "target_clones". But it froze my session. The correct way to do the grep along with the commit is the following.
git show <commit hash> | grep "taget_clones"

Output

This is called piping. This gave me all the lines where the target clones were specified before the function. Now we need to find the function that contains the code for automatic FMV. Then I searched up the word clone and after so many occurrences I found a comment.
/*If the function in the node has multiple target attributes, create the appropriate clone for each valid target.*/
The function definition looks like the following.

statuc bool expand_target_clones(struct cgraph_nodes*node, bool definition)

This function takes in an array of target clones and the function definition to be cloned. It parses the comma separated target clones and verifies if the function is versionable by using the function that we discovered previously.

tree_versionable_function_p

Cannot believe that it took me so much time. I was always searching for files with obvious names. But the actual file that was useful was /gcc/gcc/multiple_targets.cc
Then I started my work and hardcoded the array of target architectures needed and also made the definition being passed to be true to apply function multi versioning for all functions automatically.

Image description

Image description

So now we need to test it. So I wrote a simple sum of array program and built it using O3 level optimization

Image description

First I set the hard coded targets to be sve and sve2, but the program that I designed to test it did not compile because the target sve2 is not supported by GCC version 11.3.1. Which is the version that I'm using right now.

So to know which targets are supported, I used the following command.

gcc -E -march=help -xe /dev/null

Image description

But this command gave me an error, but it told me which targets are valid. And are supported target architectures by my current GCC version.

Then I changed the hardcoded array to the preferred targets. Still I got the same error.

Image description

So now I checked the file CPU info which is under the directory proc. And this file gave me the features of every processor. And also told me what all features are supported by each processor.

Image description

Wrapping It Up: A Roller Coaster Ride in Code Land

After navigating through a labyrinth of files, parsing through oceans of code, and deciphering the cryptic hieroglyphics that is GCC's inner workings, I finally emerged victorious! 🎉 Although I did face some hiccups with target architectures and GCC versions (who knew “sve2” was such a stickler for attention?), I’m now armed with knowledge and a few more grey hairs.

Key Takeaways:

  • Persistence Pays Off: It took a while to locate the right file (/gcc/gcc/multiple_targets.cc), but persistence led me to the treasure chest of FMV code.
  • Tools are Your Friends: Commands like grep, find, and git show became my trusty sidekicks in this quest. (Seriously, I might name my next pet “grep”.)
  • Know Your Limits: GCC version 11.3.1 has its own quirks, and knowing what your tools can and cannot do is half the battle.

Lessons Learned:

  • Stay Curious: Digging through the commits and code not only helped me understand FMV better, but also improved my detective skills (move over, Sherlock!).
  • Stay Organized: Keep track of useful commands and file paths. It saves time and sanity in the long run.
  • As I wrap up this chapter of my FMV journey, I look back and chuckle at the moment when I almost turned my keyboard into a Frisbee. 🥏 But hey, no keyboards were harmed in the making of this blog!

What’s Next?

Next up is testing the FMV with different GCC versions and refining my approach to cater to all the architectures out there (yes, even the picky ones like “sve2”). I’ll also be looking into more advanced optimizations and perhaps dabbling in some parallel processing fun.

Stay tuned, dear readers, as I continue to unravel the mysteries of function multi versioning. And remember, if you ever find yourself lost in a sea of code, just keep swimming… and maybe bring a snorkel. 🏊‍♂️

Reflections:

This project was like a wild roller coaster ride—thrilling, sometimes dizzying, but ultimately satisfying. I’ve learned so much about GCC’s inner workings and realized that there’s always more to explore and improve. I plan to dive deeper into compiler optimizations and perhaps even contribute to the community.

Links to My Code:

Thank you for joining me on this journey. Until next time, happy coding! 🚀

Top comments (0)