[llvm-dev] What can the optimizer assume about the memory a global function pointer points to?

Manuel Jacob via llvm-dev llvm-dev at lists.llvm.org
Wed Apr 15 17:45:52 PDT 2020

A function declaration declares a function pointer to the memory where 
the machine code will be at runtime. Besides providing the ability to 
call the function, that pointer can also be used, after bitcasting it, 
to modify the machine code implementing the function. What does the 
optimizer assume about the memory containing the machine code?

The following is an example where Alive2 assumes that transforming @src 
to @tgt is correct (note that @f is marked readnone):

declare i32 @f() readnone
declare void @modify_f()

define i32 @src() {
   call void @modify_f()
   %r = call i32 @f()
   ret i32 %r

define i32 @tgt() {
   %r = call i32 @f()
   call void @modify_f()
   ret i32 %r

Is this actually a correct transformation?

If yes, what is the exact rule?

Several possibilities come to my mind:

* The memory at @f is assumed to be constant. If this is the case, how 
can it be communicated to the optimizer that the memory is modified?
* In the following part of the definition of the "readnone" attribute, 
"memory" includes the machine code of the callee: "On a function, this 
attribute indicates that the function computes its result (or decides to 
unwind an exception) based strictly on its arguments, without 
dereferencing any pointer arguments or otherwise accessing any mutable 
state (e.g. memory, control registers, etc) visible to caller 
functions.". However, then the following part would be inconsistent (if 
executing machine code is considered reading): "If a readnone function 
reads or writes memory visible to the program, or has other 
side-effects, the behavior is undefined.".

More information about the llvm-dev mailing list