Everyone
Everyone

Reputation: 1835

LLVM InstVisitor - No Virtual Functions?

I have been looking at the LLVM InstVisitor.h file where they implement the Visitor Pattern. Their implementation is very different from anything I've seen on the Visitor Pattern.

In the documentation I found this:

To define your own visitor, inherit from this class, specifying your new type for the 'SubClass' template parameter, and "override" visitXXX functions in your class. I say "override" because this class is defined in terms of statically resolved overloading, not virtual functions.

...

Note that this class is specifically designed as a template to avoid virtual function call overhead. Defining and using an InstVisitor is just as efficient as having your own switch statement over the instruction opcode.

I am asking because this answer says that LLVM uses the Visitor Pattern in this implementation, but I cannot figure out why it is so different from any other implementation I've seen.

How is the visitor pattern exactly used in the file?

Upvotes: 3

Views: 889

Answers (1)

Daniel Otero
Daniel Otero

Reputation: 138

The llvm::InstVisitor uses the Curiously Recurring Template Pattern (CRTP), that is a C++ idiom used to perform static dispatching of the visit member functions.

This way, the correct visitXXX calls are resolved statically (at compile time) avoiding the extra cost of a dynamic virtual call resolution.

This works by calling something like this:

// The compiler will choose the Derived implementation of visitXXX
// if exists, but will fallback to the Base implementation as Derived 
// inherits from Base. All done at compile time.
void Base::do_visit() {
  return static_cast<Derived *>(this)->visitXXX();
}

Be aware that there is not "override" like mechanism: if you fail to match the exact function signature for one visit function, it will call the base class implementation and not your own.

An example of usage is exactly as the documentation explains:

struct CountAllocaVisitor : public InstVisitor<CountAllocaVisitor> {
  unsigned Count;
  CountAllocaVisitor() : Count(0) {}
  void visitAllocaInst(AllocaInst &AI) { ++Count; }
};

// And this class would be used like this:
CountAllocaVisitor CAV;
CAV.visit(function);
NumAllocas = CAV.Count;

Upvotes: 3

Related Questions