> The CPU doesn't really see functions, it just sees instructions. Functions are a convention on top of the machine code.

Not really true, most instructions set have instructions specifically to implement functions as found in normal programming languages. x86 has CALL and RET for example.

https://en.wikipedia.org/wiki/X86_calling_conventions

Of course the compiler can stil optimize by inlining etc., but functions still mostly exist at the assembly level.

they have instructions for implementing them, but the important point here is that functions are still only defined by instructions that are executing between a call and ret instruction (or their equivalent more spelled-out equivalent operations), and not only can these not match up with what the compiler considers a function (for useful reasons like tail-calls as well as not-useful reasons like compiler bugs and UB), it might not be statically obvious exactly what instructions these are. So the CPU in practice has only a rough guess of where the function boundaries are (it might use these guesses for things like branch prediction, but they don't define the visible execution of the code beyond the nuts and bolts of what those instructions actually do).