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