blob: e37efac67597f19487c4a08ff52308491a0c90b1 [file] [log] [blame]
John Bauman66b8ab22014-05-06 15:57:45 -04001// SwiftShader Software Renderer
2//
3// Copyright(c) 2005-2013 TransGaming Inc.
4//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "compiler/OutputASM.h"
13
14#include "common/debug.h"
15#include "compiler/InfoSink.h"
16
17#include "libGLESv2/Shader.h"
18
19#define GL_APICALL
20#include <GLES2/gl2.h>
21
22namespace sh
23{
24 static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4}; // (void), xxxx, xyyy, xyzz, xyzw
25
26 // Integer to TString conversion
27 TString str(int i)
28 {
29 char buffer[20];
30 sprintf(buffer, "%d", i);
31 return buffer;
32 }
33
34 class Temporary : public TIntermSymbol
35 {
36 public:
37 Temporary(OutputASM *assembler) : TIntermSymbol(0, "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, false, false)), assembler(assembler)
38 {
39 }
40
41 ~Temporary()
42 {
43 assembler->freeTemporary(this);
44 }
45
46 private:
47 OutputASM *const assembler;
48 };
49
50 class Constant : public TIntermConstantUnion
51 {
52 public:
53 Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConst, 4, false, false))
54 {
55 constants[0].setFConst(x);
56 constants[1].setFConst(y);
57 constants[2].setFConst(z);
58 constants[3].setFConst(w);
59 }
60
61 Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConst, 1, false, false))
62 {
63 constants[0].setBConst(b);
64 }
65
66 Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConst, 1, false, false))
67 {
68 constants[0].setIConst(i);
69 }
70
71 ~Constant()
72 {
73 }
74
75 private:
76 ConstantUnion constants[4];
77 };
78
John Baumand4ae8632014-05-06 16:18:33 -040079 Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex)
John Bauman66b8ab22014-05-06 15:57:45 -040080 {
81 this->type = type;
John Baumand4ae8632014-05-06 16:18:33 -040082 this->precision = precision;
John Bauman66b8ab22014-05-06 15:57:45 -040083 this->name = name;
84 this->arraySize = arraySize;
85 this->registerIndex = registerIndex;
86 }
87
88 Attribute::Attribute()
89 {
90 type = GL_NONE;
91 arraySize = 0;
92 registerIndex = 0;
93 }
94
95 Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int registerIndex)
96 {
97 this->type = type;
98 this->name = name;
99 this->arraySize = arraySize;
100 this->registerIndex = registerIndex;
101 }
102
103 OutputASM::OutputASM(TParseContext &context, gl::Shader *shaderObject) : TIntermTraverser(true, true, true), mContext(context), shaderObject(shaderObject)
104 {
105 shader = 0;
106 pixelShader = 0;
107 vertexShader = 0;
108
109 if(shaderObject)
110 {
111 shader = shaderObject->getShader();
112 pixelShader = shaderObject->getPixelShader();
113 vertexShader = shaderObject->getVertexShader();
114 }
115
116 functionArray.push_back(Function(0, "main(", 0, 0));
117 currentFunction = 0;
118 }
119
120 OutputASM::~OutputASM()
121 {
122 }
123
124 void OutputASM::output()
125 {
126 if(shader)
127 {
128 emitShader(GLOBAL);
129
130 if(functionArray.size() > 1) // Only call main() when there are other functions
131 {
132 Instruction *callMain = emit(sw::Shader::OPCODE_CALL);
133 callMain->dst.type = sw::Shader::PARAMETER_LABEL;
134 callMain->dst.index = 0; // main()
135
136 emit(sw::Shader::OPCODE_RET);
137 }
138
139 emitShader(FUNCTION);
140 }
141 }
142
143 void OutputASM::emitShader(Scope scope)
144 {
145 emitScope = scope;
146 currentScope = GLOBAL;
147 mContext.treeRoot->traverse(this);
148 }
149
150 void OutputASM::freeTemporary(Temporary *temporary)
151 {
152 free(temporaries, temporary);
153 }
154
155 void OutputASM::visitSymbol(TIntermSymbol *symbol)
156 {
157 if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut)
158 {
159 // Vertex varyings don't have to be actively used to successfully link
160 // against pixel shaders that use them. So make sure they're declared.
161 declareVarying(symbol, -1);
162 }
163 }
164
165 bool OutputASM::visitBinary(Visit visit, TIntermBinary *node)
166 {
167 if(currentScope != emitScope)
168 {
169 return false;
170 }
171
172 TIntermTyped *result = node;
173 TIntermTyped *left = node->getLeft();
174 TIntermTyped *right = node->getRight();
175 const TType &leftType = left->getType();
176 const TType &rightType = right->getType();
177 const TType &resultType = node->getType();
178
179 switch(node->getOp())
180 {
181 case EOpAssign:
182 if(visit == PostVisit)
183 {
184 assignLvalue(left, right);
185 copy(result, right);
186 }
187 break;
188 case EOpInitialize:
189 if(visit == PostVisit)
190 {
191 copy(left, right);
192 }
193 break;
194 case EOpMatrixTimesScalarAssign:
195 if(visit == PostVisit)
196 {
197 for(int i = 0; i < leftType.getNominalSize(); i++)
198 {
199 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
200 mul->dst.index += i;
201 argument(mul->src[0], left, i);
202 }
203
204 assignLvalue(left, result);
205 }
206 break;
207 case EOpVectorTimesMatrixAssign:
208 if(visit == PostVisit)
209 {
210 int size = leftType.getNominalSize();
211
212 for(int i = 0; i < size; i++)
213 {
214 Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right);
215 dot->dst.mask = 1 << i;
216 argument(dot->src[1], right, i);
217 }
218
219 assignLvalue(left, result);
220 }
221 break;
222 case EOpMatrixTimesMatrixAssign:
223 if(visit == PostVisit)
224 {
225 int dim = leftType.getNominalSize();
226
227 for(int i = 0; i < dim; i++)
228 {
229 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
230 mul->dst.index += i;
231 argument(mul->src[1], right, i);
232 mul->src[1].swizzle = 0x00;
233
234 for(int j = 1; j < dim; j++)
235 {
236 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);
237 mad->dst.index += i;
238 argument(mad->src[0], left, j);
239 argument(mad->src[1], right, i);
240 mad->src[1].swizzle = j * 0x55;
241 argument(mad->src[2], result, i);
242 }
243 }
244
245 assignLvalue(left, result);
246 }
247 break;
248 case EOpIndexDirect:
249 if(visit == PostVisit)
250 {
251 int index = right->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
252
253 if(result->isMatrix() || result->isStruct())
254 {
255 ASSERT(left->isArray());
256 copy(result, left, index * left->elementRegisterCount());
257 }
258 else if(result->isRegister())
259 {
260 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);
261
262 if(left->isRegister())
263 {
264 mov->src[0].swizzle = index;
265 }
266 else if(left->isArray())
267 {
268 argument(mov->src[0], left, index * left->elementRegisterCount());
269 }
270 else if(left->isMatrix())
271 {
272 ASSERT(index < left->getNominalSize()); // FIXME: Report semantic error
273 argument(mov->src[0], left, index);
274 }
275 else UNREACHABLE();
276 }
277 else UNREACHABLE();
278 }
279 break;
280 case EOpIndexIndirect:
281 if(visit == PostVisit)
282 {
283 if(left->isArray() || left->isMatrix())
284 {
285 for(int index = 0; index < result->totalRegisterCount(); index++)
286 {
287 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);
288
289 mov->dst.index += index;
290 argument(mov->src[0], left, index);
291
292 if(left->totalRegisterCount() > 1)
293 {
294 sw::Shader::SourceParameter relativeRegister;
295 argument(relativeRegister, right);
296
297 mov->src[0].rel.type = relativeRegister.type;
298 mov->src[0].rel.index = relativeRegister.index;
299 mov->src[0].rel.scale = result->totalRegisterCount();
300 mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
301 }
302 }
303 }
304 else if(left->isRegister())
305 {
306 emit(sw::Shader::OPCODE_EXTRACT, result, left, right);
307 }
308 else UNREACHABLE();
309 }
310 break;
311 case EOpIndexDirectStruct:
312 if(visit == PostVisit)
313 {
314 ASSERT(leftType.isStruct());
315
316 const TTypeList *structure = leftType.getStruct();
317 const TString &fieldName = rightType.getFieldName();
318 int fieldOffset = 0;
319
320 for(size_t i = 0; i < structure->size(); i++)
321 {
322 const TType &fieldType = *(*structure)[i].type;
323
324 if(fieldType.getFieldName() == fieldName)
325 {
326 break;
327 }
328
329 fieldOffset += fieldType.totalRegisterCount();
330 }
331
332 copy(result, left, fieldOffset);
333 }
334 break;
335 case EOpVectorSwizzle:
336 if(visit == PostVisit)
337 {
338 int swizzle = 0;
339 TIntermAggregate *components = right->getAsAggregate();
340
341 if(components)
342 {
343 TIntermSequence &sequence = components->getSequence();
344 int component = 0;
345
346 for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
347 {
348 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
349
350 if(element)
351 {
352 int i = element->getUnionArrayPointer()[0].getIConst();
353 swizzle |= i << (component * 2);
354 component++;
355 }
356 else UNREACHABLE();
357 }
358 }
359 else UNREACHABLE();
360
361 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);
362 mov->src[0].swizzle = swizzle;
363 }
364 break;
John Baumand4ae8632014-05-06 16:18:33 -0400365 case EOpAddAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_ADD, result, left, left, right); break;
366 case EOpAdd: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_ADD, result, left, right); break;
367 case EOpSubAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SUB, result, left, left, right); break;
368 case EOpSub: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_SUB, result, left, right); break;
369 case EOpMulAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break;
370 case EOpMul: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_MUL, result, left, right); break;
371 case EOpDivAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_DIV, result, left, left, right); break;
372 case EOpDiv: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_DIV, result, left, right); break;
John Bauman66b8ab22014-05-06 15:57:45 -0400373 case EOpEqual:
374 if(visit == PostVisit)
375 {
376 emitCmp(sw::Shader::CONTROL_EQ, result, left, right);
377
378 for(int index = 1; index < left->totalRegisterCount(); index++)
379 {
380 Temporary equal(this);
381 emitCmp(sw::Shader::CONTROL_EQ, &equal, left, right, index);
382 emit(sw::Shader::OPCODE_AND, result, result, &equal);
383 }
384 }
385 break;
386 case EOpNotEqual:
387 if(visit == PostVisit)
388 {
389 emitCmp(sw::Shader::CONTROL_NE, result, left, right);
390
391 for(int index = 1; index < left->totalRegisterCount(); index++)
392 {
393 Temporary notEqual(this);
394 emitCmp(sw::Shader::CONTROL_NE, &notEqual, left, right, index);
395 emit(sw::Shader::OPCODE_OR, result, result, &notEqual);
396 }
397 }
398 break;
399 case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break;
400 case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break;
401 case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break;
402 case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break;
403 case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break;
404 case EOpVectorTimesScalar: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, left, right); break;
405 case EOpMatrixTimesScalar:
406 if(visit == PostVisit)
407 {
408 for(int i = 0; i < leftType.getNominalSize(); i++)
409 {
410 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
411 mul->dst.index += i;
412 argument(mul->src[0], left, i);
413 }
414 }
415 break;
416 case EOpVectorTimesMatrix:
417 if(visit == PostVisit)
418 {
419 int size = leftType.getNominalSize();
420
421 for(int i = 0; i < size; i++)
422 {
423 Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right);
424 dot->dst.mask = 1 << i;
425 argument(dot->src[1], right, i);
426 }
427 }
428 break;
429 case EOpMatrixTimesVector:
430 if(visit == PostVisit)
431 {
432 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
433 mul->src[1].swizzle = 0x00;
434
435 for(int i = 1; i < leftType.getNominalSize(); i++)
436 {
437 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);
438 argument(mad->src[0], left, i);
439 mad->src[1].swizzle = i * 0x55;
440 }
441 }
442 break;
443 case EOpMatrixTimesMatrix:
444 if(visit == PostVisit)
445 {
446 int dim = leftType.getNominalSize();
447
448 for(int i = 0; i < dim; i++)
449 {
450 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
451 mul->dst.index += i;
452 argument(mul->src[1], right, i);
453 mul->src[1].swizzle = 0x00;
454
455 for(int j = 1; j < dim; j++)
456 {
457 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);
458 mad->dst.index += i;
459 argument(mad->src[0], left, j);
460 argument(mad->src[1], right, i);
461 mad->src[1].swizzle = j * 0x55;
462 argument(mad->src[2], result, i);
463 }
464 }
465 }
466 break;
467 case EOpLogicalOr:
468 if(trivial(right, 6))
469 {
470 if(visit == PostVisit)
471 {
472 emit(sw::Shader::OPCODE_OR, result, left, right);
473 }
474 }
475 else // Short-circuit evaluation
476 {
477 if(visit == InVisit)
478 {
479 emit(sw::Shader::OPCODE_MOV, result, left);
480 Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result);
481 ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT;
482 }
483 else if(visit == PostVisit)
484 {
485 emit(sw::Shader::OPCODE_MOV, result, right);
486 emit(sw::Shader::OPCODE_ENDIF);
487 }
488 }
489 break;
490 case EOpLogicalXor: if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break;
491 case EOpLogicalAnd:
492 if(trivial(right, 6))
493 {
494 if(visit == PostVisit)
495 {
496 emit(sw::Shader::OPCODE_AND, result, left, right);
497 }
498 }
499 else // Short-circuit evaluation
500 {
501 if(visit == InVisit)
502 {
503 emit(sw::Shader::OPCODE_MOV, result, left);
504 emit(sw::Shader::OPCODE_IF, 0, result);
505 }
506 else if(visit == PostVisit)
507 {
508 emit(sw::Shader::OPCODE_MOV, result, right);
509 emit(sw::Shader::OPCODE_ENDIF);
510 }
511 }
512 break;
513 default: UNREACHABLE();
514 }
515
516 return true;
517 }
518
519 bool OutputASM::visitUnary(Visit visit, TIntermUnary *node)
520 {
521 if(currentScope != emitScope)
522 {
523 return false;
524 }
525
526 Constant one(1.0f, 1.0f, 1.0f, 1.0f);
527 Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f);
528 Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f);
529
530 TIntermTyped *result = node;
531 TIntermTyped *arg = node->getOperand();
532
533 switch(node->getOp())
534 {
535 case EOpNegative:
536 if(visit == PostVisit)
537 {
538 for(int index = 0; index < arg->totalRegisterCount(); index++)
539 {
540 Instruction *neg = emit(sw::Shader::OPCODE_MOV, result, arg);
541 neg->dst.index += index;
542 argument(neg->src[0], arg, index);
543 neg->src[0].modifier = sw::Shader::MODIFIER_NEGATE;
544 }
545 }
546 break;
547 case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
548 case EOpLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
549 case EOpPostIncrement:
550 if(visit == PostVisit)
551 {
552 copy(result, arg);
553
554 for(int index = 0; index < arg->totalRegisterCount(); index++)
555 {
556 Instruction *add = emit(sw::Shader::OPCODE_ADD, arg, arg, &one);
557 add->dst.index += index;
558 argument(add->src[0], arg, index);
559 }
560
561 assignLvalue(arg, arg);
562 }
563 break;
564 case EOpPostDecrement:
565 if(visit == PostVisit)
566 {
567 copy(result, arg);
568
569 for(int index = 0; index < arg->totalRegisterCount(); index++)
570 {
571 Instruction *sub = emit(sw::Shader::OPCODE_SUB, arg, arg, &one);
572 sub->dst.index += index;
573 argument(sub->src[0], arg, index);
574 }
575
576 assignLvalue(arg, arg);
577 }
578 break;
579 case EOpPreIncrement:
580 if(visit == PostVisit)
581 {
582 for(int index = 0; index < arg->totalRegisterCount(); index++)
583 {
584 Instruction *add = emit(sw::Shader::OPCODE_ADD, result, arg, &one);
585 add->dst.index += index;
586 argument(add->src[0], arg, index);
587 }
588
589 assignLvalue(arg, result);
590 }
591 break;
592 case EOpPreDecrement:
593 if(visit == PostVisit)
594 {
595 for(int index = 0; index < arg->totalRegisterCount(); index++)
596 {
597 Instruction *sub = emit(sw::Shader::OPCODE_SUB, result, arg, &one);
598 sub->dst.index += index;
599 argument(sub->src[0], arg, index);
600 }
601
602 assignLvalue(arg, result);
603 }
604 break;
605 case EOpConvIntToBool: if(visit == PostVisit) emit(sw::Shader::OPCODE_F2B, result, arg); break; // Integers are implemented as float
606 case EOpConvFloatToBool: if(visit == PostVisit) emit(sw::Shader::OPCODE_F2B, result, arg); break;
607 case EOpConvBoolToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_B2F, result, arg); break;
608 case EOpConvIntToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_MOV, result, arg); break; // Integers are implemented as float
609 case EOpConvFloatToInt: if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break; // Integers are implemented as float
610 case EOpConvBoolToInt: if(visit == PostVisit) emit(sw::Shader::OPCODE_B2F, result, arg); break; // Integers are implemented as float
611 case EOpRadians: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break;
612 case EOpDegrees: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &deg); break;
613 case EOpSin: if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break;
614 case EOpCos: if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break;
615 case EOpTan: if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break;
616 case EOpAsin: if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break;
617 case EOpAcos: if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break;
618 case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break;
619 case EOpExp: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break;
620 case EOpLog: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break;
621 case EOpExp2: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break;
622 case EOpLog2: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break;
623 case EOpSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break;
624 case EOpInverseSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break;
625 case EOpAbs: if(visit == PostVisit) emit(sw::Shader::OPCODE_ABS, result, arg); break;
626 case EOpSign: if(visit == PostVisit) emit(sw::Shader::OPCODE_SGN, result, arg); break;
627 case EOpFloor: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break;
628 case EOpCeil: if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break;
629 case EOpFract: if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break;
630 case EOpLength: if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break;
631 case EOpNormalize: if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break;
632 case EOpDFdx: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break;
633 case EOpDFdy: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break;
634 case EOpFwidth: if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break;
635 case EOpAny: if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break;
636 case EOpAll: if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break;
637 default: UNREACHABLE();
638 }
639
640 return true;
641 }
642
643 bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node)
644 {
645 if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence)
646 {
647 return false;
648 }
649
650 TIntermTyped *result = node;
651 const TType &resultType = node->getType();
652 TIntermSequence &arg = node->getSequence();
653 int argumentCount = arg.size();
654
655 switch(node->getOp())
656 {
657 case EOpSequence: break;
658 case EOpDeclaration: break;
659 case EOpPrototype: break;
660 case EOpComma:
661 if(visit == PostVisit)
662 {
663 copy(result, arg[1]);
664 }
665 break;
666 case EOpFunction:
667 if(visit == PreVisit)
668 {
669 const TString &name = node->getName();
670
671 if(emitScope == FUNCTION)
672 {
673 if(functionArray.size() > 1) // No need for a label when there's only main()
674 {
675 Instruction *label = emit(sw::Shader::OPCODE_LABEL);
676 label->dst.type = sw::Shader::PARAMETER_LABEL;
677
678 const Function &function = findFunction(name);
679 label->dst.index = function.label;
680 currentFunction = function.label;
681 }
682 }
683 else if(emitScope == GLOBAL)
684 {
685 if(name != "main(")
686 {
687 TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence();
688 functionArray.push_back(Function(functionArray.size(), name, &arguments, node));
689 }
690 }
691 else UNREACHABLE();
692
693 currentScope = FUNCTION;
694 }
695 else if(visit == PostVisit)
696 {
697 if(emitScope == FUNCTION)
698 {
699 if(functionArray.size() > 1) // No need to return when there's only main()
700 {
701 emit(sw::Shader::OPCODE_RET);
702 }
703 }
704
705 currentScope = GLOBAL;
706 }
707 break;
708 case EOpFunctionCall:
709 if(visit == PostVisit)
710 {
711 if(node->isUserDefined())
712 {
713 const TString &name = node->getName();
714 const Function &function = findFunction(name);
715 TIntermSequence &arguments = *function.arg;
716
717 for(int i = 0; i < argumentCount; i++)
718 {
719 TIntermTyped *in = arguments[i]->getAsTyped();
720
721 if(in->getQualifier() == EvqIn ||
722 in->getQualifier() == EvqInOut ||
723 in->getQualifier() == EvqConstReadOnly)
724 {
725 copy(in, arg[i]);
726 }
727 }
728
729 Instruction *call = emit(sw::Shader::OPCODE_CALL);
730 call->dst.type = sw::Shader::PARAMETER_LABEL;
731 call->dst.index = function.label;
732
733 if(function.ret && function.ret->getType().getBasicType() != EbtVoid)
734 {
735 copy(result, function.ret);
736 }
737
738 for(int i = 0; i < argumentCount; i++)
739 {
740 TIntermTyped *argument = arguments[i]->getAsTyped();
741 TIntermTyped *out = arg[i]->getAsTyped();
742
743 if(argument->getQualifier() == EvqOut ||
744 argument->getQualifier() == EvqInOut)
745 {
746 copy(out, argument);
747 }
748 }
749 }
750 else
751 {
752 TString name = TFunction::unmangleName(node->getName());
753
754 if(name == "texture2D" || name == "textureCube")
755 {
756 if(argumentCount == 2)
757 {
758 emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]);
759 }
760 else if(argumentCount == 3) // bias
761 {
762 Temporary uvwb(this);
763 emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]);
764 Instruction *bias = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]);
765 bias->dst.mask = 0x8;
766
767 Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &uvwb, arg[0]); // FIXME: Implement an efficient TEXLDB instruction
768 tex->bias = true;
769 }
770 else UNREACHABLE();
771 }
772 else if(name == "texture2DProj")
773 {
774 TIntermTyped *t = arg[1]->getAsTyped();
775
776 if(argumentCount == 2)
777 {
778 Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]);
779 tex->project = true;
780
781 if(t->getNominalSize() == 3)
782 {
783 tex->src[0].swizzle = 0xA4;
784 }
785 else ASSERT(t->getNominalSize() == 4);
786 }
787 else if(argumentCount == 3) // bias
788 {
789 Temporary proj(this);
790 emit(sw::Shader::OPCODE_MOV, &proj, arg[1]);
791
792 if(t->getNominalSize() == 3)
793 {
794 Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj);
795 div->src[0].swizzle = 0xAA;
796 div->dst.mask = 0x3;
797 }
798 else if(t->getNominalSize() == 4)
799 {
800 Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj);
801 div->src[0].swizzle = 0xFF;
802 div->dst.mask = 0x3;
803 }
804 else UNREACHABLE();
805
806 Instruction *bias = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]);
807 bias->dst.mask = 0x8;
808
809 Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &proj, arg[0]);
810 tex->bias = true;
811 }
812 else UNREACHABLE();
813 }
814 else if(name == "texture2DLod" || name == "textureCubeLod")
815 {
816 Temporary uvwb(this);
817 emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]);
818 Instruction *lod = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]);
819 lod->dst.mask = 0x8;
820
821 emit(sw::Shader::OPCODE_TEXLDL, result, &uvwb, arg[0]);
822 }
823 else if(name == "texture2DProjLod")
824 {
825 TIntermTyped *t = arg[1]->getAsTyped();
826
827 Temporary proj(this);
828 emit(sw::Shader::OPCODE_MOV, &proj, arg[1]);
829
830 if(t->getNominalSize() == 3)
831 {
832 Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj);
833 div->src[0].swizzle = 0xAA;
834 div->dst.mask = 0x3;
835 }
836 else if(t->getNominalSize() == 4)
837 {
838 Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj);
839 div->src[0].swizzle = 0xFF;
840 div->dst.mask = 0x3;
841 }
842 else UNREACHABLE();
843
844 Instruction *lod = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]);
845 lod->dst.mask = 0x8;
846
847 emit(sw::Shader::OPCODE_TEXLDL, result, &proj, arg[0]);
848 }
849 else UNREACHABLE();
850 }
851 }
852 break;
853 case EOpParameters: break;
854 case EOpConstructFloat:
855 case EOpConstructVec2:
856 case EOpConstructVec3:
857 case EOpConstructVec4:
858 case EOpConstructBool:
859 case EOpConstructBVec2:
860 case EOpConstructBVec3:
861 case EOpConstructBVec4:
862 case EOpConstructInt:
863 case EOpConstructIVec2:
864 case EOpConstructIVec3:
865 case EOpConstructIVec4:
866 if(visit == PostVisit)
867 {
868 int component = 0;
869
870 for(int i = 0; i < argumentCount; i++)
871 {
872 TIntermTyped *argi = arg[i]->getAsTyped();
873 int size = argi->getNominalSize();
874 ASSERT(!argi->isMatrix());
875
876 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi);
877 mov->dst.mask = (0xF << component) & 0xF;
878 mov->src[0].swizzle = swizzleSize[size] << (component * 2);
879
880 component += size;
881 }
882 }
883 break;
884 case EOpConstructMat2:
885 case EOpConstructMat3:
886 case EOpConstructMat4:
887 if(visit == PostVisit)
888 {
889 TIntermTyped *arg0 = arg[0]->getAsTyped();
890 const int dim = result->getNominalSize();
891
892 if(arg0->isMatrix())
893 {
894 for(int i = 0; i < dim; i++)
895 {
896 if(dim > dim2(arg0))
897 {
898 // Initialize to identity matrix
899 Constant col((i == 0 ? 1.0f : 0.0f), (i == 1 ? 1.0f : 0.0f), (i == 2 ? 1.0f : 0.0f), (i == 3 ? 1.0f : 0.0f));
900 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, &col);
901 mov->dst.index += i;
902 }
903
904 if(i < dim2(arg0))
905 {
906 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, arg0);
907 mov->dst.index += i;
908 mov->dst.mask = 0xF >> (4 - dim2(arg0));
909 argument(mov->src[0], arg0, i);
910 }
911 }
912 }
913 else
914 {
915 int column = 0;
916 int row = 0;
917
918 for(int i = 0; i < argumentCount; i++)
919 {
920 TIntermTyped *argi = arg[i]->getAsTyped();
921 int size = argi->getNominalSize();
922 int element = 0;
923
924 while(element < size)
925 {
926 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi);
927 mov->dst.index += column;
928 mov->dst.mask = (0xF << row) & 0xF;
929 mov->src[0].swizzle = (swizzleSize[size] << (row * 2)) + 0x55 * element;
930
931 int end = row + size - element;
932 column = end >= dim ? column + 1 : column;
933 element = element + dim - row;
934 row = end >= dim ? 0 : end;
935 }
936 }
937 }
938 }
939 break;
940 case EOpConstructStruct:
941 if(visit == PostVisit)
942 {
943 int offset = 0;
944 for(int i = 0; i < argumentCount; i++)
945 {
946 TIntermTyped *argi = arg[i]->getAsTyped();
947 int size = argi->totalRegisterCount();
948
949 for(int index = 0; index < size; index++)
950 {
951 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi);
952 mov->dst.index += index + offset;
953 mov->dst.mask = writeMask(result, offset + index);
954 argument(mov->src[0], argi, index);
955 }
956
957 offset += size;
958 }
959 }
960 break;
961 case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break;
962 case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break;
963 case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break;
964 case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break;
965 case EOpVectorEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break;
966 case EOpVectorNotEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break;
967 case EOpMod: if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break;
968 case EOpPow: if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break;
969 case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break;
970 case EOpMin: if(visit == PostVisit) emit(sw::Shader::OPCODE_MIN, result, arg[0], arg[1]); break;
971 case EOpMax: if(visit == PostVisit) emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]); break;
972 case EOpClamp:
973 if(visit == PostVisit)
974 {
975 emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]);
976 emit(sw::Shader::OPCODE_MIN, result, result, arg[2]);
977 }
978 break;
979 case EOpMix: if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;
980 case EOpStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;
981 case EOpSmoothStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;
982 case EOpDistance: if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;
983 case EOpDot: if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break;
984 case EOpCross: if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break;
985 case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
986 case EOpReflect: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break;
987 case EOpRefract: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
988 case EOpMul:
989 if(visit == PostVisit)
990 {
991 ASSERT(dim2(arg[0]) == dim2(arg[1]));
992
993 for(int i = 0; i < dim2(arg[0]); i++)
994 {
995 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, arg[0], arg[1]);
996 mul->dst.index += i;
997 argument(mul->src[0], arg[0], i);
998 argument(mul->src[1], arg[1], i);
999 }
1000 }
1001 break;
1002 default: UNREACHABLE();
1003 }
1004
1005 return true;
1006 }
1007
1008 bool OutputASM::visitSelection(Visit visit, TIntermSelection *node)
1009 {
1010 if(currentScope != emitScope)
1011 {
1012 return false;
1013 }
1014
1015 TIntermTyped *condition = node->getCondition();
1016 TIntermNode *trueBlock = node->getTrueBlock();
1017 TIntermNode *falseBlock = node->getFalseBlock();
1018 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
1019
1020 condition->traverse(this);
1021
1022 if(node->usesTernaryOperator())
1023 {
1024 if(constantCondition)
1025 {
1026 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
1027
1028 if(trueCondition)
1029 {
1030 trueBlock->traverse(this);
1031 copy(node, trueBlock);
1032 }
1033 else
1034 {
1035 falseBlock->traverse(this);
1036 copy(node, falseBlock);
1037 }
1038 }
1039 else if(trivial(node, 6)) // Fast to compute both potential results and no side effects
1040 {
1041 trueBlock->traverse(this);
1042 falseBlock->traverse(this);
1043 emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock);
1044 }
1045 else
1046 {
1047 emit(sw::Shader::OPCODE_IF, 0, condition);
1048
1049 if(trueBlock)
1050 {
1051 trueBlock->traverse(this);
1052 copy(node, trueBlock);
1053 }
1054
1055 if(falseBlock)
1056 {
1057 emit(sw::Shader::OPCODE_ELSE);
1058 falseBlock->traverse(this);
1059 copy(node, falseBlock);
1060 }
1061
1062 emit(sw::Shader::OPCODE_ENDIF);
1063 }
1064 }
1065 else // if/else statement
1066 {
1067 if(constantCondition)
1068 {
1069 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
1070
1071 if(trueCondition)
1072 {
1073 if(trueBlock)
1074 {
1075 trueBlock->traverse(this);
1076 }
1077 }
1078 else
1079 {
1080 if(falseBlock)
1081 {
1082 falseBlock->traverse(this);
1083 }
1084 }
1085 }
1086 else
1087 {
1088 emit(sw::Shader::OPCODE_IF, 0, condition);
1089
1090 if(trueBlock)
1091 {
1092 trueBlock->traverse(this);
1093 }
1094
1095 if(falseBlock)
1096 {
1097 emit(sw::Shader::OPCODE_ELSE);
1098 falseBlock->traverse(this);
1099 }
1100
1101 emit(sw::Shader::OPCODE_ENDIF);
1102 }
1103 }
1104
1105 return false;
1106 }
1107
1108 bool OutputASM::visitLoop(Visit visit, TIntermLoop *node)
1109 {
1110 if(currentScope != emitScope)
1111 {
1112 return false;
1113 }
1114
John Baumand4ae8632014-05-06 16:18:33 -04001115 unsigned int iterations = loopCount(node);
1116
1117 if(iterations == 0)
1118 {
1119 return false;
1120 }
1121
1122 bool unroll = (iterations <= 4);
1123
1124 if(unroll)
1125 {
1126 DetectLoopDiscontinuity detectLoopDiscontinuity;
1127 unroll = !detectLoopDiscontinuity.traverse(node);
1128 }
1129
John Bauman66b8ab22014-05-06 15:57:45 -04001130 TIntermNode *init = node->getInit();
1131 TIntermTyped *condition = node->getCondition();
1132 TIntermTyped *expression = node->getExpression();
1133 TIntermNode *body = node->getBody();
1134
1135 if(node->getType() == ELoopDoWhile)
1136 {
1137 Temporary iterate(this);
1138 Constant True(true);
1139 emit(sw::Shader::OPCODE_MOV, &iterate, &True);
1140
1141 emit(sw::Shader::OPCODE_WHILE, 0, &iterate); // FIXME: Implement real do-while
1142
1143 if(body)
1144 {
1145 body->traverse(this);
1146 }
1147
1148 emit(sw::Shader::OPCODE_TEST);
1149
1150 condition->traverse(this);
1151 emit(sw::Shader::OPCODE_MOV, &iterate, condition);
1152
1153 emit(sw::Shader::OPCODE_ENDWHILE);
1154 }
1155 else
1156 {
1157 if(init)
1158 {
1159 init->traverse(this);
1160 }
1161
John Baumand4ae8632014-05-06 16:18:33 -04001162 if(unroll)
John Bauman66b8ab22014-05-06 15:57:45 -04001163 {
John Baumand4ae8632014-05-06 16:18:33 -04001164 for(unsigned int i = 0; i < iterations; i++)
1165 {
1166 // condition->traverse(this); // Condition could contain statements, but not in an unrollable loop
1167
1168 if(body)
1169 {
1170 body->traverse(this);
1171 }
1172
1173 if(expression)
1174 {
1175 expression->traverse(this);
1176 }
1177 }
John Bauman66b8ab22014-05-06 15:57:45 -04001178 }
John Baumand4ae8632014-05-06 16:18:33 -04001179 else
John Bauman66b8ab22014-05-06 15:57:45 -04001180 {
John Baumand4ae8632014-05-06 16:18:33 -04001181 condition->traverse(this);
1182
1183 emit(sw::Shader::OPCODE_WHILE, 0, condition);
1184
1185 if(body)
1186 {
1187 body->traverse(this);
1188 }
1189
1190 emit(sw::Shader::OPCODE_TEST);
1191
1192 if(expression)
1193 {
1194 expression->traverse(this);
1195 }
1196
1197 condition->traverse(this);
1198
1199 emit(sw::Shader::OPCODE_ENDWHILE);
John Bauman66b8ab22014-05-06 15:57:45 -04001200 }
John Bauman66b8ab22014-05-06 15:57:45 -04001201 }
1202
1203 return false;
1204 }
1205
1206 bool OutputASM::visitBranch(Visit visit, TIntermBranch *node)
1207 {
1208 if(currentScope != emitScope)
1209 {
1210 return false;
1211 }
1212
1213 switch(node->getFlowOp())
1214 {
1215 case EOpKill: if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD); break;
1216 case EOpBreak: if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK); break;
1217 case EOpContinue: if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break;
1218 case EOpReturn:
1219 if(visit == PostVisit)
1220 {
1221 TIntermTyped *value = node->getExpression();
1222
1223 if(value)
1224 {
1225 copy(functionArray[currentFunction].ret, value);
1226 }
1227
1228 emit(sw::Shader::OPCODE_LEAVE);
1229 }
1230 break;
1231 default: UNREACHABLE();
1232 }
1233
1234 return true;
1235 }
1236
John Baumand4ae8632014-05-06 16:18:33 -04001237 Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, int index)
John Bauman66b8ab22014-05-06 15:57:45 -04001238 {
1239 if(dst && registerType(dst) == sw::Shader::PARAMETER_SAMPLER)
1240 {
John Baumand4ae8632014-05-06 16:18:33 -04001241 op = sw::Shader::OPCODE_NULL; // Can't assign to a sampler, but this is hit when indexing sampler arrays
John Bauman66b8ab22014-05-06 15:57:45 -04001242 }
1243
1244 Instruction *instruction = new Instruction(op);
1245
1246 if(dst)
1247 {
1248 instruction->dst.type = registerType(dst);
John Baumand4ae8632014-05-06 16:18:33 -04001249 instruction->dst.index = registerIndex(dst) + index;
John Bauman66b8ab22014-05-06 15:57:45 -04001250 instruction->dst.mask = writeMask(dst);
1251 instruction->dst.integer = (dst->getBasicType() == EbtInt);
1252 }
1253
John Baumand4ae8632014-05-06 16:18:33 -04001254 argument(instruction->src[0], src0, index);
1255 argument(instruction->src[1], src1, index);
1256 argument(instruction->src[2], src2, index);
John Bauman66b8ab22014-05-06 15:57:45 -04001257
1258 shader->append(instruction);
1259
1260 return instruction;
1261 }
1262
John Baumand4ae8632014-05-06 16:18:33 -04001263 void OutputASM::emitBinary(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2)
1264 {
1265 for(int index = 0; index < dst->elementRegisterCount(); index++)
1266 {
1267 emit(op, dst, src0, src1, src2, index);
1268 }
1269 }
1270
John Bauman66b8ab22014-05-06 15:57:45 -04001271 void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1)
1272 {
John Baumand4ae8632014-05-06 16:18:33 -04001273 emitBinary(op, result, src0, src1);
John Bauman66b8ab22014-05-06 15:57:45 -04001274 assignLvalue(lhs, result);
1275 }
1276
1277 void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index)
1278 {
1279 bool boolean = (left->getAsTyped()->getBasicType() == EbtBool);
1280 sw::Shader::Opcode opcode = boolean ? sw::Shader::OPCODE_ICMP : sw::Shader::OPCODE_CMP;
1281
1282 Instruction *cmp = emit(opcode, dst, left, right);
1283 cmp->control = cmpOp;
1284 argument(cmp->src[0], left, index);
1285 argument(cmp->src[1], right, index);
1286 }
1287
1288 int componentCount(const TType &type, int registers)
1289 {
1290 if(registers == 0)
1291 {
1292 return 0;
1293 }
1294
1295 if(type.isArray() && registers >= type.elementRegisterCount())
1296 {
1297 int index = registers / type.elementRegisterCount();
1298 registers -= index * type.elementRegisterCount();
1299 return index * type.getElementSize() + componentCount(type, registers);
1300 }
1301
1302 if(type.isStruct())
1303 {
1304 TTypeList *structure = type.getStruct();
1305 int elements = 0;
1306
1307 for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)
1308 {
1309 const TType &fieldType = *field->type;
1310
1311 if(fieldType.totalRegisterCount() <= registers)
1312 {
1313 registers -= fieldType.totalRegisterCount();
1314 elements += fieldType.getObjectSize();
1315 }
1316 else // Register within this field
1317 {
1318 return elements + componentCount(fieldType, registers);
1319 }
1320 }
1321 }
1322 else if(type.isMatrix())
1323 {
1324 return registers * type.getNominalSize();
1325 }
1326
1327 UNREACHABLE();
1328 return 0;
1329 }
1330
1331 int registerSize(const TType &type, int registers)
1332 {
1333 if(registers == 0)
1334 {
1335 if(type.isStruct())
1336 {
1337 return registerSize(*type.getStruct()->begin()->type, 0);
1338 }
1339
1340 return type.getNominalSize();
1341 }
1342
1343 if(type.isArray() && registers >= type.elementRegisterCount())
1344 {
1345 int index = registers / type.elementRegisterCount();
1346 registers -= index * type.elementRegisterCount();
1347 return registerSize(type, registers);
1348 }
1349
1350 if(type.isStruct())
1351 {
1352 TTypeList *structure = type.getStruct();
1353 int elements = 0;
1354
1355 for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)
1356 {
1357 const TType &fieldType = *field->type;
1358
1359 if(fieldType.totalRegisterCount() <= registers)
1360 {
1361 registers -= fieldType.totalRegisterCount();
1362 elements += fieldType.getObjectSize();
1363 }
1364 else // Register within this field
1365 {
1366 return registerSize(fieldType, registers);
1367 }
1368 }
1369 }
1370 else if(type.isMatrix())
1371 {
1372 return registerSize(type, 0);
1373 }
1374
1375 UNREACHABLE();
1376 return 0;
1377 }
1378
1379 void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
1380 {
1381 if(argument)
1382 {
1383 TIntermTyped *arg = argument->getAsTyped();
1384 const TType &type = arg->getType();
1385 const TTypeList *structure = type.getStruct();
1386 ASSERT(index < arg->totalRegisterCount());
1387
1388 int size = registerSize(type, index);
1389
1390 parameter.type = registerType(arg);
1391
1392 if(arg->getQualifier() == EvqConst)
1393 {
1394 int component = componentCount(type, index);
1395 ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();
1396
1397 for(int i = 0; i < 4; i++)
1398 {
1399 if(size == 1) // Replicate
1400 {
1401 parameter.value[i] = constants[component + 0].getAsFloat();
1402 }
1403 else if(i < size)
1404 {
1405 parameter.value[i] = constants[component + i].getAsFloat();
1406 }
1407 else
1408 {
1409 parameter.value[i] = 0.0f;
1410 }
1411 }
1412 }
1413 else
1414 {
1415 parameter.index = registerIndex(arg) + index;
1416
1417 if(registerType(arg) == sw::Shader::PARAMETER_SAMPLER)
1418 {
1419 TIntermBinary *binary = argument->getAsBinaryNode();
1420
1421 if(binary)
1422 {
1423 TIntermTyped *left = binary->getLeft();
1424 TIntermTyped *right = binary->getRight();
1425
1426 if(binary->getOp() == EOpIndexDirect)
1427 {
1428 parameter.index += right->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
1429 }
1430 else if(binary->getOp() == EOpIndexIndirect)
1431 {
1432 if(left->getArraySize() > 1)
1433 {
1434 parameter.rel.type = registerType(binary->getRight());
1435 parameter.rel.index = registerIndex(binary->getRight());
1436 parameter.rel.scale = 1;
1437 parameter.rel.deterministic = true;
1438 }
1439 }
1440 else UNREACHABLE();
1441 }
1442 }
1443 }
1444
1445 if(!IsSampler(arg->getBasicType()))
1446 {
1447 parameter.swizzle = swizzleSize[size];
1448 }
1449 }
1450 }
1451
1452 void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)
1453 {
1454 for(int index = 0; index < dst->totalRegisterCount(); index++)
1455 {
1456 Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, src);
1457 mov->dst.index += index;
1458 mov->dst.mask = writeMask(dst, index);
1459 argument(mov->src[0], src, offset + index);
1460 }
1461 }
1462
1463 int swizzleElement(int swizzle, int index)
1464 {
1465 return (swizzle >> (index * 2)) & 0x03;
1466 }
1467
1468 int swizzleSwizzle(int leftSwizzle, int rightSwizzle)
1469 {
1470 return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) |
1471 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) |
1472 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) |
1473 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6);
1474 }
1475
1476 void OutputASM::assignLvalue(TIntermTyped *dst, TIntermNode *src)
1477 {
1478 TIntermBinary *binary = dst->getAsBinaryNode();
1479
1480 if(binary && binary->getOp() == EOpIndexIndirect && dst->isScalar())
1481 {
1482 Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);
1483
1484 Temporary address(this);
1485 lvalue(insert->dst, address, dst);
1486
1487 insert->src[0].type = insert->dst.type;
1488 insert->src[0].index = insert->dst.index;
1489 insert->src[0].rel = insert->dst.rel;
1490 argument(insert->src[1], src);
1491 argument(insert->src[2], binary->getRight());
1492
1493 shader->append(insert);
1494 }
1495 else
1496 {
1497 for(int offset = 0; offset < dst->totalRegisterCount(); offset++)
1498 {
1499 Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);
1500
1501 Temporary address(this);
1502 int swizzle = lvalue(mov->dst, address, dst);
1503 mov->dst.index += offset;
1504
1505 if(offset > 0)
1506 {
1507 mov->dst.mask = writeMask(dst, offset);
1508 }
1509
1510 argument(mov->src[0], src, offset);
1511 mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle);
1512
1513 shader->append(mov);
1514 }
1515 }
1516 }
1517
1518 int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)
1519 {
1520 TIntermTyped *result = node;
1521 TIntermBinary *binary = node->getAsBinaryNode();
1522 TIntermSymbol *symbol = node->getAsSymbolNode();
1523
1524 if(binary)
1525 {
1526 TIntermTyped *left = binary->getLeft();
1527 TIntermTyped *right = binary->getRight();
1528
1529 int leftSwizzle = lvalue(dst, address, left); // Resolve the l-value of the left side
1530
1531 switch(binary->getOp())
1532 {
1533 case EOpIndexDirect:
1534 {
1535 int rightIndex = right->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
1536
1537 if(left->isRegister())
1538 {
1539 int leftMask = dst.mask;
1540
1541 dst.mask = 1;
1542 while((leftMask & dst.mask) == 0)
1543 {
1544 dst.mask = dst.mask << 1;
1545 }
1546
1547 int element = swizzleElement(leftSwizzle, rightIndex);
1548 dst.mask = 1 << element;
1549
1550 return element;
1551 }
1552 else if(left->isArray() || left->isMatrix())
1553 {
1554 dst.index += rightIndex * result->totalRegisterCount();
1555 return 0xE4;
1556 }
1557 else UNREACHABLE();
1558 }
1559 break;
1560 case EOpIndexIndirect:
1561 {
1562 if(left->isRegister())
1563 {
1564 // Requires INSERT instruction (handled by calling function)
1565 }
1566 else if(left->isArray() || left->isMatrix())
1567 {
1568 int scale = result->totalRegisterCount();
1569
1570 if(dst.rel.type == sw::Shader::PARAMETER_VOID) // Use the index register as the relative address directly
1571 {
1572 if(left->totalRegisterCount() > 1)
1573 {
1574 sw::Shader::SourceParameter relativeRegister;
1575 argument(relativeRegister, right);
1576
1577 dst.rel.index = relativeRegister.index;
1578 dst.rel.type = relativeRegister.type;
1579 dst.rel.scale = scale;
1580 dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
1581 }
1582 }
1583 else if(dst.rel.index != registerIndex(&address)) // Move the previous index register to the address register
1584 {
1585 if(scale == 1)
1586 {
1587 Constant oldScale((int)dst.rel.scale);
1588 Instruction *mad = emit(sw::Shader::OPCODE_MAD, &address, &address, &oldScale, right);
1589 mad->src[0].index = dst.rel.index;
1590 mad->src[0].type = dst.rel.type;
1591 }
1592 else
1593 {
1594 Constant oldScale((int)dst.rel.scale);
1595 Instruction *mul = emit(sw::Shader::OPCODE_MUL, &address, &address, &oldScale);
1596 mul->src[0].index = dst.rel.index;
1597 mul->src[0].type = dst.rel.type;
1598
1599 Constant newScale(scale);
1600 emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address);
1601 }
1602
1603 dst.rel.type = sw::Shader::PARAMETER_TEMP;
1604 dst.rel.index = registerIndex(&address);
1605 dst.rel.scale = 1;
1606 }
1607 else // Just add the new index to the address register
1608 {
1609 if(scale == 1)
1610 {
1611 emit(sw::Shader::OPCODE_ADD, &address, &address, right);
1612 }
1613 else
1614 {
1615 Constant newScale(scale);
1616 emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address);
1617 }
1618 }
1619 }
1620 else UNREACHABLE();
1621 }
1622 break;
1623 case EOpIndexDirectStruct:
1624 {
1625 const TTypeList *structure = left->getType().getStruct();
1626 const TString &fieldName = right->getType().getFieldName();
1627
1628 int offset = 0;
1629 for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)
1630 {
1631 if(field->type->getFieldName() == fieldName)
1632 {
1633 dst.type = registerType(left);
1634 dst.index += offset;
1635 dst.mask = writeMask(right);
1636
1637 return 0xE4;
1638 }
1639
1640 offset += field->type->totalRegisterCount();
1641 }
1642 }
1643 break;
1644 case EOpVectorSwizzle:
1645 {
1646 ASSERT(left->isRegister());
1647
1648 int leftMask = dst.mask;
1649
1650 int swizzle = 0;
1651 int rightMask = 0;
1652
1653 TIntermSequence &sequence = right->getAsAggregate()->getSequence();
1654
1655 for(unsigned int i = 0; i < sequence.size(); i++)
1656 {
1657 int index = sequence[i]->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
1658
1659 int element = swizzleElement(leftSwizzle, index);
1660 rightMask = rightMask | (1 << element);
1661 swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);
1662 }
1663
1664 dst.mask = leftMask & rightMask;
1665
1666 return swizzle;
1667 }
1668 break;
1669 default:
1670 UNREACHABLE(); // Not an l-value operator
1671 break;
1672 }
1673 }
1674 else if(symbol)
1675 {
1676 dst.type = registerType(symbol);
1677 dst.index = registerIndex(symbol);
1678 dst.mask = writeMask(symbol);
1679 return 0xE4;
1680 }
1681
1682 return 0xE4;
1683 }
1684
1685 sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand)
1686 {
1687 if(IsSampler(operand->getBasicType()) && (operand->getQualifier() == EvqUniform || operand->getQualifier() == EvqTemporary)) // Function parameters are temporaries
1688 {
1689 return sw::Shader::PARAMETER_SAMPLER;
1690 }
1691
1692 switch(operand->getQualifier())
1693 {
1694 case EvqTemporary: return sw::Shader::PARAMETER_TEMP;
1695 case EvqGlobal: return sw::Shader::PARAMETER_TEMP;
1696 case EvqConst: return sw::Shader::PARAMETER_FLOAT4LITERAL; // All converted to float
1697 case EvqAttribute: return sw::Shader::PARAMETER_INPUT;
1698 case EvqVaryingIn: return sw::Shader::PARAMETER_INPUT;
1699 case EvqVaryingOut: return sw::Shader::PARAMETER_OUTPUT;
1700 case EvqInvariantVaryingIn: return sw::Shader::PARAMETER_INPUT; // FIXME: Guarantee invariance at the backend
1701 case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT; // FIXME: Guarantee invariance at the backend
1702 case EvqUniform: return sw::Shader::PARAMETER_CONST;
1703 case EvqIn: return sw::Shader::PARAMETER_TEMP;
1704 case EvqOut: return sw::Shader::PARAMETER_TEMP;
1705 case EvqInOut: return sw::Shader::PARAMETER_TEMP;
1706 case EvqConstReadOnly: return sw::Shader::PARAMETER_TEMP;
1707 case EvqPosition: return sw::Shader::PARAMETER_OUTPUT;
1708 case EvqPointSize: return sw::Shader::PARAMETER_OUTPUT;
1709 case EvqFragCoord: return sw::Shader::PARAMETER_MISCTYPE;
1710 case EvqFrontFacing: return sw::Shader::PARAMETER_MISCTYPE;
1711 case EvqPointCoord: return sw::Shader::PARAMETER_INPUT;
1712 case EvqFragColor: return sw::Shader::PARAMETER_COLOROUT;
1713 case EvqFragData: return sw::Shader::PARAMETER_COLOROUT;
1714 default: UNREACHABLE();
1715 }
1716
1717 return sw::Shader::PARAMETER_VOID;
1718 }
1719
1720 int OutputASM::registerIndex(TIntermTyped *operand)
1721 {
1722 if(registerType(operand) == sw::Shader::PARAMETER_SAMPLER)
1723 {
1724 return samplerRegister(operand);
1725 }
1726
1727 switch(operand->getQualifier())
1728 {
1729 case EvqTemporary: return temporaryRegister(operand);
1730 case EvqGlobal: return temporaryRegister(operand);
1731 case EvqConst: UNREACHABLE();
1732 case EvqAttribute: return attributeRegister(operand);
1733 case EvqVaryingIn: return varyingRegister(operand);
1734 case EvqVaryingOut: return varyingRegister(operand);
1735 case EvqInvariantVaryingIn: return varyingRegister(operand);
1736 case EvqInvariantVaryingOut: return varyingRegister(operand);
1737 case EvqUniform: return uniformRegister(operand);
1738 case EvqIn: return temporaryRegister(operand);
1739 case EvqOut: return temporaryRegister(operand);
1740 case EvqInOut: return temporaryRegister(operand);
1741 case EvqConstReadOnly: return temporaryRegister(operand);
1742 case EvqPosition: return varyingRegister(operand);
1743 case EvqPointSize: return varyingRegister(operand);
1744 case EvqFragCoord: pixelShader->vPosDeclared = true; return 0;
1745 case EvqFrontFacing: pixelShader->vFaceDeclared = true; return 1;
1746 case EvqPointCoord: return varyingRegister(operand);
1747 case EvqFragColor: return 0;
1748 case EvqFragData: return 0;
1749 default: UNREACHABLE();
1750 }
1751
1752 return 0;
1753 }
1754
1755 int OutputASM::writeMask(TIntermTyped *destination, int index)
1756 {
1757 if(destination->getQualifier() == EvqPointSize)
1758 {
1759 return 0x2; // Point size stored in the y component
1760 }
1761
1762 return 0xF >> (4 - registerSize(destination->getType(), index));
1763 }
1764
1765 // Conservatively checks whether an expression is fast to compute and has no side effects
1766 bool OutputASM::trivial(TIntermTyped *expression, int budget)
1767 {
1768 if(!expression->isRegister())
1769 {
1770 return false;
1771 }
1772
1773 return cost(expression, budget) >= 0;
1774 }
1775
1776 // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects)
1777 int OutputASM::cost(TIntermNode *expression, int budget)
1778 {
1779 if(budget < 0)
1780 {
1781 return budget;
1782 }
1783
1784 if(expression->getAsSymbolNode())
1785 {
1786 return budget;
1787 }
1788 else if(expression->getAsConstantUnion())
1789 {
1790 return budget;
1791 }
1792 else if(expression->getAsBinaryNode())
1793 {
1794 TIntermBinary *binary = expression->getAsBinaryNode();
1795
1796 switch(binary->getOp())
1797 {
1798 case EOpVectorSwizzle:
1799 case EOpIndexDirect:
1800 case EOpIndexDirectStruct:
1801 return cost(binary->getLeft(), budget - 0);
1802 case EOpAdd:
1803 case EOpSub:
1804 case EOpMul:
1805 return cost(binary->getLeft(), cost(binary->getRight(), budget - 1));
1806 default:
1807 return -1;
1808 }
1809 }
1810 else if(expression->getAsUnaryNode())
1811 {
1812 TIntermUnary *unary = expression->getAsUnaryNode();
1813
1814 switch(unary->getOp())
1815 {
1816 case EOpAbs:
1817 case EOpNegative:
1818 return cost(unary->getOperand(), budget - 1);
1819 default:
1820 return -1;
1821 }
1822 }
1823 else if(expression->getAsSelectionNode())
1824 {
1825 TIntermSelection *selection = expression->getAsSelectionNode();
1826
1827 if(selection->usesTernaryOperator())
1828 {
1829 TIntermTyped *condition = selection->getCondition();
1830 TIntermNode *trueBlock = selection->getTrueBlock();
1831 TIntermNode *falseBlock = selection->getFalseBlock();
1832 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
1833
1834 if(constantCondition)
1835 {
1836 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
1837
1838 if(trueCondition)
1839 {
1840 return cost(trueBlock, budget - 0);
1841 }
1842 else
1843 {
1844 return cost(falseBlock, budget - 0);
1845 }
1846 }
1847 else
1848 {
1849 return cost(trueBlock, cost(falseBlock, budget - 2));
1850 }
1851 }
1852 }
1853
1854 return -1;
1855 }
1856
1857 const Function &OutputASM::findFunction(const TString &name)
1858 {
1859 for(unsigned int f = 0; f < functionArray.size(); f++)
1860 {
1861 if(functionArray[f].name == name)
1862 {
1863 return functionArray[f];
1864 }
1865 }
1866
1867 UNREACHABLE();
1868 return functionArray[0];
1869 }
1870
1871 int OutputASM::temporaryRegister(TIntermTyped *temporary)
1872 {
1873 return allocate(temporaries, temporary);
1874 }
1875
1876 int OutputASM::varyingRegister(TIntermTyped *varying)
1877 {
1878 int var = lookup(varyings, varying);
1879
1880 if(var == -1)
1881 {
1882 var = allocate(varyings, varying);
1883 int componentCount = varying->getNominalSize();
1884 int registerCount = varying->totalRegisterCount();
1885
1886 if(pixelShader && (var + registerCount) <= sw::PixelShader::MAX_INPUT_VARYINGS)
1887 {
1888 if(varying->getQualifier() == EvqPointCoord)
1889 {
1890 ASSERT(varying->isRegister());
1891 if(componentCount >= 1) pixelShader->semantic[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);
1892 if(componentCount >= 2) pixelShader->semantic[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);
1893 if(componentCount >= 3) pixelShader->semantic[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);
1894 if(componentCount >= 4) pixelShader->semantic[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);
1895 }
1896 else
1897 {
1898 for(int i = 0; i < varying->totalRegisterCount(); i++)
1899 {
1900 if(componentCount >= 1) pixelShader->semantic[var + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);
1901 if(componentCount >= 2) pixelShader->semantic[var + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);
1902 if(componentCount >= 3) pixelShader->semantic[var + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);
1903 if(componentCount >= 4) pixelShader->semantic[var + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);
1904 }
1905 }
1906 }
1907 else if(vertexShader && (var + registerCount) <= sw::VertexShader::MAX_OUTPUT_VARYINGS)
1908 {
1909 if(varying->getQualifier() == EvqPosition)
1910 {
1911 ASSERT(varying->isRegister());
1912 vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);
1913 vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);
1914 vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);
1915 vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);
1916 vertexShader->positionRegister = var;
1917 }
1918 else if(varying->getQualifier() == EvqPointSize)
1919 {
1920 ASSERT(varying->isRegister());
1921 vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);
1922 vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);
1923 vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);
1924 vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);
1925 vertexShader->pointSizeRegister = var;
1926 }
1927 else
1928 {
1929 // Semantic indexes for user varyings will be assigned during program link to match the pixel shader
1930 }
1931 }
1932 else UNREACHABLE();
1933
1934 declareVarying(varying, var);
1935 }
1936
1937 return var;
1938 }
1939
1940 void OutputASM::declareVarying(TIntermTyped *varying, int reg)
1941 {
1942 if(varying->getQualifier() != EvqPointCoord) // gl_PointCoord does not need linking
1943 {
1944 const TType &type = varying->getType();
1945 const char *name = varying->getAsSymbolNode()->getSymbol().c_str();
1946 gl::VaryingList &activeVaryings = shaderObject->varyings;
1947
1948 // Check if this varying has been declared before without having a register assigned
1949 for(gl::VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)
1950 {
1951 if(v->name == name)
1952 {
1953 if(reg >= 0)
1954 {
1955 ASSERT(v->reg < 0 || v->reg == reg);
1956 v->reg = reg;
1957 }
1958
1959 return;
1960 }
1961 }
1962
1963 activeVaryings.push_back(gl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0));
1964 }
1965 }
1966
1967 int OutputASM::uniformRegister(TIntermTyped *uniform)
1968 {
1969 const TType &type = uniform->getType();
1970 ASSERT(!IsSampler(type.getBasicType()));
1971 TIntermSymbol *symbol = uniform->getAsSymbolNode();
1972 ASSERT(symbol);
1973
1974 if(symbol)
1975 {
1976 int index = lookup(uniforms, uniform);
1977
1978 if(index == -1)
1979 {
1980 index = allocate(uniforms, uniform);
1981 const TString &name = symbol->getSymbol().c_str();
1982
1983 declareUniform(type, name, index);
1984 }
1985
1986 return index;
1987 }
1988
1989 return 0;
1990 }
1991
1992 int OutputASM::attributeRegister(TIntermTyped *attribute)
1993 {
1994 ASSERT(!attribute->isArray());
1995 ASSERT(attribute->getBasicType() == EbtFloat);
1996
1997 int index = lookup(attributes, attribute);
1998
1999 if(index == -1)
2000 {
2001 TIntermSymbol *symbol = attribute->getAsSymbolNode();
2002 ASSERT(symbol);
2003
2004 if(symbol)
2005 {
2006 index = allocate(attributes, attribute);
2007 const TType &type = attribute->getType();
2008 int registerCount = attribute->totalRegisterCount();
2009
2010 if(vertexShader && (index + registerCount) <= sw::VertexShader::MAX_INPUT_ATTRIBUTES)
2011 {
2012 for(int i = 0; i < registerCount; i++)
2013 {
2014 vertexShader->input[index + i] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i);
2015 }
2016 }
2017
2018 ActiveAttributes &activeAttributes = shaderObject->activeAttributes;
2019
2020 const char *name = symbol->getSymbol().c_str();
2021 activeAttributes.push_back(Attribute(glVariableType(type), name, 0, index));
2022 }
2023 }
2024
2025 return index;
2026 }
2027
2028 int OutputASM::samplerRegister(TIntermTyped *sampler)
2029 {
2030 const TType &type = sampler->getType();
2031 ASSERT(IsSampler(type.getBasicType()));
2032 TIntermSymbol *symbol = sampler->getAsSymbolNode();
2033 TIntermBinary *binary = sampler->getAsBinaryNode();
2034
2035 if(symbol)
2036 {
2037 int index = lookup(samplers, sampler);
2038
2039 if(index == -1)
2040 {
2041 index = allocate(samplers, sampler);
2042 ActiveUniforms &activeUniforms = shaderObject->activeUniforms;
2043 const char *name = symbol->getSymbol().c_str();
John Baumand4ae8632014-05-06 16:18:33 -04002044 activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name, sampler->getArraySize(), index));
John Bauman66b8ab22014-05-06 15:57:45 -04002045
2046 for(int i = 0; i < sampler->totalRegisterCount(); i++)
2047 {
2048 shader->declareSampler(index + i);
2049 }
2050 }
2051
2052 return index;
2053 }
2054 else if(binary)
2055 {
2056 ASSERT(binary->getOp() == EOpIndexDirect || binary->getOp() == EOpIndexIndirect);
2057
2058 return samplerRegister(binary->getLeft()); // Index added later
2059 }
2060 else UNREACHABLE();
2061
2062 return 0;
2063 }
2064
2065 int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)
2066 {
2067 for(unsigned int i = 0; i < list.size(); i++)
2068 {
2069 if(list[i] == variable)
2070 {
2071 return i; // Pointer match
2072 }
2073 }
2074
2075 TIntermSymbol *varSymbol = variable->getAsSymbolNode();
2076
2077 if(varSymbol)
2078 {
2079 for(unsigned int i = 0; i < list.size(); i++)
2080 {
2081 if(list[i])
2082 {
2083 TIntermSymbol *listSymbol = list[i]->getAsSymbolNode();
2084
2085 if(listSymbol)
2086 {
2087 if(listSymbol->getId() == varSymbol->getId())
2088 {
2089 ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol());
2090 ASSERT(listSymbol->getType() == varSymbol->getType());
2091 ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier());
2092
2093 return i;
2094 }
2095 }
2096 }
2097 }
2098 }
2099
2100 return -1;
2101 }
2102
2103 int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)
2104 {
2105 int index = lookup(list, variable);
2106
2107 if(index == -1)
2108 {
2109 unsigned int registerCount = variable->totalRegisterCount();
2110
2111 for(unsigned int i = 0; i < list.size(); i++)
2112 {
2113 if(list[i] == 0)
2114 {
2115 unsigned int j = 1;
2116 for( ; j < registerCount && (i + j) < list.size(); j++)
2117 {
2118 if(list[i + j] != 0)
2119 {
2120 break;
2121 }
2122 }
2123
2124 if(j == registerCount) // Found free slots
2125 {
2126 for(unsigned int j = 0; j < registerCount; j++)
2127 {
2128 list[i + j] = variable;
2129 }
2130
2131 return i;
2132 }
2133 }
2134 }
2135
2136 index = list.size();
2137
2138 for(unsigned int i = 0; i < registerCount; i++)
2139 {
2140 list.push_back(variable);
2141 }
2142 }
2143
2144 return index;
2145 }
2146
2147 void OutputASM::free(VariableArray &list, TIntermTyped *variable)
2148 {
2149 int index = lookup(list, variable);
2150
2151 if(index >= 0)
2152 {
2153 list[index] = 0;
2154 }
2155 }
2156
2157 void OutputASM::declareUniform(const TType &type, const TString &name, int index)
2158 {
2159 const TTypeList *structure = type.getStruct();
2160 ActiveUniforms &activeUniforms = shaderObject->activeUniforms;
2161
2162 if(!structure)
2163 {
John Baumand4ae8632014-05-06 16:18:33 -04002164 activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));
John Bauman66b8ab22014-05-06 15:57:45 -04002165 }
2166 else
2167 {
2168 if(type.isArray())
2169 {
2170 int elementIndex = index;
2171
2172 for(int i = 0; i < type.getArraySize(); i++)
2173 {
2174 for(size_t j = 0; j < structure->size(); j++)
2175 {
2176 const TType &fieldType = *(*structure)[j].type;
2177 const TString &fieldName = fieldType.getFieldName();
2178
2179 const TString uniformName = name + "[" + str(i) + "]." + fieldName;
2180 declareUniform(fieldType, uniformName, elementIndex);
2181 elementIndex += fieldType.totalRegisterCount();
2182 }
2183 }
2184 }
2185 else
2186 {
2187 int fieldIndex = index;
2188
2189 for(size_t i = 0; i < structure->size(); i++)
2190 {
2191 const TType &fieldType = *(*structure)[i].type;
2192 const TString &fieldName = fieldType.getFieldName();
2193
2194 const TString uniformName = name + "." + fieldName;
2195 declareUniform(fieldType, uniformName, fieldIndex);
2196 fieldIndex += fieldType.totalRegisterCount();
2197 }
2198 }
2199 }
2200 }
2201
2202 GLenum OutputASM::glVariableType(const TType &type)
2203 {
2204 if(type.getBasicType() == EbtFloat)
2205 {
2206 if(type.isScalar())
2207 {
2208 return GL_FLOAT;
2209 }
2210 else if(type.isVector())
2211 {
2212 switch(type.getNominalSize())
2213 {
2214 case 2: return GL_FLOAT_VEC2;
2215 case 3: return GL_FLOAT_VEC3;
2216 case 4: return GL_FLOAT_VEC4;
2217 default: UNREACHABLE();
2218 }
2219 }
2220 else if(type.isMatrix())
2221 {
2222 switch(type.getNominalSize())
2223 {
2224 case 2: return GL_FLOAT_MAT2;
2225 case 3: return GL_FLOAT_MAT3;
2226 case 4: return GL_FLOAT_MAT4;
2227 default: UNREACHABLE();
2228 }
2229 }
2230 else UNREACHABLE();
2231 }
2232 else if(type.getBasicType() == EbtInt)
2233 {
2234 if(type.isScalar())
2235 {
2236 return GL_INT;
2237 }
2238 else if(type.isVector())
2239 {
2240 switch(type.getNominalSize())
2241 {
2242 case 2: return GL_INT_VEC2;
2243 case 3: return GL_INT_VEC3;
2244 case 4: return GL_INT_VEC4;
2245 default: UNREACHABLE();
2246 }
2247 }
2248 else UNREACHABLE();
2249 }
2250 else if(type.getBasicType() == EbtBool)
2251 {
2252 if(type.isScalar())
2253 {
2254 return GL_BOOL;
2255 }
2256 else if(type.isVector())
2257 {
2258 switch(type.getNominalSize())
2259 {
2260 case 2: return GL_BOOL_VEC2;
2261 case 3: return GL_BOOL_VEC3;
2262 case 4: return GL_BOOL_VEC4;
2263 default: UNREACHABLE();
2264 }
2265 }
2266 else UNREACHABLE();
2267 }
2268 else if(type.getBasicType() == EbtSampler2D)
2269 {
2270 return GL_SAMPLER_2D;
2271 }
2272 else if(type.getBasicType() == EbtSamplerCube)
2273 {
2274 return GL_SAMPLER_CUBE;
2275 }
2276 else UNREACHABLE();
2277
2278 return GL_NONE;
2279 }
2280
John Baumand4ae8632014-05-06 16:18:33 -04002281 GLenum OutputASM::glVariablePrecision(const TType &type)
2282 {
2283 if(type.getBasicType() == EbtFloat)
2284 {
2285 switch(type.getPrecision())
2286 {
2287 case EbpHigh: return GL_HIGH_FLOAT;
2288 case EbpMedium: return GL_MEDIUM_FLOAT;
2289 case EbpLow: return GL_LOW_FLOAT;
2290 case EbpUndefined:
2291 // Should be defined as the default precision by the parser
2292 default: UNREACHABLE();
2293 }
2294 }
2295 else if (type.getBasicType() == EbtInt)
2296 {
2297 switch (type.getPrecision())
2298 {
2299 case EbpHigh: return GL_HIGH_INT;
2300 case EbpMedium: return GL_MEDIUM_INT;
2301 case EbpLow: return GL_LOW_INT;
2302 case EbpUndefined:
2303 // Should be defined as the default precision by the parser
2304 default: UNREACHABLE();
2305 }
2306 }
2307
2308 // Other types (boolean, sampler) don't have a precision
2309 return GL_NONE;
2310 }
2311
John Bauman66b8ab22014-05-06 15:57:45 -04002312 int OutputASM::dim(TIntermNode *v)
2313 {
2314 TIntermTyped *vector = v->getAsTyped();
2315 ASSERT(vector && vector->isRegister());
2316 return vector->getNominalSize();
2317 }
2318
2319 int OutputASM::dim2(TIntermNode *m)
2320 {
2321 TIntermTyped *matrix = m->getAsTyped();
2322 ASSERT(matrix && matrix->isMatrix() && !matrix->isArray());
2323 return matrix->getNominalSize();
2324 }
John Baumand4ae8632014-05-06 16:18:33 -04002325
2326 // Returns ~0 if no loop count could be determined
2327 unsigned int OutputASM::loopCount(TIntermLoop *node)
2328 {
2329 // Parse loops of the form:
2330 // for(int index = initial; index [comparator] limit; index += increment)
2331 TIntermSymbol *index = 0;
2332 TOperator comparator = EOpNull;
2333 int initial = 0;
2334 int limit = 0;
2335 int increment = 0;
2336
2337 // Parse index name and intial value
2338 if(node->getInit())
2339 {
2340 TIntermAggregate *init = node->getInit()->getAsAggregate();
2341
2342 if(init)
2343 {
2344 TIntermSequence &sequence = init->getSequence();
2345 TIntermTyped *variable = sequence[0]->getAsTyped();
2346
2347 if(variable && variable->getQualifier() == EvqTemporary)
2348 {
2349 TIntermBinary *assign = variable->getAsBinaryNode();
2350
2351 if(assign->getOp() == EOpInitialize)
2352 {
2353 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2354 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2355
2356 if(symbol && constant)
2357 {
2358 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2359 {
2360 index = symbol;
2361 initial = constant->getUnionArrayPointer()[0].getIConst();
2362 }
2363 }
2364 }
2365 }
2366 }
2367 }
2368
2369 // Parse comparator and limit value
2370 if(index && node->getCondition())
2371 {
2372 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
2373
2374 if(test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2375 {
2376 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2377
2378 if(constant)
2379 {
2380 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2381 {
2382 comparator = test->getOp();
2383 limit = constant->getUnionArrayPointer()[0].getIConst();
2384 }
2385 }
2386 }
2387 }
2388
2389 // Parse increment
2390 if(index && comparator != EOpNull && node->getExpression())
2391 {
2392 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2393 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
2394
2395 if(binaryTerminal)
2396 {
2397 TOperator op = binaryTerminal->getOp();
2398 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2399
2400 if(constant)
2401 {
2402 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2403 {
2404 int value = constant->getUnionArrayPointer()[0].getIConst();
2405
2406 switch(op)
2407 {
2408 case EOpAddAssign: increment = value; break;
2409 case EOpSubAssign: increment = -value; break;
2410 default: UNIMPLEMENTED();
2411 }
2412 }
2413 }
2414 }
2415 else if(unaryTerminal)
2416 {
2417 TOperator op = unaryTerminal->getOp();
2418
2419 switch(op)
2420 {
2421 case EOpPostIncrement: increment = 1; break;
2422 case EOpPostDecrement: increment = -1; break;
2423 case EOpPreIncrement: increment = 1; break;
2424 case EOpPreDecrement: increment = -1; break;
2425 default: UNIMPLEMENTED();
2426 }
2427 }
2428 }
2429
2430 if(index && comparator != EOpNull && increment != 0)
2431 {
2432 if(comparator == EOpLessThanEqual)
2433 {
2434 comparator = EOpLessThan;
2435 limit += 1;
2436 }
2437
2438 if(comparator == EOpLessThan)
2439 {
2440 int iterations = (limit - initial) / increment;
2441
2442 if(iterations <= 0)
2443 {
2444 iterations = 0;
2445 }
2446
2447 return iterations;
2448 }
2449 else UNIMPLEMENTED(); // Falls through
2450 }
2451
2452 return ~0;
2453 }
2454
2455 bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
2456 {
2457 loopDepth = 0;
2458 loopDiscontinuity = false;
2459
2460 node->traverse(this);
2461
2462 return loopDiscontinuity;
2463 }
2464
2465 bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
2466 {
2467 if(visit == PreVisit)
2468 {
2469 loopDepth++;
2470 }
2471 else if(visit == PostVisit)
2472 {
2473 loopDepth++;
2474 }
2475
2476 return true;
2477 }
2478
2479 bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
2480 {
2481 if(loopDiscontinuity)
2482 {
2483 return false;
2484 }
2485
2486 if(!loopDepth)
2487 {
2488 return true;
2489 }
2490
2491 switch(node->getFlowOp())
2492 {
2493 case EOpKill:
2494 break;
2495 case EOpBreak:
2496 case EOpContinue:
2497 case EOpReturn:
2498 loopDiscontinuity = true;
2499 break;
2500 default: UNREACHABLE();
2501 }
2502
2503 return !loopDiscontinuity;
2504 }
2505
2506 bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
2507 {
2508 return !loopDiscontinuity;
2509 }
John Bauman66b8ab22014-05-06 15:57:45 -04002510}