I have an understanding of how the likely()/unlikely() macros work and I also have an understanding of branch prediction. Unfortunately, I did not learn branch prediction in the context of high level programming.
What I want to know is if the evaluation within the likely/unlikely macro results in a segmentation fault, how does that impact the branch prediction history or even the current outcome/pipeline.
I fail to understand that if the validation of the prediction didn't complete, how do we know if it was a success or a failure ?
__builtin_expect (used in the definition of the likely/unlikely macros) doesn't generate actual code to evaluate either of its arguments. All it does is tell the compiler what result to expect if it were evaluated.
It might confuse the optimizer if you tell it that
*(int*)NULL is usually
13, but (barring compiler bugs) it won't segfault the compiler, or produce code which segfaults at run-time.
Another answer on the old question has actual asm with/without the macro, showing that their effect is in how gcc lays out the code (e.g. putting the unlikely case off by itself, and the likely case in the fall-through not-taken side of a conditional branch where instruction-cache misses are less likely).
This isn't quite a duplicate of likely()/unlikely() macros in the Linux kernel - how do they work? What's their benefit?, but you will find much more info about how these macros work and what their effect is on that Q&A.