Replies: 1 comment
-
|
So I looked a little bit at the resources you provided. Thanks for them, I learned something. After reading them, I agree with you that it is absolutely possible to support these instructions (in contrast to what I stated in these issues). Currently, the RVSDG creation process looks like this from a 10000 feet level:
Now, we could easily support these constructs by:
This would add support for these instructions without the need to expand our IR. However, it would also make us pay the performance penalty, but there might be a chance to eventually recover (some) performance by implementing predicate control flow recovery as mentioned in the above linked paper. I do not know whether this would recover the performance, but it is certainly worth a shot as it would allow us to have the cake and also eat it:
I am sure that it is somehow possible to natively support these constructs in the RVSDG, but their nature clashes with the RVSDGs philosophy to have normalized control flow and explicit (data) dependencies. The idea of In contrast, I find the first described route way more appealing:
I would like to let the compiler make the decisions for me regarding efficient control flow generation, but such language constructs make this very hard. They already lock in a solution/path and then the compiler has to work very hard to lift this again to a higher abstraction level in order to be able to potentially make a different/better decision in terms of control flow generation than what the user already provided. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Some context: #52 (and #217).
This is a GCC/Clang extension that is useful in language interpreters, emulators, etc. Back in the day, you could see speedups all the way up to 50% on the high end when using this feature (depending on lots of factors), but nowadays, 15-30% is more common as CPUs have gotten beefier and smarter. Still, that's enough of a performance gain that the feature remains in use ubiquitously in those domains. For these reasons, it seems worth figuring out how it can be supported in the RVSDG.
In LLVM land, the feature is modeled with
blockaddressconstants andindirectbrinstructions. Helpfully, block addresses are defined very opaquely, so there is quite a lot of implementation flexibility. Also helpfully,indirectbrinstructions must explicitly list all possible target blocks. Some background on the addition of these LLVM constructs.It is possible to emulate this feature by assigning an ID to each target block, lowering
blockaddressto the appropriate ID, and loweringindirectbrto a switch containing branches for each assigned ID. This undermines the performance benefits, but it does at least allow such code to compile. This is what LLVM used to do, and it still has a pass to do it for targets that require it. WebAssembly (which doesn't support irreducible control flow) uses that pass, for example.The fact that the feature reduces to features that the RVSDG can already represent -- that is, a regular switch on a value to pick one of several statically-known branches -- makes me think that there's no particular reason why it shouldn't also be representable natively in the RVSDG.
At a very high level, I imagine the native representation might look something like:
blockaddress).indirectbr).ptringoto *ptr).Of course, the hard part would be teaching RVSDG construction to create these. 🙂
All this being said, I don't have the theoretical background to say anything with certainty here, so I would very much like to hear everyone's thoughts.
Beta Was this translation helpful? Give feedback.
All reactions