[llvm-dev] How to build a target-specific LLVM pipeline from within the middle-end
Anna Sophia Welker via llvm-dev
llvm-dev at lists.llvm.org
Tue Mar 2 01:25:53 PST 2021
Hello experts,
I am trying to build an LLVM pass that can make predictions about the
benefits of certain transformations by exploring them, i.e., sending the
respective code sections 'ahead in time' and comparing the outcome if
this or that choice is made.
To my understanding, because of how the pass pipeline is set up, this
does require to build an entirely new pipeline (or at least parts of
it), to which I pass the module I create from the code I want to examine.
I haven't really found any documentation on how the pass pipeline is
stitched together, so everything I know about how to do it comes from
reading code present in LLVM. Specifically, I've been looking at
EmitAssemblyHelper::EmitAssemblyWithNewPassManager in clang's
BackendUtil, as I expect the run my pass would be used in to be started
from there, and I want to exactly copy what happens to the real code.
What I have achieved so far:
I have imitated the creation of the AnalysisManagers and have the
PassBuilder pass information like PTO and PGOOpt to the constructor of
my pass, so when the pass is run in the middle-end I can build a new
PassBuilder from that information, register all the AnalysisManagers and
build a pipeline (using buildPerModuleDefaultPipeline). As the old
PassManager structure allows it, I can even hand over a complete CodeGen
pipeline to said constructor. So my pass can run the module it creates
through the middle-end passes all the way to code generation in the
backend with no issues.
My problem:
The middle-end run that I am getting is a 'generic' one, it does not
exhibit the characteristics that I expect to see for the concrete
architecture I specify on the command line. E.g., it is using a plain
TTI instead of the target's TTI, so for my partial code vectorization
does not at all do what it would do for the normal run. Which kind of
defeats the whole point of the exploration.
I have identified the issue to be the TargetMachine, which seems to be
responsible for any target-specific adaptations in the middle-end. From
my understanding, if it is set to nullptr, you get a generic run like I
do, if it isn't, you should get a run fine-tuned for the architecture
you're looking at. The problem is, what is the proper way to acquire a
TargetMachine?
The copy-constructor of the class has been deleted, so I cannot simply
hand it over to my pass like I do for the other information. In
BackendUtil, the TargetMachine is constructed as a singleton from a long
range of option information, some of it clang options. From trying and
failing I gather that I can not include clang headers in my llvm pass,
so I don't know how to even pass all the required options to my pass if
I were to build the machine on my own from scratch, which does not feel
like the right thing to do anyway. I have tried passing the whole
original PassBuilder to my pass, which works fine, and then taking the
TargetMachine from there when creating my new PassBuilder (I added a
function getTargetMachine() to the class for testing purposes). All I
get is a nullptr.
Can anyone give me a hint on what I am doing wrong, or how to do it
right? Or is this simply something that LLVM is not supposed to allow,
period?
I do realise I could just manually add the passes I need for the
architecture I'm looking at, but the idea was to make the tool usable
for any architecture by just doing exactly what the 'parent run' is
doing. Only, everything is so nicely encapsulated that I'm struggeling
to access the information necessary in the place I need it.
Looking forward to any feedback or suggestions!
Many thanks,
Anna Welker
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210302/9727d1f0/attachment.html>
More information about the llvm-dev
mailing list