I have a C function:
__attribute__((__visibility__("default")))
__attribute__((used))
__attribute__((noinline))
void please_do_not_optimize_me_away(int arg1, void *arg2) {
asm volatile("" :::);
}
(the purpose is that this function will be used dynamically at runtime, perhaps by interposing the function, or via the debugger)
I really thought this will not get optimized out, but I've realized (the hard way) that LLVM will happily optimize a call to this function, and replace all arguments with undef, because it figures out that they're not really needed.
I'm going to fix this by passing the arguments explicitly as inputs to the asm, but is that expected? Is there any more reasonable way (attribute) of telling that the compiler should really not expect anything from the body of the function, not assume that it's not doing anything, and not optimizing out arguments?
Thanks,
Kuba
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Actually, it should be enough to use:
__attribute__((noinline))
void please_do_not_optimize_me_away(int arg1, void *arg2) {
asm volatile("":::"memory");
}
Creating a real barrier is important.
Joerg
I don't think it is reasonable to expect "noinline" to mean "must not do
IPA". There are different reasons for using "noinline": ensuring a stack
frame, forcing outlining of "cold" code etc. Many of those reasons are
perfectly fine to still allow IPA. Debug hooks fall into two categories:
making sure that the call happens (noinline should allow that) and
making sure that the debugger can actually do something at this point
(noinline should not have to allow that).
On Thu, Jun 22, 2017 at 05:35:51PM +0000, David Blaikie wrote:
> optnone should work, but really noinline should probably (Chandler: Can you
> confirm: is it reasonable to model noinline as "no interprocedural analysis
> across this function boundary" (so FunctionAttrs should do the same thing
> for noinline as it does for optnone, for example? ie: not derive any new
> attributes) - allowing the function to be optimized internally (unlike
> optnone) but not allowing interprocedural analysis inside the function to
> be used in callers (unlike optnone)) work as well?
I don't think it is reasonable to expect "noinline" to mean "must not do
IPA". There are different reasons for using "noinline": ensuring a stack
frame, forcing outlining of "cold" code etc. Many of those reasons are
perfectly fine to still allow IPA. Debug hooks fall into two categories:
making sure that the call happens (noinline should allow that)
I agree, but still I don't think it's `noinline` job to prevent this
from happening. It sounds weird (and probably a POLA violation) having
`noinline` preventing interprocedural constant propagation.
About `optnone`, I'm surprised is not powerful enough to prevent this
from happening, modulo bugs of course. Do you have other examples?
--
Davide
--
Davide
optnone should work, but really noinline should probably (Chandler: Can you confirm: is it reasonable to model noinline as "no interprocedural analysis across this function boundary" (so FunctionAttrs should do the same thing for noinline as it does for optnone, for example? ie: not derive any new attributes) - allowing the function to be optimized internally (unlike optnone) but not allowing interprocedural analysis inside the function to be used in callers (unlike optnone)) work as well?
This doesn't work – the call still gets turned into please_do_not_optimize_me_away(undef, undef).
> __attribute__((optnone))
optnone works, but I'm actually surprised by this. I would expect that it would only affect the generated code of that function...
Is it guaranteed to work? Or is my safest bet still to use:
__attribute__((noinline))
void please_do_not_optimize_me_away(int arg1, void *arg2) {
asm volatile("" :: "r" (arg1), "r" (arg2) : "memory");
}
(The other benefit compared to optnone is that this will actually generate a nice empty function. Using optnone generates code that stores the arguments to the stack.)
Kuba
> Actually, it should be enough to use:
>
> __attribute__((noinline))
> void please_do_not_optimize_me_away(int arg1, void *arg2) {
> asm volatile("":::"memory");
> }
>
> Creating a real barrier is important.
This doesn't work – the call still gets turned into please_do_not_optimize_me_away(undef, undef).
> __attribute__((optnone))
optnone works, but I'm actually surprised by this. I would expect that it would only affect the generated code of that function...
Is it guaranteed to work?
- Matthias
I'm not saying it does that. But I am saying that is why someone might
want to use it. That's why I gave the example with the memory clobber --
that is known to work for both GCC and Clang and fits here in the sense
that (1) it can't be duplicated (2) it contains a side effect. Now
whether this is the semantic we want to have for noinline is a different
question.
If you also want it to preserve the arguments (that wasn't clear to me),
just add them as arguments to the asm statement?
Joerg