[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