Roman Lebedev via llvm-dev
2021-Apr-18 16:42 UTC
[llvm-dev] Revisiting/refining the definition of optnone with interprocedural transformations
There's 'noipa' attribute in GCC, currently it is not supported by clang. Theoretically, how would one implement it? With your proposal, clang `noipa` attribute could be lowered to `optnone` on the whole function, To me that seems like too much of a hammer, should that be the path forward. Would it not be best to not conflate the two, and just introduce the `noipa` attribute? Roman On Sun, Apr 18, 2021 at 7:37 PM David Blaikie <dblaikie at gmail.com> wrote:> > While trying to reproduce some debug info thing (I don't have the exact example at the moment - but I think it was more aggressive than the example I have now, but something like this: > > __attribute__((optnone)) int f1() { > return 3; > } > int main() { > return f1(); > } > > > (actually I think in my case I had a variable to hold the return value from f1, with the intent that this variable's location couldn't use a constant - a load from a volatile variable would probably have provided similar functionality in this case) > > LLVM (& specifically Sparse Conditional Constant Propagation, llvm/lib/Transforms/Scalar/SCCP.cpp) optimizes this code noting that f1 always returns 3, so rather than using the return value from the call to f1, it ends up hardcoding the return value: > > define dso_local i32 @main() local_unnamed_addr #1 { > > entry: > > %call = tail call i32 @_Z2f1v() > > ret i32 3 > > } > > > I consider this a bug - in that optnone is used to implement -O0 for LTO, so it seemed to me that the correct behavior is for an optnone function to behave as though it were compiled in another object file outside the purview of optimizations - interprocedural or intraprocedural. > > So I sent https://reviews.llvm.org/D100353 to fix that. > > Florian pointed out that this wasn't quite specified in the LangRef, which says this about optnone: > > This function attribute indicates that most optimization passes will skip this function, with the exception of interprocedural optimization passes. Code generation defaults to the “fast” instruction selector. This attribute cannot be used together with the alwaysinline attribute; this attribute is also incompatible with the minsize attribute and the optsize attribute. > > This attribute requires the noinline attribute to be specified on the function as well, so the function is never inlined into any caller. Only functions with the alwaysinline attribute are valid candidates for inlining into the body of this function. > > > So the spec of optnone is unclear (or arguably explicitly disallows) whether interprocedural optimizations should treat optnone functions in any particular way. > > So I was going to update the wording to rephrase this to say "Interprocedural optimizations should treat this function as though it were defined in an isolated module/object." (perhaps "interprocedural optimizations should treat optnone functions as opaque" or "as though they were only declarations") > > The choice of this direction was based on my (possibly incorrect or debatable) understanding of optnone, that it was equivalent to the function being in a separate/non-lto object. (this seems consistent with the way optnone is used to implement -O0 under lto - you could imagine a user debugging a binary, using -O0 for the code they're interested in debugging, and potentially using an interactive debugger to change some state in the function causing it to return a different value - which would get quite confusing if the return value was effectively hardcoded into the caller) > > What're folks thoughts on this? > > - Dave
David Blaikie via llvm-dev
2021-Apr-18 17:06 UTC
[llvm-dev] Revisiting/refining the definition of optnone with interprocedural transformations
On Sun, Apr 18, 2021 at 9:43 AM Roman Lebedev <lebedev.ri at gmail.com> wrote:> There's 'noipa' attribute in GCC, currently it is not supported by clang. > Theoretically, how would one implement it? >If we wanted to do this really robustly, I guess we might have to introduce some sort of "here's the usual way to check if this is a definition/get the body of the function" (which for noipa it says "there is no body/don't look here") and "no, really, I need the definition" (for actual code generation). Though I'm not advocating for that - I'm OK with a more ad-hoc/best-effort implementation targeting the -O0/debugging assistant __attribute__((optnone)) kind of use case - happy to fix cases as they come up to improve the user experience for these situations. Maybe we could get away with generalizing this by having an optnone (or noipa) function appear "interposable" even though it doesn't have a real interposable linkage? That should hinder/disable any IPA. Hmm, looks like GlobalValue::isDefinitionExact would be best to return false in this case (whatever we end up naming it) /maybe/ mayBeDerefined should return false too. Yeah, I guess if we can implement such a robust generalization, then it'd probably be OK/easy enough to implement both noipa and optnone implies noipa the same as it implies noinline (well, I guess noipa would subsume the noinline implication - if the function isn't exact, the inliner won't inline it so there wouldn't be any need for the explicit noinline)> With your proposal, clang `noipa` attribute could be lowered > to `optnone` on the whole function, To me that seems like > too much of a hammer, should that be the path forward. >I agree that lowering noipa to optnone would be a very aggressive form of noipa - likely if we want to support noipa it would be to support it separately and maybe either lower -O0 (& maybe __attribute__((optnone))) to both optnone+noipa+noinline (since optnone already implies noinline) or make optnone imply ipa/be a superset of it implicitly (if we do have noipa it's probably best to have "optnone requires noipa" the same way "optnone requires noinline" rather than an implicit superset sort of thing). I think that'd certainly be appropriate for -O0, and I'd argue it'd be appropriate for __attribute__((optnone)) because I think it'd be what people expect/is consistent with the motivation for the attribute (for debuggability - so you wouldn't want a caller to not fill in parameters/pass in garbage because it knows the implementation doesn't matter, or not use the result because it knows what the result should be).> Would it not be best to not conflate the two, > and just introduce the `noipa` attribute? >I think we'd still want to conflate them for user-facing functionality, even if they were separable at the IR level. - Dave> Roman > > On Sun, Apr 18, 2021 at 7:37 PM David Blaikie <dblaikie at gmail.com> wrote: > > > > While trying to reproduce some debug info thing (I don't have the exact > example at the moment - but I think it was more aggressive than the example > I have now, but something like this: > > > > __attribute__((optnone)) int f1() { > > return 3; > > } > > int main() { > > return f1(); > > } > > > > > > (actually I think in my case I had a variable to hold the return value > from f1, with the intent that this variable's location couldn't use a > constant - a load from a volatile variable would probably have provided > similar functionality in this case) > > > > LLVM (& specifically Sparse Conditional Constant Propagation, > llvm/lib/Transforms/Scalar/SCCP.cpp) optimizes this code noting that f1 > always returns 3, so rather than using the return value from the call to > f1, it ends up hardcoding the return value: > > > > define dso_local i32 @main() local_unnamed_addr #1 { > > > > entry: > > > > %call = tail call i32 @_Z2f1v() > > > > ret i32 3 > > > > } > > > > > > I consider this a bug - in that optnone is used to implement -O0 for > LTO, so it seemed to me that the correct behavior is for an optnone > function to behave as though it were compiled in another object file > outside the purview of optimizations - interprocedural or intraprocedural. > > > > So I sent https://reviews.llvm.org/D100353 to fix that. > > > > Florian pointed out that this wasn't quite specified in the LangRef, > which says this about optnone: > > > > This function attribute indicates that most optimization passes will > skip this function, with the exception of interprocedural optimization > passes. Code generation defaults to the “fast” instruction selector. This > attribute cannot be used together with the alwaysinline attribute; this > attribute is also incompatible with the minsize attribute and the optsize > attribute. > > > > This attribute requires the noinline attribute to be specified on the > function as well, so the function is never inlined into any caller. Only > functions with the alwaysinline attribute are valid candidates for inlining > into the body of this function. > > > > > > So the spec of optnone is unclear (or arguably explicitly disallows) > whether interprocedural optimizations should treat optnone functions in any > particular way. > > > > So I was going to update the wording to rephrase this to say > "Interprocedural optimizations should treat this function as though it were > defined in an isolated module/object." (perhaps "interprocedural > optimizations should treat optnone functions as opaque" or "as though they > were only declarations") > > > > The choice of this direction was based on my (possibly incorrect or > debatable) understanding of optnone, that it was equivalent to the function > being in a separate/non-lto object. (this seems consistent with the way > optnone is used to implement -O0 under lto - you could imagine a user > debugging a binary, using -O0 for the code they're interested in debugging, > and potentially using an interactive debugger to change some state in the > function causing it to return a different value - which would get quite > confusing if the return value was effectively hardcoded into the caller) > > > > What're folks thoughts on this? > > > > - Dave >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210418/06a41b7c/attachment.html>