llvm.org GIT mirror llvm / 36be1ae
docs: Add HowToSetUpLLVMStyleRTTI.rst. This document describes how to set up LLVM-style RTTI for a class hierarchy. Surprisingly, this was not previously documented. Also, link it into ProgrammersManual.html. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165293 91177308-0d34-0410-b5e6-96231b3b80d8 Sean Silva 6 years ago
3 changed file(s) with 291 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
0 .. _how-to-set-up-llvm-style-rtti:
1
2 ======================================================
3 How to set up LLVM-style RTTI for your class hierarchy
4 ======================================================
5
6 .. sectionauthor:: Sean Silva
7
8 .. contents::
9
10 Background
11 ==========
12
13 LLVM avoids using C++'s built in RTTI. Instead, it pervasively uses its
14 own hand-rolled form of RTTI which is much more efficient and flexible,
15 although it requires a bit more work from you as a class author.
16
17 A description of how to use LLVM-style RTTI from a client's perspective is
18 given in the `Programmer's Manual `_. This
19 document, in contrast, discusses the steps you need to take as a class
20 hierarchy author to make LLVM-style RTTI available to your clients.
21
22 Before diving in, make sure that you are familiar with the Object Oriented
23 Programming concept of "`is-a`_".
24
25 .. _is-a: http://en.wikipedia.org/wiki/Is-a
26
27 Basic Setup
28 ===========
29
30 This section describes how to set up the most basic form of LLVM-style RTTI
31 (which is sufficient for 99.9% of the cases). We will set up LLVM-style
32 RTTI for this class hierarchy:
33
34 .. code-block:: c++
35
36 class Shape {
37 public:
38 Shape() {};
39 virtual double computeArea() = 0;
40 };
41
42 class Square : public Shape {
43 double SideLength;
44 public:
45 Square(double S) : SideLength(S) {}
46 double computeArea() /* override */;
47 };
48
49 class Circle : public Shape {
50 double Radius;
51 public:
52 Circle(double R) : Radius(R) {}
53 double computeArea() /* override */;
54 };
55
56 The most basic working setup for LLVM-style RTTI requires the following
57 steps:
58
59 #. In the header where you declare ``Shape``, you will want to ``#include
60 "llvm/Support/Casting.h"``, which declares LLVM's RTTI templates. That
61 way your clients don't even have to think about it.
62
63 .. code-block:: c++
64
65 #include "llvm/Support/Casting.h"
66
67
68 #. In the base class, introduce an enum which discriminates all of the
69 different classes in the hierarchy, and stash the enum value somewhere in
70 the base class.
71
72 Here is the code after introducing this change:
73
74 .. code-block:: c++
75
76 class Shape {
77 public:
78 + /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
79 + enum ShapeKind {
80 + SquareKind,
81 + CircleKind
82 + };
83 +private:
84 + const ShapeKind Kind;
85 +public:
86 + ShapeKind getKind() const { return Kind; }
87 +
88 Shape() {};
89 virtual double computeArea() = 0;
90 };
91
92 You will usually want to keep the ``Kind`` member encapsulated and
93 private, but let the enum ``ShapeKind`` be public along with providing a
94 ``getKind()`` method. This is convenient for clients so that they can do
95 a ``switch`` over the enum.
96
97 A common naming convention is that these enums are "kind"s, to avoid
98 ambiguity with the words "type" or "class" which have overloaded meanings
99 in many contexts within LLVM. Sometimes there will be a natural name for
100 it, like "opcode". Don't bikeshed over this; when in doubt use ``Kind``.
101
102 You might wonder why the ``Kind`` enum doesn't have an entry for
103 ``Shape``. The reason for this is that since ``Shape`` is abstract
104 (``computeArea() = 0;``), you will never actually have non-derived
105 instances of exactly that class (only subclasses). See `Concrete Bases
106 and Deeper Hierarchies`_ for information on how to deal with
107 non-abstract bases. It's worth mentioning here that unlike
108 ``dynamic_cast<>``, LLVM-style RTTI can be used (and is often used) for
109 classes that don't have v-tables.
110
111 #. Next, you need to make sure that the ``Kind`` gets initialized to the
112 value corresponding to the dynamic type of the class. Typically, you will
113 want to have it be an argument to the constructor of the base class, and
114 then pass in the respective ``XXXKind`` from subclass constructors.
115
116 Here is the code after that change:
117
118 .. code-block:: c++
119
120 class Shape {
121 public:
122 /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
123 enum ShapeKind {
124 SquareKind,
125 CircleKind
126 };
127 private:
128 const ShapeKind Kind;
129 public:
130 ShapeKind getKind() const { return Kind; }
131
132 - Shape() {};
133 + Shape(ShapeKind K) : Kind(K) {};
134 virtual double computeArea() = 0;
135 };
136
137 class Square : public Shape {
138 double SideLength;
139 public:
140 - Square(double S) : SideLength(S) {}
141 + Square(double S) : Shape(SquareKind), SideLength(S) {}
142 double computeArea() /* override */;
143 };
144
145 class Circle : public Shape {
146 double Radius;
147 public:
148 - Circle(double R) : Radius(R) {}
149 + Circle(double R) : Shape(CircleKind), Radius(R) {}
150 double computeArea() /* override */;
151 };
152
153 #. Finally, you need to inform LLVM's RTTI templates how to dynamically
154 determine the type of a class (i.e. whether the ``isa<>``/``dyn_cast<>``
155 should succeed). The default "99.9% of use cases" way to accomplish this
156 is through a small static member function ``classof``. In order to have
157 proper context for an explanation, we will display this code first, and
158 then below describe each part:
159
160 .. code-block:: c++
161
162 class Shape {
163 public:
164 /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
165 enum ShapeKind {
166 SquareKind,
167 CircleKind
168 };
169 private:
170 const ShapeKind Kind;
171 public:
172 ShapeKind getKind() const { return Kind; }
173
174 Shape(ShapeKind K) : Kind(K) {};
175 virtual double computeArea() = 0;
176 +
177 + static bool classof(const Shape *) { return true; }
178 };
179
180 class Square : public Shape {
181 double SideLength;
182 public:
183 Square(double S) : Shape(SquareKind), SideLength(S) {}
184 double computeArea() /* override */;
185 +
186 + static bool classof(const Square *) { return true; }
187 + static bool classof(const Shape *S) {
188 + return S->getKind() == SquareKind;
189 + }
190 };
191
192 class Circle : public Shape {
193 double Radius;
194 public:
195 Circle(double R) : Shape(CircleKind), Radius(R) {}
196 double computeArea() /* override */;
197 +
198 + static bool classof(const Circle *) { return true; }
199 + static bool classof(const Shape *S) {
200 + return S->getKind() == CircleKind;
201 + }
202 };
203
204 Basically, the job of ``classof`` is to return ``true`` if its argument
205 is of the enclosing class's type. As you can see, there are two general
206 overloads of ``classof`` in use here.
207
208 #. The first, which just returns ``true``, means that if we know that the
209 argument of the cast is of the enclosing type *at compile time*, then
210 we don't need to bother to check anything since we already know that
211 the type is convertible. This is an optimization for the case that we
212 statically know the conversion is OK.
213
214 #. The other overload takes a pointer to an object of the base of the
215 class hierarchy: this is the "general case" of the cast. We need to
216 check the ``Kind`` to dynamically decide if the argument is of (or
217 derived from) the enclosing type.
218
219 To be more precise, let ``classof`` be inside a class ``C``. Then the
220 contract for ``classof`` is "return ``true`` if the argument is-a
221 ``C``". As long as your implementation fulfills this contract, you can
222 tweak and optimize it as much as you want.
223
224 Although for this small example setting up LLVM-style RTTI seems like a lot
225 of "boilerplate", if your classes are doing anything interesting then this
226 will end up being a tiny fraction of the code.
227
228 Concrete Bases and Deeper Hierarchies
229 =====================================
230
231 For concrete bases (i.e. non-abstract interior nodes of the inheritance
232 tree), the ``Kind`` check inside ``classof`` needs to be a bit more
233 complicated. Say that ``SpecialSquare`` and ``OtherSpecialSquare`` derive
234 from ``Square``, and so ``ShapeKind`` becomes:
235
236 .. code-block:: c++
237
238 enum ShapeKind {
239 SquareKind,
240 + SpecialSquareKind,
241 + OtherSpecialSquareKind,
242 CircleKind
243 }
244
245 Then in ``Square``, we would need to modify the ``classof`` like so:
246
247 .. code-block:: c++
248
249 static bool classof(const Square *) { return true; }
250 - static bool classof(const Shape *S) {
251 - return S->getKind() == SquareKind;
252 - }
253 + static bool classof(const Shape *S) {
254 + return S->getKind() >= SquareKind &&
255 + S->getKind() <= OtherSpecialSquareKind;
256 + }
257
258 The reason that we need to test a range like this instead of just equality
259 is that both ``SpecialSquare`` and ``OtherSpecialSquare`` "is-a"
260 ``Square``, and so ``classof`` needs to return ``true`` for them.
261
262 This approach can be made to scale to arbitrarily deep hierarchies. The
263 trick is that you arrange the enum values so that they correspond to a
264 preorder traversal of the class hierarchy tree. With that arrangement, all
265 subclass tests can be done with two comparisons as shown above. If you just
266 list the class hierarchy like a list of bullet points, you'll get the
267 ordering right::
268
269 | Shape
270 | Square
271 | SpecialSquare
272 | OtherSpecialSquare
273 | Circle
274
275 .. TODO::
276
277 Touch on some of the more advanced features, like ``isa_impl`` and
278 ``simplify_type``. However, those two need reference documentation in
279 the form of doxygen comments as well. We need the doxygen so that we can
280 say "for full details, see http://llvm.org/doxygen/..."
431431
432432
433433

These five templates can be used with any classes, whether they have a

434 v-table or not. To add support for these templates, you simply need to add
435 classof static methods to the class you are interested casting
436 to. Describing this is currently outside the scope of this document, but there
437 are lots of examples in the LLVM source base.

434 v-table or not. If you want to add support for these templates, see the
435 document How to set up LLVM-style
436 RTTI for your class hierarchy .
437

438438
439439
440440
88 CodingStandards
99 CommandLine
1010 Atomics
11 HowToSetUpLLVMStyleRTTI
1112
1213 * `LLVM Language Reference Manual `_
1314
3233 Details the LLVM coding standards and provides useful information on writing
3334 efficient C++ code.
3435
36 * :doc:`HowToSetUpLLVMStyleRTTI`
37
38 How to make ``isa<>``, ``dyn_cast<>``, etc. available for clients of your
39 class hierarchy.
40
3541 * `Extending LLVM `_
3642
3743 Look here to see how to add instructions and intrinsics to LLVM.