How to recover function parameter Value* when -O2 active

Dear LLVM mailing list,

I am currently having difficulty with figuring out how to get a function parameter Value* when I am compiling with -O2. It seems -O2 performs an optimization that optimizes out the local variable formed for the function parameter.

I have a pass where I am inserting new function calls, and need to pass the function parameters variable address. With -O0 this issue does not come up as each function parameter when using -O0 gets its own AllocaInst and I can leverage that Value* to pass to my new function call. I have tried to leverage llvm.dbg information but it seems LLVM is not inserting llvm.dbg.addr for me to use.

Below is the code example I am working with:
/* example.c */

int fd_in;
char* ut_addr;

attribute((noinline)) void bar (int b){
my_pass_function( &b ); // NEW (what I want to be done by my pass)

ut_addr = (char*) mmap( 0, b, my_prot, MAP_PRIVATE, fd_in, 0);
}

attribute((noinline)) void foo (int f){
bar( f );
}

int main(int argc, char** argv){
int m;
struct stat statbuf;
char *input;

if( (fd_in = open ( input, O_RDONLY)) < 0){ /* open the input file /
return 0;
}
if( fstat( fd_in , &statbuf ) < 0 ){ /
find size of input file */
return 0;
}

m = statbuf.st_size;
foo( m );
return 0;
}

If you want to access the `llvm::AllocaInst` generated by Clang for
the argument you should run your pass early in the pipeline. If you
just want to see the value passed to `bar`, take the `llvm::Argument`
and pass it to your profiling function. If you need indirection for
some reason, create a new `llvm::AllocaInst`, store the `llvm::Argument`
you are interested in in it, and pass the `llvm::AllocaInst` to your
function.

I hope this helps.

~ Johannes

Thank you so much for your reply!

I want my pass to run as late as possible to not be messed up by any of the regular internal optimizations. I need a reference of i32 %b (regularly we see this in IR as i32* %b) so if I understand you I think I need an indirection.
In that case is it safe to just create an AllocaInst ? Does adding the AllocaInst effect the way the data flows between functions?

The reason I am saying this is: Following my above example code, assuming I am interested in the local variable “m” declared and set in main() (so a memory slot dedicated for “m” is created in the stack, right?), “m” is passed to foo(m), nothing is altered, “m” is further passed to bar().
If I created the AllocaInst in bar and assign %b to it, will I be creating a new stack memory slot for bar’s Argument “b” and will then I be passing in the memory address of “b” (context of bar()) and not “m” (context of main()).

I want to, if possible, pass the stack address of “m” (from the context of main) to my profiling function call that is currently in the context of bar().

Thank you so much for your reply!

I want my pass to run as late as possible to not be messed up by any of the
regular internal optimizations. I need a reference of i32 %b (regularly we
see this in IR as i32* %b) so if I understand you I think I need an
indirection.
In that case is it safe to just create an AllocaInst ? Does adding the
AllocaInst effect the way the data flows between functions?

The reason I am saying this is: Following my above example code, assuming I
am interested in the local variable "m" declared and set in main() (so a
memory slot dedicated for "m" is created in the stack, right?), "m" is
passed to foo(m), nothing is altered, "m" is further passed to bar().
If I created the AllocaInst in bar and assign %b to it, will I be creating
a new stack memory slot for bar's Argument "b" and will then I be passing
in the memory address of "b" (context of bar()) and not "m" (context of
main()).

I want to, if possible, pass the stack address of "m" (from the context of
main) to my profiling function call that is currently in the context of
bar().

Your code *does not* pass the address of `m` in `main` to `foo`.
It passes `m` by value to `foo`, thus the argument `b`is a copy
of `m` if you want. You cannot recover the address of `m` in `foo`
by any legal means. In fact, the optimizer will realize there is
no need for stack allocations and put both `m` and `b` into (virtual)
registers instead. If you want to trace a stack allocation, trace
it early. If you "wait" and it is remove because it was not observed/
needed, it's gone for good.

For your code, change it to:

void foo(int *bptr) { int b = *bptr; ... }
void main(...) {
...
*m = ...
...
foo(&m);
}

and then you can profile the `i32* %bptr` argument of foo which is
the "stack" address of `m` in `main`.

~ Johannes

Ah makes sense completely, I forgot about it being pass by value. Thanks again for clearing this up.

Also unrelated but: I just discovered LLVM has its own discord and I posted my question there first, is it popular? Or is mailing list still more responsive?

Ah makes sense completely, I forgot about it being pass by value. Thanks
again for clearing this up.

Also unrelated but: I just discovered LLVM has its own discord and I posted
my question there first, is it popular? Or is mailing list still more
responsive?

I'd say that depends (on what and who you ask). You reach different
people through the different channels, for better or worse.

~ Johannes