xref: /aosp_15_r20/external/swiftshader/docs/Reactor.md (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard WorkerReactor Documentation
2*03ce13f7SAndroid Build Coastguard Worker=====================
3*03ce13f7SAndroid Build Coastguard Worker
4*03ce13f7SAndroid Build Coastguard WorkerReactor is an embedded language for C++ to facilitate dynamic code generation and specialization.
5*03ce13f7SAndroid Build Coastguard Worker
6*03ce13f7SAndroid Build Coastguard WorkerIntroduction
7*03ce13f7SAndroid Build Coastguard Worker------------
8*03ce13f7SAndroid Build Coastguard Worker
9*03ce13f7SAndroid Build Coastguard WorkerTo generate the code for an expression such as
10*03ce13f7SAndroid Build Coastguard Worker```C++
11*03ce13f7SAndroid Build Coastguard Workerfloat y = 1 - x;
12*03ce13f7SAndroid Build Coastguard Worker```
13*03ce13f7SAndroid Build Coastguard Workerusing the LLVM compiler framework, one needs to execute
14*03ce13f7SAndroid Build Coastguard Worker```C++
15*03ce13f7SAndroid Build Coastguard WorkerValue *valueY = BinaryOperator::CreateSub(ConstantInt::get(Type::getInt32Ty(Context), 1), valueX, "y", basicBlock);
16*03ce13f7SAndroid Build Coastguard Worker```
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard WorkerFor large expressions this quickly becomes hard to read, and tedious to write and modify.
19*03ce13f7SAndroid Build Coastguard Worker
20*03ce13f7SAndroid Build Coastguard WorkerWith Reactor, it becomes as simple as writing
21*03ce13f7SAndroid Build Coastguard Worker```C++
22*03ce13f7SAndroid Build Coastguard WorkerFloat y = 1 - x;
23*03ce13f7SAndroid Build Coastguard Worker```
24*03ce13f7SAndroid Build Coastguard WorkerNote the capital letter for the type. This is not the code to perform the calculation. It's the code that when executed will record the calculation to be performed.
25*03ce13f7SAndroid Build Coastguard Worker
26*03ce13f7SAndroid Build Coastguard WorkerThis is possible through the use of C++ operator overloading. Reactor also supports control flow constructs and pointer arithmetic with C-like syntax.
27*03ce13f7SAndroid Build Coastguard Worker
28*03ce13f7SAndroid Build Coastguard WorkerMotivation
29*03ce13f7SAndroid Build Coastguard Worker----------
30*03ce13f7SAndroid Build Coastguard Worker
31*03ce13f7SAndroid Build Coastguard WorkerJust-in-time (JIT) compiled code has the potential to be faster than statically compiled code, through [run-time specialization](http://en.wikipedia.org/wiki/Run-time_algorithm_specialisation). However, this is rarely achieved in practice.
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard WorkerSpecialization in general is the use of a more optimal routine that is specific for a certain set of conditions. For example when sorting two numbers it is faster to swap them if they are not yet in order, than to call a generic quicksort function. Specialization can be done statically, by explicitly writing each variant or by using metaprogramming to generate multiple variants at static compile time, or dynamically by examining the parameters at run-time and generating a specialized path.
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard WorkerBecause specialization can be done statically, sometimes aided by metaprogramming, the ability of a JIT-compiler to do it at run-time is often disregarded. Specialized benchmarks show no advantage of JIT code over static code. However, having a specialized benchmark does not take into account that a typical real-world application deals with many unpredictable conditions. Systems can have one core or several dozen cores, and many different ISA extensions. This alone can make it impractical to write fully specialized routines manually, and with the help of metaprogramming it results in code bloat. Worse yet, any non-trivial application has a layered architecture in which lower layers (e.g. framework APIs) know very little or nothing about the usage by higher layers. Various parameters also depend on user input. Run-time specialization can have access to the full context in which each routine executes, and although the optimization contribution of specialization for a single parameter is small, the combined speedup can be huge. As an extreme example, interpreters can execute any kind of program in any language, but by specializing for a specific program you get a compiled version of that program. But you don't need a full-blown language to observe a huge difference between interpretation and specialization through compilation. Most applications process some form of list of commands in an interpreted fashion, and even the series of calls into a framework API can be compiled into a more efficient whole at run-time.
36*03ce13f7SAndroid Build Coastguard Worker
37*03ce13f7SAndroid Build Coastguard WorkerWhile the benefit of run-time specialization should now be apparent, JIT-compiled languages lack many of the practical advantages of static compilation. JIT-compilers are very constrained in how much time they can spend on compiling the bytecode into machine code. This limits their ability to even reach parity with static compilation, let alone attempt to exceed it by performing run-time specialization. Also, even if the compilation time was not as constrained, they can't specialize at every opportunity because it would result in an explosive growth of the amount of generated code. There's a need to be very selective in only specializing the hotspots for often recurring conditions, and to manage a cache of the different variants. Even just selecting the size of the set of variables that form the entire condition to specialize for can get immensely complicated.
38*03ce13f7SAndroid Build Coastguard Worker
39*03ce13f7SAndroid Build Coastguard WorkerClearly we need a manageable way to benefit from run-time specialization where it would help significantly, while still resorting to static compilation for anything else. A crucial observation is that the developer has expectations about the application's behavior, which is valuable information which can be exploited to choose between static or JIT-compilation. One way to do that is to use an API which JIT-compiles the commands provided by the application developer. An example of this is an advanced DBMS which compiles the query into an optimized sequence of routines, each specialized to the data types involved, the sizes of the CPU caches, etc. Another example is a modern graphics API, which takes shaders (a routine executed per pixel or other element) and a set of parameters which affect their execution, and compiles them into GPU-specific code. However, these examples have a very hard divide between what goes on inside the API and outside. You can't exchange data between the statically compiled outside world and the JIT-compiled routines, unless through the API, and they have very different execution models. In other words they are highly domain specific and not generic ways to exploit run-time specialization in arbitrary code.
40*03ce13f7SAndroid Build Coastguard Worker
41*03ce13f7SAndroid Build Coastguard WorkerThis is becoming especially problematic for GPUs, as they are now just as programmable as CPUs but you can still only command them through an API. Attempts to disguise this by using a single language, such as C++AMP and SYCL, still have difficulties expressing how data is exchanged, don't actually provide control over the specialization, they have hidden overhead, and they have unpredictable performance characteristics across devices. Meanwhile CPUs gain ever more cores and wider SIMD vector units, but statically compiled languages don't readily exploit this and can't deal with the many code paths required to extract optimal performance. A different language and framework is required.
42*03ce13f7SAndroid Build Coastguard Worker
43*03ce13f7SAndroid Build Coastguard WorkerConcepts and Syntax
44*03ce13f7SAndroid Build Coastguard Worker-------------------
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker### Routine and Function<>
47*03ce13f7SAndroid Build Coastguard Worker
48*03ce13f7SAndroid Build Coastguard WorkerReactor allows you to create new functions at run-time. Their generation happens in C++, and after materializing them they can be called during the execution of the same C++ program. We call these dynamically generated functions "routines", to discern them from statically compiled functions and methods. Reactor's `Routine` class encapsulates a routine. Deleting a Routine object also frees the memory used to store the routine.
49*03ce13f7SAndroid Build Coastguard Worker
50*03ce13f7SAndroid Build Coastguard WorkerTo declare the function signature of a routine, use the `Function<>` template. The template argument is the signature of a function, using Reactor variable types. Here's a complete definition of a routine taking no arguments and returning an integer:
51*03ce13f7SAndroid Build Coastguard Worker
52*03ce13f7SAndroid Build Coastguard Worker`C++
53*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Void)> function;
54*03ce13f7SAndroid Build Coastguard Worker{
55*03ce13f7SAndroid Build Coastguard Worker    Return(1);
56*03ce13f7SAndroid Build Coastguard Worker}
57*03ce13f7SAndroid Build Coastguard Worker`
58*03ce13f7SAndroid Build Coastguard Worker
59*03ce13f7SAndroid Build Coastguard WorkerThe braces are superfluous. They just make the syntax look more like regular C++, and they offer a new scope for Reactor variables.
60*03ce13f7SAndroid Build Coastguard Worker
61*03ce13f7SAndroid Build Coastguard WorkerThe Routine is obtained and materialized by "calling" the `Function<>` object to give it a name:
62*03ce13f7SAndroid Build Coastguard Worker
63*03ce13f7SAndroid Build Coastguard Worker```C++
64*03ce13f7SAndroid Build Coastguard Workerauto routine = function("one");
65*03ce13f7SAndroid Build Coastguard Worker```
66*03ce13f7SAndroid Build Coastguard Worker
67*03ce13f7SAndroid Build Coastguard WorkerFinally, we can obtain the function pointer to the entry point of the routine, and call it:
68*03ce13f7SAndroid Build Coastguard Worker
69*03ce13f7SAndroid Build Coastguard Worker```C++
70*03ce13f7SAndroid Build Coastguard Workerint (*callable)() = (int(*)())routine->getEntry();
71*03ce13f7SAndroid Build Coastguard Worker
72*03ce13f7SAndroid Build Coastguard Workerint result = callable();
73*03ce13f7SAndroid Build Coastguard Workerassert(result == 1);
74*03ce13f7SAndroid Build Coastguard Worker```
75*03ce13f7SAndroid Build Coastguard Worker
76*03ce13f7SAndroid Build Coastguard WorkerNote that `Function<>` objects are relatively heavyweight, since they have the entire JIT-compiler behind them, while `Routine` objects are lightweight and merely provide storage and lifetime management of generated routines. So we typically allow the `Function<>` object to be destroyed (by going out of scope), while the `Routine` object is retained until we no longer need to call the routine. Hence the distinction between them and the need for a couple of lines of boilerplate code.
77*03ce13f7SAndroid Build Coastguard Worker
78*03ce13f7SAndroid Build Coastguard Worker### Arguments and Expressions
79*03ce13f7SAndroid Build Coastguard Worker
80*03ce13f7SAndroid Build Coastguard WorkerRoutines can take various arguments. The following example illustrates the syntax for accessing the arguments of a routine which takes two integer arguments and returns their sum:
81*03ce13f7SAndroid Build Coastguard Worker
82*03ce13f7SAndroid Build Coastguard Worker```C++
83*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Int, Int)> function;
84*03ce13f7SAndroid Build Coastguard Worker{
85*03ce13f7SAndroid Build Coastguard Worker    Int x = function.Arg<0>();
86*03ce13f7SAndroid Build Coastguard Worker    Int y = function.Arg<1>();
87*03ce13f7SAndroid Build Coastguard Worker
88*03ce13f7SAndroid Build Coastguard Worker    Int sum = x + y;
89*03ce13f7SAndroid Build Coastguard Worker
90*03ce13f7SAndroid Build Coastguard Worker    Return(sum);
91*03ce13f7SAndroid Build Coastguard Worker}
92*03ce13f7SAndroid Build Coastguard Worker```
93*03ce13f7SAndroid Build Coastguard Worker
94*03ce13f7SAndroid Build Coastguard WorkerReactor supports various types which correspond to C++ types:
95*03ce13f7SAndroid Build Coastguard Worker
96*03ce13f7SAndroid Build Coastguard Worker| Class name    | C++ equivalent |
97*03ce13f7SAndroid Build Coastguard Worker| ------------- |----------------|
98*03ce13f7SAndroid Build Coastguard Worker| Int           | int32_t        |
99*03ce13f7SAndroid Build Coastguard Worker| UInt          | uint32_t       |
100*03ce13f7SAndroid Build Coastguard Worker| Short         | int16_t        |
101*03ce13f7SAndroid Build Coastguard Worker| UShort        | uint16_t       |
102*03ce13f7SAndroid Build Coastguard Worker| Byte          | uint8_t        |
103*03ce13f7SAndroid Build Coastguard Worker| SByte         | int8_t         |
104*03ce13f7SAndroid Build Coastguard Worker| Long          | int64_t        |
105*03ce13f7SAndroid Build Coastguard Worker| ULong         | uint64_t       |
106*03ce13f7SAndroid Build Coastguard Worker| Float         | float          |
107*03ce13f7SAndroid Build Coastguard Worker
108*03ce13f7SAndroid Build Coastguard WorkerNote that bytes are unsigned unless prefixed with S, while larger integers are signed unless prefixed with U.
109*03ce13f7SAndroid Build Coastguard Worker
110*03ce13f7SAndroid Build Coastguard WorkerThese scalar types support all of the C++ arithmetic operations.
111*03ce13f7SAndroid Build Coastguard Worker
112*03ce13f7SAndroid Build Coastguard WorkerReactor also supports several vector types. For example `Float4` is a vector of four floats. They support a select number of C++ operators, and several "intrinsic" functions such as `Max()` to compute the element-wise maximum and return a bit mask. Check [Reactor.hpp](../src/Reactor/Reactor.hpp) for all the types, operators and intrinsics.
113*03ce13f7SAndroid Build Coastguard Worker
114*03ce13f7SAndroid Build Coastguard Worker### Casting and Reinterpreting
115*03ce13f7SAndroid Build Coastguard Worker
116*03ce13f7SAndroid Build Coastguard WorkerTypes can be cast using the constructor-style syntax:
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker```C++
119*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Float)> function;
120*03ce13f7SAndroid Build Coastguard Worker{
121*03ce13f7SAndroid Build Coastguard Worker    Float x = function.Arg<0>();
122*03ce13f7SAndroid Build Coastguard Worker
123*03ce13f7SAndroid Build Coastguard Worker    Int cast = Int(x);
124*03ce13f7SAndroid Build Coastguard Worker
125*03ce13f7SAndroid Build Coastguard Worker    Return(cast);
126*03ce13f7SAndroid Build Coastguard Worker}
127*03ce13f7SAndroid Build Coastguard Worker```
128*03ce13f7SAndroid Build Coastguard Worker
129*03ce13f7SAndroid Build Coastguard WorkerYou can reinterpret-cast a variable using `As<>`:
130*03ce13f7SAndroid Build Coastguard Worker
131*03ce13f7SAndroid Build Coastguard Worker```C++
132*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Float)> function;
133*03ce13f7SAndroid Build Coastguard Worker{
134*03ce13f7SAndroid Build Coastguard Worker    Float x = function.Arg<0>();
135*03ce13f7SAndroid Build Coastguard Worker
136*03ce13f7SAndroid Build Coastguard Worker    Int reinterpret = As<Int>(x);
137*03ce13f7SAndroid Build Coastguard Worker
138*03ce13f7SAndroid Build Coastguard Worker    Return(reinterpret);
139*03ce13f7SAndroid Build Coastguard Worker}
140*03ce13f7SAndroid Build Coastguard Worker```
141*03ce13f7SAndroid Build Coastguard Worker
142*03ce13f7SAndroid Build Coastguard WorkerNote that this is a bitwise cast. Unlike C++'s `reinterpret_cast<>`, it does not allow casting between different sized types. Think of it as storing the value in memory and then loading from that same address into the casted type.
143*03ce13f7SAndroid Build Coastguard Worker
144*03ce13f7SAndroid Build Coastguard WorkerAn important exception is that 16-, 8-, and 4-byte vectors can be cast to other vectors of one of these sizes. Casting to a longer vector leaves the upper contents undefined.
145*03ce13f7SAndroid Build Coastguard Worker
146*03ce13f7SAndroid Build Coastguard Worker### Pointers
147*03ce13f7SAndroid Build Coastguard Worker
148*03ce13f7SAndroid Build Coastguard WorkerPointers also use a template class:
149*03ce13f7SAndroid Build Coastguard Worker
150*03ce13f7SAndroid Build Coastguard Worker```C++
151*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Pointer<Int>)> function;
152*03ce13f7SAndroid Build Coastguard Worker{
153*03ce13f7SAndroid Build Coastguard Worker    Pointer<Int> x = function.Arg<0>();
154*03ce13f7SAndroid Build Coastguard Worker
155*03ce13f7SAndroid Build Coastguard Worker    Int dereference = *x;
156*03ce13f7SAndroid Build Coastguard Worker
157*03ce13f7SAndroid Build Coastguard Worker    Return(dereference);
158*03ce13f7SAndroid Build Coastguard Worker}
159*03ce13f7SAndroid Build Coastguard Worker```
160*03ce13f7SAndroid Build Coastguard Worker
161*03ce13f7SAndroid Build Coastguard WorkerPointer arithmetic is only supported on `Pointer<Byte>`, and can be used to access structure fields:
162*03ce13f7SAndroid Build Coastguard Worker
163*03ce13f7SAndroid Build Coastguard Worker```C++
164*03ce13f7SAndroid Build Coastguard Workerstruct S
165*03ce13f7SAndroid Build Coastguard Worker{
166*03ce13f7SAndroid Build Coastguard Worker    int x;
167*03ce13f7SAndroid Build Coastguard Worker    int y;
168*03ce13f7SAndroid Build Coastguard Worker};
169*03ce13f7SAndroid Build Coastguard Worker
170*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Pointer<Byte>)> function;
171*03ce13f7SAndroid Build Coastguard Worker{
172*03ce13f7SAndroid Build Coastguard Worker    Pointer<Byte> s = function.Arg<0>();
173*03ce13f7SAndroid Build Coastguard Worker
174*03ce13f7SAndroid Build Coastguard Worker    Int y = *Pointer<Int>(s + offsetof(S, y));
175*03ce13f7SAndroid Build Coastguard Worker
176*03ce13f7SAndroid Build Coastguard Worker    Return(y);
177*03ce13f7SAndroid Build Coastguard Worker}
178*03ce13f7SAndroid Build Coastguard Worker```
179*03ce13f7SAndroid Build Coastguard Worker
180*03ce13f7SAndroid Build Coastguard WorkerReactor also defines an `OFFSET()` macro, which is a generalization of the `offsetof()` macro defined in `<cstddef>`. It allows e.g. getting the offset of array elements, even when indexed dynamically.
181*03ce13f7SAndroid Build Coastguard Worker
182*03ce13f7SAndroid Build Coastguard Worker### Conditionals
183*03ce13f7SAndroid Build Coastguard Worker
184*03ce13f7SAndroid Build Coastguard WorkerTo generate for example the [unit step](https://en.wikipedia.org/wiki/Heaviside_step_function) function:
185*03ce13f7SAndroid Build Coastguard Worker
186*03ce13f7SAndroid Build Coastguard Worker```C++
187*03ce13f7SAndroid Build Coastguard WorkerFunction<Float(Float)> function;
188*03ce13f7SAndroid Build Coastguard Worker{
189*03ce13f7SAndroid Build Coastguard Worker    Pointer<Float> x = function.Arg<0>();
190*03ce13f7SAndroid Build Coastguard Worker
191*03ce13f7SAndroid Build Coastguard Worker    If(x > 0.0f)
192*03ce13f7SAndroid Build Coastguard Worker    {
193*03ce13f7SAndroid Build Coastguard Worker        Return(1.0f);
194*03ce13f7SAndroid Build Coastguard Worker    }
195*03ce13f7SAndroid Build Coastguard Worker    Else If(x < 0.0f)
196*03ce13f7SAndroid Build Coastguard Worker    {
197*03ce13f7SAndroid Build Coastguard Worker        Return(0.0f);
198*03ce13f7SAndroid Build Coastguard Worker    }
199*03ce13f7SAndroid Build Coastguard Worker    Else
200*03ce13f7SAndroid Build Coastguard Worker    {
201*03ce13f7SAndroid Build Coastguard Worker        Return(0.5f);
202*03ce13f7SAndroid Build Coastguard Worker    }
203*03ce13f7SAndroid Build Coastguard Worker}
204*03ce13f7SAndroid Build Coastguard Worker```
205*03ce13f7SAndroid Build Coastguard Worker
206*03ce13f7SAndroid Build Coastguard WorkerThere's also an IfThenElse() intrinsic function which corresponds with the C++ ?: operator.
207*03ce13f7SAndroid Build Coastguard Worker
208*03ce13f7SAndroid Build Coastguard Worker### Loops
209*03ce13f7SAndroid Build Coastguard Worker
210*03ce13f7SAndroid Build Coastguard WorkerLoops also have a syntax similar to C++:
211*03ce13f7SAndroid Build Coastguard Worker
212*03ce13f7SAndroid Build Coastguard Worker```C++
213*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Pointer<Int>, Int)> function;
214*03ce13f7SAndroid Build Coastguard Worker{
215*03ce13f7SAndroid Build Coastguard Worker    Pointer<Int> p = function.Arg<0>();
216*03ce13f7SAndroid Build Coastguard Worker    Int n = function.Arg<1>();
217*03ce13f7SAndroid Build Coastguard Worker    Int total = 0;
218*03ce13f7SAndroid Build Coastguard Worker
219*03ce13f7SAndroid Build Coastguard Worker    For(Int i = 0, i < n, i++)
220*03ce13f7SAndroid Build Coastguard Worker    {
221*03ce13f7SAndroid Build Coastguard Worker        total += p[i];
222*03ce13f7SAndroid Build Coastguard Worker    }
223*03ce13f7SAndroid Build Coastguard Worker
224*03ce13f7SAndroid Build Coastguard Worker    Return(total);
225*03ce13f7SAndroid Build Coastguard Worker}
226*03ce13f7SAndroid Build Coastguard Worker```
227*03ce13f7SAndroid Build Coastguard Worker
228*03ce13f7SAndroid Build Coastguard WorkerNote the use of commas instead of semicolons to separate the loop expressions.
229*03ce13f7SAndroid Build Coastguard Worker
230*03ce13f7SAndroid Build Coastguard Worker`While(expr) {}` also works as expected, but there is no `Do {} While(expr)` equivalent because we can't discern between them. Instead, there's a `Do {} Until(expr)` where you can use the inverse expression to exit the loop.
231*03ce13f7SAndroid Build Coastguard Worker
232*03ce13f7SAndroid Build Coastguard WorkerSpecialization
233*03ce13f7SAndroid Build Coastguard Worker--------------
234*03ce13f7SAndroid Build Coastguard Worker
235*03ce13f7SAndroid Build Coastguard WorkerThe above examples don't illustrate anything that can't be written as regular C++ function. The real power of Reactor is to generate routines that are specialized for a certain set of conditions, or "state".
236*03ce13f7SAndroid Build Coastguard Worker
237*03ce13f7SAndroid Build Coastguard Worker```C++
238*03ce13f7SAndroid Build Coastguard WorkerFunction<Int(Pointer<Int>, Int)> function;
239*03ce13f7SAndroid Build Coastguard Worker{
240*03ce13f7SAndroid Build Coastguard Worker    Pointer<Int> p = function.Arg<0>();
241*03ce13f7SAndroid Build Coastguard Worker    Int n = function.Arg<1>();
242*03ce13f7SAndroid Build Coastguard Worker    Int total = 0;
243*03ce13f7SAndroid Build Coastguard Worker
244*03ce13f7SAndroid Build Coastguard Worker    For(Int i = 0, i < n, i++)
245*03ce13f7SAndroid Build Coastguard Worker    {
246*03ce13f7SAndroid Build Coastguard Worker        if(state.operation == ADD)
247*03ce13f7SAndroid Build Coastguard Worker        {
248*03ce13f7SAndroid Build Coastguard Worker            total += p[i];
249*03ce13f7SAndroid Build Coastguard Worker        }
250*03ce13f7SAndroid Build Coastguard Worker        else if(state.operation == SUBTRACT)
251*03ce13f7SAndroid Build Coastguard Worker        {
252*03ce13f7SAndroid Build Coastguard Worker            total -= p[i];
253*03ce13f7SAndroid Build Coastguard Worker        }
254*03ce13f7SAndroid Build Coastguard Worker        else if(state.operation == AND)
255*03ce13f7SAndroid Build Coastguard Worker        {
256*03ce13f7SAndroid Build Coastguard Worker            total &= p[i];
257*03ce13f7SAndroid Build Coastguard Worker        }
258*03ce13f7SAndroid Build Coastguard Worker        else if(...)
259*03ce13f7SAndroid Build Coastguard Worker        {
260*03ce13f7SAndroid Build Coastguard Worker            ...
261*03ce13f7SAndroid Build Coastguard Worker        }
262*03ce13f7SAndroid Build Coastguard Worker    }
263*03ce13f7SAndroid Build Coastguard Worker
264*03ce13f7SAndroid Build Coastguard Worker    Return(total);
265*03ce13f7SAndroid Build Coastguard Worker}
266*03ce13f7SAndroid Build Coastguard Worker```
267*03ce13f7SAndroid Build Coastguard Worker
268*03ce13f7SAndroid Build Coastguard WorkerNote that this example uses regular C++ `if` and `else` constructs. They only determine which code ends up in the generated routine, and don't end up in the generated code themselves. Thus the routine contains a loop with just one arithmetic or logical operation, making it more efficient than if this was written in regular C++.
269*03ce13f7SAndroid Build Coastguard Worker
270*03ce13f7SAndroid Build Coastguard WorkerOf course one could write an equivalent efficient function in regular C++ like this:
271*03ce13f7SAndroid Build Coastguard Worker
272*03ce13f7SAndroid Build Coastguard Worker```C++
273*03ce13f7SAndroid Build Coastguard Workerint function(int *p, int n)
274*03ce13f7SAndroid Build Coastguard Worker{
275*03ce13f7SAndroid Build Coastguard Worker    int total = 0;
276*03ce13f7SAndroid Build Coastguard Worker
277*03ce13f7SAndroid Build Coastguard Worker    if(state.operation == ADD)
278*03ce13f7SAndroid Build Coastguard Worker    {
279*03ce13f7SAndroid Build Coastguard Worker        for(int i = 0; i < n; i++)
280*03ce13f7SAndroid Build Coastguard Worker        {
281*03ce13f7SAndroid Build Coastguard Worker            total += p[i];
282*03ce13f7SAndroid Build Coastguard Worker        }
283*03ce13f7SAndroid Build Coastguard Worker    }
284*03ce13f7SAndroid Build Coastguard Worker    else if(state.operation == SUBTRACT)
285*03ce13f7SAndroid Build Coastguard Worker    {
286*03ce13f7SAndroid Build Coastguard Worker        for(int i = 0; i < n; i++)
287*03ce13f7SAndroid Build Coastguard Worker        {
288*03ce13f7SAndroid Build Coastguard Worker            total -= p[i];
289*03ce13f7SAndroid Build Coastguard Worker        }
290*03ce13f7SAndroid Build Coastguard Worker    }
291*03ce13f7SAndroid Build Coastguard Worker    else if(state.operation == AND)
292*03ce13f7SAndroid Build Coastguard Worker    {
293*03ce13f7SAndroid Build Coastguard Worker        for(int i = 0; i < n; i++)
294*03ce13f7SAndroid Build Coastguard Worker        {
295*03ce13f7SAndroid Build Coastguard Worker            total &= p[i];
296*03ce13f7SAndroid Build Coastguard Worker        }
297*03ce13f7SAndroid Build Coastguard Worker    }
298*03ce13f7SAndroid Build Coastguard Worker    else if(...)
299*03ce13f7SAndroid Build Coastguard Worker    {
300*03ce13f7SAndroid Build Coastguard Worker        ...
301*03ce13f7SAndroid Build Coastguard Worker    }
302*03ce13f7SAndroid Build Coastguard Worker
303*03ce13f7SAndroid Build Coastguard Worker    return total;
304*03ce13f7SAndroid Build Coastguard Worker}
305*03ce13f7SAndroid Build Coastguard Worker```
306*03ce13f7SAndroid Build Coastguard Worker
307*03ce13f7SAndroid Build Coastguard WorkerBut now there's a lot of repeated code. It could be made more manageable using macros or templates, but that doesn't help reduce the binary size of the statically compiled code. That's fine when there are only a handful of state conditions to specialize for, but when you have multiple state variables with many possible values each, the total number of combinations can be prohibitive.
308*03ce13f7SAndroid Build Coastguard Worker
309*03ce13f7SAndroid Build Coastguard WorkerThis is especially the case when implementing APIs which offer a broad set of features but developers are likely to only use a select set. The quintessential example is graphics processing, where there are are long pipelines of optional operations and both fixed-function and programmable stages. Applications configure the state of these stages between each draw call.
310*03ce13f7SAndroid Build Coastguard Worker
311*03ce13f7SAndroid Build Coastguard WorkerWith Reactor, we can write the code for such pipelines in a syntax that is as easy to read as a naive unoptimized implementation, while at the same time specializing the code for exactly the operations required by the pipeline configuration.
312