Pass registered multiple times!

Hi,

I'm writing my first hello world Pass with the class name First, but
when I tried to load it using opt, I got the following error:

/var/soft/llvm-2.2-build/lib/Transforms/Hello$ opt
-load ../../../Debug/lib/First.so --help
opt: /var/soft/llvm-2.2/lib/VMCore/Pass.cpp:157:
void<unnamed>::PassRegistrar::RegisterPass(llvm::PassInfo&): Assertion
`Inserted && "Pass registered multiple times!"' failed.
Aborted

The code is as follows.

#include "llvm/Pass.h"
#include "llvm/Function.h"

using namespace llvm;

namespace {
  struct First : public FunctionPass {
    static char ID;
    First(): FunctionPass((intptr_t)&ID) {}

    virtual bool runOnFunction(Function &F)
    {
      llvm::cerr << "First: " << F.getName() << "\n";
      return false;
    }
  };

  char First::ID = 0;
  RegisterPass<First> X("first", "First world pass");
}

and the Makefile:

LEVEL = ../../..
LIBRARYNAME = First
LOADABLE_MODULE = 1
LLVMLIBS = LLVMCore.a LLVMSupport.a LLVMSystem.a
include $(LEVEL)/Makefile.common

Thanks in advance.
Lu

It turned out to be the problem of this line in Makefile

LLVMLIBS = LLVMCore.a LLVMSupport.a LLVMSystem.a

The error is gone when I remove the above line.

However, the pass output only contains one line of the main function.

First: main

It does not have puts and __main as shown in this page:
http://llvm.org/docs/WritingAnLLVMPass.html#running

So I guess the drived FunctionPass only works on the application
functions, not on the library functions of LLVM. Is that right?

Thanks.
Lu

Lu Zhao wrote:

It turned out to be the problem of this line in Makefile

LLVMLIBS = LLVMCore.a LLVMSupport.a LLVMSystem.a

The error is gone when I remove the above line.

However, the pass output only contains one line of the main function.

First: main

It does not have puts and __main as shown in this page:
Writing an LLVM Pass — LLVM 18.0.0git documentation

So I guess the drived FunctionPass only works on the application
functions, not on the library functions of LLVM. Is that right?
  

LLVM does not distinguish between application and library functions, unless you mean that it distinguishes between defined functions and functions defined in another module. It's possible that runOnFunction() is not called for functions with no function body (aka external declarations or external functions).

If you disassemble your input bytecode file and look at the LLVM disassembly, I'd bet that either __main() and puts are external functions with no function body or are not present in the file at all.

-- John T.

If you disassemble your input bytecode file and look at the LLVM
disassembly, I'd bet that either __main() and puts are external
functions with no function body or are not present in the file at all.

You're right. The assembly code only has the body of main function and
the external function declaration puts

declare i32 @puts(i8*)

It makes sense, I think, that my derived FunctionPass is not invoked on
external functions when I intend to optimize code such as C. However,
if my code was written in LLVM and I wanted to trigger it on all LLVM
functions including external functions outside the module, how could I
do it?

Thanks.
Lu

Lu Zhao wrote:

If you disassemble your input bytecode file and look at the LLVM
disassembly, I'd bet that either __main() and puts are external
functions with no function body or are not present in the file at all.
    
You're right. The assembly code only has the body of main function and
the external function declaration puts

declare i32 @puts(i8*)

It makes sense, I think, that my derived FunctionPass is not invoked on
external functions when I intend to optimize code such as C. However,
if my code was written in LLVM and I wanted to trigger it on all LLVM
functions including external functions outside the module, how could I
do it?
  

Within the PassManager framework, all of your analysis and transforms are performed on a single LLVM Module (roughly speaking, an LLVM Module represents one LLVM bytecode file). Depending on what you're doing, you can either process each bytecode file separately (e.g., run opt on each bytecode file individually), or you can link all the bytecode files together into one bytecode file using llvm-ld and run opt on the single bytecode file.

The former is good for intra-procedural passes; the latter is good for inter-procedural passes (it's what allows LLVM to do inter-procedural optimization beyond the boundaries of individual compilation units).

If your pass simply needs to add instructions to empty functions, there are two ways to do it. First, you can make your pass a ModulePass so that it can analyze and modify any part of the program at any time. Second, as an alternative, you could add a doInitialization() or doFinalization() method to your FunctionPass that handles empty functions.

I am assuming that you're writing a pass to be used via opt. If you're doing something more sophisticated (like writing a JIT that dynamically loads LLVM bytecode files), then I'm not sure what the right option is.

Does this answer your question?

-- John T.

Does this answer your question?

Yeah, that gives me a very clear picture how it works and where to go.
Thank you very much.

Lu