Skip to content

Instantly share code, notes, and snippets.

@davezarzycki
Created April 30, 2018 11:05
Show Gist options
  • Select an option

  • Save davezarzycki/e1181101841a62b612415e14afb8f072 to your computer and use it in GitHub Desktop.

Select an option

Save davezarzycki/e1181101841a62b612415e14afb8f072 to your computer and use it in GitHub Desktop.
//===- 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)
// int 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) \
->Method##_virtualbody_(std::forward<Args>(args)...); \
}
#define LLVM_VIRTUAL(Method) \
__attribute__((always_inline)) Method##_virtualbody_
#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
@davezarzycki
Copy link
Author

davezarzycki commented Apr 30, 2018

Hey @rjmccall, @DougGregor, @jckarter, and @jrose-apple

I toyed with the above "LLVM style" vtable dispatch a while back. Do any of you think this idea is worth pursuing further at some point? The performance/code-gen should be essentially the same as normal virtual method dispatch, and saving eight bytes per [virtual using] AST node feels compelling.

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment