Fedor Sergeev via llvm-dev
2018-Oct-01 18:32 UTC
[llvm-dev] OptBisect implementation for new pass manager
On 10/01/2018 08:39 PM, David Greene wrote:> "Kaylor, Andrew" <andrew.kaylor at intel.com> writes: > >> What if in the registration interface we had three options: skippable, >> not skippable, and run at OptLevel::None. > I kind of like this idea. If necessary, the pass could even query the > target (or some other entity) about what OptLevel::None means. > > If we have such query hooks, do we need "not skippable?" If a pass is > not skippable, then running at OptLevel::None should be fine, as long as > the pass can know what it needs to do at OptLevel::None (at minimum > produce functional code). > > "Not skippable" seems to imply "run the pass at full(-ish) optimization > always." Maybe that's a useful third state, I'm not sure.Seems like our current vocabulary is somewhat imprecise. I'm not sure that I fully gather which part of pipeline construction/execution and which object interaction do you mean when talking about "query hooks" or "run the pass". Right now we have the following objects: - OptBisect, which is pass-instrumentation object - PassBuilder object that constructs the pipeline - PassManager object that controls the pass execution - Pass object, which is being constructed for PassBuilder and then executed with PassManager At construction time there are: Pass, OptBisect, PassBuilder objects and at execution time there are: Pass, OptBisect, PassManager objects which of those do you see interacting when you talk about "query hooks"? My mental model of "not skippable" handling: - OptBisect is the controlling object. - at construction time it tracks objects being constructed and stores its "skippable"/"unskippable" properties. - at run-time PassManager asks OptBisect and it reports whether to skip the pass or not. PassManager acts accordingly. "run the pass at full optimization" is something that I dont see a clear mental model of. Obviously it is the Pass itself that can run itself at full optimization *if* it gets control. PassManager can pass the control to the Pass. OptBisect does not run at all, it just advises the PassManager. How Pass decides that it runs at full optimization/half optimization? (side note - it appears that for any kind of interaction we first should design the execution part of it, and only then go for the construction time) regards, Fedor.
David Greene via llvm-dev
2018-Oct-01 19:16 UTC
[llvm-dev] OptBisect implementation for new pass manager
Fedor Sergeev <fedor.sergeev at azul.com> writes:> I'm not sure that I fully gather which part of pipeline > construction/execution and which > object interaction do you mean when talking about "query hooks" or > "run the pass". > > Right now we have the following objects: > - OptBisect, which is pass-instrumentation object > - PassBuilder object that constructs the pipeline > - PassManager object that controls the pass execution > - Pass object, which is being constructed for PassBuilder and then > executed with PassManager > > At construction time there are: > Pass, OptBisect, PassBuilder objects > and at execution time there are: > Pass, OptBisect, PassManager objects > which of those do you see interacting when you talk about "query hooks"?There are more objects involved, I think. I am specifically thinking of TargetMachine and TargetTransformInfo. The former is used by various codegen passes to determine what to do and how to do it. I'm supposing it may be reasonable to extend that interface to support a pass asking what it needs to do at a bare minimum to produce functional code. I really don't have a good idea what that looks like however. TargetMachine may be the wrong place for it. TargetTransformInfo plays a similar role for IR/non-codegen passes. Again, TTI may or may not be the right place to put such a query interface, but it seems in-line with the role TTI plays. Again, this isn't something that needs to be solved right now, but in my head the model looks something like this: MySchedulingPass::run() { DelaySlotDescriptor = TM.getDelaySlotInfo(); InterlockDescriptor = TM.getSoftwareInterlocks(); VLIWDescriptor = TM.getBundleInfo(); if (PassInstrumentor.getOptLevel() == OptLevel::None) { // Schedule only for the above constraints (e.g. fill all delay slots // with nops, identifying the branches needing to be filled via // DelaySlotDescriptor). ... } else { // Do full scheduling. ... } } This is just quickly thrown together and is likely not the right interface, but hopefully the idea comes across.> My mental model of "not skippable" handling: > - OptBisect is the controlling object. > - at construction time it tracks objects being constructed and > stores its "skippable"/"unskippable" properties. > - at run-time PassManager asks OptBisect and it reports whether to > skip the pass or not. > PassManager acts accordingly.Sure, that makes sense.> "run the pass at full optimization" is something that I dont see a > clear mental model of. > Obviously it is the Pass itself that can run itself at full > optimization *if* it gets control. > PassManager can pass the control to the Pass. > OptBisect does not run at all, it just advises the PassManager. > How Pass decides that it runs at full optimization/half optimization?The above hints at it. A pass this is not skippable may very well be able to run in a "degraded" mode, where it does the bare minimum to produce functional code. That degraded mode could be used by OptBisect to narrow the pieces of the pass that are wrong (e.g. it fails in normal mode but passes in degraded mode). Andy identified three things OptBisect could do with a pass: run it, skip it or run it at OptLevel::None. If the pass is skipped, that's all handled in the PassManager and the pass isn't even aware of it. That leaves two choices. Either the pass is fully run or it is run in degraded mode (OptLevel::None). What I was trying to get at is that I think there are really only two states: either the pass is fully run (not skipped) or it is run in degraded mode. For almost all passes "degraded mode" is the same thing as not running the pass at all (degraded mode == skip). What "degraded mode" means for a pass is likely a decision to be made among the pass and other entities, such as target info. At registration time, we can encode Andy's three choices: // PassManager can not run the pass at all. registerPass(MyPass, PassInstrumentor::DegradeMode::Skip); // PassManager must run the pass, but it can tell the pass to // run in degraded mode. registerPass(MyOtherPass, PassInstrumentor::DegradeMode::OptNone); // PassManager must run the pass and the pass must operate as it always // does, even when "bisected out." registerPass(MyThirdPass, PassInstrumentor::DegradeMode::Default); I'm saying we don't really need DegradeMode::Default as the pass itself can decide to just ignore OptLevel::None and always run as it normally does, depending on what TargetMachine/TargetTransformInfo/whatever tell it to do (or if the pass itself knows enough to ignore OptLevel::None). I feel like we're getting into the weeds, though. :) -David
Philip Pfaffe via llvm-dev
2018-Oct-01 19:49 UTC
[llvm-dev] OptBisect implementation for new pass manager
Sorry, but I strongly oppose to the road you're suggesting here. As I said before the Pass*Manager* is entirely the wrong place to handle OptNone, the absolutely the wrong design. It makes sense for function *only*, and immediately breaks down everywhere else. Frankly, OptNone should take no role in this particular discussion, and I feel like so far it has because "We've always done it this way". Second, I don't completely subscribe to the arguments towards not-skippable passes. Fundamentally: Who decides whether a pass is skippable or not? _When_ is a pass skippable, when isn't it? Neither the Pass nor the PassManager may actually decide that. The only things that do are the pipeline builder and the bisecter. Pipeline builder here means the driver tool that constructs and executes the pipeline (like clang or opt), not PassBuilder. We can achieve that if we put this feature into the instrumentation instead. Here we have the right amount of control, at least cost and minimal complexity. Then, all we need to is get the default treatment right. If we can agree on whether we truly want to not skip some passes 90% of the time, than we can just encode that as an overrideable default, such as by tracking a list of non-skippable passes right there in the implementation. Cheers, Philip On Mon, Oct 1, 2018 at 9:16 PM David Greene <dag at cray.com> wrote:> Fedor Sergeev <fedor.sergeev at azul.com> writes: > > > I'm not sure that I fully gather which part of pipeline > > construction/execution and which > > object interaction do you mean when talking about "query hooks" or > > "run the pass". > > > > Right now we have the following objects: > > - OptBisect, which is pass-instrumentation object > > - PassBuilder object that constructs the pipeline > > - PassManager object that controls the pass execution > > - Pass object, which is being constructed for PassBuilder and then > > executed with PassManager > > > > At construction time there are: > > Pass, OptBisect, PassBuilder objects > > and at execution time there are: > > Pass, OptBisect, PassManager objects > > which of those do you see interacting when you talk about "query hooks"? > > There are more objects involved, I think. I am specifically thinking of > TargetMachine and TargetTransformInfo. The former is used by various > codegen passes to determine what to do and how to do it. I'm supposing > it may be reasonable to extend that interface to support a pass asking > what it needs to do at a bare minimum to produce functional code. I > really don't have a good idea what that looks like however. > TargetMachine may be the wrong place for it. > > TargetTransformInfo plays a similar role for IR/non-codegen passes. > Again, TTI may or may not be the right place to put such a query > interface, but it seems in-line with the role TTI plays. > > Again, this isn't something that needs to be solved right now, but in > my head the model looks something like this: > > MySchedulingPass::run() { > DelaySlotDescriptor = TM.getDelaySlotInfo(); > InterlockDescriptor = TM.getSoftwareInterlocks(); > VLIWDescriptor = TM.getBundleInfo(); > > if (PassInstrumentor.getOptLevel() == OptLevel::None) { > // Schedule only for the above constraints (e.g. fill all delay slots > // with nops, identifying the branches needing to be filled via > // DelaySlotDescriptor). > ... > } > else { > // Do full scheduling. > ... > } > } > > This is just quickly thrown together and is likely not the right > interface, but hopefully the idea comes across. > > > My mental model of "not skippable" handling: > > - OptBisect is the controlling object. > > - at construction time it tracks objects being constructed and > > stores its "skippable"/"unskippable" properties. > > - at run-time PassManager asks OptBisect and it reports whether to > > skip the pass or not. > > PassManager acts accordingly. > > Sure, that makes sense. > > > "run the pass at full optimization" is something that I dont see a > > clear mental model of. > > Obviously it is the Pass itself that can run itself at full > > optimization *if* it gets control. > > PassManager can pass the control to the Pass. > > OptBisect does not run at all, it just advises the PassManager. > > How Pass decides that it runs at full optimization/half optimization? > > The above hints at it. A pass this is not skippable may very well be > able to run in a "degraded" mode, where it does the bare minimum to > produce functional code. That degraded mode could be used by OptBisect > to narrow the pieces of the pass that are wrong (e.g. it fails in normal > mode but passes in degraded mode). > > Andy identified three things OptBisect could do with a pass: run it, > skip it or run it at OptLevel::None. > > If the pass is skipped, that's all handled in the PassManager and the > pass isn't even aware of it. > > That leaves two choices. Either the pass is fully run or it is run in > degraded mode (OptLevel::None). What I was trying to get at is that I > think there are really only two states: either the pass is fully run > (not skipped) or it is run in degraded mode. For almost all passes > "degraded mode" is the same thing as not running the pass at all > (degraded mode == skip). What "degraded mode" means for a pass is > likely a decision to be made among the pass and other entities, such as > target info. > > At registration time, we can encode Andy's three choices: > > // PassManager can not run the pass at all. > registerPass(MyPass, PassInstrumentor::DegradeMode::Skip); > > // PassManager must run the pass, but it can tell the pass to > // run in degraded mode. > registerPass(MyOtherPass, PassInstrumentor::DegradeMode::OptNone); > > // PassManager must run the pass and the pass must operate as it always > // does, even when "bisected out." > registerPass(MyThirdPass, PassInstrumentor::DegradeMode::Default); > > I'm saying we don't really need DegradeMode::Default as the pass itself > can decide to just ignore OptLevel::None and always run as it normally > does, depending on what TargetMachine/TargetTransformInfo/whatever tell > it to do (or if the pass itself knows enough to ignore OptLevel::None). > > I feel like we're getting into the weeds, though. :) > > -David >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181001/f9543c80/attachment.html>