Allow out-of-tree code to customize a target using a
mechanism similar to addGlobalExtension in PassManagerBuilder but for
machine passes.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Hi this is my first submission to the LLVM project. I selected reviewers by looking at the recent commit history of TargetPassConfig.h so I hope I haven't gone too far wrong with that. Evan Cheng is listed in the CODE_OWNERS.txt for "parts of code generator not covered by someone else" but I couldn't find his user name on Phabricator (perhaps he doesn't have one).
Could you add an example like llvm/examples/Bye and a test using llc -load?
llvm/include/llvm/CodeGen/TargetPassConfig.h | ||
---|---|---|
367 | Why is Target needed? A plugin could query TargetPassConfig about which target it wants to register itself. | |
llvm/unittests/CodeGen/TargetExtensionTest.cpp | ||
54 | I think testing the default target should be enough. Why we test all targets here? |
Thanks very much @ychen for looking at my review, and thanks for pointing me at the examples/Bye/Bye.cpp example code. I didn't know we could do that kind of thing in the build and I'll post an update with a new example later this week.
I see your other two comments as being closely related to each other. If we handle target filtering in the TargetPassConfig implementation then it makes sense for the test to confirm that the filtering works, i.e. an extension registered for one target is not mistakenly invoked for a different one. If we put the responsibility on the client code to filter out unwanted targets then the test wouldn't have to care and any target machine (so long as it can be cast to LLVMTargetMachine, of course) would do.
I can see one benefit to doing the filtering in the implementation rather than the client - in makes it obvious that the filtering is necessary, i.e. the API forces the client code to select a specific target. Otherwise the client code could omit the filtering and then it would work during developer testing say, but crash mysteriously if invoked on an unsuitable target. Maybe that's unlikely, so please let me know if you'd prefer me to simpilfy the implementation by removing the filtering.
Yeah, I still think the filtering should be removed. The plugin should not reply on a Target instance to work and ideally, the plugin should be able to cope with more than one target (most likely a machine-independent pass).
I've made the changes to remove the filtering and simplify the test but I'm having some trouble with the Bye example. When I enable this via cmake ... -DLLVM_BYE_LINK_INTO_TOOLS=ON I get some test failures from llvm-check. Is that expected?
Failed Tests (6):
LLVM :: Other/new-pm-O0-defaults.ll LLVM :: Other/opt-O0-pipeline.ll LLVM :: Other/opt-O2-pipeline.ll LLVM :: Other/opt-O3-pipeline-enable-matrix.ll LLVM :: Other/opt-O3-pipeline.ll LLVM :: Other/opt-Os-pipeline.ll
Example error output:
- TEST 'LLVM :: Other/opt-O3-pipeline-enable-matrix.ll' FAILED ****
Script:
: 'RUN: at line 1'; /home/raoul/build/llvm/head-static/bin/opt -enable-new-pm=0 -O3 -enable-matrix -debug-pass=Structure < /home/raoul/src/llvm/llvm-project/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll -o /dev/null 2>&1 | /home/raoul/build/llvm/head-static/bin/FileCheck /home/raoul/src/llvm/llvm-project/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
Exit Code: 1
Command Output (stderr):
/home/raoul/src/llvm/llvm-project/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll:216:15: error: CHECK-NEXT: is not on the line after the previous match
; CHECK-NEXT: Canonicalize natural loops
^
<stdin>:212:2: note: 'next' match was here
Canonicalize natural loops
^
<stdin>:208:11: note: previous match ended here
Early CSE
^
<stdin>:209:1: note: non-matching line after previous match is here
Good Bye World Pass
^
Input file: <stdin>
Check file: /home/raoul/src/llvm/llvm-project/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
-dump-input=help explains the following input dump.
Input was:
<<<<<<
. . . 207: Lower the matrix intrinsics 208: Early CSE 209: Good Bye World Pass 210: Dominator Tree Construction 211: Natural Loop Information 212: Canonicalize natural loops
next:216 !~~~~~~~~~~~~~~~~~~~~~~~~~ error: match on wrong line
213: LCSSA Verifier 214: Loop-Closed SSA Form Pass 215: Basic Alias Analysis (stateless AA impl) 216: Function Alias Analysis Results 217: Scalar Evolution Analysis . . .
[CodeGen] Simplify unit test for TargetPassConfig::addExtension and
add example plugin module
The example MachineExtension plugin module has a lit test which runs
if examples are enabled.
@ychen I've updated this review with your suggested changes. I've removed the extension filtering in TargetPassConfig, simplified the test and added an example. The example doesn't try to use the new pass manager because the last time I checked it still wasn't useful for machine passes. What do you think?
@drti hi, could you please rebase the patch? The base commit seems not in the git history.
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses
Allow out-of-tree code to customize a target using a
mechanism similar to addGlobalExtension in PassManagerBuilder but for
machine passes.
@ychen apologies for that, the base revision should now be efc013ec4d950a68e6f80dd98cda35e1a96a6fc8 from the main repo.
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses Allow out-of-tree code to customize a target using a mechanism similar to addGlobalExtension in PassManagerBuilder but for machine passes.
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses
Allow out-of-tree code to customize a target using a
mechanism similar to addGlobalExtension in PassManagerBuilder but for
machine passes.
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses
Allow out-of-tree code to customize a target using a
mechanism similar to addGlobalExtension in PassManagerBuilder but for
machine passes.
@ychen I've rebased and fixed some pre-merge build and formatting issues. Could you please have another look at this review? If it looks OK could I also ask you to commit it for me, please? It's my first submission and I don't have commit rights myself.
Regards,
Raoul
llvm/examples/Bye/CMakeLists.txt | ||
---|---|---|
10 ↗ | (On Diff #345076) | Why this? |
llvm/examples/CMakeLists.txt | ||
11 | I think it's better to call this MachineBye to reflect that the usage/implementation are similar between the two. If you think it makes sense, make sure the class name is also renamed accordingly. | |
llvm/examples/MachineExtension/MachineExtension.cpp | ||
33 ↗ | (On Diff #345076) | No need for anything concrete there. I think printing some string using errs() should be enough. |
62 ↗ | (On Diff #345076) | Better to use lambda for this one-time registration. |
llvm/include/llvm/CodeGen/TargetPassConfig.h | ||
91 | How about reducing these extension points to a list that very likely to be useful? Unlike IR pipeline, the order among machine passes is pretty firm, if there are no concrete use cases for an extension point, it may become dead code, or we would need to move/rename it in the future. | |
505 | I'd prefer to call it addMachinePassExtentions. | |
518 | format | |
529 | format | |
llvm/include/llvm/Target/TargetMachine.h | ||
170 | asLLVMTargetMachine is not needed. If you could just static_cast to LLVMTargetMachine directly since TargetMachine object is almost never created. |
llvm/examples/Bye/CMakeLists.txt | ||
---|---|---|
10 ↗ | (On Diff #345076) | On my Linux system at least (Fedora 33) the Bye example fails to build when configured with -DBUILD_SHARED_LIBS=true. Strictly speaking this belongs in a separate review but seeing as I'm fixing it for the new example I thought I'd sneak this one in. The failures is because -zdefs is enabled via CMAKE_SHARED_LINKER_FLAGS in llvm/cmake/modules/HandleLLVMOptions.cmake - this linker flag effectively introduces the same restriction against undefined symbols in shared objects as applies to DLLs on Windows (where the Bye example is disabled) Example error: |
llvm/include/llvm/CodeGen/TargetPassConfig.h | ||
91 | I agree that we should limit the number of extension points, but I think we also should try to cater for a range of possible usages. The list at the moment more-or-less mirrors the virtual function extension points for the TargetPassConfig derived classes, which I thought was a fair compromise. There's a tradeoff here of course, but I would tend to err on the side of having more rather than fewer, simply because it's a high barrier for someone working on out-of-tree code to get an extension point added if necessary, compared to an in-tree change that needs, say, a new virtual function extension point. | |
518 | This was auto-formatted this way, either during arcanist processing or to satisfy some lint/format warnings. I'd be hesitant to change this, even though I agree it doesn't look "right". | |
529 | Also auto-formatted this way. | |
llvm/include/llvm/Target/TargetMachine.h | ||
170 | I've seen quite a few places in the code doing the exact unchecked static_cast you suggest, but I hadn't wanted to follow that pattern myself. I didn't think this base class warrants the full LLVM RTTI support, and the virtual function seemed like an easy solution. I had intended to submit another review to introduce it in the existing use-cases that are simple enough (see, e.g. the related TODO comment in llvm/tools/llvm-exegesis/lib/Assembler.cpp and FIXME in llvm/tools/opt/opt.cpp) |
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses
Allow out-of-tree code to customize a target using a
mechanism similar to addGlobalExtension in PassManagerBuilder but for
machine passes.
llvm/include/llvm/CodeGen/TargetPassConfig.h | ||
---|---|---|
505 | Well my reasoning was that addExtension "adds" an extension function and "apply" runs the functions (if any). It may also be that a callback doesn't add any passes for a particular target so strictly speaking all we're doing is invoking the callbacks. What do you think? |
@ychen could you please take another look at this review? I'll understand if you don't have time for this - perhaps you could let me know if I should look for another reviewer. It's been quite a while now...
I'm sure this needs a rebase. Should also be reviewed by out of tree target maintainers
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses Allow out-of-tree code to customize a target using a mechanism similar to addGlobalExtension in PassManagerBuilder but for machine passes.
[CodeGen] Add extension points for TargetPassConfig::addMachinePasses
Rebase to see if the lljit-with-thinlto-summaries.test has been fixed
llvm/include/llvm/Target/TargetMachine.h | ||
---|---|---|
440 | This overrides the baseclass version of the function which returns nullptr. I think ideally we'd have proper dyn_cast<LLVMTargetMachine> support but the TargetMachine base class isn't set up for this. The virtual function here is just an easy way to get safer downcasting rather than client code using an unchecked static_cast. @ychen was also questioning the utility of this, by the way, suggesting to use the static_cast like some existing code already does. What do you think? | |
llvm/lib/CodeGen/TargetPassConfig.cpp | ||
730 | I guess the only situation where it's useful is if shared objects/DLLs are dynamically unloaded - any registered extension would crash if not removed before unloading its code. |
Hi @arsenm I'm not really sure what the process is here. I'm happy to change the code just wanted some clarification on your opinion - have commented on the issues you raised.
llvm/include/llvm/CodeGen/TargetPassConfig.h | ||
---|---|---|
100 | I don't think it can in general because we need to store a list of these and the function_ref docs say "This class does not own the callable, so it is not in general safe to store a function_ref" |
I think it's better to call this MachineBye to reflect that the usage/implementation are similar between the two. If you think it makes sense, make sure the class name is also renamed accordingly.