Skip to content

Latest commit

 

History

History
34 lines (26 loc) · 3.26 KB

C++.md

File metadata and controls

34 lines (26 loc) · 3.26 KB

C++ (following the C++ 11 standard) is the implementation language for the compiler. This file contains notes on how we use C++ and conventions we use for things that C++ does not handle well.

Multiple virtual dispatch

C++ does not support multiple virtual dispatch, but we use it heavily in the design of the Visitor classes for the compiler. To support this use (reasonably) cleanly, we use a preprocessor ir-generator to read the IR classes from .def files and generate all the necessary boilerplate for multiple dispatch in the IR and Visitor classes.

Inner classes

C++ does not handle inner classes natively, so to implement an inner class, we use a nested class with a reference member to the containing class called self.

RTTI

IR nodes and their handling code (e.g. Visitors) make extensive use of RTTI to perform type-checking and corresponding downcasting from Node* down to a particular implementation. C++ native RTTI as implemented in dynamic_cast and typeid built-ins is inherently slow and has lots of overhead. To circumvent this IR node classes use dedicated light-weight RTTI designed for semi-open class hierarchies. The implementation itself requires some boilerplate that is automatically generated by ir-generator for all IR classes from .def. The corresponding RTTI functionality could be accessed via ICastable interface from lib/castable.h. There are also freestandig helper functions and type traits in lib/rtti_utils.h, these helpers are mainly useful with generic algorithms and ranges. The lower-level RTTI implementation details are in lib/rtti.h. Overall, use of dynamic_cast and typeid for IR nodes is discouraged.

Using lightweight RTTI for other class hierarchies

Other class hierarchies besides IR::Node descendants could also benefit from lightweight RTTI functionality. In order to use it one needs to annotate the intended class hierarchy as follows:

  • Derive from IR::Castable (or lower-level RTTI::Base)
  • Use DECLARE_TYPEINFO(Class, Bases..) macro call inside class to generate necessary boilerplate. Here typeid for Class will automatically be generated at compile time from the type name. Should necessary, explicit typeid could be specified by DECLARE_TYPEINFO(Class, TypeId, Bases...).
  • DECLARE_TYPEINFO with no bases could be used to indicate the base class for the given hierarchy (e.g. DECLARE_TYPEINFO(Class)) and separate different class hierarchies from each other.

One example of custom hierarchy using this RTTI implementation could be seen in frontends/p4/typeChecking/typeConstraints.h.

Important notes:

  • In order for RTTI to work all class hierarchy should be annotated using DECLARE_TYPEINFO macro. Static assert would fire if something is missed.
  • One need to correctly specify all direct bases for the given Class including virtual ones. Otherwise upcasts and downcasts will not work via missed bases.
  • The typeid values are unique only for the given class hierarchy, they are not intended to be compared across different class hierarchies (although this is always something questionable).
  • DECLARE_TYPEINFO should likely be the last in the class as it expands to a series or private and public fields. Alternatively, a visibility must be explicitly specified after DECLARE_TYPEINFO.