Need usage help w/ new pass manager for opt analysis Natural Loop information

I recently upgraded to a modern version of clang/opt. Previously, I was using:

clang  -S -emit-llvm app.c -o app.ll
opt -analyze --loops app.ll

to identify loop depth, but alas, the new pass manager broke my script. opt --passes=print-loops -disable-output app.ll is what I gather from the docs. Is there an easy cmd line way to get the Natural Loop information?

I think -passes='print<loops>' is what you are looking for.

I also scanned the llvm-project repo in an attempt to find any documentation referring to print-loops, but did not get any matches. So not sure where you got that information.

For all my life when I see a document that states -option="literal<some_text_here>" the “<some_text_here>” should be substituted with some other literal… but what you’re telling me is that I should literally type -passes='print<loops>' :exploding_head:
my previous attempts have come from these:

https://llvm.org/docs/Passes.html#loops-natural-loop-information

OK tried it … nothing.

$ clang -S -emit-llvm app2.c -o app2.ll
$ opt -passes='print<loops>' app2.ll
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.
$ opt -passes='print<loops>' -disable-output  app2.ll
$

under the old version it was as easy as this:

$ clang  -S -emit-llvm app2.c -o app2.ll
$ opt -analyze -loops app2.ll
Printing analysis 'Natural Loop Information' for function 'rotf':
Loop at depth 1 containing: %5<header><exiting>,%8,%11,%28,%38<latch>,%15,%25
    Loop at depth 2 containing: %11<header><exiting>,%15,%25<latch>
Printing analysis 'Natural Loop Information' for function 'rotf2':
Loop at depth 1 containing: %5<header><exiting>,%8,%11,%28,%38<latch>,%15,%25
    Loop at depth 2 containing: %11<header><exiting>,%15,%25<latch>
Printing analysis 'Natural Loop Information' for function 'main':
Loop at depth 1 containing: %4<header><exiting>,%7,%15,%11,%19,%24,%28,%29<latch>

I really appreciate you helping, but I’m still failing to get the the output I need.

I should also mention the specific version I’m using:

$ opt --version
LLVM (http://llvm.org/):
  LLVM version 16.0.6
  Optimized build.
  Default target: x86_64-redhat-linux-gnu
  Host CPU: alderlake

and a opt --help-list mentions:

OVERVIEW: llvm .bc -> .bc modular optimizer and analysis printer

USAGE: opt [options] <input bitcode file>

OPTIONS:
...
  Optimizations available (use '-passes=' for the new pass manager)
...
      --loops                                                              - Natural Loop Information
...

that --loops seems to be what I’m after
and opt --print-passes list the one you suggested but under Function passes:

Module passes:
  ...
Module passes with params:
  ...
Function passes:
...
  print<loops>

I had another look at your problem. Seems like the LoopPrinterPass isn’t defining:
static bool isRequired() { return true; }

And then it is skipped when for example compiling with -O0 since the functions will be given the optnone attribute.

I think that you will see that if using the -debug-pass-manager option. Something like this:

opt foo.ll -passes="print<loops>" -disable-output -debug-pass-manager
Running analysis: InnerAnalysisManagerProxy<AnalysisManager<Function>, Module> on [module]
Running analysis: PreservedCFGCheckerAnalysis on foo
Skipping pass LoopPrinterPass on foo due to optnone attribute
Skipping pass: LoopPrinterPass on foo
Running pass: VerifierPass on [module]
Running analysis: VerifierAnalysis on [module]

So maybe a workaround could be to use O1 or higher when invoking clang.

To me it looks like a bug that the LoopPrinterPass behaves this way. Other “printing passes” usually implement the isRequired() method to make sure the pass won’t be skipped. Same problem seesm to exist for verify<loops> and the LoopVerifierPass.

Probably worth a bug report (and it might be worth checking the code base if similar problem exist for other printer/verifier passes).

thanks for following up! I can confirm that adding -O1 to the clang step does indeed solve the “null” output from opt… now I need to determine if adding -O1 will have any unintended side-effects.

I’ll leave the bug report for you, I’m sure you would describe better.

One more issue, the old version also had a line that the identified the function that the loop was in:

Printing analysis 'Natural Loop Information' for function 'rotf':
Loop at depth 1...

Either that’s missing, or the -O1 caused the function(s) to get inlined.

I have created these pull requests:
[opt][NewPM] Add isRequired to passes named as *PrinterPass by bjope · Pull Request #76516 · llvm/llvm-project · GitHub
[opt][NewPM] Add isRequired to passes named *VerifierPass by bjope · Pull Request #76517 · llvm/llvm-project · GitHub

Proposed this patch [LoopInfo][NewPM] Print function name in LoopPrinterPass by bjope · Pull Request #76527 · llvm/llvm-project · GitHub to make sure the function name is printed before the loop info (like it used to be done in legacy PM).

thanks. Do you know if that fix will make it all the back to version 16.x?

Only the current version of LLVM will get patch updates (currently v17), and at some point the current version will receive its last update (that was 17.0.6 for v17). So these changes will probably make their way into LLVM 18, but will not make their way into LLVM 17 or LLVM 16.

I’ve now pushed the fixes to the llvm-project main branch (to be included in LLVM 18). See Some print/verify passes are blocked by optnone (and other gates) with NewPM · Issue #76762 · llvm/llvm-project · GitHub for the github issue that connects the three commits I made.

(It would probably be safe to include this in a patch release on LLVM 17. But I don’t know much about the current procedure for patch releases. Such as who decides what to include, and how to trigger a merge of the commits, etc.)