In C, if I have a function pointer
int (*f_ptr) (int)
it will be in the instruction cache or in the data cache ? I wouldn't be surprised to find f_ptr in either of those caches. There is a way to debug this under linux maybe with perf, kinda like a bird eye view of the data cache, instruction cache and translation lookaside buffer ?
EDIT
"It depends" is the answer. First and foremost some caches have I and D combined, some have them separate, some are configurable.
The bottom line is a data access with caching enabled is a data access for the data cache, an instruction fetch with caching enabled is connected to the instruction cache.
The manipulation of the function pointer unless optimized into a register is is a data access for the data cache. Executing the function requires that address so either it is optimized into a register and no access is required, or a data access is required to get the address and then that address is called/branched to which results in the instructions at that address to be candidates for the instruction cache.
Not uncommon for function pointers to be used for loadable modules or an abstraction layer, where one time you change the address of the functions to point at the loaded module, etc then many times you simply call those functions. Depending on your system and application the time between calls to that function may be such that other data accesses evict that function pointer address to L2 or L3 ... and eventually main/slow ram, and in that case it is no longer in any cache. When eventually the call happens then the data access happens and the address is read and lands in the layers of caches it passes through (however many you have).
Some simple examples:
One compiler produces:
and as expected the read of the address to the pointer is a data access
also as not only expected but required the call
14: e12fff33 blx r3
would be an instruction fetch at that address. On an arm which the above example is the L1 can/is combined I and D, so had the write to that address been recent enough and not evicted then it would have pulled it from the cache. otherwise l2 or l3 ... or main/slow ram
Now do something like this:
which gives
so the address for f_ptr is stored but it is not read nor used in fact.
do this
and
and the store happens but there is no function call at all
intersting:
the compiler missed an opportunity
Could have probably gotten away with
as the reset is dead code.
so switch compilers and the opportunity was taken
neither was there a data write nor read with respect to the address of f_ptr. so you cannot universally say that f_ptr is in cache at all.
the poster tagged more than one instruction set, and perhaps within those we can probably agree that there will be a data instruction to get the function pointer address then a call/branch to that address would fetch instructions AT that address. But there are instruction sets that have double indirect data instructions, there perhaps are those with jump table instructions, and yes the read of the address is a data operation true, but is that how that processor would work? esp if it is a harvard architecture perhaps and the jump table instruction is relative to the instruction location (guaranteed to be right next to the instruction in .text, would be inefficient to re-read the same space you may have already have fetched).
short answer, the instructions for the function are instruction fetches and would go through the i cache. Manipulation of the function pointer including the read of it to perform the call is most likely a data access and if cached in the d cache. Unless someone thinks of an instruction in some instruction set the f_ptr address will be in the data cache, to be in i cache would have to be a special instruction for some specific processor and the compiler will have to have used that instruction (which leads to a race condition between manipulation of the address and the use of the address which the compiler would have to cause a flush which it would probably rather implement a data read then call than use the special instruction).
EDIT 2
A simple example of the address being optimized into a register
gives
no data accesses at all.