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