[llvm-dev] RFC: virtual-like methods via LLVM-style RTTI

David Zarzycki via llvm-dev llvm-dev at lists.llvm.org
Thu May 3 14:09:05 PDT 2018


Hello,

In an effort to help LLVM-style projects save memory, I’ve been toying with some macros that provide an alternative to C++ vtables that use LLVM-style RTTI design patterns instead. Is this something that LLVM or sub-projects think is worth pursuing? Or are the macros below too ugly/problematic? Feedback would be appreciated.

Thanks,
Dave




//===- llvm/Support/VTable.h - LLVM-style vtables ---------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides LLVM_VIRTUAL() and related macros for creating virtual
// methods that demultiplex via LLVM-style RTTI.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_VTABLE_H
#define LLVM_SUPPORT_VTABLE_H

#include <functional>

namespace llvm {

//===----------------------------------------------------------------------===//
//                   LLVM-style VTable Support macros
//===----------------------------------------------------------------------===//

// Virtual method dispatch via LLVM runtime type information. This approach
// requires a little bit more work than native C++ 'virtual' methods, but the
// memory savings can be well worth it. On non-PIC x86 systems, the same
// number of instructions are generated. On PIC x86 systems, one additional
// instruction is generated to compute (or load) the pointer to the vtable
// (LEA or MOV respectively), and the compiler is smart enough to hoist the
// LEA/MOV outside of loops and cache the result.
//
// For subclasses, virtual methods are declared like so:
//
//   LLVM_VIRTUAL_THUNK(BaseTy, makeSound)
//   void LLVM_VIRTUAL(makeSound)(int howLoud) { /* normal body */ }
//
// For base classes, one must do a little more work. The simplest case is an
// abstract virtual method in a type called 'Base':
//
//   void LLVM_ABSTRACT_VIRTUAL(BaseTy, makeSound)
//
// And then later in the header file, the vtable definition:
//
// LLVM_ABSTRACT_VIRTUAL_BEGIN(BaseTy, makeSound)
// #define BASE_NODE(Ty, ...) LLVM_ABSTRACT_VIRTUAL_SLOT(Ty, makeSound)
// #include <BaseTy.inc>
// LLVM_ABSTRACT_VIRTUAL_END(getKind())
//
//
// Example:
//
// class Cat {
//   ...
//
//   void LLVM_ABSTRACT_VIRTUAL(Base, makeSound)
//
//   LLVM_BASE_VIRTUAL(Base, getOffspringCount)
//   size_t LLVM_VIRTUAL(getOffspringCount)() const {
//     return 0;
//   }
// };
//
//
// class Lion : public Cat {
//   ...
//
//   LLVM_VIRTUAL_THUNK(Base, makeSound)
//   void LLVM_VIRTUAL(makeSound)() {
//     ...
//   }
//
//   LLVM_VIRTUAL_THUNK(Base, getOffspringCount)
//   size_t LLVM_VIRTUAL(getOffspringCount)() const {
//     ...
//   }
// };


#define LLVM_VIRTUAL_THUNK(Ty, BaseTy, Method) \
  template <typename... Args> \
  static auto _virtual_##Method(BaseTy *b, Args... args) -> auto { \
    return static_cast<Ty*>(b) \
      ->_virtualbody_##Method(std::forward<Args>(args)...); \
  }

#define LLVM_VIRTUAL(Method) \
  __attribute__((always_inline)) _virtualbody_##Method

#define LLVM_ABSTRACT_VIRTUAL(BaseTy, Method) \
  __attribute__((noreturn)) \
  LLVM_VIRTUAL(Method)(...) { \
    llvm_unreachable("Unhandled LLVM-virtual method"); \
  } \
  template <typename... Args> \
  auto Method(Args... args) -> auto; \
  LLVM_VIRTUAL_THUNK(BaseTy, BaseTy, Method)

#define LLVM_BASE_VIRTUAL(BaseTy, Method) \
  template <typename... Args> \
  auto Method(Args... args) -> auto; \
  LLVM_VIRTUAL_THUNK(BaseTy, BaseTy, Method)

#define LLVM_ABSTRACT_VIRTUAL_BEGIN(BaseTy, Method) \
  template <typename... Args> \
  auto BaseTy::Method(Args... args) -> auto { \
    static const decltype(&BaseTy::_virtual_##Method<Args...>) vtable[] = {

#define LLVM_ABSTRACT_VIRTUAL_SLOT(Ty, Method) \
      &Ty::_virtual_##Method<Args...>,

#define LLVM_ABSTRACT_VIRTUAL_END(GetKind) \
    }; \
    return vtable[GetKind](this, std::forward<Args>(args)...); \
  }

} // end namespace llvm

#endif // LLVM_SUPPORT_VTABLE_H


More information about the llvm-dev mailing list