1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <Device/Vertex.hpp>
16#include "SetupRoutine.hpp"
17
18#include "Constants.hpp"
19#include "Device/Primitive.hpp"
20#include "Device/Polygon.hpp"
21#include "Device/Renderer.hpp"
22#include "Reactor/Reactor.hpp"
23
24namespace sw
25{
26 SetupRoutine::SetupRoutine(const SetupProcessor::State &state) : state(state)
27 {
28 }
29
30 SetupRoutine::~SetupRoutine()
31 {
32 }
33
34 void SetupRoutine::generate()
35 {
36 SetupFunction function;
37 {
38 Pointer<Byte> primitive(function.Arg<0>());
39 Pointer<Byte> tri(function.Arg<1>());
40 Pointer<Byte> polygon(function.Arg<2>());
41 Pointer<Byte> data(function.Arg<3>());
42
43 Pointer<Byte> constants = *Pointer<Pointer<Byte> >(data + OFFSET(DrawData,constants));
44
45 const bool point = state.isDrawPoint;
46 const bool line = state.isDrawLine;
47 const bool triangle = state.isDrawTriangle;
48
49 const int V0 = OFFSET(Triangle,v0);
50 const int V1 = (triangle || line) ? OFFSET(Triangle,v1) : OFFSET(Triangle,v0);
51 const int V2 = triangle ? OFFSET(Triangle,v2) : (line ? OFFSET(Triangle,v1) : OFFSET(Triangle,v0));
52
53 Pointer<Byte> v0 = tri + V0;
54 Pointer<Byte> v1 = tri + V1;
55 Pointer<Byte> v2 = tri + V2;
56
57 Array<Int> X(16);
58 Array<Int> Y(16);
59
60 X[0] = *Pointer<Int>(v0 + OFFSET(Vertex,projected.x));
61 X[1] = *Pointer<Int>(v1 + OFFSET(Vertex,projected.x));
62 X[2] = *Pointer<Int>(v2 + OFFSET(Vertex,projected.x));
63
64 Y[0] = *Pointer<Int>(v0 + OFFSET(Vertex,projected.y));
65 Y[1] = *Pointer<Int>(v1 + OFFSET(Vertex,projected.y));
66 Y[2] = *Pointer<Int>(v2 + OFFSET(Vertex,projected.y));
67
68 Int d = 1; // Winding direction
69
70 // Culling
71 if(triangle)
72 {
73 Float x0 = Float(X[0]);
74 Float x1 = Float(X[1]);
75 Float x2 = Float(X[2]);
76
77 Float y0 = Float(Y[0]);
78 Float y1 = Float(Y[1]);
79 Float y2 = Float(Y[2]);
80
81 Float A = (y0 - y2) * x1 + (y2 - y1) * x0 + (y1 - y0) * x2; // Area
82
83 If(A == 0.0f)
84 {
85 Return(0);
86 }
87
88 Int w0w1w2 = *Pointer<Int>(v0 + OFFSET(Vertex, w)) ^
89 *Pointer<Int>(v1 + OFFSET(Vertex, w)) ^
90 *Pointer<Int>(v2 + OFFSET(Vertex, w));
91
92 A = IfThenElse(w0w1w2 < 0, -A, A);
93
94 Bool frontFacing = (state.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE) ? A > 0.0f : A < 0.0f;
95
96 if(state.cullMode & VK_CULL_MODE_FRONT_BIT)
97 {
98 If(frontFacing) Return(0);
99 }
100 if(state.cullMode & VK_CULL_MODE_BACK_BIT)
101 {
102 If(!frontFacing) Return(0);
103 }
104
105 d = IfThenElse(A > 0.0f, d, Int(0));
106
107 If(frontFacing)
108 {
109 *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
110 *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
111 }
112 Else
113 {
114 *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
115 *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
116 }
117 }
118 else
119 {
120 *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
121 *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
122 }
123
124 Int n = *Pointer<Int>(polygon + OFFSET(Polygon,n));
125 Int m = *Pointer<Int>(polygon + OFFSET(Polygon,i));
126
127 If(m != 0 || Bool(!triangle)) // Clipped triangle; reproject
128 {
129 Pointer<Byte> V = polygon + OFFSET(Polygon,P) + m * sizeof(void*) * 16;
130
131 Int i = 0;
132
133 Do
134 {
135 Pointer<Float4> p = *Pointer<Pointer<Float4> >(V + i * sizeof(void*));
136 Float4 v = *Pointer<Float4>(p, 16);
137
138 Float w = v.w;
139 Float rhw = IfThenElse(w != 0.0f, 1.0f / w, Float(1.0f));
140
141 X[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData,X0xF)) + v.x * rhw * *Pointer<Float>(data + OFFSET(DrawData,WxF)));
142 Y[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData,Y0xF)) + v.y * rhw * *Pointer<Float>(data + OFFSET(DrawData,HxF)));
143
144 i++;
145 }
146 Until(i >= n)
147 }
148
149 // Vertical range
150 Int yMin = Y[0];
151 Int yMax = Y[0];
152
153 Int i = 1;
154
155 Do
156 {
157 yMin = Min(Y[i], yMin);
158 yMax = Max(Y[i], yMax);
159
160 i++;
161 }
162 Until(i >= n)
163
164 constexpr int subPixB = vk::SUBPIXEL_PRECISION_BITS;
165 constexpr int subPixM = vk::SUBPIXEL_PRECISION_MASK;
166 constexpr float subPixF = vk::SUBPIXEL_PRECISION_FACTOR;
167
168 if(state.multiSample > 1)
169 {
170 yMin = (yMin + Constants::yMinMultiSampleOffset) >> subPixB;
171 yMax = (yMax + Constants::yMaxMultiSampleOffset) >> subPixB;
172 }
173 else
174 {
175 yMin = (yMin + subPixM) >> subPixB;
176 yMax = (yMax + subPixM) >> subPixB;
177 }
178
179 yMin = Max(yMin, *Pointer<Int>(data + OFFSET(DrawData,scissorY0)));
180 yMax = Min(yMax, *Pointer<Int>(data + OFFSET(DrawData,scissorY1)));
181
182 // If yMin and yMax are initially negative, the scissor clamping above will typically result
183 // in yMin == 0 and yMax unchanged. We bail as we don't need to rasterize this primitive, and
184 // code below assumes yMin < yMax.
185 If(yMin >= yMax)
186 {
187 Return(0);
188 }
189
190 For(Int q = 0, q < state.multiSample, q++)
191 {
192 Array<Int> Xq(16);
193 Array<Int> Yq(16);
194
195 Int i = 0;
196
197 Do
198 {
199 Xq[i] = X[i];
200 Yq[i] = Y[i];
201
202 if(state.multiSample > 1)
203 {
204 Xq[i] = Xq[i] + *Pointer<Int>(constants + OFFSET(Constants,Xf) + q * sizeof(int));
205 Yq[i] = Yq[i] + *Pointer<Int>(constants + OFFSET(Constants,Yf) + q * sizeof(int));
206 }
207
208 i++;
209 }
210 Until(i >= n)
211
212 Pointer<Byte> leftEdge = Pointer<Byte>(primitive + OFFSET(Primitive,outline->left)) + q * sizeof(Primitive);
213 Pointer<Byte> rightEdge = Pointer<Byte>(primitive + OFFSET(Primitive,outline->right)) + q * sizeof(Primitive);
214
215 if(state.multiSample > 1)
216 {
217 Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
218 Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
219 Short x = Short(Clamp((X[0] + subPixM) >> subPixB, xMin, xMax));
220
221 For(Int y = yMin - 1, y < yMax + 1, y++)
222 {
223 *Pointer<Short>(leftEdge + y * sizeof(Primitive::Span)) = x;
224 *Pointer<Short>(rightEdge + y * sizeof(Primitive::Span)) = x;
225 }
226 }
227
228 Xq[n] = Xq[0];
229 Yq[n] = Yq[0];
230
231 // Rasterize
232 {
233 Int i = 0;
234
235 Do
236 {
237 edge(primitive, data, Xq[i + 1 - d], Yq[i + 1 - d], Xq[i + d], Yq[i + d], q);
238
239 i++;
240 }
241 Until(i >= n)
242 }
243
244 if(state.multiSample == 1)
245 {
246 For(, yMin < yMax && *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + yMin * sizeof(Primitive::Span)), yMin++)
247 {
248 // Increments yMin
249 }
250
251 For(, yMax > yMin && *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + (yMax - 1) * sizeof(Primitive::Span)), yMax--)
252 {
253 // Decrements yMax
254 }
255
256 If(yMin == yMax)
257 {
258 Return(0);
259 }
260
261 *Pointer<Short>(leftEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
262 *Pointer<Short>(rightEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
263 *Pointer<Short>(leftEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
264 *Pointer<Short>(rightEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
265 }
266 }
267
268 *Pointer<Int>(primitive + OFFSET(Primitive,yMin)) = yMin;
269 *Pointer<Int>(primitive + OFFSET(Primitive,yMax)) = yMax;
270
271 // Sort by minimum y
272 if(triangle)
273 {
274 Float y0 = *Pointer<Float>(v0 + OFFSET(Vertex, y));
275 Float y1 = *Pointer<Float>(v1 + OFFSET(Vertex, y));
276 Float y2 = *Pointer<Float>(v2 + OFFSET(Vertex, y));
277
278 Float yMin = Min(Min(y0, y1), y2);
279
280 conditionalRotate1(yMin == y1, v0, v1, v2);
281 conditionalRotate2(yMin == y2, v0, v1, v2);
282 }
283
284 // Sort by maximum w
285 if(triangle)
286 {
287 Float w0 = *Pointer<Float>(v0 + OFFSET(Vertex, w));
288 Float w1 = *Pointer<Float>(v1 + OFFSET(Vertex, w));
289 Float w2 = *Pointer<Float>(v2 + OFFSET(Vertex, w));
290
291 Float wMax = Max(Max(w0, w1), w2);
292
293 conditionalRotate1(wMax == w1, v0, v1, v2);
294 conditionalRotate2(wMax == w2, v0, v1, v2);
295 }
296
297 Float w0 = *Pointer<Float>(v0 + OFFSET(Vertex, w));
298 Float w1 = *Pointer<Float>(v1 + OFFSET(Vertex, w));
299 Float w2 = *Pointer<Float>(v2 + OFFSET(Vertex, w));
300
301 Float4 w012;
302
303 w012.x = w0;
304 w012.y = w1;
305 w012.z = w2;
306 w012.w = 1;
307
308 Float rhw0 = *Pointer<Float>(v0 + OFFSET(Vertex,projected.w));
309
310 Int X0 = *Pointer<Int>(v0 + OFFSET(Vertex,projected.x));
311 Int X1 = *Pointer<Int>(v1 + OFFSET(Vertex,projected.x));
312 Int X2 = *Pointer<Int>(v2 + OFFSET(Vertex,projected.x));
313
314 Int Y0 = *Pointer<Int>(v0 + OFFSET(Vertex,projected.y));
315 Int Y1 = *Pointer<Int>(v1 + OFFSET(Vertex,projected.y));
316 Int Y2 = *Pointer<Int>(v2 + OFFSET(Vertex,projected.y));
317
318 if(point)
319 {
320 *Pointer<Float>(primitive + OFFSET(Primitive, pointCoordX)) = Float(1.0f / subPixF) * Float(X0);
321 *Pointer<Float>(primitive + OFFSET(Primitive, pointCoordY)) = Float(1.0f / subPixF) * Float(Y0);
322 }
323
324 if(line)
325 {
326 X2 = X1 + Y1 - Y0;
327 Y2 = Y1 + X0 - X1;
328 }
329
330 Float dx = Float(X0) * (1.0f / subPixF);
331 Float dy = Float(Y0) * (1.0f / subPixF);
332
333 X1 -= X0;
334 Y1 -= Y0;
335
336 X2 -= X0;
337 Y2 -= Y0;
338
339 Float x1 = w1 * (1.0f / subPixF) * Float(X1);
340 Float y1 = w1 * (1.0f / subPixF) * Float(Y1);
341
342 Float x2 = w2 * (1.0f / subPixF) * Float(X2);
343 Float y2 = w2 * (1.0f / subPixF) * Float(Y2);
344
345 Float a = x1 * y2 - x2 * y1;
346
347 Float4 xQuad = Float4(0, 1, 0, 1) - Float4(dx);
348 Float4 yQuad = Float4(0, 0, 1, 1) - Float4(dy);
349
350 *Pointer<Float4>(primitive + OFFSET(Primitive,xQuad), 16) = xQuad;
351 *Pointer<Float4>(primitive + OFFSET(Primitive,yQuad), 16) = yQuad;
352
353 Float4 M[3];
354
355 M[0] = Float4(0, 0, 0, 0);
356 M[1] = Float4(0, 0, 0, 0);
357 M[2] = Float4(0, 0, 0, 0);
358
359 M[0].z = rhw0;
360
361 If(a != 0.0f)
362 {
363 Float A = 1.0f / a;
364 Float D = A * rhw0;
365
366 M[0].x = (y1 * w2 - y2 * w1) * D;
367 M[0].y = (x2 * w1 - x1 * w2) * D;
368 // M[0].z = rhw0;
369 // M[0].w = 0;
370
371 M[1].x = y2 * A;
372 M[1].y = -x2 * A;
373 // M[1].z = 0;
374 // M[1].w = 0;
375
376 M[2].x = -y1 * A;
377 M[2].y = x1 * A;
378 // M[2].z = 0;
379 // M[2].w = 0;
380 }
381
382 if(state.interpolateW)
383 {
384 Float4 ABC = M[0] + M[1] + M[2];
385
386 Float4 A = ABC.x;
387 Float4 B = ABC.y;
388 Float4 C = ABC.z;
389
390 *Pointer<Float4>(primitive + OFFSET(Primitive,w.A), 16) = A;
391 *Pointer<Float4>(primitive + OFFSET(Primitive,w.B), 16) = B;
392 *Pointer<Float4>(primitive + OFFSET(Primitive,w.C), 16) = C;
393 }
394
395 if(state.interpolateZ)
396 {
397 Float z0 = *Pointer<Float>(v0 + OFFSET(Vertex,projected.z));
398 Float z1 = *Pointer<Float>(v1 + OFFSET(Vertex,projected.z));
399 Float z2 = *Pointer<Float>(v2 + OFFSET(Vertex,projected.z));
400
401 z1 -= z0;
402 z2 -= z0;
403
404 Float4 A;
405 Float4 B;
406 Float4 C;
407
408 if(!point)
409 {
410 Float x1 = Float(X1) * (1.0f / subPixF);
411 Float y1 = Float(Y1) * (1.0f / subPixF);
412 Float x2 = Float(X2) * (1.0f / subPixF);
413 Float y2 = Float(Y2) * (1.0f / subPixF);
414
415 Float D = *Pointer<Float>(data + OFFSET(DrawData,depthRange)) / (x1 * y2 - x2 * y1);
416
417 Float a = (y2 * z1 - y1 * z2) * D;
418 Float b = (x1 * z2 - x2 * z1) * D;
419
420 A = Float4(a);
421 B = Float4(b);
422 }
423 else
424 {
425 A = Float4(0, 0, 0, 0);
426 B = Float4(0, 0, 0, 0);
427 }
428
429 *Pointer<Float4>(primitive + OFFSET(Primitive,z.A), 16) = A;
430 *Pointer<Float4>(primitive + OFFSET(Primitive,z.B), 16) = B;
431
432 Float c = z0;
433
434 if(state.applySlopeDepthBias)
435 {
436 Float bias = Max(Abs(Float(A.x)), Abs(Float(B.x)));
437 bias *= *Pointer<Float>(data + OFFSET(DrawData,slopeDepthBias));
438
439 c += bias;
440 }
441
442 C = Float4(c * *Pointer<Float>(data + OFFSET(DrawData,depthRange)) + *Pointer<Float>(data + OFFSET(DrawData,depthNear)));
443
444 *Pointer<Float4>(primitive + OFFSET(Primitive,z.C), 16) = C;
445 }
446
447 for (int interpolant = 0; interpolant < MAX_INTERFACE_COMPONENTS; interpolant++)
448 {
449 if (state.gradient[interpolant].Type != SpirvShader::ATTRIBTYPE_UNUSED)
450 {
451 setupGradient(primitive, tri, w012, M, v0, v1, v2,
452 OFFSET(Vertex, v[interpolant]),
453 OFFSET(Primitive, V[interpolant]),
454 state.gradient[interpolant].Flat,
455 !state.gradient[interpolant].NoPerspective, 0);
456 }
457 }
458
459 Return(1);
460 }
461
462 routine = function("SetupRoutine");
463 }
464
465 void SetupRoutine::setupGradient(Pointer<Byte> &primitive, Pointer<Byte> &triangle, Float4 &w012, Float4 (&m)[3], Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2, int attribute, int planeEquation, bool flat, bool perspective, int component)
466 {
467 if(!flat)
468 {
469 Float4 i;
470 i.x = *Pointer<Float>(v0 + attribute);
471 i.y = *Pointer<Float>(v1 + attribute);
472 i.z = *Pointer<Float>(v2 + attribute);
473 i.w = 0;
474
475 if(!perspective)
476 {
477 i *= w012;
478 }
479
480 Float4 A = i.xxxx * m[0];
481 Float4 B = i.yyyy * m[1];
482 Float4 C = i.zzzz * m[2];
483
484 C = A + B + C;
485
486 A = C.xxxx;
487 B = C.yyyy;
488 C = C.zzzz;
489
490 *Pointer<Float4>(primitive + planeEquation + 0, 16) = A;
491 *Pointer<Float4>(primitive + planeEquation + 16, 16) = B;
492 *Pointer<Float4>(primitive + planeEquation + 32, 16) = C;
493 }
494 else
495 {
496 int leadingVertex = OFFSET(Triangle,v0);
497 Float C = *Pointer<Float>(triangle + leadingVertex + attribute);
498
499 *Pointer<Float4>(primitive + planeEquation + 0, 16) = Float4(0, 0, 0, 0);
500 *Pointer<Float4>(primitive + planeEquation + 16, 16) = Float4(0, 0, 0, 0);
501 *Pointer<Float4>(primitive + planeEquation + 32, 16) = Float4(C);
502 }
503 }
504
505 void SetupRoutine::edge(Pointer<Byte> &primitive, Pointer<Byte> &data, const Int &Xa, const Int &Ya, const Int &Xb, const Int &Yb, Int &q)
506 {
507 If(Ya != Yb)
508 {
509 Bool swap = Yb < Ya;
510
511 Int X1 = IfThenElse(swap, Xb, Xa);
512 Int X2 = IfThenElse(swap, Xa, Xb);
513 Int Y1 = IfThenElse(swap, Yb, Ya);
514 Int Y2 = IfThenElse(swap, Ya, Yb);
515
516 constexpr int subPixB = vk::SUBPIXEL_PRECISION_BITS;
517 constexpr int subPixM = vk::SUBPIXEL_PRECISION_MASK;
518
519 Int y1 = Max((Y1 + subPixM) >> subPixB, *Pointer<Int>(data + OFFSET(DrawData,scissorY0)));
520 Int y2 = Min((Y2 + subPixM) >> subPixB, *Pointer<Int>(data + OFFSET(DrawData,scissorY1)));
521
522 If(y1 < y2)
523 {
524 Int xMin = *Pointer<Int>(data + OFFSET(DrawData,scissorX0));
525 Int xMax = *Pointer<Int>(data + OFFSET(DrawData,scissorX1));
526
527 Pointer<Byte> leftEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->left);
528 Pointer<Byte> rightEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->right);
529 Pointer<Byte> edge = IfThenElse(swap, rightEdge, leftEdge);
530
531 // Deltas
532 Int DX12 = X2 - X1;
533 Int DY12 = Y2 - Y1;
534
535 Int FDX12 = DX12 << subPixB;
536 Int FDY12 = DY12 << subPixB;
537
538 Int X = DX12 * ((y1 << subPixB) - Y1) + (X1 & subPixM) * DY12;
539 Int x = (X1 >> subPixB) + X / FDY12; // Edge
540 Int d = X % FDY12; // Error-term
541 Int ceil = -d >> 31; // Ceiling division: remainder <= 0
542 x -= ceil;
543 d -= ceil & FDY12;
544
545 Int Q = FDX12 / FDY12; // Edge-step
546 Int R = FDX12 % FDY12; // Error-step
547 Int floor = R >> 31; // Flooring division: remainder >= 0
548 Q += floor;
549 R += floor & FDY12;
550
551 Int D = FDY12; // Error-overflow
552 Int y = y1;
553
554 Do
555 {
556 *Pointer<Short>(edge + y * sizeof(Primitive::Span)) = Short(Clamp(x, xMin, xMax));
557
558 x += Q;
559 d += R;
560
561 Int overflow = -d >> 31;
562
563 d -= D & overflow;
564 x -= overflow;
565
566 y++;
567 }
568 Until(y >= y2)
569 }
570 }
571 }
572
573 void SetupRoutine::conditionalRotate1(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
574 {
575 #if 0 // Rely on LLVM optimization
576 If(condition)
577 {
578 Pointer<Byte> vX;
579
580 vX = v0;
581 v0 = v1;
582 v1 = v2;
583 v2 = vX;
584 }
585 #else
586 Pointer<Byte> vX = v0;
587 v0 = IfThenElse(condition, v1, v0);
588 v1 = IfThenElse(condition, v2, v1);
589 v2 = IfThenElse(condition, vX, v2);
590 #endif
591 }
592
593 void SetupRoutine::conditionalRotate2(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
594 {
595 #if 0 // Rely on LLVM optimization
596 If(condition)
597 {
598 Pointer<Byte> vX;
599
600 vX = v2;
601 v2 = v1;
602 v1 = v0;
603 v0 = vX;
604 }
605 #else
606 Pointer<Byte> vX = v2;
607 v2 = IfThenElse(condition, v1, v2);
608 v1 = IfThenElse(condition, v0, v1);
609 v0 = IfThenElse(condition, vX, v0);
610 #endif
611 }
612
613 SetupFunction::RoutineType SetupRoutine::getRoutine()
614 {
615 return routine;
616 }
617}
618