Johannes Doerfert via llvm-dev
2021-Apr-22 15:42 UTC
[llvm-dev] Revisiting/refining the definition of optnone with interprocedural transformations
On 4/22/21 9:43 AM, paul.robinson at sony.com wrote:>> That said, I believe it is a mistake that `optnone` requires >> `noinline`. There is no reason for it to do so on the IR level. >> If you argue C-level `optnone` should imply `noinline`, that is >> a something worth discussing, though on the IR level we can >> decouple them. Use case, for example, the not-optimized version >> is called from functions that are `optnone` themselves while >> other call sites are inlined and your function is optimized. So >> you can use the two attributes to do context sensitive `optnone`. > The original intent for `optnone` was to imitate the -O0 pipeline > to the extent that was feasible. The -O0 pipeline (as constructed > by Clang) runs just the always-inliner, not the regular inliner; > so, functions marked `optnone` should not be inlined. The way > to achieve that effect most simply is to have `optnone` require > `noinline` and that's what we did. > > If we have `optnone` stop requiring `noinline` and teach the > inliner to inline an `optnone` callee only into an `optnone` caller, > then we are violating the intent that `optnone` imitate -O0, because > that inlining would not have happened at -O0.I think I initially read this wrong, hence the part below. After reading it again, I have one question: Why would the inliner inline something that is not `always_inline` into an `optnone` caller? That would violate the idea of `optnone`, IMHO, regardless if the callee is `optnone` or not. That is why I don't believe `noinline` on the callee is necessary for your use case. --- I misread and I wrote this, might be useful still --- Let's look at an example. I show it in C but what I am arguing about is still IR, as described earlier, C is different. ``` __attribute__((optnone)) void foo() { ... } __attribute__((optnone, noinline)) void bar() { foo(); ... } void baz() { foo(); bar(); ... } ``` Here, the user has utilized optnone and noinline to get different kinds of distinct effects that you could all want: - foo is not optimized, not inlined into bar, but inlined into baz - bar is not optimized and not inlined into baz I hope this makes sense. ~ Johannes> --paulr
via llvm-dev
2021-Apr-22 16:05 UTC
[llvm-dev] Revisiting/refining the definition of optnone with interprocedural transformations
> On 4/22/21 9:43 AM, paul.robinson at sony.com wrote: > >> That said, I believe it is a mistake that `optnone` requires > >> `noinline`. There is no reason for it to do so on the IR level. > >> If you argue C-level `optnone` should imply `noinline`, that is > >> a something worth discussing, though on the IR level we can > >> decouple them. Use case, for example, the not-optimized version > >> is called from functions that are `optnone` themselves while > >> other call sites are inlined and your function is optimized. So > >> you can use the two attributes to do context sensitive `optnone`. > > The original intent for `optnone` was to imitate the -O0 pipeline > > to the extent that was feasible. The -O0 pipeline (as constructed > > by Clang) runs just the always-inliner, not the regular inliner; > > so, functions marked `optnone` should not be inlined. The way > > to achieve that effect most simply is to have `optnone` require > > `noinline` and that's what we did. > > > > If we have `optnone` stop requiring `noinline` and teach the > > inliner to inline an `optnone` callee only into an `optnone` caller, > > then we are violating the intent that `optnone` imitate -O0, because > > that inlining would not have happened at -O0. > > I think I initially read this wrong, hence the part below. > After reading it again, I have one question: Why would the > inliner inline something that is not `always_inline` into > an `optnone` caller? That would violate the idea of `optnone`, > IMHO, regardless if the callee is `optnone` or not. That is > why I don't believe `noinline` on the callee is necessary > for your use case.The inliner should be ignoring `optnone` callers, so it would never inline *anything* into an `optnone` caller. (Other than an `alwaysinline` function.) I had read this:> >> I believe it is a mistake that `optnone` requires `noinline`.and the case that came to mind is inlining an `optnone` callee into a not-`optnone` caller. The inlined copy would then be treated to further optimization, which violates the idea of `optnone`. Now, the inliner already knows to avoid `noinline` callees, so attaching `noinline` to `optnone` functions was (at the time) considered an optimal way to avoid the problematic case. We could instead teach the inliner to skip `optnone` callees, and that would allow us to eliminate the requirement that `optnone` functions must also be `noinline`. I am unclear why redefining `optnone` to _imply_ `noinline` (rather than _require_ `noinline`) is better, but then I don't work much with attributes. The notion of allowing an `optnone` caller to inline an `optnone` callee sounds like it would also violate the intent of `optnone` in that it should imitate -O0, where inlining is confined to `alwaysinline` callees, and `optnone` is defined to conflict with `alwaysinline` (because if you always inline something, you are allowing it to have subsequent optimizations same as the caller, which conflicts with `optnone`). So, if you want to undo the _requirement_ that `optnone` must have `noinline`, but then redefine `optnone` such that it can't be inlined anywhere, you've done something that seems to have no practical effect. Maybe that helps Attributor in some way, but I don't see any other reason to be making this change. --paulr
via llvm-dev
2021-Apr-22 16:44 UTC
[llvm-dev] Revisiting/refining the definition of optnone with interprocedural transformations
> Let's look at an example. I show it in C but what I am arguing > about is still IR, as described earlier, C is different. > > ``` > __attribute__((optnone)) > void foo() { ... } > __attribute__((optnone, noinline)) > void bar() { foo(); ... } > void baz() { foo(); bar(); ... } > ``` > Here, the user has utilized optnone and noinline to get different > kinds of distinct effects that you could all want: > - foo is not optimized, not inlined into bar, but inlined into bazfoo's non-inlined instance is not optimized; but, the instance that is inlined into baz *is* optimized. How does that obey `optnone`?> - bar is not optimized and not inlined into baz > > I hope this makes sense. > > ~ JohannesThe use-case for `optnone` is to allow selectively not-optimizing a function, which I've seen used only to permit better debugging of that function. Inlining optimizes (some instances of) the function, against the coder's express wishes, and interfering with the better debugging enabled by not-optimizing. I don't see how that is beneficial to the coder, or any other use-case. If you have a practical use-case I would love to hear it. Yes, I do see that separating the concerns allows this weird case of a sometimes-optimized function, but I don't see any benefit. Certainly it would be super confusing to the coder, and at the Clang level I would strenuously oppose decoupling these. Apologies for mentioning Attributor; I have no idea how it works, and I was rather idly speculating why you want to decouple the optnone and noinline attributes. --paulr