blob: 3d196b242497ec5404416370fa95b1b80100999d [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "OutputASM.h"
16#include "Common/Math.hpp"
17
18#include "common/debug.h"
19#include "InfoSink.h"
20
21#include "libGLESv2/Shader.h"
22
23#include <GLES2/gl2.h>
24#include <GLES2/gl2ext.h>
25#include <GLES3/gl3.h>
26
Nicolas Capens930b7002017-01-06 17:22:13 -050027#include <stdlib.h>
28
Nicolas Capens0bac2852016-05-07 06:09:58 -040029namespace glsl
30{
31 // Integer to TString conversion
32 TString str(int i)
33 {
34 char buffer[20];
35 sprintf(buffer, "%d", i);
36 return buffer;
37 }
38
39 class Temporary : public TIntermSymbol
40 {
41 public:
42 Temporary(OutputASM *assembler) : TIntermSymbol(TSymbolTableLevel::nextUniqueId(), "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, 1, false)), assembler(assembler)
43 {
44 }
45
46 ~Temporary()
47 {
48 assembler->freeTemporary(this);
49 }
50
51 private:
52 OutputASM *const assembler;
53 };
54
55 class Constant : public TIntermConstantUnion
56 {
57 public:
58 Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConstExpr, 4, 1, false))
59 {
60 constants[0].setFConst(x);
61 constants[1].setFConst(y);
62 constants[2].setFConst(z);
63 constants[3].setFConst(w);
64 }
65
66 Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConstExpr, 1, 1, false))
67 {
68 constants[0].setBConst(b);
69 }
70
71 Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConstExpr, 1, 1, false))
72 {
73 constants[0].setIConst(i);
74 }
75
76 ~Constant()
77 {
78 }
79
80 private:
81 ConstantUnion constants[4];
82 };
83
84 Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) :
85 type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), blockId(blockId), blockInfo(blockMemberInfo)
86 {
87 }
88
89 UniformBlock::UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize,
90 TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId) :
91 name(name), dataSize(dataSize), arraySize(arraySize), layout(layout),
92 isRowMajorLayout(isRowMajorLayout), registerIndex(registerIndex), blockId(blockId)
93 {
94 }
95
96 BlockLayoutEncoder::BlockLayoutEncoder(bool rowMajor)
97 : mCurrentOffset(0), isRowMajor(rowMajor)
98 {
99 }
100
101 BlockMemberInfo BlockLayoutEncoder::encodeType(const TType &type)
102 {
103 int arrayStride;
104 int matrixStride;
105
106 getBlockLayoutInfo(type, type.getArraySize(), isRowMajor, &arrayStride, &matrixStride);
107
108 const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
109 static_cast<int>(arrayStride * BytesPerComponent),
110 static_cast<int>(matrixStride * BytesPerComponent),
111 (matrixStride > 0) && isRowMajor);
112
113 advanceOffset(type, type.getArraySize(), isRowMajor, arrayStride, matrixStride);
114
115 return memberInfo;
116 }
117
118 // static
119 size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
120 {
121 return (info.offset / BytesPerComponent) / ComponentsPerRegister;
122 }
123
124 // static
125 size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
126 {
127 return (info.offset / BytesPerComponent) % ComponentsPerRegister;
128 }
129
130 void BlockLayoutEncoder::nextRegister()
131 {
132 mCurrentOffset = sw::align(mCurrentOffset, ComponentsPerRegister);
133 }
134
135 Std140BlockEncoder::Std140BlockEncoder(bool rowMajor) : BlockLayoutEncoder(rowMajor)
136 {
137 }
138
139 void Std140BlockEncoder::enterAggregateType()
140 {
141 nextRegister();
142 }
143
144 void Std140BlockEncoder::exitAggregateType()
145 {
146 nextRegister();
147 }
148
149 void Std140BlockEncoder::getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
150 {
151 size_t baseAlignment = 0;
152 int matrixStride = 0;
153 int arrayStride = 0;
154
155 if(type.isMatrix())
156 {
157 baseAlignment = ComponentsPerRegister;
158 matrixStride = ComponentsPerRegister;
159
160 if(arraySize > 0)
161 {
162 const int numRegisters = isRowMajorMatrix ? type.getSecondarySize() : type.getNominalSize();
163 arrayStride = ComponentsPerRegister * numRegisters;
164 }
165 }
166 else if(arraySize > 0)
167 {
168 baseAlignment = ComponentsPerRegister;
169 arrayStride = ComponentsPerRegister;
170 }
171 else
172 {
173 const size_t numComponents = type.getElementSize();
174 baseAlignment = (numComponents == 3 ? 4u : numComponents);
175 }
176
177 mCurrentOffset = sw::align(mCurrentOffset, baseAlignment);
178
179 *matrixStrideOut = matrixStride;
180 *arrayStrideOut = arrayStride;
181 }
182
183 void Std140BlockEncoder::advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
184 {
185 if(arraySize > 0)
186 {
187 mCurrentOffset += arrayStride * arraySize;
188 }
189 else if(type.isMatrix())
190 {
191 ASSERT(matrixStride == ComponentsPerRegister);
192 const int numRegisters = isRowMajorMatrix ? type.getSecondarySize() : type.getNominalSize();
193 mCurrentOffset += ComponentsPerRegister * numRegisters;
194 }
195 else
196 {
197 mCurrentOffset += type.getElementSize();
198 }
199 }
200
201 Attribute::Attribute()
202 {
203 type = GL_NONE;
204 arraySize = 0;
205 registerIndex = 0;
206 }
207
208 Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex)
209 {
210 this->type = type;
211 this->name = name;
212 this->arraySize = arraySize;
213 this->location = location;
214 this->registerIndex = registerIndex;
215 }
216
217 sw::PixelShader *Shader::getPixelShader() const
218 {
219 return 0;
220 }
221
222 sw::VertexShader *Shader::getVertexShader() const
223 {
224 return 0;
225 }
226
227 OutputASM::TextureFunction::TextureFunction(const TString& nodeName) : method(IMPLICIT), proj(false), offset(false)
228 {
229 TString name = TFunction::unmangleName(nodeName);
230
231 if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D")
232 {
233 method = IMPLICIT;
234 }
235 else if(name == "texture2DProj" || name == "textureProj")
236 {
237 method = IMPLICIT;
238 proj = true;
239 }
240 else if(name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod")
241 {
242 method = LOD;
243 }
244 else if(name == "texture2DProjLod" || name == "textureProjLod")
245 {
246 method = LOD;
247 proj = true;
248 }
249 else if(name == "textureSize")
250 {
251 method = SIZE;
252 }
253 else if(name == "textureOffset")
254 {
255 method = IMPLICIT;
256 offset = true;
257 }
258 else if(name == "textureProjOffset")
259 {
260 method = IMPLICIT;
261 offset = true;
262 proj = true;
263 }
264 else if(name == "textureLodOffset")
265 {
266 method = LOD;
267 offset = true;
268 }
269 else if(name == "textureProjLodOffset")
270 {
271 method = LOD;
272 proj = true;
273 offset = true;
274 }
275 else if(name == "texelFetch")
276 {
277 method = FETCH;
278 }
279 else if(name == "texelFetchOffset")
280 {
281 method = FETCH;
282 offset = true;
283 }
284 else if(name == "textureGrad")
285 {
286 method = GRAD;
287 }
288 else if(name == "textureGradOffset")
289 {
290 method = GRAD;
291 offset = true;
292 }
293 else if(name == "textureProjGrad")
294 {
295 method = GRAD;
296 proj = true;
297 }
298 else if(name == "textureProjGradOffset")
299 {
300 method = GRAD;
301 proj = true;
302 offset = true;
303 }
304 else UNREACHABLE(0);
305 }
306
307 OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), shaderObject(shaderObject), mContext(context)
308 {
309 shader = 0;
310 pixelShader = 0;
311 vertexShader = 0;
312
313 if(shaderObject)
314 {
315 shader = shaderObject->getShader();
316 pixelShader = shaderObject->getPixelShader();
317 vertexShader = shaderObject->getVertexShader();
318 }
319
320 functionArray.push_back(Function(0, "main(", 0, 0));
321 currentFunction = 0;
322 outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData
323 }
324
325 OutputASM::~OutputASM()
326 {
327 }
328
329 void OutputASM::output()
330 {
331 if(shader)
332 {
333 emitShader(GLOBAL);
334
335 if(functionArray.size() > 1) // Only call main() when there are other functions
336 {
337 Instruction *callMain = emit(sw::Shader::OPCODE_CALL);
338 callMain->dst.type = sw::Shader::PARAMETER_LABEL;
339 callMain->dst.index = 0; // main()
340
341 emit(sw::Shader::OPCODE_RET);
342 }
343
344 emitShader(FUNCTION);
345 }
346 }
347
348 void OutputASM::emitShader(Scope scope)
349 {
350 emitScope = scope;
351 currentScope = GLOBAL;
352 mContext.getTreeRoot()->traverse(this);
353 }
354
355 void OutputASM::freeTemporary(Temporary *temporary)
356 {
357 free(temporaries, temporary);
358 }
359
360 sw::Shader::Opcode OutputASM::getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const
361 {
362 TBasicType baseType = in->getType().getBasicType();
363
364 switch(op)
365 {
366 case sw::Shader::OPCODE_NEG:
367 switch(baseType)
368 {
369 case EbtInt:
370 case EbtUInt:
371 return sw::Shader::OPCODE_INEG;
372 case EbtFloat:
373 default:
374 return op;
375 }
376 case sw::Shader::OPCODE_ABS:
377 switch(baseType)
378 {
379 case EbtInt:
380 return sw::Shader::OPCODE_IABS;
381 case EbtFloat:
382 default:
383 return op;
384 }
385 case sw::Shader::OPCODE_SGN:
386 switch(baseType)
387 {
388 case EbtInt:
389 return sw::Shader::OPCODE_ISGN;
390 case EbtFloat:
391 default:
392 return op;
393 }
394 case sw::Shader::OPCODE_ADD:
395 switch(baseType)
396 {
397 case EbtInt:
398 case EbtUInt:
399 return sw::Shader::OPCODE_IADD;
400 case EbtFloat:
401 default:
402 return op;
403 }
404 case sw::Shader::OPCODE_SUB:
405 switch(baseType)
406 {
407 case EbtInt:
408 case EbtUInt:
409 return sw::Shader::OPCODE_ISUB;
410 case EbtFloat:
411 default:
412 return op;
413 }
414 case sw::Shader::OPCODE_MUL:
415 switch(baseType)
416 {
417 case EbtInt:
418 case EbtUInt:
419 return sw::Shader::OPCODE_IMUL;
420 case EbtFloat:
421 default:
422 return op;
423 }
424 case sw::Shader::OPCODE_DIV:
425 switch(baseType)
426 {
427 case EbtInt:
428 return sw::Shader::OPCODE_IDIV;
429 case EbtUInt:
430 return sw::Shader::OPCODE_UDIV;
431 case EbtFloat:
432 default:
433 return op;
434 }
435 case sw::Shader::OPCODE_IMOD:
436 return baseType == EbtUInt ? sw::Shader::OPCODE_UMOD : op;
437 case sw::Shader::OPCODE_ISHR:
438 return baseType == EbtUInt ? sw::Shader::OPCODE_USHR : op;
439 case sw::Shader::OPCODE_MIN:
440 switch(baseType)
441 {
442 case EbtInt:
443 return sw::Shader::OPCODE_IMIN;
444 case EbtUInt:
445 return sw::Shader::OPCODE_UMIN;
446 case EbtFloat:
447 default:
448 return op;
449 }
450 case sw::Shader::OPCODE_MAX:
451 switch(baseType)
452 {
453 case EbtInt:
454 return sw::Shader::OPCODE_IMAX;
455 case EbtUInt:
456 return sw::Shader::OPCODE_UMAX;
457 case EbtFloat:
458 default:
459 return op;
460 }
461 default:
462 return op;
463 }
464 }
465
466 void OutputASM::visitSymbol(TIntermSymbol *symbol)
467 {
468 // Vertex varyings don't have to be actively used to successfully link
469 // against pixel shaders that use them. So make sure they're declared.
470 if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)
471 {
472 if(symbol->getBasicType() != EbtInvariant) // Typeless declarations are not new varyings
473 {
474 declareVarying(symbol, -1);
475 }
476 }
477
478 TInterfaceBlock* block = symbol->getType().getInterfaceBlock();
479 // OpenGL ES 3.0.4 spec, section 2.12.6 Uniform Variables:
480 // "All members of a named uniform block declared with a shared or std140 layout qualifier
481 // are considered active, even if they are not referenced in any shader in the program.
482 // The uniform block itself is also considered active, even if no member of the block is referenced."
483 if(block && ((block->blockStorage() == EbsShared) || (block->blockStorage() == EbsStd140)))
484 {
485 uniformRegister(symbol);
486 }
487 }
488
489 bool OutputASM::visitBinary(Visit visit, TIntermBinary *node)
490 {
491 if(currentScope != emitScope)
492 {
493 return false;
494 }
495
496 TIntermTyped *result = node;
497 TIntermTyped *left = node->getLeft();
498 TIntermTyped *right = node->getRight();
499 const TType &leftType = left->getType();
500 const TType &rightType = right->getType();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400501
502 if(isSamplerRegister(result))
503 {
504 return false; // Don't traverse, the register index is determined statically
505 }
506
507 switch(node->getOp())
508 {
509 case EOpAssign:
Nicolas Capens84249fd2017-11-09 11:20:51 -0500510 assert(visit == PreVisit);
511 right->traverse(this);
512 assignLvalue(left, right);
513 copy(result, right);
514 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400515 case EOpInitialize:
Nicolas Capens84249fd2017-11-09 11:20:51 -0500516 assert(visit == PreVisit);
517 right->traverse(this);
518 copy(left, right);
519 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400520 case EOpMatrixTimesScalarAssign:
Nicolas Capens84249fd2017-11-09 11:20:51 -0500521 assert(visit == PreVisit);
522 right->traverse(this);
523 for(int i = 0; i < leftType.getNominalSize(); i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400524 {
Nicolas Capens84249fd2017-11-09 11:20:51 -0500525 emit(sw::Shader::OPCODE_MUL, result, i, left, i, right);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400526 }
Nicolas Capens84249fd2017-11-09 11:20:51 -0500527
528 assignLvalue(left, result);
529 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400530 case EOpVectorTimesMatrixAssign:
Nicolas Capens84249fd2017-11-09 11:20:51 -0500531 assert(visit == PreVisit);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400532 {
Nicolas Capens84249fd2017-11-09 11:20:51 -0500533 right->traverse(this);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400534 int size = leftType.getNominalSize();
535
536 for(int i = 0; i < size; i++)
537 {
538 Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, 0, left, 0, right, i);
539 dot->dst.mask = 1 << i;
540 }
541
542 assignLvalue(left, result);
543 }
Nicolas Capens84249fd2017-11-09 11:20:51 -0500544 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400545 case EOpMatrixTimesMatrixAssign:
Nicolas Capens84249fd2017-11-09 11:20:51 -0500546 assert(visit == PreVisit);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400547 {
Nicolas Capens84249fd2017-11-09 11:20:51 -0500548 right->traverse(this);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400549 int dim = leftType.getNominalSize();
550
551 for(int i = 0; i < dim; i++)
552 {
553 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
554 mul->src[1].swizzle = 0x00;
555
556 for(int j = 1; j < dim; j++)
557 {
558 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, i, left, j, right, i, result, i);
559 mad->src[1].swizzle = j * 0x55;
560 }
561 }
562
563 assignLvalue(left, result);
564 }
Nicolas Capens84249fd2017-11-09 11:20:51 -0500565 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400566 case EOpIndexDirect:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400567 case EOpIndexIndirect:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400568 case EOpIndexDirectStruct:
569 case EOpIndexDirectInterfaceBlock:
Nicolas Capensd469de22017-11-16 10:42:20 -0500570 assert(visit == PreVisit);
571 evaluateRvalue(node);
572 return false;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400573 case EOpVectorSwizzle:
574 if(visit == PostVisit)
575 {
576 int swizzle = 0;
577 TIntermAggregate *components = right->getAsAggregate();
578
579 if(components)
580 {
581 TIntermSequence &sequence = components->getSequence();
582 int component = 0;
583
584 for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
585 {
586 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
587
588 if(element)
589 {
590 int i = element->getUnionArrayPointer()[0].getIConst();
591 swizzle |= i << (component * 2);
592 component++;
593 }
594 else UNREACHABLE(0);
595 }
596 }
597 else UNREACHABLE(0);
598
599 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);
600 mov->src[0].swizzle = swizzle;
601 }
602 break;
603 case EOpAddAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, left, right); break;
604 case EOpAdd: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, right); break;
605 case EOpSubAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, left, right); break;
606 case EOpSub: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, right); break;
607 case EOpMulAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, left, right); break;
608 case EOpMul: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, right); break;
609 case EOpDivAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, left, right); break;
610 case EOpDiv: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, right); break;
611 case EOpIModAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, left, right); break;
612 case EOpIMod: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, right); break;
613 case EOpBitShiftLeftAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SHL, result, left, left, right); break;
614 case EOpBitShiftLeft: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_SHL, result, left, right); break;
615 case EOpBitShiftRightAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, left, right); break;
616 case EOpBitShiftRight: if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, right); break;
617 case EOpBitwiseAndAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_AND, result, left, left, right); break;
618 case EOpBitwiseAnd: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_AND, result, left, right); break;
619 case EOpBitwiseXorAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_XOR, result, left, left, right); break;
620 case EOpBitwiseXor: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_XOR, result, left, right); break;
621 case EOpBitwiseOrAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_OR, result, left, left, right); break;
622 case EOpBitwiseOr: if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_OR, result, left, right); break;
623 case EOpEqual:
624 if(visit == PostVisit)
625 {
626 emitBinary(sw::Shader::OPCODE_EQ, result, left, right);
627
628 for(int index = 1; index < left->totalRegisterCount(); index++)
629 {
630 Temporary equal(this);
631 emit(sw::Shader::OPCODE_EQ, &equal, 0, left, index, right, index);
632 emit(sw::Shader::OPCODE_AND, result, result, &equal);
633 }
634 }
635 break;
636 case EOpNotEqual:
637 if(visit == PostVisit)
638 {
639 emitBinary(sw::Shader::OPCODE_NE, result, left, right);
640
641 for(int index = 1; index < left->totalRegisterCount(); index++)
642 {
643 Temporary notEqual(this);
644 emit(sw::Shader::OPCODE_NE, &notEqual, 0, left, index, right, index);
645 emit(sw::Shader::OPCODE_OR, result, result, &notEqual);
646 }
647 }
648 break;
649 case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break;
650 case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break;
651 case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break;
652 case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break;
653 case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, left, right); break;
654 case EOpVectorTimesScalar: if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, right); break;
655 case EOpMatrixTimesScalar:
656 if(visit == PostVisit)
657 {
658 if(left->isMatrix())
659 {
660 for(int i = 0; i < leftType.getNominalSize(); i++)
661 {
662 emit(sw::Shader::OPCODE_MUL, result, i, left, i, right, 0);
663 }
664 }
665 else if(right->isMatrix())
666 {
667 for(int i = 0; i < rightType.getNominalSize(); i++)
668 {
669 emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
670 }
671 }
672 else UNREACHABLE(0);
673 }
674 break;
675 case EOpVectorTimesMatrix:
676 if(visit == PostVisit)
677 {
678 sw::Shader::Opcode dpOpcode = sw::Shader::OPCODE_DP(leftType.getNominalSize());
679
680 int size = rightType.getNominalSize();
681 for(int i = 0; i < size; i++)
682 {
683 Instruction *dot = emit(dpOpcode, result, 0, left, 0, right, i);
684 dot->dst.mask = 1 << i;
685 }
686 }
687 break;
688 case EOpMatrixTimesVector:
689 if(visit == PostVisit)
690 {
691 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
692 mul->src[1].swizzle = 0x00;
693
694 int size = rightType.getNominalSize();
695 for(int i = 1; i < size; i++)
696 {
697 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, 0, left, i, right, 0, result);
698 mad->src[1].swizzle = i * 0x55;
699 }
700 }
701 break;
702 case EOpMatrixTimesMatrix:
703 if(visit == PostVisit)
704 {
705 int dim = leftType.getNominalSize();
706
707 int size = rightType.getNominalSize();
708 for(int i = 0; i < size; i++)
709 {
710 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
711 mul->src[1].swizzle = 0x00;
712
713 for(int j = 1; j < dim; j++)
714 {
715 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, i, left, j, right, i, result, i);
716 mad->src[1].swizzle = j * 0x55;
717 }
718 }
719 }
720 break;
721 case EOpLogicalOr:
722 if(trivial(right, 6))
723 {
724 if(visit == PostVisit)
725 {
726 emit(sw::Shader::OPCODE_OR, result, left, right);
727 }
728 }
729 else // Short-circuit evaluation
730 {
731 if(visit == InVisit)
732 {
733 emit(sw::Shader::OPCODE_MOV, result, left);
734 Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result);
735 ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT;
736 }
737 else if(visit == PostVisit)
738 {
739 emit(sw::Shader::OPCODE_MOV, result, right);
740 emit(sw::Shader::OPCODE_ENDIF);
741 }
742 }
743 break;
744 case EOpLogicalXor: if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break;
745 case EOpLogicalAnd:
746 if(trivial(right, 6))
747 {
748 if(visit == PostVisit)
749 {
750 emit(sw::Shader::OPCODE_AND, result, left, right);
751 }
752 }
753 else // Short-circuit evaluation
754 {
755 if(visit == InVisit)
756 {
757 emit(sw::Shader::OPCODE_MOV, result, left);
758 emit(sw::Shader::OPCODE_IF, 0, result);
759 }
760 else if(visit == PostVisit)
761 {
762 emit(sw::Shader::OPCODE_MOV, result, right);
763 emit(sw::Shader::OPCODE_ENDIF);
764 }
765 }
766 break;
767 default: UNREACHABLE(node->getOp());
768 }
769
770 return true;
771 }
772
773 void OutputASM::emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col, int row, int outCol, int outRow)
774 {
775 switch(size)
776 {
777 case 1: // Used for cofactor computation only
778 {
779 // For a 2x2 matrix, the cofactor is simply a transposed move or negate
780 bool isMov = (row == col);
781 sw::Shader::Opcode op = isMov ? sw::Shader::OPCODE_MOV : sw::Shader::OPCODE_NEG;
782 Instruction *mov = emit(op, result, outCol, arg, isMov ? 1 - row : row);
783 mov->src[0].swizzle = 0x55 * (isMov ? 1 - col : col);
784 mov->dst.mask = 1 << outRow;
785 }
786 break;
787 case 2:
788 {
789 static const unsigned int swizzle[3] = { 0x99, 0x88, 0x44 }; // xy?? : yzyz, xzxz, xyxy
790
791 bool isCofactor = (col >= 0) && (row >= 0);
792 int col0 = (isCofactor && (col <= 0)) ? 1 : 0;
793 int col1 = (isCofactor && (col <= 1)) ? 2 : 1;
794 bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));
795
796 Instruction *det = emit(sw::Shader::OPCODE_DET2, result, outCol, arg, negate ? col1 : col0, arg, negate ? col0 : col1);
797 det->src[0].swizzle = det->src[1].swizzle = swizzle[isCofactor ? row : 2];
798 det->dst.mask = 1 << outRow;
799 }
800 break;
801 case 3:
802 {
803 static const unsigned int swizzle[4] = { 0xF9, 0xF8, 0xF4, 0xE4 }; // xyz? : yzww, xzww, xyww, xyzw
804
805 bool isCofactor = (col >= 0) && (row >= 0);
806 int col0 = (isCofactor && (col <= 0)) ? 1 : 0;
807 int col1 = (isCofactor && (col <= 1)) ? 2 : 1;
808 int col2 = (isCofactor && (col <= 2)) ? 3 : 2;
809 bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));
810
811 Instruction *det = emit(sw::Shader::OPCODE_DET3, result, outCol, arg, col0, arg, negate ? col2 : col1, arg, negate ? col1 : col2);
812 det->src[0].swizzle = det->src[1].swizzle = det->src[2].swizzle = swizzle[isCofactor ? row : 3];
813 det->dst.mask = 1 << outRow;
814 }
815 break;
816 case 4:
817 {
818 Instruction *det = emit(sw::Shader::OPCODE_DET4, result, outCol, arg, 0, arg, 1, arg, 2, arg, 3);
819 det->dst.mask = 1 << outRow;
820 }
821 break;
822 default:
823 UNREACHABLE(size);
824 break;
825 }
826 }
827
828 bool OutputASM::visitUnary(Visit visit, TIntermUnary *node)
829 {
830 if(currentScope != emitScope)
831 {
832 return false;
833 }
834
835 TIntermTyped *result = node;
836 TIntermTyped *arg = node->getOperand();
837 TBasicType basicType = arg->getType().getBasicType();
838
839 union
840 {
841 float f;
842 int i;
843 } one_value;
844
845 if(basicType == EbtInt || basicType == EbtUInt)
846 {
847 one_value.i = 1;
848 }
849 else
850 {
851 one_value.f = 1.0f;
852 }
853
854 Constant one(one_value.f, one_value.f, one_value.f, one_value.f);
855 Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f);
856 Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f);
857
858 switch(node->getOp())
859 {
860 case EOpNegative:
861 if(visit == PostVisit)
862 {
863 sw::Shader::Opcode negOpcode = getOpcode(sw::Shader::OPCODE_NEG, arg);
864 for(int index = 0; index < arg->totalRegisterCount(); index++)
865 {
866 emit(negOpcode, result, index, arg, index);
867 }
868 }
869 break;
870 case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
871 case EOpLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
Alexis Hetu18e2a972017-07-28 13:43:25 -0400872 case EOpBitwiseNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400873 case EOpPostIncrement:
874 if(visit == PostVisit)
875 {
876 copy(result, arg);
877
878 sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);
879 for(int index = 0; index < arg->totalRegisterCount(); index++)
880 {
881 emit(addOpcode, arg, index, arg, index, &one);
882 }
883
884 assignLvalue(arg, arg);
885 }
886 break;
887 case EOpPostDecrement:
888 if(visit == PostVisit)
889 {
890 copy(result, arg);
891
892 sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);
893 for(int index = 0; index < arg->totalRegisterCount(); index++)
894 {
895 emit(subOpcode, arg, index, arg, index, &one);
896 }
897
898 assignLvalue(arg, arg);
899 }
900 break;
901 case EOpPreIncrement:
902 if(visit == PostVisit)
903 {
904 sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);
905 for(int index = 0; index < arg->totalRegisterCount(); index++)
906 {
907 emit(addOpcode, result, index, arg, index, &one);
908 }
909
910 assignLvalue(arg, result);
911 }
912 break;
913 case EOpPreDecrement:
914 if(visit == PostVisit)
915 {
916 sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);
917 for(int index = 0; index < arg->totalRegisterCount(); index++)
918 {
919 emit(subOpcode, result, index, arg, index, &one);
920 }
921
922 assignLvalue(arg, result);
923 }
924 break;
925 case EOpRadians: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break;
926 case EOpDegrees: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &deg); break;
927 case EOpSin: if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break;
928 case EOpCos: if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break;
929 case EOpTan: if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break;
930 case EOpAsin: if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break;
931 case EOpAcos: if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break;
932 case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break;
933 case EOpSinh: if(visit == PostVisit) emit(sw::Shader::OPCODE_SINH, result, arg); break;
934 case EOpCosh: if(visit == PostVisit) emit(sw::Shader::OPCODE_COSH, result, arg); break;
935 case EOpTanh: if(visit == PostVisit) emit(sw::Shader::OPCODE_TANH, result, arg); break;
936 case EOpAsinh: if(visit == PostVisit) emit(sw::Shader::OPCODE_ASINH, result, arg); break;
937 case EOpAcosh: if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOSH, result, arg); break;
938 case EOpAtanh: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATANH, result, arg); break;
939 case EOpExp: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break;
940 case EOpLog: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break;
941 case EOpExp2: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break;
942 case EOpLog2: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break;
943 case EOpSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break;
944 case EOpInverseSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break;
945 case EOpAbs: if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_ABS, result), result, arg); break;
946 case EOpSign: if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_SGN, result), result, arg); break;
947 case EOpFloor: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break;
948 case EOpTrunc: if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break;
949 case EOpRound: if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUND, result, arg); break;
950 case EOpRoundEven: if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUNDEVEN, result, arg); break;
951 case EOpCeil: if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break;
952 case EOpFract: if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break;
953 case EOpIsNan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ISNAN, result, arg); break;
954 case EOpIsInf: if(visit == PostVisit) emit(sw::Shader::OPCODE_ISINF, result, arg); break;
955 case EOpLength: if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break;
956 case EOpNormalize: if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break;
957 case EOpDFdx: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break;
958 case EOpDFdy: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break;
959 case EOpFwidth: if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break;
960 case EOpAny: if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break;
961 case EOpAll: if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break;
962 case EOpFloatBitsToInt: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOINT, result, arg); break;
963 case EOpFloatBitsToUint: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOUINT, result, arg); break;
964 case EOpIntBitsToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_INTBITSTOFLOAT, result, arg); break;
965 case EOpUintBitsToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_UINTBITSTOFLOAT, result, arg); break;
966 case EOpPackSnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKSNORM2x16, result, arg); break;
967 case EOpPackUnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKUNORM2x16, result, arg); break;
968 case EOpPackHalf2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKHALF2x16, result, arg); break;
969 case EOpUnpackSnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKSNORM2x16, result, arg); break;
970 case EOpUnpackUnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKUNORM2x16, result, arg); break;
971 case EOpUnpackHalf2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKHALF2x16, result, arg); break;
972 case EOpTranspose:
973 if(visit == PostVisit)
974 {
975 int numCols = arg->getNominalSize();
976 int numRows = arg->getSecondarySize();
977 for(int i = 0; i < numCols; ++i)
978 {
979 for(int j = 0; j < numRows; ++j)
980 {
981 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, j, arg, i);
982 mov->src[0].swizzle = 0x55 * j;
983 mov->dst.mask = 1 << i;
984 }
985 }
986 }
987 break;
988 case EOpDeterminant:
989 if(visit == PostVisit)
990 {
991 int size = arg->getNominalSize();
992 ASSERT(size == arg->getSecondarySize());
993
994 emitDeterminant(result, arg, size);
995 }
996 break;
997 case EOpInverse:
998 if(visit == PostVisit)
999 {
1000 int size = arg->getNominalSize();
1001 ASSERT(size == arg->getSecondarySize());
1002
1003 // Compute transposed matrix of cofactors
1004 for(int i = 0; i < size; ++i)
1005 {
1006 for(int j = 0; j < size; ++j)
1007 {
1008 // For a 2x2 matrix, the cofactor is simply a transposed move or negate
1009 // For a 3x3 or 4x4 matrix, the cofactor is a transposed determinant
1010 emitDeterminant(result, arg, size - 1, j, i, i, j);
1011 }
1012 }
1013
1014 // Compute 1 / determinant
1015 Temporary invDet(this);
1016 emitDeterminant(&invDet, arg, size);
1017 Constant one(1.0f, 1.0f, 1.0f, 1.0f);
1018 Instruction *div = emit(sw::Shader::OPCODE_DIV, &invDet, &one, &invDet);
1019 div->src[1].swizzle = 0x00; // xxxx
1020
1021 // Divide transposed matrix of cofactors by determinant
1022 for(int i = 0; i < size; ++i)
1023 {
1024 emit(sw::Shader::OPCODE_MUL, result, i, result, i, &invDet);
1025 }
1026 }
1027 break;
1028 default: UNREACHABLE(node->getOp());
1029 }
1030
1031 return true;
1032 }
1033
1034 bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node)
1035 {
1036 if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence)
1037 {
1038 return false;
1039 }
1040
1041 Constant zero(0.0f, 0.0f, 0.0f, 0.0f);
1042
1043 TIntermTyped *result = node;
1044 const TType &resultType = node->getType();
1045 TIntermSequence &arg = node->getSequence();
1046 size_t argumentCount = arg.size();
1047
1048 switch(node->getOp())
1049 {
1050 case EOpSequence: break;
1051 case EOpDeclaration: break;
1052 case EOpInvariantDeclaration: break;
1053 case EOpPrototype: break;
1054 case EOpComma:
1055 if(visit == PostVisit)
1056 {
1057 copy(result, arg[1]);
1058 }
1059 break;
1060 case EOpFunction:
1061 if(visit == PreVisit)
1062 {
1063 const TString &name = node->getName();
1064
1065 if(emitScope == FUNCTION)
1066 {
1067 if(functionArray.size() > 1) // No need for a label when there's only main()
1068 {
1069 Instruction *label = emit(sw::Shader::OPCODE_LABEL);
1070 label->dst.type = sw::Shader::PARAMETER_LABEL;
1071
1072 const Function *function = findFunction(name);
1073 ASSERT(function); // Should have been added during global pass
1074 label->dst.index = function->label;
1075 currentFunction = function->label;
1076 }
1077 }
1078 else if(emitScope == GLOBAL)
1079 {
1080 if(name != "main(")
1081 {
1082 TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence();
1083 functionArray.push_back(Function(functionArray.size(), name, &arguments, node));
1084 }
1085 }
1086 else UNREACHABLE(emitScope);
1087
1088 currentScope = FUNCTION;
1089 }
1090 else if(visit == PostVisit)
1091 {
1092 if(emitScope == FUNCTION)
1093 {
1094 if(functionArray.size() > 1) // No need to return when there's only main()
1095 {
1096 emit(sw::Shader::OPCODE_RET);
1097 }
1098 }
1099
1100 currentScope = GLOBAL;
1101 }
1102 break;
1103 case EOpFunctionCall:
1104 if(visit == PostVisit)
1105 {
1106 if(node->isUserDefined())
1107 {
1108 const TString &name = node->getName();
1109 const Function *function = findFunction(name);
1110
1111 if(!function)
1112 {
1113 mContext.error(node->getLine(), "function definition not found", name.c_str());
1114 return false;
1115 }
1116
1117 TIntermSequence &arguments = *function->arg;
1118
1119 for(size_t i = 0; i < argumentCount; i++)
1120 {
1121 TIntermTyped *in = arguments[i]->getAsTyped();
1122
1123 if(in->getQualifier() == EvqIn ||
1124 in->getQualifier() == EvqInOut ||
1125 in->getQualifier() == EvqConstReadOnly)
1126 {
1127 copy(in, arg[i]);
1128 }
1129 }
1130
1131 Instruction *call = emit(sw::Shader::OPCODE_CALL);
1132 call->dst.type = sw::Shader::PARAMETER_LABEL;
1133 call->dst.index = function->label;
1134
1135 if(function->ret && function->ret->getType().getBasicType() != EbtVoid)
1136 {
1137 copy(result, function->ret);
1138 }
1139
1140 for(size_t i = 0; i < argumentCount; i++)
1141 {
1142 TIntermTyped *argument = arguments[i]->getAsTyped();
1143 TIntermTyped *out = arg[i]->getAsTyped();
1144
1145 if(argument->getQualifier() == EvqOut ||
1146 argument->getQualifier() == EvqInOut)
1147 {
Nicolas Capens5da2d3f2016-06-11 00:41:49 -04001148 assignLvalue(out, argument);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001149 }
1150 }
1151 }
1152 else
1153 {
1154 const TextureFunction textureFunction(node->getName());
Nicolas Capensa0b57832017-11-07 13:07:53 -05001155 TIntermTyped *s = arg[0]->getAsTyped();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001156 TIntermTyped *t = arg[1]->getAsTyped();
1157
1158 Temporary coord(this);
1159
1160 if(textureFunction.proj)
1161 {
Nicolas Capens0484c792016-06-13 22:02:36 -04001162 Instruction *rcp = emit(sw::Shader::OPCODE_RCPX, &coord, arg[1]);
1163 rcp->src[0].swizzle = 0x55 * (t->getNominalSize() - 1);
1164 rcp->dst.mask = 0x7;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001165
Nicolas Capens0484c792016-06-13 22:02:36 -04001166 Instruction *mul = emit(sw::Shader::OPCODE_MUL, &coord, arg[1], &coord);
1167 mul->dst.mask = 0x7;
Nicolas Capensa0b57832017-11-07 13:07:53 -05001168
1169 if(IsShadowSampler(s->getBasicType()))
1170 {
1171 ASSERT(s->getBasicType() == EbtSampler2DShadow);
1172 Instruction *mov = emit(sw::Shader::OPCODE_MOV, &coord, &coord);
1173 mov->src[0].swizzle = 0xA4;
1174 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001175 }
1176 else
1177 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001178 Instruction *mov = emit(sw::Shader::OPCODE_MOV, &coord, arg[1]);
1179
1180 if(IsShadowSampler(s->getBasicType()) && t->getNominalSize() == 3)
1181 {
1182 ASSERT(s->getBasicType() == EbtSampler2DShadow);
1183 mov->src[0].swizzle = 0xA4;
1184 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001185 }
1186
1187 switch(textureFunction.method)
1188 {
1189 case TextureFunction::IMPLICIT:
Nicolas Capensa0b57832017-11-07 13:07:53 -05001190 if(!textureFunction.offset)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001191 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001192 if(argumentCount == 2)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001193 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001194 emit(sw::Shader::OPCODE_TEX, result, &coord, s);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001195 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001196 else if(argumentCount == 3) // Bias
Nicolas Capens0bac2852016-05-07 06:09:58 -04001197 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001198 emit(sw::Shader::OPCODE_TEXBIAS, result, &coord, s, arg[2]);
1199 }
1200 else UNREACHABLE(argumentCount);
1201 }
1202 else // Offset
1203 {
1204 if(argumentCount == 3)
1205 {
1206 emit(sw::Shader::OPCODE_TEXOFFSET, result, &coord, s, arg[2]);
1207 }
1208 else if(argumentCount == 4) // Bias
1209 {
1210 emit(sw::Shader::OPCODE_TEXOFFSETBIAS, result, &coord, s, arg[2], arg[3]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001211 }
1212 else UNREACHABLE(argumentCount);
1213 }
1214 break;
1215 case TextureFunction::LOD:
Nicolas Capensa0b57832017-11-07 13:07:53 -05001216 if(!textureFunction.offset && argumentCount == 3)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001217 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001218 emit(sw::Shader::OPCODE_TEXLOD, result, &coord, s, arg[2]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001219 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001220 else if(argumentCount == 4) // Offset
1221 {
1222 emit(sw::Shader::OPCODE_TEXLODOFFSET, result, &coord, s, arg[3], arg[2]);
1223 }
1224 else UNREACHABLE(argumentCount);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001225 break;
1226 case TextureFunction::FETCH:
Nicolas Capensa0b57832017-11-07 13:07:53 -05001227 if(!textureFunction.offset && argumentCount == 3)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001228 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001229 emit(sw::Shader::OPCODE_TEXELFETCH, result, &coord, s, arg[2]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001230 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001231 else if(argumentCount == 4) // Offset
1232 {
1233 emit(sw::Shader::OPCODE_TEXELFETCHOFFSET, result, &coord, s, arg[3], arg[2]);
1234 }
1235 else UNREACHABLE(argumentCount);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001236 break;
1237 case TextureFunction::GRAD:
Nicolas Capensa0b57832017-11-07 13:07:53 -05001238 if(!textureFunction.offset && argumentCount == 4)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001239 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001240 emit(sw::Shader::OPCODE_TEXGRAD, result, &coord, s, arg[2], arg[3]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001241 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001242 else if(argumentCount == 5) // Offset
1243 {
1244 emit(sw::Shader::OPCODE_TEXGRADOFFSET, result, &coord, s, arg[2], arg[3], arg[4]);
1245 }
1246 else UNREACHABLE(argumentCount);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001247 break;
1248 case TextureFunction::SIZE:
Nicolas Capensa0b57832017-11-07 13:07:53 -05001249 emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], s);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001250 break;
1251 default:
1252 UNREACHABLE(textureFunction.method);
1253 }
1254 }
1255 }
1256 break;
1257 case EOpParameters:
1258 break;
1259 case EOpConstructFloat:
1260 case EOpConstructVec2:
1261 case EOpConstructVec3:
1262 case EOpConstructVec4:
1263 case EOpConstructBool:
1264 case EOpConstructBVec2:
1265 case EOpConstructBVec3:
1266 case EOpConstructBVec4:
1267 case EOpConstructInt:
1268 case EOpConstructIVec2:
1269 case EOpConstructIVec3:
1270 case EOpConstructIVec4:
1271 case EOpConstructUInt:
1272 case EOpConstructUVec2:
1273 case EOpConstructUVec3:
1274 case EOpConstructUVec4:
1275 if(visit == PostVisit)
1276 {
1277 int component = 0;
Alexis Hetu2a198552016-09-27 20:50:45 -04001278 int arrayMaxIndex = result->isArray() ? result->getArraySize() - 1 : 0;
1279 int arrayComponents = result->getType().getElementSize();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001280 for(size_t i = 0; i < argumentCount; i++)
1281 {
1282 TIntermTyped *argi = arg[i]->getAsTyped();
1283 int size = argi->getNominalSize();
Alexis Hetu2a198552016-09-27 20:50:45 -04001284 int arrayIndex = std::min(component / arrayComponents, arrayMaxIndex);
1285 int swizzle = component - (arrayIndex * arrayComponents);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001286
1287 if(!argi->isMatrix())
1288 {
Alexis Hetu2a198552016-09-27 20:50:45 -04001289 Instruction *mov = emitCast(result, arrayIndex, argi, 0);
1290 mov->dst.mask = (0xF << swizzle) & 0xF;
1291 mov->src[0].swizzle = readSwizzle(argi, size) << (swizzle * 2);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001292
1293 component += size;
1294 }
1295 else // Matrix
1296 {
1297 int column = 0;
1298
1299 while(component < resultType.getNominalSize())
1300 {
Alexis Hetu2a198552016-09-27 20:50:45 -04001301 Instruction *mov = emitCast(result, arrayIndex, argi, column);
1302 mov->dst.mask = (0xF << swizzle) & 0xF;
1303 mov->src[0].swizzle = readSwizzle(argi, size) << (swizzle * 2);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001304
1305 column++;
1306 component += size;
1307 }
1308 }
1309 }
1310 }
1311 break;
1312 case EOpConstructMat2:
1313 case EOpConstructMat2x3:
1314 case EOpConstructMat2x4:
1315 case EOpConstructMat3x2:
1316 case EOpConstructMat3:
1317 case EOpConstructMat3x4:
1318 case EOpConstructMat4x2:
1319 case EOpConstructMat4x3:
1320 case EOpConstructMat4:
1321 if(visit == PostVisit)
1322 {
1323 TIntermTyped *arg0 = arg[0]->getAsTyped();
1324 const int outCols = result->getNominalSize();
1325 const int outRows = result->getSecondarySize();
1326
1327 if(arg0->isScalar() && arg.size() == 1) // Construct scale matrix
1328 {
1329 for(int i = 0; i < outCols; i++)
1330 {
Alexis Hetu7208e932016-06-02 11:19:24 -04001331 emit(sw::Shader::OPCODE_MOV, result, i, &zero);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001332 Instruction *mov = emitCast(result, i, arg0, 0);
1333 mov->dst.mask = 1 << i;
1334 ASSERT(mov->src[0].swizzle == 0x00);
1335 }
1336 }
1337 else if(arg0->isMatrix())
1338 {
Alexis Hetu2a198552016-09-27 20:50:45 -04001339 int arraySize = result->isArray() ? result->getArraySize() : 1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001340
Alexis Hetu2a198552016-09-27 20:50:45 -04001341 for(int n = 0; n < arraySize; n++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001342 {
Alexis Hetu2a198552016-09-27 20:50:45 -04001343 TIntermTyped *argi = arg[n]->getAsTyped();
1344 const int inCols = argi->getNominalSize();
1345 const int inRows = argi->getSecondarySize();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001346
Alexis Hetu2a198552016-09-27 20:50:45 -04001347 for(int i = 0; i < outCols; i++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001348 {
Alexis Hetu2a198552016-09-27 20:50:45 -04001349 if(i >= inCols || outRows > inRows)
1350 {
1351 // Initialize to identity matrix
1352 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));
1353 emitCast(result, i + n * outCols, &col, 0);
1354 }
1355
1356 if(i < inCols)
1357 {
1358 Instruction *mov = emitCast(result, i + n * outCols, argi, i);
1359 mov->dst.mask = 0xF >> (4 - inRows);
1360 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001361 }
1362 }
1363 }
1364 else
1365 {
1366 int column = 0;
1367 int row = 0;
1368
1369 for(size_t i = 0; i < argumentCount; i++)
1370 {
1371 TIntermTyped *argi = arg[i]->getAsTyped();
1372 int size = argi->getNominalSize();
1373 int element = 0;
1374
1375 while(element < size)
1376 {
1377 Instruction *mov = emitCast(result, column, argi, 0);
1378 mov->dst.mask = (0xF << row) & 0xF;
1379 mov->src[0].swizzle = (readSwizzle(argi, size) << (row * 2)) + 0x55 * element;
1380
1381 int end = row + size - element;
1382 column = end >= outRows ? column + 1 : column;
1383 element = element + outRows - row;
1384 row = end >= outRows ? 0 : end;
1385 }
1386 }
1387 }
1388 }
1389 break;
1390 case EOpConstructStruct:
1391 if(visit == PostVisit)
1392 {
1393 int offset = 0;
1394 for(size_t i = 0; i < argumentCount; i++)
1395 {
1396 TIntermTyped *argi = arg[i]->getAsTyped();
1397 int size = argi->totalRegisterCount();
1398
1399 for(int index = 0; index < size; index++)
1400 {
1401 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, index + offset, argi, index);
1402 mov->dst.mask = writeMask(result, offset + index);
1403 }
1404
1405 offset += size;
1406 }
1407 }
1408 break;
1409 case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break;
1410 case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break;
1411 case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break;
1412 case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break;
1413 case EOpVectorEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break;
1414 case EOpVectorNotEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break;
1415 case EOpMod: if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break;
1416 case EOpModf:
1417 if(visit == PostVisit)
1418 {
1419 TIntermTyped* arg1 = arg[1]->getAsTyped();
1420 emit(sw::Shader::OPCODE_TRUNC, arg1, arg[0]);
1421 assignLvalue(arg1, arg1);
1422 emitBinary(sw::Shader::OPCODE_SUB, result, arg[0], arg1);
1423 }
1424 break;
1425 case EOpPow: if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break;
1426 case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break;
1427 case EOpMin: if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, arg[0], arg[1]); break;
1428 case EOpMax: if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]); break;
1429 case EOpClamp:
1430 if(visit == PostVisit)
1431 {
1432 emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]);
1433 emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, result, arg[2]);
1434 }
1435 break;
1436 case EOpMix: if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;
1437 case EOpStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;
1438 case EOpSmoothStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;
1439 case EOpDistance: if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;
1440 case EOpDot: if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break;
1441 case EOpCross: if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break;
1442 case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
1443 case EOpReflect: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break;
1444 case EOpRefract: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
1445 case EOpMul:
1446 if(visit == PostVisit)
1447 {
1448 TIntermTyped *arg0 = arg[0]->getAsTyped();
Alexis Hetue97a31e2016-11-14 14:10:47 -05001449 ASSERT((arg0->getNominalSize() == arg[1]->getAsTyped()->getNominalSize()) &&
1450 (arg0->getSecondarySize() == arg[1]->getAsTyped()->getSecondarySize()));
Nicolas Capens0bac2852016-05-07 06:09:58 -04001451
1452 int size = arg0->getNominalSize();
1453 for(int i = 0; i < size; i++)
1454 {
1455 emit(sw::Shader::OPCODE_MUL, result, i, arg[0], i, arg[1], i);
1456 }
1457 }
1458 break;
1459 case EOpOuterProduct:
1460 if(visit == PostVisit)
1461 {
1462 for(int i = 0; i < dim(arg[1]); i++)
1463 {
1464 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, arg[0], 0, arg[1]);
1465 mul->src[1].swizzle = 0x55 * i;
1466 }
1467 }
1468 break;
1469 default: UNREACHABLE(node->getOp());
1470 }
1471
1472 return true;
1473 }
1474
1475 bool OutputASM::visitSelection(Visit visit, TIntermSelection *node)
1476 {
1477 if(currentScope != emitScope)
1478 {
1479 return false;
1480 }
1481
1482 TIntermTyped *condition = node->getCondition();
1483 TIntermNode *trueBlock = node->getTrueBlock();
1484 TIntermNode *falseBlock = node->getFalseBlock();
1485 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
1486
1487 condition->traverse(this);
1488
1489 if(node->usesTernaryOperator())
1490 {
1491 if(constantCondition)
1492 {
1493 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
1494
1495 if(trueCondition)
1496 {
1497 trueBlock->traverse(this);
1498 copy(node, trueBlock);
1499 }
1500 else
1501 {
1502 falseBlock->traverse(this);
1503 copy(node, falseBlock);
1504 }
1505 }
1506 else if(trivial(node, 6)) // Fast to compute both potential results and no side effects
1507 {
1508 trueBlock->traverse(this);
1509 falseBlock->traverse(this);
1510 emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock);
1511 }
1512 else
1513 {
1514 emit(sw::Shader::OPCODE_IF, 0, condition);
1515
1516 if(trueBlock)
1517 {
1518 trueBlock->traverse(this);
1519 copy(node, trueBlock);
1520 }
1521
1522 if(falseBlock)
1523 {
1524 emit(sw::Shader::OPCODE_ELSE);
1525 falseBlock->traverse(this);
1526 copy(node, falseBlock);
1527 }
1528
1529 emit(sw::Shader::OPCODE_ENDIF);
1530 }
1531 }
1532 else // if/else statement
1533 {
1534 if(constantCondition)
1535 {
1536 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
1537
1538 if(trueCondition)
1539 {
1540 if(trueBlock)
1541 {
1542 trueBlock->traverse(this);
1543 }
1544 }
1545 else
1546 {
1547 if(falseBlock)
1548 {
1549 falseBlock->traverse(this);
1550 }
1551 }
1552 }
1553 else
1554 {
1555 emit(sw::Shader::OPCODE_IF, 0, condition);
1556
1557 if(trueBlock)
1558 {
1559 trueBlock->traverse(this);
1560 }
1561
1562 if(falseBlock)
1563 {
1564 emit(sw::Shader::OPCODE_ELSE);
1565 falseBlock->traverse(this);
1566 }
1567
1568 emit(sw::Shader::OPCODE_ENDIF);
1569 }
1570 }
1571
1572 return false;
1573 }
1574
1575 bool OutputASM::visitLoop(Visit visit, TIntermLoop *node)
1576 {
1577 if(currentScope != emitScope)
1578 {
1579 return false;
1580 }
1581
1582 unsigned int iterations = loopCount(node);
1583
1584 if(iterations == 0)
1585 {
1586 return false;
1587 }
1588
1589 bool unroll = (iterations <= 4);
1590
1591 if(unroll)
1592 {
1593 LoopUnrollable loopUnrollable;
1594 unroll = loopUnrollable.traverse(node);
1595 }
1596
1597 TIntermNode *init = node->getInit();
1598 TIntermTyped *condition = node->getCondition();
1599 TIntermTyped *expression = node->getExpression();
1600 TIntermNode *body = node->getBody();
1601 Constant True(true);
1602
1603 if(node->getType() == ELoopDoWhile)
1604 {
1605 Temporary iterate(this);
1606 emit(sw::Shader::OPCODE_MOV, &iterate, &True);
1607
1608 emit(sw::Shader::OPCODE_WHILE, 0, &iterate); // FIXME: Implement real do-while
1609
1610 if(body)
1611 {
1612 body->traverse(this);
1613 }
1614
1615 emit(sw::Shader::OPCODE_TEST);
1616
1617 condition->traverse(this);
1618 emit(sw::Shader::OPCODE_MOV, &iterate, condition);
1619
1620 emit(sw::Shader::OPCODE_ENDWHILE);
1621 }
1622 else
1623 {
1624 if(init)
1625 {
1626 init->traverse(this);
1627 }
1628
1629 if(unroll)
1630 {
1631 for(unsigned int i = 0; i < iterations; i++)
1632 {
1633 // condition->traverse(this); // Condition could contain statements, but not in an unrollable loop
1634
1635 if(body)
1636 {
1637 body->traverse(this);
1638 }
1639
1640 if(expression)
1641 {
1642 expression->traverse(this);
1643 }
1644 }
1645 }
1646 else
1647 {
1648 if(condition)
1649 {
1650 condition->traverse(this);
1651 }
1652 else
1653 {
1654 condition = &True;
1655 }
1656
1657 emit(sw::Shader::OPCODE_WHILE, 0, condition);
1658
1659 if(body)
1660 {
1661 body->traverse(this);
1662 }
1663
1664 emit(sw::Shader::OPCODE_TEST);
1665
1666 if(expression)
1667 {
1668 expression->traverse(this);
1669 }
1670
1671 if(condition)
1672 {
1673 condition->traverse(this);
1674 }
1675
1676 emit(sw::Shader::OPCODE_ENDWHILE);
1677 }
1678 }
1679
1680 return false;
1681 }
1682
1683 bool OutputASM::visitBranch(Visit visit, TIntermBranch *node)
1684 {
1685 if(currentScope != emitScope)
1686 {
1687 return false;
1688 }
1689
1690 switch(node->getFlowOp())
1691 {
1692 case EOpKill: if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD); break;
1693 case EOpBreak: if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK); break;
1694 case EOpContinue: if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break;
1695 case EOpReturn:
1696 if(visit == PostVisit)
1697 {
1698 TIntermTyped *value = node->getExpression();
1699
1700 if(value)
1701 {
1702 copy(functionArray[currentFunction].ret, value);
1703 }
1704
1705 emit(sw::Shader::OPCODE_LEAVE);
1706 }
1707 break;
1708 default: UNREACHABLE(node->getFlowOp());
1709 }
1710
1711 return true;
1712 }
1713
Alexis Hetu9aa83a92016-05-02 17:34:46 -04001714 bool OutputASM::visitSwitch(Visit visit, TIntermSwitch *node)
1715 {
1716 if(currentScope != emitScope)
1717 {
1718 return false;
1719 }
1720
1721 TIntermTyped* switchValue = node->getInit();
1722 TIntermAggregate* opList = node->getStatementList();
1723
1724 if(!switchValue || !opList)
1725 {
1726 return false;
1727 }
1728
1729 switchValue->traverse(this);
1730
1731 emit(sw::Shader::OPCODE_SWITCH);
1732
1733 TIntermSequence& sequence = opList->getSequence();
1734 TIntermSequence::iterator it = sequence.begin();
1735 TIntermSequence::iterator defaultIt = sequence.end();
1736 int nbCases = 0;
1737 for(; it != sequence.end(); ++it)
1738 {
1739 TIntermCase* currentCase = (*it)->getAsCaseNode();
1740 if(currentCase)
1741 {
1742 TIntermSequence::iterator caseIt = it;
1743
1744 TIntermTyped* condition = currentCase->getCondition();
1745 if(condition) // non default case
1746 {
1747 if(nbCases != 0)
1748 {
1749 emit(sw::Shader::OPCODE_ELSE);
1750 }
1751
1752 condition->traverse(this);
1753 Temporary result(this);
1754 emitBinary(sw::Shader::OPCODE_EQ, &result, switchValue, condition);
1755 emit(sw::Shader::OPCODE_IF, 0, &result);
1756 nbCases++;
1757
1758 for(++caseIt; caseIt != sequence.end(); ++caseIt)
1759 {
1760 (*caseIt)->traverse(this);
1761 if((*caseIt)->getAsBranchNode()) // Kill, Break, Continue or Return
1762 {
1763 break;
1764 }
1765 }
1766 }
1767 else
1768 {
1769 defaultIt = it; // The default case might not be the last case, keep it for last
1770 }
1771 }
1772 }
1773
1774 // If there's a default case, traverse it here
1775 if(defaultIt != sequence.end())
1776 {
1777 emit(sw::Shader::OPCODE_ELSE);
1778 for(++defaultIt; defaultIt != sequence.end(); ++defaultIt)
1779 {
1780 (*defaultIt)->traverse(this);
1781 if((*defaultIt)->getAsBranchNode()) // Kill, Break, Continue or Return
1782 {
1783 break;
1784 }
1785 }
1786 }
1787
1788 for(int i = 0; i < nbCases; ++i)
1789 {
1790 emit(sw::Shader::OPCODE_ENDIF);
1791 }
1792
1793 emit(sw::Shader::OPCODE_ENDSWITCH);
1794
1795 return false;
1796 }
1797
Nicolas Capens0bac2852016-05-07 06:09:58 -04001798 Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, TIntermNode *src3, TIntermNode *src4)
1799 {
1800 return emit(op, dst, 0, src0, 0, src1, 0, src2, 0, src3, 0, src4, 0);
1801 }
1802
1803 Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0, int index0, TIntermNode *src1, int index1,
1804 TIntermNode *src2, int index2, TIntermNode *src3, int index3, TIntermNode *src4, int index4)
1805 {
1806 Instruction *instruction = new Instruction(op);
1807
1808 if(dst)
1809 {
Nicolas Capens0530b452017-11-15 16:39:47 -05001810 destination(instruction->dst, dst, dstIndex);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001811 }
1812
Alexis Hetu929c6b02017-11-07 16:04:25 -05001813 if(src0)
1814 {
1815 TIntermTyped* src = src0->getAsTyped();
1816 instruction->dst.partialPrecision = src && (src->getPrecision() <= EbpLow);
1817 }
1818
Nicolas Capens0530b452017-11-15 16:39:47 -05001819 source(instruction->src[0], src0, index0);
1820 source(instruction->src[1], src1, index1);
1821 source(instruction->src[2], src2, index2);
1822 source(instruction->src[3], src3, index3);
1823 source(instruction->src[4], src4, index4);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001824
1825 shader->append(instruction);
1826
1827 return instruction;
1828 }
1829
1830 Instruction *OutputASM::emitCast(TIntermTyped *dst, TIntermTyped *src)
1831 {
1832 return emitCast(dst, 0, src, 0);
1833 }
1834
1835 Instruction *OutputASM::emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex)
1836 {
1837 switch(src->getBasicType())
1838 {
1839 case EbtBool:
1840 switch(dst->getBasicType())
1841 {
1842 case EbtInt: return emit(sw::Shader::OPCODE_B2I, dst, dstIndex, src, srcIndex);
1843 case EbtUInt: return emit(sw::Shader::OPCODE_B2I, dst, dstIndex, src, srcIndex);
1844 case EbtFloat: return emit(sw::Shader::OPCODE_B2F, dst, dstIndex, src, srcIndex);
1845 default: break;
1846 }
1847 break;
1848 case EbtInt:
1849 switch(dst->getBasicType())
1850 {
1851 case EbtBool: return emit(sw::Shader::OPCODE_I2B, dst, dstIndex, src, srcIndex);
1852 case EbtFloat: return emit(sw::Shader::OPCODE_I2F, dst, dstIndex, src, srcIndex);
1853 default: break;
1854 }
1855 break;
1856 case EbtUInt:
1857 switch(dst->getBasicType())
1858 {
1859 case EbtBool: return emit(sw::Shader::OPCODE_I2B, dst, dstIndex, src, srcIndex);
1860 case EbtFloat: return emit(sw::Shader::OPCODE_U2F, dst, dstIndex, src, srcIndex);
1861 default: break;
1862 }
1863 break;
1864 case EbtFloat:
1865 switch(dst->getBasicType())
1866 {
1867 case EbtBool: return emit(sw::Shader::OPCODE_F2B, dst, dstIndex, src, srcIndex);
1868 case EbtInt: return emit(sw::Shader::OPCODE_F2I, dst, dstIndex, src, srcIndex);
1869 case EbtUInt: return emit(sw::Shader::OPCODE_F2U, dst, dstIndex, src, srcIndex);
1870 default: break;
1871 }
1872 break;
1873 default:
1874 break;
1875 }
1876
1877 ASSERT((src->getBasicType() == dst->getBasicType()) ||
1878 ((src->getBasicType() == EbtInt) && (dst->getBasicType() == EbtUInt)) ||
1879 ((src->getBasicType() == EbtUInt) && (dst->getBasicType() == EbtInt)));
1880
1881 return emit(sw::Shader::OPCODE_MOV, dst, dstIndex, src, srcIndex);
1882 }
1883
1884 void OutputASM::emitBinary(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2)
1885 {
1886 for(int index = 0; index < dst->elementRegisterCount(); index++)
1887 {
1888 emit(op, dst, index, src0, index, src1, index, src2, index);
1889 }
1890 }
1891
1892 void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1)
1893 {
1894 emitBinary(op, result, src0, src1);
1895 assignLvalue(lhs, result);
1896 }
1897
1898 void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index)
1899 {
1900 sw::Shader::Opcode opcode;
1901 switch(left->getAsTyped()->getBasicType())
1902 {
1903 case EbtBool:
1904 case EbtInt:
1905 opcode = sw::Shader::OPCODE_ICMP;
1906 break;
1907 case EbtUInt:
1908 opcode = sw::Shader::OPCODE_UCMP;
1909 break;
1910 default:
1911 opcode = sw::Shader::OPCODE_CMP;
1912 break;
1913 }
1914
1915 Instruction *cmp = emit(opcode, dst, 0, left, index, right, index);
1916 cmp->control = cmpOp;
1917 }
1918
1919 int componentCount(const TType &type, int registers)
1920 {
1921 if(registers == 0)
1922 {
1923 return 0;
1924 }
1925
1926 if(type.isArray() && registers >= type.elementRegisterCount())
1927 {
1928 int index = registers / type.elementRegisterCount();
1929 registers -= index * type.elementRegisterCount();
1930 return index * type.getElementSize() + componentCount(type, registers);
1931 }
1932
1933 if(type.isStruct() || type.isInterfaceBlock())
1934 {
1935 const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
1936 int elements = 0;
1937
1938 for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
1939 {
1940 const TType &fieldType = *((*field)->type());
1941
1942 if(fieldType.totalRegisterCount() <= registers)
1943 {
1944 registers -= fieldType.totalRegisterCount();
1945 elements += fieldType.getObjectSize();
1946 }
1947 else // Register within this field
1948 {
1949 return elements + componentCount(fieldType, registers);
1950 }
1951 }
1952 }
1953 else if(type.isMatrix())
1954 {
1955 return registers * type.registerSize();
1956 }
1957
1958 UNREACHABLE(0);
1959 return 0;
1960 }
1961
1962 int registerSize(const TType &type, int registers)
1963 {
1964 if(registers == 0)
1965 {
1966 if(type.isStruct())
1967 {
1968 return registerSize(*((*(type.getStruct()->fields().begin()))->type()), 0);
1969 }
1970 else if(type.isInterfaceBlock())
1971 {
1972 return registerSize(*((*(type.getInterfaceBlock()->fields().begin()))->type()), 0);
1973 }
1974
1975 return type.registerSize();
1976 }
1977
1978 if(type.isArray() && registers >= type.elementRegisterCount())
1979 {
1980 int index = registers / type.elementRegisterCount();
1981 registers -= index * type.elementRegisterCount();
1982 return registerSize(type, registers);
1983 }
1984
1985 if(type.isStruct() || type.isInterfaceBlock())
1986 {
1987 const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
1988 int elements = 0;
1989
1990 for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
1991 {
1992 const TType &fieldType = *((*field)->type());
1993
1994 if(fieldType.totalRegisterCount() <= registers)
1995 {
1996 registers -= fieldType.totalRegisterCount();
1997 elements += fieldType.getObjectSize();
1998 }
1999 else // Register within this field
2000 {
2001 return registerSize(fieldType, registers);
2002 }
2003 }
2004 }
2005 else if(type.isMatrix())
2006 {
2007 return registerSize(type, 0);
2008 }
2009
2010 UNREACHABLE(0);
2011 return 0;
2012 }
2013
2014 int OutputASM::getBlockId(TIntermTyped *arg)
2015 {
2016 if(arg)
2017 {
2018 const TType &type = arg->getType();
2019 TInterfaceBlock* block = type.getInterfaceBlock();
2020 if(block && (type.getQualifier() == EvqUniform))
2021 {
2022 // Make sure the uniform block is declared
2023 uniformRegister(arg);
2024
2025 const char* blockName = block->name().c_str();
2026
2027 // Fetch uniform block index from array of blocks
2028 for(ActiveUniformBlocks::const_iterator it = shaderObject->activeUniformBlocks.begin(); it != shaderObject->activeUniformBlocks.end(); ++it)
2029 {
2030 if(blockName == it->name)
2031 {
2032 return it->blockId;
2033 }
2034 }
2035
2036 ASSERT(false);
2037 }
2038 }
2039
2040 return -1;
2041 }
2042
2043 OutputASM::ArgumentInfo OutputASM::getArgumentInfo(TIntermTyped *arg, int index)
2044 {
2045 const TType &type = arg->getType();
2046 int blockId = getBlockId(arg);
2047 ArgumentInfo argumentInfo(BlockMemberInfo::getDefaultBlockInfo(), type, -1, -1);
2048 if(blockId != -1)
2049 {
2050 argumentInfo.bufferIndex = 0;
2051 for(int i = 0; i < blockId; ++i)
2052 {
2053 int blockArraySize = shaderObject->activeUniformBlocks[i].arraySize;
2054 argumentInfo.bufferIndex += blockArraySize > 0 ? blockArraySize : 1;
2055 }
2056
2057 const BlockDefinitionIndexMap& blockDefinition = blockDefinitions[blockId];
2058
2059 BlockDefinitionIndexMap::const_iterator itEnd = blockDefinition.end();
2060 BlockDefinitionIndexMap::const_iterator it = itEnd;
2061
2062 argumentInfo.clampedIndex = index;
2063 if(type.isInterfaceBlock())
2064 {
2065 // Offset index to the beginning of the selected instance
2066 int blockRegisters = type.elementRegisterCount();
2067 int bufferOffset = argumentInfo.clampedIndex / blockRegisters;
2068 argumentInfo.bufferIndex += bufferOffset;
2069 argumentInfo.clampedIndex -= bufferOffset * blockRegisters;
2070 }
2071
2072 int regIndex = registerIndex(arg);
2073 for(int i = regIndex + argumentInfo.clampedIndex; i >= regIndex; --i)
2074 {
2075 it = blockDefinition.find(i);
2076 if(it != itEnd)
2077 {
2078 argumentInfo.clampedIndex -= (i - regIndex);
2079 break;
2080 }
2081 }
2082 ASSERT(it != itEnd);
2083
2084 argumentInfo.typedMemberInfo = it->second;
2085
2086 int registerCount = argumentInfo.typedMemberInfo.type.totalRegisterCount();
2087 argumentInfo.clampedIndex = (argumentInfo.clampedIndex >= registerCount) ? registerCount - 1 : argumentInfo.clampedIndex;
2088 }
2089 else
2090 {
2091 argumentInfo.clampedIndex = (index >= arg->totalRegisterCount()) ? arg->totalRegisterCount() - 1 : index;
2092 }
2093
2094 return argumentInfo;
2095 }
2096
Nicolas Capens0530b452017-11-15 16:39:47 -05002097 void OutputASM::source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002098 {
2099 if(argument)
2100 {
2101 TIntermTyped *arg = argument->getAsTyped();
2102 Temporary unpackedUniform(this);
2103
2104 const TType& srcType = arg->getType();
2105 TInterfaceBlock* srcBlock = srcType.getInterfaceBlock();
2106 if(srcBlock && (srcType.getQualifier() == EvqUniform))
2107 {
2108 const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);
2109 const TType &memberType = argumentInfo.typedMemberInfo.type;
2110
2111 if(memberType.getBasicType() == EbtBool)
2112 {
Alexis Hetue97a31e2016-11-14 14:10:47 -05002113 ASSERT(argumentInfo.clampedIndex < (memberType.isArray() ? memberType.getArraySize() : 1)); // index < arraySize
Nicolas Capens0bac2852016-05-07 06:09:58 -04002114
2115 // Convert the packed bool, which is currently an int, to a true bool
2116 Instruction *instruction = new Instruction(sw::Shader::OPCODE_I2B);
2117 instruction->dst.type = sw::Shader::PARAMETER_TEMP;
2118 instruction->dst.index = registerIndex(&unpackedUniform);
2119 instruction->src[0].type = sw::Shader::PARAMETER_CONST;
2120 instruction->src[0].bufferIndex = argumentInfo.bufferIndex;
2121 instruction->src[0].index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * argumentInfo.typedMemberInfo.arrayStride;
2122
2123 shader->append(instruction);
2124
2125 arg = &unpackedUniform;
2126 index = 0;
2127 }
2128 else if((srcBlock->matrixPacking() == EmpRowMajor) && memberType.isMatrix())
2129 {
2130 int numCols = memberType.getNominalSize();
2131 int numRows = memberType.getSecondarySize();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002132
Alexis Hetue97a31e2016-11-14 14:10:47 -05002133 ASSERT(argumentInfo.clampedIndex < (numCols * (memberType.isArray() ? memberType.getArraySize() : 1))); // index < cols * arraySize
Nicolas Capens0bac2852016-05-07 06:09:58 -04002134
2135 unsigned int dstIndex = registerIndex(&unpackedUniform);
2136 unsigned int srcSwizzle = (argumentInfo.clampedIndex % numCols) * 0x55;
2137 int arrayIndex = argumentInfo.clampedIndex / numCols;
2138 int matrixStartOffset = argumentInfo.typedMemberInfo.offset + arrayIndex * argumentInfo.typedMemberInfo.arrayStride;
2139
2140 for(int j = 0; j < numRows; ++j)
2141 {
2142 // Transpose the row major matrix
2143 Instruction *instruction = new Instruction(sw::Shader::OPCODE_MOV);
2144 instruction->dst.type = sw::Shader::PARAMETER_TEMP;
2145 instruction->dst.index = dstIndex;
2146 instruction->dst.mask = 1 << j;
2147 instruction->src[0].type = sw::Shader::PARAMETER_CONST;
2148 instruction->src[0].bufferIndex = argumentInfo.bufferIndex;
2149 instruction->src[0].index = matrixStartOffset + j * argumentInfo.typedMemberInfo.matrixStride;
2150 instruction->src[0].swizzle = srcSwizzle;
2151
2152 shader->append(instruction);
2153 }
2154
2155 arg = &unpackedUniform;
2156 index = 0;
2157 }
2158 }
2159
2160 const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);
2161 const TType &type = argumentInfo.typedMemberInfo.type;
2162
2163 int size = registerSize(type, argumentInfo.clampedIndex);
2164
2165 parameter.type = registerType(arg);
2166 parameter.bufferIndex = argumentInfo.bufferIndex;
2167
2168 if(arg->getAsConstantUnion() && arg->getAsConstantUnion()->getUnionArrayPointer())
2169 {
2170 int component = componentCount(type, argumentInfo.clampedIndex);
2171 ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();
2172
2173 for(int i = 0; i < 4; i++)
2174 {
2175 if(size == 1) // Replicate
2176 {
2177 parameter.value[i] = constants[component + 0].getAsFloat();
2178 }
2179 else if(i < size)
2180 {
2181 parameter.value[i] = constants[component + i].getAsFloat();
2182 }
2183 else
2184 {
2185 parameter.value[i] = 0.0f;
2186 }
2187 }
2188 }
2189 else
2190 {
2191 parameter.index = registerIndex(arg) + argumentInfo.clampedIndex;
2192
2193 if(parameter.bufferIndex != -1)
2194 {
2195 int stride = (argumentInfo.typedMemberInfo.matrixStride > 0) ? argumentInfo.typedMemberInfo.matrixStride : argumentInfo.typedMemberInfo.arrayStride;
2196 parameter.index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * stride;
2197 }
2198 }
2199
2200 if(!IsSampler(arg->getBasicType()))
2201 {
2202 parameter.swizzle = readSwizzle(arg, size);
2203 }
2204 }
2205 }
2206
Nicolas Capens0530b452017-11-15 16:39:47 -05002207 void OutputASM::destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *arg, int index)
2208 {
2209 parameter.type = registerType(arg);
2210 parameter.index = registerIndex(arg) + index;
Nicolas Capens3ae571e2017-11-16 15:28:14 -05002211 parameter.mask = writeMask(arg, index);
Nicolas Capens0530b452017-11-15 16:39:47 -05002212 }
2213
Nicolas Capens0bac2852016-05-07 06:09:58 -04002214 void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)
2215 {
2216 for(int index = 0; index < dst->totalRegisterCount(); index++)
2217 {
2218 Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, index, src, offset + index);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002219 }
2220 }
2221
2222 int swizzleElement(int swizzle, int index)
2223 {
2224 return (swizzle >> (index * 2)) & 0x03;
2225 }
2226
2227 int swizzleSwizzle(int leftSwizzle, int rightSwizzle)
2228 {
2229 return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) |
2230 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) |
2231 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) |
2232 (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6);
2233 }
2234
2235 void OutputASM::assignLvalue(TIntermTyped *dst, TIntermTyped *src)
2236 {
Nicolas Capens84249fd2017-11-09 11:20:51 -05002237 if((src->isVector() && (!dst->isVector() || (src->getNominalSize() != dst->getNominalSize()))) ||
2238 (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize()) || (src->getSecondarySize() != dst->getSecondarySize()))))
Nicolas Capens0bac2852016-05-07 06:09:58 -04002239 {
2240 return mContext.error(src->getLine(), "Result type should match the l-value type in compound assignment", src->isVector() ? "vector" : "matrix");
2241 }
2242
2243 TIntermBinary *binary = dst->getAsBinaryNode();
2244
2245 if(binary && binary->getOp() == EOpIndexIndirect && binary->getLeft()->isVector() && dst->isScalar())
2246 {
2247 Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);
2248
Nicolas Capens6986b282017-11-16 10:38:19 -05002249 lvalue(insert->dst, dst);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002250
2251 insert->src[0].type = insert->dst.type;
2252 insert->src[0].index = insert->dst.index;
2253 insert->src[0].rel = insert->dst.rel;
Nicolas Capens0530b452017-11-15 16:39:47 -05002254 source(insert->src[1], src);
2255 source(insert->src[2], binary->getRight());
Nicolas Capens0bac2852016-05-07 06:09:58 -04002256
2257 shader->append(insert);
2258 }
2259 else
2260 {
Nicolas Capens84249fd2017-11-09 11:20:51 -05002261 Instruction *mov1 = new Instruction(sw::Shader::OPCODE_MOV);
2262
Nicolas Capens6986b282017-11-16 10:38:19 -05002263 int swizzle = lvalue(mov1->dst, dst);
Nicolas Capens84249fd2017-11-09 11:20:51 -05002264
Nicolas Capens0530b452017-11-15 16:39:47 -05002265 source(mov1->src[0], src);
Nicolas Capens84249fd2017-11-09 11:20:51 -05002266 mov1->src[0].swizzle = swizzleSwizzle(mov1->src[0].swizzle, swizzle);
2267
2268 shader->append(mov1);
2269
2270 for(int offset = 1; offset < dst->totalRegisterCount(); offset++)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002271 {
2272 Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);
2273
Nicolas Capens84249fd2017-11-09 11:20:51 -05002274 mov->dst = mov1->dst;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002275 mov->dst.index += offset;
Nicolas Capens84249fd2017-11-09 11:20:51 -05002276 mov->dst.mask = writeMask(dst, offset);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002277
Nicolas Capens0530b452017-11-15 16:39:47 -05002278 source(mov->src[0], src, offset);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002279
2280 shader->append(mov);
2281 }
2282 }
2283 }
2284
Nicolas Capensd469de22017-11-16 10:42:20 -05002285 void OutputASM::evaluateRvalue(TIntermTyped *node)
2286 {
2287 TIntermBinary *binary = node->getAsBinaryNode();
2288
2289 if(binary && binary->getOp() == EOpIndexIndirect && binary->getLeft()->isVector() && node->isScalar())
2290 {
2291 Instruction *insert = new Instruction(sw::Shader::OPCODE_EXTRACT);
2292
2293 destination(insert->dst, node);
2294
2295 Temporary address(this);
2296 unsigned char mask;
2297 TIntermTyped *root = nullptr;
2298 unsigned int offset = 0;
2299 int swizzle = lvalue(root, offset, insert->src[0].rel, mask, address, node);
2300
2301 source(insert->src[0], root, offset);
2302 insert->src[0].swizzle = swizzleSwizzle(insert->src[0].swizzle, swizzle);
2303
2304 source(insert->src[1], binary->getRight());
2305
2306 shader->append(insert);
2307 }
2308 else
2309 {
2310 Instruction *mov1 = new Instruction(sw::Shader::OPCODE_MOV);
2311
2312 destination(mov1->dst, node, 0);
2313
2314 Temporary address(this);
2315 unsigned char mask;
2316 TIntermTyped *root = nullptr;
2317 unsigned int offset = 0;
2318 int swizzle = lvalue(root, offset, mov1->src[0].rel, mask, address, node);
2319
2320 source(mov1->src[0], root, offset);
2321 mov1->src[0].swizzle = swizzleSwizzle(mov1->src[0].swizzle, swizzle);
2322
2323 shader->append(mov1);
2324
2325 for(int i = 1; i < node->totalRegisterCount(); i++)
2326 {
2327 Instruction *mov = emit(sw::Shader::OPCODE_MOV, node, i, root, offset + i);
2328 mov->src[0].rel = mov1->src[0].rel;
2329 }
2330 }
2331 }
2332
Nicolas Capens6986b282017-11-16 10:38:19 -05002333 int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002334 {
Nicolas Capens6986b282017-11-16 10:38:19 -05002335 Temporary address(this);
Nicolas Capens0530b452017-11-15 16:39:47 -05002336 TIntermTyped *root = nullptr;
2337 unsigned int offset = 0;
2338 unsigned char mask = 0xF;
2339 int swizzle = lvalue(root, offset, dst.rel, mask, address, node);
2340
2341 dst.type = registerType(root);
2342 dst.index = registerIndex(root) + offset;
2343 dst.mask = mask;
2344
2345 return swizzle;
2346 }
2347
2348 int OutputASM::lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node)
2349 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002350 TIntermTyped *result = node;
2351 TIntermBinary *binary = node->getAsBinaryNode();
2352 TIntermSymbol *symbol = node->getAsSymbolNode();
2353
2354 if(binary)
2355 {
2356 TIntermTyped *left = binary->getLeft();
2357 TIntermTyped *right = binary->getRight();
2358
Nicolas Capens0530b452017-11-15 16:39:47 -05002359 int leftSwizzle = lvalue(root, offset, rel, mask, address, left); // Resolve the l-value of the left side
Nicolas Capens0bac2852016-05-07 06:09:58 -04002360
2361 switch(binary->getOp())
2362 {
2363 case EOpIndexDirect:
2364 {
2365 int rightIndex = right->getAsConstantUnion()->getIConst(0);
2366
2367 if(left->isRegister())
2368 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002369 int leftMask = mask;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002370
Nicolas Capens0530b452017-11-15 16:39:47 -05002371 mask = 1;
2372 while((leftMask & mask) == 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002373 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002374 mask = mask << 1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002375 }
2376
2377 int element = swizzleElement(leftSwizzle, rightIndex);
Nicolas Capens0530b452017-11-15 16:39:47 -05002378 mask = 1 << element;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002379
2380 return element;
2381 }
2382 else if(left->isArray() || left->isMatrix())
2383 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002384 offset += rightIndex * result->totalRegisterCount();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002385 return 0xE4;
2386 }
2387 else UNREACHABLE(0);
2388 }
2389 break;
2390 case EOpIndexIndirect:
2391 {
Nicolas Capens84249fd2017-11-09 11:20:51 -05002392 right->traverse(this);
2393
Nicolas Capens0bac2852016-05-07 06:09:58 -04002394 if(left->isRegister())
2395 {
2396 // Requires INSERT instruction (handled by calling function)
2397 }
2398 else if(left->isArray() || left->isMatrix())
2399 {
2400 int scale = result->totalRegisterCount();
2401
Nicolas Capens0530b452017-11-15 16:39:47 -05002402 if(rel.type == sw::Shader::PARAMETER_VOID) // Use the index register as the relative address directly
Nicolas Capens0bac2852016-05-07 06:09:58 -04002403 {
2404 if(left->totalRegisterCount() > 1)
2405 {
2406 sw::Shader::SourceParameter relativeRegister;
Nicolas Capens0530b452017-11-15 16:39:47 -05002407 source(relativeRegister, right);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002408
Nicolas Capens0530b452017-11-15 16:39:47 -05002409 rel.index = relativeRegister.index;
2410 rel.type = relativeRegister.type;
2411 rel.scale = scale;
2412 rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002413 }
2414 }
Nicolas Capens0530b452017-11-15 16:39:47 -05002415 else if(rel.index != registerIndex(&address)) // Move the previous index register to the address register
Nicolas Capens0bac2852016-05-07 06:09:58 -04002416 {
2417 if(scale == 1)
2418 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002419 Constant oldScale((int)rel.scale);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002420 Instruction *mad = emit(sw::Shader::OPCODE_IMAD, &address, &address, &oldScale, right);
Nicolas Capens0530b452017-11-15 16:39:47 -05002421 mad->src[0].index = rel.index;
2422 mad->src[0].type = rel.type;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002423 }
2424 else
2425 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002426 Constant oldScale((int)rel.scale);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002427 Instruction *mul = emit(sw::Shader::OPCODE_IMUL, &address, &address, &oldScale);
Nicolas Capens0530b452017-11-15 16:39:47 -05002428 mul->src[0].index = rel.index;
2429 mul->src[0].type = rel.type;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002430
2431 Constant newScale(scale);
2432 emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
2433 }
2434
Nicolas Capens0530b452017-11-15 16:39:47 -05002435 rel.type = sw::Shader::PARAMETER_TEMP;
2436 rel.index = registerIndex(&address);
2437 rel.scale = 1;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002438 }
2439 else // Just add the new index to the address register
2440 {
2441 if(scale == 1)
2442 {
2443 emit(sw::Shader::OPCODE_IADD, &address, &address, right);
2444 }
2445 else
2446 {
2447 Constant newScale(scale);
2448 emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
2449 }
2450 }
2451 }
2452 else UNREACHABLE(0);
2453 }
2454 break;
2455 case EOpIndexDirectStruct:
2456 case EOpIndexDirectInterfaceBlock:
2457 {
2458 const TFieldList& fields = (binary->getOp() == EOpIndexDirectStruct) ?
2459 left->getType().getStruct()->fields() :
2460 left->getType().getInterfaceBlock()->fields();
2461 int index = right->getAsConstantUnion()->getIConst(0);
2462 int fieldOffset = 0;
2463
2464 for(int i = 0; i < index; i++)
2465 {
2466 fieldOffset += fields[i]->type()->totalRegisterCount();
2467 }
2468
Nicolas Capens0530b452017-11-15 16:39:47 -05002469 offset += fieldOffset;
2470 mask = writeMask(result);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002471
2472 return 0xE4;
2473 }
2474 break;
2475 case EOpVectorSwizzle:
2476 {
2477 ASSERT(left->isRegister());
2478
Nicolas Capens0530b452017-11-15 16:39:47 -05002479 int leftMask = mask;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002480
2481 int swizzle = 0;
2482 int rightMask = 0;
2483
2484 TIntermSequence &sequence = right->getAsAggregate()->getSequence();
2485
2486 for(unsigned int i = 0; i < sequence.size(); i++)
2487 {
2488 int index = sequence[i]->getAsConstantUnion()->getIConst(0);
2489
2490 int element = swizzleElement(leftSwizzle, index);
2491 rightMask = rightMask | (1 << element);
2492 swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);
2493 }
2494
Nicolas Capens0530b452017-11-15 16:39:47 -05002495 mask = leftMask & rightMask;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002496
2497 return swizzle;
2498 }
2499 break;
2500 default:
2501 UNREACHABLE(binary->getOp()); // Not an l-value operator
2502 break;
2503 }
2504 }
2505 else if(symbol)
2506 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002507 root = symbol;
2508 offset = 0;
2509 mask = writeMask(symbol);
2510
2511 return 0xE4;
2512 }
2513 else
2514 {
2515 node->traverse(this);
2516
2517 root = node;
2518 offset = 0;
2519 mask = writeMask(node);
2520
Nicolas Capens0bac2852016-05-07 06:09:58 -04002521 return 0xE4;
2522 }
2523
2524 return 0xE4;
2525 }
2526
2527 sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand)
2528 {
2529 if(isSamplerRegister(operand))
2530 {
2531 return sw::Shader::PARAMETER_SAMPLER;
2532 }
2533
2534 const TQualifier qualifier = operand->getQualifier();
Nicolas Capens0530b452017-11-15 16:39:47 -05002535 if((qualifier == EvqFragColor) || (qualifier == EvqFragData))
Nicolas Capens0bac2852016-05-07 06:09:58 -04002536 {
Nicolas Capens0530b452017-11-15 16:39:47 -05002537 if(((qualifier == EvqFragData) && (outputQualifier == EvqFragColor)) ||
2538 ((qualifier == EvqFragColor) && (outputQualifier == EvqFragData)))
Nicolas Capens0bac2852016-05-07 06:09:58 -04002539 {
2540 mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");
2541 }
2542 outputQualifier = qualifier;
2543 }
2544
2545 if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))
2546 {
2547 return sw::Shader::PARAMETER_TEMP;
2548 }
2549
2550 switch(qualifier)
2551 {
2552 case EvqTemporary: return sw::Shader::PARAMETER_TEMP;
2553 case EvqGlobal: return sw::Shader::PARAMETER_TEMP;
2554 case EvqConstExpr: return sw::Shader::PARAMETER_FLOAT4LITERAL; // All converted to float
2555 case EvqAttribute: return sw::Shader::PARAMETER_INPUT;
2556 case EvqVaryingIn: return sw::Shader::PARAMETER_INPUT;
2557 case EvqVaryingOut: return sw::Shader::PARAMETER_OUTPUT;
2558 case EvqVertexIn: return sw::Shader::PARAMETER_INPUT;
2559 case EvqFragmentOut: return sw::Shader::PARAMETER_COLOROUT;
2560 case EvqVertexOut: return sw::Shader::PARAMETER_OUTPUT;
2561 case EvqFragmentIn: return sw::Shader::PARAMETER_INPUT;
2562 case EvqInvariantVaryingIn: return sw::Shader::PARAMETER_INPUT; // FIXME: Guarantee invariance at the backend
2563 case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT; // FIXME: Guarantee invariance at the backend
2564 case EvqSmooth: return sw::Shader::PARAMETER_OUTPUT;
2565 case EvqFlat: return sw::Shader::PARAMETER_OUTPUT;
2566 case EvqCentroidOut: return sw::Shader::PARAMETER_OUTPUT;
2567 case EvqSmoothIn: return sw::Shader::PARAMETER_INPUT;
2568 case EvqFlatIn: return sw::Shader::PARAMETER_INPUT;
2569 case EvqCentroidIn: return sw::Shader::PARAMETER_INPUT;
2570 case EvqUniform: return sw::Shader::PARAMETER_CONST;
2571 case EvqIn: return sw::Shader::PARAMETER_TEMP;
2572 case EvqOut: return sw::Shader::PARAMETER_TEMP;
2573 case EvqInOut: return sw::Shader::PARAMETER_TEMP;
2574 case EvqConstReadOnly: return sw::Shader::PARAMETER_TEMP;
2575 case EvqPosition: return sw::Shader::PARAMETER_OUTPUT;
2576 case EvqPointSize: return sw::Shader::PARAMETER_OUTPUT;
2577 case EvqInstanceID: return sw::Shader::PARAMETER_MISCTYPE;
Alexis Hetu877ddfc2017-07-25 17:48:00 -04002578 case EvqVertexID: return sw::Shader::PARAMETER_MISCTYPE;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002579 case EvqFragCoord: return sw::Shader::PARAMETER_MISCTYPE;
2580 case EvqFrontFacing: return sw::Shader::PARAMETER_MISCTYPE;
2581 case EvqPointCoord: return sw::Shader::PARAMETER_INPUT;
2582 case EvqFragColor: return sw::Shader::PARAMETER_COLOROUT;
2583 case EvqFragData: return sw::Shader::PARAMETER_COLOROUT;
2584 case EvqFragDepth: return sw::Shader::PARAMETER_DEPTHOUT;
2585 default: UNREACHABLE(qualifier);
2586 }
2587
2588 return sw::Shader::PARAMETER_VOID;
2589 }
2590
Alexis Hetu12b00502016-05-20 13:01:11 -04002591 bool OutputASM::hasFlatQualifier(TIntermTyped *operand)
2592 {
2593 const TQualifier qualifier = operand->getQualifier();
2594 return qualifier == EvqFlat || qualifier == EvqFlatOut || qualifier == EvqFlatIn;
2595 }
2596
Nicolas Capens0bac2852016-05-07 06:09:58 -04002597 unsigned int OutputASM::registerIndex(TIntermTyped *operand)
2598 {
2599 if(isSamplerRegister(operand))
2600 {
2601 return samplerRegister(operand);
2602 }
2603
2604 switch(operand->getQualifier())
2605 {
2606 case EvqTemporary: return temporaryRegister(operand);
2607 case EvqGlobal: return temporaryRegister(operand);
2608 case EvqConstExpr: return temporaryRegister(operand); // Unevaluated constant expression
2609 case EvqAttribute: return attributeRegister(operand);
2610 case EvqVaryingIn: return varyingRegister(operand);
2611 case EvqVaryingOut: return varyingRegister(operand);
2612 case EvqVertexIn: return attributeRegister(operand);
2613 case EvqFragmentOut: return fragmentOutputRegister(operand);
2614 case EvqVertexOut: return varyingRegister(operand);
2615 case EvqFragmentIn: return varyingRegister(operand);
2616 case EvqInvariantVaryingIn: return varyingRegister(operand);
2617 case EvqInvariantVaryingOut: return varyingRegister(operand);
2618 case EvqSmooth: return varyingRegister(operand);
2619 case EvqFlat: return varyingRegister(operand);
2620 case EvqCentroidOut: return varyingRegister(operand);
2621 case EvqSmoothIn: return varyingRegister(operand);
2622 case EvqFlatIn: return varyingRegister(operand);
2623 case EvqCentroidIn: return varyingRegister(operand);
2624 case EvqUniform: return uniformRegister(operand);
2625 case EvqIn: return temporaryRegister(operand);
2626 case EvqOut: return temporaryRegister(operand);
2627 case EvqInOut: return temporaryRegister(operand);
2628 case EvqConstReadOnly: return temporaryRegister(operand);
2629 case EvqPosition: return varyingRegister(operand);
2630 case EvqPointSize: return varyingRegister(operand);
Alexis Hetu877ddfc2017-07-25 17:48:00 -04002631 case EvqInstanceID: vertexShader->declareInstanceId(); return sw::Shader::InstanceIDIndex;
2632 case EvqVertexID: vertexShader->declareVertexId(); return sw::Shader::VertexIDIndex;
2633 case EvqFragCoord: pixelShader->declareVPos(); return sw::Shader::VPosIndex;
2634 case EvqFrontFacing: pixelShader->declareVFace(); return sw::Shader::VFaceIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002635 case EvqPointCoord: return varyingRegister(operand);
2636 case EvqFragColor: return 0;
2637 case EvqFragData: return fragmentOutputRegister(operand);
2638 case EvqFragDepth: return 0;
2639 default: UNREACHABLE(operand->getQualifier());
2640 }
2641
2642 return 0;
2643 }
2644
2645 int OutputASM::writeMask(TIntermTyped *destination, int index)
2646 {
2647 if(destination->getQualifier() == EvqPointSize)
2648 {
2649 return 0x2; // Point size stored in the y component
2650 }
2651
2652 return 0xF >> (4 - registerSize(destination->getType(), index));
2653 }
2654
2655 int OutputASM::readSwizzle(TIntermTyped *argument, int size)
2656 {
2657 if(argument->getQualifier() == EvqPointSize)
2658 {
2659 return 0x55; // Point size stored in the y component
2660 }
2661
2662 static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4}; // (void), xxxx, xyyy, xyzz, xyzw
2663
2664 return swizzleSize[size];
2665 }
2666
2667 // Conservatively checks whether an expression is fast to compute and has no side effects
2668 bool OutputASM::trivial(TIntermTyped *expression, int budget)
2669 {
2670 if(!expression->isRegister())
2671 {
2672 return false;
2673 }
2674
2675 return cost(expression, budget) >= 0;
2676 }
2677
2678 // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects)
2679 int OutputASM::cost(TIntermNode *expression, int budget)
2680 {
2681 if(budget < 0)
2682 {
2683 return budget;
2684 }
2685
2686 if(expression->getAsSymbolNode())
2687 {
2688 return budget;
2689 }
2690 else if(expression->getAsConstantUnion())
2691 {
2692 return budget;
2693 }
2694 else if(expression->getAsBinaryNode())
2695 {
2696 TIntermBinary *binary = expression->getAsBinaryNode();
2697
2698 switch(binary->getOp())
2699 {
2700 case EOpVectorSwizzle:
2701 case EOpIndexDirect:
2702 case EOpIndexDirectStruct:
2703 case EOpIndexDirectInterfaceBlock:
2704 return cost(binary->getLeft(), budget - 0);
2705 case EOpAdd:
2706 case EOpSub:
2707 case EOpMul:
2708 return cost(binary->getLeft(), cost(binary->getRight(), budget - 1));
2709 default:
2710 return -1;
2711 }
2712 }
2713 else if(expression->getAsUnaryNode())
2714 {
2715 TIntermUnary *unary = expression->getAsUnaryNode();
2716
2717 switch(unary->getOp())
2718 {
2719 case EOpAbs:
2720 case EOpNegative:
2721 return cost(unary->getOperand(), budget - 1);
2722 default:
2723 return -1;
2724 }
2725 }
2726 else if(expression->getAsSelectionNode())
2727 {
2728 TIntermSelection *selection = expression->getAsSelectionNode();
2729
2730 if(selection->usesTernaryOperator())
2731 {
2732 TIntermTyped *condition = selection->getCondition();
2733 TIntermNode *trueBlock = selection->getTrueBlock();
2734 TIntermNode *falseBlock = selection->getFalseBlock();
2735 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
2736
2737 if(constantCondition)
2738 {
2739 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
2740
2741 if(trueCondition)
2742 {
2743 return cost(trueBlock, budget - 0);
2744 }
2745 else
2746 {
2747 return cost(falseBlock, budget - 0);
2748 }
2749 }
2750 else
2751 {
2752 return cost(trueBlock, cost(falseBlock, budget - 2));
2753 }
2754 }
2755 }
2756
2757 return -1;
2758 }
2759
2760 const Function *OutputASM::findFunction(const TString &name)
2761 {
2762 for(unsigned int f = 0; f < functionArray.size(); f++)
2763 {
2764 if(functionArray[f].name == name)
2765 {
2766 return &functionArray[f];
2767 }
2768 }
2769
2770 return 0;
2771 }
2772
2773 int OutputASM::temporaryRegister(TIntermTyped *temporary)
2774 {
2775 return allocate(temporaries, temporary);
2776 }
2777
Alexis Hetu49351232017-11-02 16:00:32 -04002778 void OutputASM::setPixelShaderInputs(const TType& type, int var, bool flat)
2779 {
2780 if(type.isStruct())
2781 {
2782 const TFieldList &fields = type.getStruct()->fields();
2783 int fieldVar = var;
2784 for(size_t i = 0; i < fields.size(); i++)
2785 {
2786 const TType& fieldType = *(fields[i]->type());
2787 setPixelShaderInputs(fieldType, fieldVar, flat);
2788 fieldVar += fieldType.totalRegisterCount();
2789 }
2790 }
2791 else
2792 {
2793 for(int i = 0; i < type.totalRegisterCount(); i++)
2794 {
2795 pixelShader->setInput(var + i, type.registerSize(), sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i, flat));
2796 }
2797 }
2798 }
2799
Nicolas Capens0bac2852016-05-07 06:09:58 -04002800 int OutputASM::varyingRegister(TIntermTyped *varying)
2801 {
2802 int var = lookup(varyings, varying);
2803
2804 if(var == -1)
2805 {
2806 var = allocate(varyings, varying);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002807 int registerCount = varying->totalRegisterCount();
2808
2809 if(pixelShader)
2810 {
Nicolas Capens3b4c93f2016-05-18 12:51:37 -04002811 if((var + registerCount) > sw::MAX_FRAGMENT_INPUTS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002812 {
2813 mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "fragment shader");
2814 return 0;
2815 }
2816
2817 if(varying->getQualifier() == EvqPointCoord)
2818 {
2819 ASSERT(varying->isRegister());
Alexis Hetu49351232017-11-02 16:00:32 -04002820 pixelShader->setInput(var, varying->registerSize(), sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002821 }
2822 else
2823 {
Alexis Hetu49351232017-11-02 16:00:32 -04002824 setPixelShaderInputs(varying->getType(), var, hasFlatQualifier(varying));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002825 }
2826 }
2827 else if(vertexShader)
2828 {
Nicolas Capensec0936c2016-05-18 12:32:02 -04002829 if((var + registerCount) > sw::MAX_VERTEX_OUTPUTS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002830 {
2831 mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "vertex shader");
2832 return 0;
2833 }
2834
2835 if(varying->getQualifier() == EvqPosition)
2836 {
2837 ASSERT(varying->isRegister());
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04002838 vertexShader->setPositionRegister(var);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002839 }
2840 else if(varying->getQualifier() == EvqPointSize)
2841 {
2842 ASSERT(varying->isRegister());
Alexis Hetu02ad0aa2016-08-02 11:18:14 -04002843 vertexShader->setPointSizeRegister(var);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002844 }
2845 else
2846 {
2847 // Semantic indexes for user varyings will be assigned during program link to match the pixel shader
2848 }
2849 }
2850 else UNREACHABLE(0);
2851
2852 declareVarying(varying, var);
2853 }
2854
2855 return var;
2856 }
2857
2858 void OutputASM::declareVarying(TIntermTyped *varying, int reg)
2859 {
2860 if(varying->getQualifier() != EvqPointCoord) // gl_PointCoord does not need linking
2861 {
Alexis Hetu49351232017-11-02 16:00:32 -04002862 TIntermSymbol *symbol = varying->getAsSymbolNode();
2863 declareVarying(varying->getType(), symbol->getSymbol(), reg);
2864 }
2865 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002866
Alexis Hetu49351232017-11-02 16:00:32 -04002867 void OutputASM::declareVarying(const TType &type, const TString &varyingName, int registerIndex)
2868 {
2869 const char *name = varyingName.c_str();
2870 VaryingList &activeVaryings = shaderObject->varyings;
2871
2872 TStructure* structure = type.getStruct();
2873 if(structure)
2874 {
2875 int fieldRegisterIndex = registerIndex;
2876
2877 const TFieldList &fields = type.getStruct()->fields();
2878 for(size_t i = 0; i < fields.size(); i++)
2879 {
2880 const TType& fieldType = *(fields[i]->type());
2881 declareVarying(fieldType, varyingName + "." + fields[i]->name(), fieldRegisterIndex);
2882 if(fieldRegisterIndex >= 0)
2883 {
2884 fieldRegisterIndex += fieldType.totalRegisterCount();
2885 }
2886 }
2887 }
2888 else
2889 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002890 // Check if this varying has been declared before without having a register assigned
2891 for(VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)
2892 {
2893 if(v->name == name)
2894 {
Alexis Hetu49351232017-11-02 16:00:32 -04002895 if(registerIndex >= 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002896 {
Alexis Hetu49351232017-11-02 16:00:32 -04002897 ASSERT(v->reg < 0 || v->reg == registerIndex);
2898 v->reg = registerIndex;
Nicolas Capens0bac2852016-05-07 06:09:58 -04002899 }
2900
2901 return;
2902 }
2903 }
2904
Alexis Hetu49351232017-11-02 16:00:32 -04002905 activeVaryings.push_back(glsl::Varying(glVariableType(type), name, type.getArraySize(), registerIndex, 0));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002906 }
2907 }
2908
2909 int OutputASM::uniformRegister(TIntermTyped *uniform)
2910 {
2911 const TType &type = uniform->getType();
2912 ASSERT(!IsSampler(type.getBasicType()));
2913 TInterfaceBlock *block = type.getAsInterfaceBlock();
2914 TIntermSymbol *symbol = uniform->getAsSymbolNode();
2915 ASSERT(symbol || block);
2916
2917 if(symbol || block)
2918 {
2919 TInterfaceBlock* parentBlock = type.getInterfaceBlock();
2920 bool isBlockMember = (!block && parentBlock);
2921 int index = isBlockMember ? lookup(uniforms, parentBlock) : lookup(uniforms, uniform);
2922
2923 if(index == -1 || isBlockMember)
2924 {
2925 if(index == -1)
2926 {
2927 index = allocate(uniforms, uniform);
2928 }
2929
2930 // Verify if the current uniform is a member of an already declared block
2931 const TString &name = symbol ? symbol->getSymbol() : block->name();
2932 int blockMemberIndex = blockMemberLookup(type, name, index);
2933 if(blockMemberIndex == -1)
2934 {
2935 declareUniform(type, name, index);
2936 }
2937 else
2938 {
2939 index = blockMemberIndex;
2940 }
2941 }
2942
2943 return index;
2944 }
2945
2946 return 0;
2947 }
2948
2949 int OutputASM::attributeRegister(TIntermTyped *attribute)
2950 {
2951 ASSERT(!attribute->isArray());
2952
2953 int index = lookup(attributes, attribute);
2954
2955 if(index == -1)
2956 {
2957 TIntermSymbol *symbol = attribute->getAsSymbolNode();
2958 ASSERT(symbol);
2959
2960 if(symbol)
2961 {
2962 index = allocate(attributes, attribute);
2963 const TType &type = attribute->getType();
2964 int registerCount = attribute->totalRegisterCount();
Alexis Hetub7508b82016-09-22 15:36:45 -04002965 sw::VertexShader::AttribType attribType = sw::VertexShader::ATTRIBTYPE_FLOAT;
2966 switch(type.getBasicType())
2967 {
2968 case EbtInt:
2969 attribType = sw::VertexShader::ATTRIBTYPE_INT;
2970 break;
2971 case EbtUInt:
2972 attribType = sw::VertexShader::ATTRIBTYPE_UINT;
2973 break;
2974 case EbtFloat:
2975 default:
2976 break;
2977 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002978
Nicolas Capensf0aef1a2016-05-18 14:44:21 -04002979 if(vertexShader && (index + registerCount) <= sw::MAX_VERTEX_INPUTS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002980 {
2981 for(int i = 0; i < registerCount; i++)
2982 {
Alexis Hetub7508b82016-09-22 15:36:45 -04002983 vertexShader->setInput(index + i, sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i, false), attribType);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002984 }
2985 }
2986
2987 ActiveAttributes &activeAttributes = shaderObject->activeAttributes;
2988
2989 const char *name = symbol->getSymbol().c_str();
2990 activeAttributes.push_back(Attribute(glVariableType(type), name, type.getArraySize(), type.getLayoutQualifier().location, index));
2991 }
2992 }
2993
2994 return index;
2995 }
2996
2997 int OutputASM::fragmentOutputRegister(TIntermTyped *fragmentOutput)
2998 {
2999 return allocate(fragmentOutputs, fragmentOutput);
3000 }
3001
3002 int OutputASM::samplerRegister(TIntermTyped *sampler)
3003 {
3004 const TType &type = sampler->getType();
3005 ASSERT(IsSampler(type.getBasicType()) || type.isStruct()); // Structures can contain samplers
3006
3007 TIntermSymbol *symbol = sampler->getAsSymbolNode();
3008 TIntermBinary *binary = sampler->getAsBinaryNode();
3009
Nicolas Capensfcb70fd2017-05-17 15:16:51 -04003010 if(symbol)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003011 {
Nicolas Capensfcb70fd2017-05-17 15:16:51 -04003012 switch(type.getQualifier())
3013 {
3014 case EvqUniform:
3015 return samplerRegister(symbol);
3016 case EvqIn:
3017 case EvqConstReadOnly:
3018 // Function arguments are not (uniform) sampler registers
3019 return -1;
3020 default:
3021 UNREACHABLE(type.getQualifier());
3022 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003023 }
3024 else if(binary)
3025 {
3026 TIntermTyped *left = binary->getLeft();
3027 TIntermTyped *right = binary->getRight();
3028 const TType &leftType = left->getType();
3029 int index = right->getAsConstantUnion() ? right->getAsConstantUnion()->getIConst(0) : 0;
3030 int offset = 0;
3031
3032 switch(binary->getOp())
3033 {
3034 case EOpIndexDirect:
3035 ASSERT(left->isArray());
3036 offset = index * leftType.elementRegisterCount();
3037 break;
3038 case EOpIndexDirectStruct:
3039 ASSERT(leftType.isStruct());
3040 {
3041 const TFieldList &fields = leftType.getStruct()->fields();
3042
3043 for(int i = 0; i < index; i++)
3044 {
3045 offset += fields[i]->type()->totalRegisterCount();
3046 }
3047 }
3048 break;
3049 case EOpIndexIndirect: // Indirect indexing produces a temporary, not a sampler register
3050 return -1;
3051 case EOpIndexDirectInterfaceBlock: // Interface blocks can't contain samplers
3052 default:
3053 UNREACHABLE(binary->getOp());
3054 return -1;
3055 }
3056
3057 int base = samplerRegister(left);
3058
3059 if(base < 0)
3060 {
3061 return -1;
3062 }
3063
3064 return base + offset;
3065 }
3066
3067 UNREACHABLE(0);
Nicolas Capensfcb70fd2017-05-17 15:16:51 -04003068 return -1; // Not a (uniform) sampler register
Nicolas Capens0bac2852016-05-07 06:09:58 -04003069 }
3070
3071 int OutputASM::samplerRegister(TIntermSymbol *sampler)
3072 {
3073 const TType &type = sampler->getType();
3074 ASSERT(IsSampler(type.getBasicType()) || type.isStruct()); // Structures can contain samplers
3075
3076 int index = lookup(samplers, sampler);
3077
3078 if(index == -1)
3079 {
3080 index = allocate(samplers, sampler);
3081
3082 if(sampler->getQualifier() == EvqUniform)
3083 {
3084 const char *name = sampler->getSymbol().c_str();
3085 declareUniform(type, name, index);
3086 }
3087 }
3088
3089 return index;
3090 }
3091
3092 bool OutputASM::isSamplerRegister(TIntermTyped *operand)
3093 {
3094 return operand && IsSampler(operand->getBasicType()) && samplerRegister(operand) >= 0;
3095 }
3096
3097 int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)
3098 {
3099 for(unsigned int i = 0; i < list.size(); i++)
3100 {
3101 if(list[i] == variable)
3102 {
3103 return i; // Pointer match
3104 }
3105 }
3106
3107 TIntermSymbol *varSymbol = variable->getAsSymbolNode();
3108 TInterfaceBlock *varBlock = variable->getType().getAsInterfaceBlock();
3109
3110 if(varBlock)
3111 {
3112 for(unsigned int i = 0; i < list.size(); i++)
3113 {
3114 if(list[i])
3115 {
3116 TInterfaceBlock *listBlock = list[i]->getType().getAsInterfaceBlock();
3117
3118 if(listBlock)
3119 {
3120 if(listBlock->name() == varBlock->name())
3121 {
3122 ASSERT(listBlock->arraySize() == varBlock->arraySize());
3123 ASSERT(listBlock->fields() == varBlock->fields());
3124 ASSERT(listBlock->blockStorage() == varBlock->blockStorage());
3125 ASSERT(listBlock->matrixPacking() == varBlock->matrixPacking());
3126
3127 return i;
3128 }
3129 }
3130 }
3131 }
3132 }
3133 else if(varSymbol)
3134 {
3135 for(unsigned int i = 0; i < list.size(); i++)
3136 {
3137 if(list[i])
3138 {
3139 TIntermSymbol *listSymbol = list[i]->getAsSymbolNode();
3140
3141 if(listSymbol)
3142 {
3143 if(listSymbol->getId() == varSymbol->getId())
3144 {
3145 ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol());
3146 ASSERT(listSymbol->getType() == varSymbol->getType());
3147 ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier());
3148
3149 return i;
3150 }
3151 }
3152 }
3153 }
3154 }
3155
3156 return -1;
3157 }
3158
3159 int OutputASM::lookup(VariableArray &list, TInterfaceBlock *block)
3160 {
3161 for(unsigned int i = 0; i < list.size(); i++)
3162 {
3163 if(list[i] && (list[i]->getType().getInterfaceBlock() == block))
3164 {
3165 return i; // Pointer match
3166 }
3167 }
3168 return -1;
3169 }
3170
3171 int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)
3172 {
3173 int index = lookup(list, variable);
3174
3175 if(index == -1)
3176 {
3177 unsigned int registerCount = variable->blockRegisterCount();
3178
3179 for(unsigned int i = 0; i < list.size(); i++)
3180 {
3181 if(list[i] == 0)
3182 {
3183 unsigned int j = 1;
3184 for( ; j < registerCount && (i + j) < list.size(); j++)
3185 {
3186 if(list[i + j] != 0)
3187 {
3188 break;
3189 }
3190 }
3191
3192 if(j == registerCount) // Found free slots
3193 {
3194 for(unsigned int j = 0; j < registerCount; j++)
3195 {
3196 list[i + j] = variable;
3197 }
3198
3199 return i;
3200 }
3201 }
3202 }
3203
3204 index = list.size();
3205
3206 for(unsigned int i = 0; i < registerCount; i++)
3207 {
3208 list.push_back(variable);
3209 }
3210 }
3211
3212 return index;
3213 }
3214
3215 void OutputASM::free(VariableArray &list, TIntermTyped *variable)
3216 {
3217 int index = lookup(list, variable);
3218
3219 if(index >= 0)
3220 {
3221 list[index] = 0;
3222 }
3223 }
3224
3225 int OutputASM::blockMemberLookup(const TType &type, const TString &name, int registerIndex)
3226 {
3227 const TInterfaceBlock *block = type.getInterfaceBlock();
3228
3229 if(block)
3230 {
3231 ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;
3232 const TFieldList& fields = block->fields();
3233 const TString &blockName = block->name();
3234 int fieldRegisterIndex = registerIndex;
3235
3236 if(!type.isInterfaceBlock())
3237 {
3238 // This is a uniform that's part of a block, let's see if the block is already defined
3239 for(size_t i = 0; i < activeUniformBlocks.size(); ++i)
3240 {
3241 if(activeUniformBlocks[i].name == blockName.c_str())
3242 {
3243 // The block is already defined, find the register for the current uniform and return it
3244 for(size_t j = 0; j < fields.size(); j++)
3245 {
3246 const TString &fieldName = fields[j]->name();
3247 if(fieldName == name)
3248 {
3249 return fieldRegisterIndex;
3250 }
3251
3252 fieldRegisterIndex += fields[j]->type()->totalRegisterCount();
3253 }
3254
3255 ASSERT(false);
3256 return fieldRegisterIndex;
3257 }
3258 }
3259 }
3260 }
3261
3262 return -1;
3263 }
3264
3265 void OutputASM::declareUniform(const TType &type, const TString &name, int registerIndex, int blockId, BlockLayoutEncoder* encoder)
3266 {
3267 const TStructure *structure = type.getStruct();
3268 const TInterfaceBlock *block = (type.isInterfaceBlock() || (blockId == -1)) ? type.getInterfaceBlock() : nullptr;
3269
3270 if(!structure && !block)
3271 {
3272 ActiveUniforms &activeUniforms = shaderObject->activeUniforms;
3273 const BlockMemberInfo blockInfo = encoder ? encoder->encodeType(type) : BlockMemberInfo::getDefaultBlockInfo();
3274 if(blockId >= 0)
3275 {
3276 blockDefinitions[blockId][registerIndex] = TypedMemberInfo(blockInfo, type);
3277 shaderObject->activeUniformBlocks[blockId].fields.push_back(activeUniforms.size());
3278 }
3279 int fieldRegisterIndex = encoder ? shaderObject->activeUniformBlocks[blockId].registerIndex + BlockLayoutEncoder::getBlockRegister(blockInfo) : registerIndex;
3280 activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(),
3281 fieldRegisterIndex, blockId, blockInfo));
3282 if(IsSampler(type.getBasicType()))
3283 {
3284 for(int i = 0; i < type.totalRegisterCount(); i++)
3285 {
3286 shader->declareSampler(fieldRegisterIndex + i);
3287 }
3288 }
3289 }
3290 else if(block)
3291 {
3292 ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;
3293 const TFieldList& fields = block->fields();
3294 const TString &blockName = block->name();
3295 int fieldRegisterIndex = registerIndex;
3296 bool isUniformBlockMember = !type.isInterfaceBlock() && (blockId == -1);
3297
3298 blockId = activeUniformBlocks.size();
3299 bool isRowMajor = block->matrixPacking() == EmpRowMajor;
3300 activeUniformBlocks.push_back(UniformBlock(blockName.c_str(), 0, block->arraySize(),
3301 block->blockStorage(), isRowMajor, registerIndex, blockId));
3302 blockDefinitions.push_back(BlockDefinitionIndexMap());
3303
3304 Std140BlockEncoder currentBlockEncoder(isRowMajor);
3305 currentBlockEncoder.enterAggregateType();
3306 for(size_t i = 0; i < fields.size(); i++)
3307 {
3308 const TType &fieldType = *(fields[i]->type());
3309 const TString &fieldName = fields[i]->name();
3310 if(isUniformBlockMember && (fieldName == name))
3311 {
3312 registerIndex = fieldRegisterIndex;
3313 }
3314
3315 const TString uniformName = block->hasInstanceName() ? blockName + "." + fieldName : fieldName;
3316
3317 declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, &currentBlockEncoder);
3318 fieldRegisterIndex += fieldType.totalRegisterCount();
3319 }
3320 currentBlockEncoder.exitAggregateType();
3321 activeUniformBlocks[blockId].dataSize = currentBlockEncoder.getBlockSize();
3322 }
3323 else
3324 {
3325 int fieldRegisterIndex = registerIndex;
3326
3327 const TFieldList& fields = structure->fields();
3328 if(type.isArray() && (structure || type.isInterfaceBlock()))
3329 {
3330 for(int i = 0; i < type.getArraySize(); i++)
3331 {
3332 if(encoder)
3333 {
3334 encoder->enterAggregateType();
3335 }
3336 for(size_t j = 0; j < fields.size(); j++)
3337 {
3338 const TType &fieldType = *(fields[j]->type());
3339 const TString &fieldName = fields[j]->name();
3340 const TString uniformName = name + "[" + str(i) + "]." + fieldName;
3341
3342 declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
3343 fieldRegisterIndex += fieldType.totalRegisterCount();
3344 }
3345 if(encoder)
3346 {
3347 encoder->exitAggregateType();
3348 }
3349 }
3350 }
3351 else
3352 {
3353 if(encoder)
3354 {
3355 encoder->enterAggregateType();
3356 }
3357 for(size_t i = 0; i < fields.size(); i++)
3358 {
3359 const TType &fieldType = *(fields[i]->type());
3360 const TString &fieldName = fields[i]->name();
3361 const TString uniformName = name + "." + fieldName;
3362
3363 declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
3364 fieldRegisterIndex += fieldType.totalRegisterCount();
3365 }
3366 if(encoder)
3367 {
3368 encoder->exitAggregateType();
3369 }
3370 }
3371 }
3372 }
3373
3374 GLenum OutputASM::glVariableType(const TType &type)
3375 {
3376 switch(type.getBasicType())
3377 {
3378 case EbtFloat:
3379 if(type.isScalar())
3380 {
3381 return GL_FLOAT;
3382 }
3383 else if(type.isVector())
3384 {
3385 switch(type.getNominalSize())
3386 {
3387 case 2: return GL_FLOAT_VEC2;
3388 case 3: return GL_FLOAT_VEC3;
3389 case 4: return GL_FLOAT_VEC4;
3390 default: UNREACHABLE(type.getNominalSize());
3391 }
3392 }
3393 else if(type.isMatrix())
3394 {
3395 switch(type.getNominalSize())
3396 {
3397 case 2:
3398 switch(type.getSecondarySize())
3399 {
3400 case 2: return GL_FLOAT_MAT2;
3401 case 3: return GL_FLOAT_MAT2x3;
3402 case 4: return GL_FLOAT_MAT2x4;
3403 default: UNREACHABLE(type.getSecondarySize());
3404 }
3405 case 3:
3406 switch(type.getSecondarySize())
3407 {
3408 case 2: return GL_FLOAT_MAT3x2;
3409 case 3: return GL_FLOAT_MAT3;
3410 case 4: return GL_FLOAT_MAT3x4;
3411 default: UNREACHABLE(type.getSecondarySize());
3412 }
3413 case 4:
3414 switch(type.getSecondarySize())
3415 {
3416 case 2: return GL_FLOAT_MAT4x2;
3417 case 3: return GL_FLOAT_MAT4x3;
3418 case 4: return GL_FLOAT_MAT4;
3419 default: UNREACHABLE(type.getSecondarySize());
3420 }
3421 default: UNREACHABLE(type.getNominalSize());
3422 }
3423 }
3424 else UNREACHABLE(0);
3425 break;
3426 case EbtInt:
3427 if(type.isScalar())
3428 {
3429 return GL_INT;
3430 }
3431 else if(type.isVector())
3432 {
3433 switch(type.getNominalSize())
3434 {
3435 case 2: return GL_INT_VEC2;
3436 case 3: return GL_INT_VEC3;
3437 case 4: return GL_INT_VEC4;
3438 default: UNREACHABLE(type.getNominalSize());
3439 }
3440 }
3441 else UNREACHABLE(0);
3442 break;
3443 case EbtUInt:
3444 if(type.isScalar())
3445 {
3446 return GL_UNSIGNED_INT;
3447 }
3448 else if(type.isVector())
3449 {
3450 switch(type.getNominalSize())
3451 {
3452 case 2: return GL_UNSIGNED_INT_VEC2;
3453 case 3: return GL_UNSIGNED_INT_VEC3;
3454 case 4: return GL_UNSIGNED_INT_VEC4;
3455 default: UNREACHABLE(type.getNominalSize());
3456 }
3457 }
3458 else UNREACHABLE(0);
3459 break;
3460 case EbtBool:
3461 if(type.isScalar())
3462 {
3463 return GL_BOOL;
3464 }
3465 else if(type.isVector())
3466 {
3467 switch(type.getNominalSize())
3468 {
3469 case 2: return GL_BOOL_VEC2;
3470 case 3: return GL_BOOL_VEC3;
3471 case 4: return GL_BOOL_VEC4;
3472 default: UNREACHABLE(type.getNominalSize());
3473 }
3474 }
3475 else UNREACHABLE(0);
3476 break;
3477 case EbtSampler2D:
3478 return GL_SAMPLER_2D;
3479 case EbtISampler2D:
3480 return GL_INT_SAMPLER_2D;
3481 case EbtUSampler2D:
3482 return GL_UNSIGNED_INT_SAMPLER_2D;
3483 case EbtSamplerCube:
3484 return GL_SAMPLER_CUBE;
3485 case EbtISamplerCube:
3486 return GL_INT_SAMPLER_CUBE;
3487 case EbtUSamplerCube:
3488 return GL_UNSIGNED_INT_SAMPLER_CUBE;
3489 case EbtSamplerExternalOES:
3490 return GL_SAMPLER_EXTERNAL_OES;
3491 case EbtSampler3D:
3492 return GL_SAMPLER_3D_OES;
3493 case EbtISampler3D:
3494 return GL_INT_SAMPLER_3D;
3495 case EbtUSampler3D:
3496 return GL_UNSIGNED_INT_SAMPLER_3D;
3497 case EbtSampler2DArray:
3498 return GL_SAMPLER_2D_ARRAY;
3499 case EbtISampler2DArray:
3500 return GL_INT_SAMPLER_2D_ARRAY;
3501 case EbtUSampler2DArray:
3502 return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
3503 case EbtSampler2DShadow:
3504 return GL_SAMPLER_2D_SHADOW;
3505 case EbtSamplerCubeShadow:
3506 return GL_SAMPLER_CUBE_SHADOW;
3507 case EbtSampler2DArrayShadow:
3508 return GL_SAMPLER_2D_ARRAY_SHADOW;
3509 default:
3510 UNREACHABLE(type.getBasicType());
3511 break;
3512 }
3513
3514 return GL_NONE;
3515 }
3516
3517 GLenum OutputASM::glVariablePrecision(const TType &type)
3518 {
3519 if(type.getBasicType() == EbtFloat)
3520 {
3521 switch(type.getPrecision())
3522 {
3523 case EbpHigh: return GL_HIGH_FLOAT;
3524 case EbpMedium: return GL_MEDIUM_FLOAT;
3525 case EbpLow: return GL_LOW_FLOAT;
3526 case EbpUndefined:
3527 // Should be defined as the default precision by the parser
3528 default: UNREACHABLE(type.getPrecision());
3529 }
3530 }
3531 else if(type.getBasicType() == EbtInt)
3532 {
3533 switch(type.getPrecision())
3534 {
3535 case EbpHigh: return GL_HIGH_INT;
3536 case EbpMedium: return GL_MEDIUM_INT;
3537 case EbpLow: return GL_LOW_INT;
3538 case EbpUndefined:
3539 // Should be defined as the default precision by the parser
3540 default: UNREACHABLE(type.getPrecision());
3541 }
3542 }
3543
3544 // Other types (boolean, sampler) don't have a precision
3545 return GL_NONE;
3546 }
3547
3548 int OutputASM::dim(TIntermNode *v)
3549 {
3550 TIntermTyped *vector = v->getAsTyped();
3551 ASSERT(vector && vector->isRegister());
3552 return vector->getNominalSize();
3553 }
3554
3555 int OutputASM::dim2(TIntermNode *m)
3556 {
3557 TIntermTyped *matrix = m->getAsTyped();
3558 ASSERT(matrix && matrix->isMatrix() && !matrix->isArray());
3559 return matrix->getSecondarySize();
3560 }
3561
3562 // Returns ~0u if no loop count could be determined
3563 unsigned int OutputASM::loopCount(TIntermLoop *node)
3564 {
3565 // Parse loops of the form:
3566 // for(int index = initial; index [comparator] limit; index += increment)
3567 TIntermSymbol *index = 0;
3568 TOperator comparator = EOpNull;
3569 int initial = 0;
3570 int limit = 0;
3571 int increment = 0;
3572
3573 // Parse index name and intial value
3574 if(node->getInit())
3575 {
3576 TIntermAggregate *init = node->getInit()->getAsAggregate();
3577
3578 if(init)
3579 {
3580 TIntermSequence &sequence = init->getSequence();
3581 TIntermTyped *variable = sequence[0]->getAsTyped();
3582
Nicolas Capense3f05552017-05-24 10:45:56 -04003583 if(variable && variable->getQualifier() == EvqTemporary && variable->getBasicType() == EbtInt)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003584 {
3585 TIntermBinary *assign = variable->getAsBinaryNode();
3586
Nicolas Capensd0bfd912017-05-24 10:20:24 -04003587 if(assign && assign->getOp() == EOpInitialize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003588 {
3589 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
3590 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
3591
3592 if(symbol && constant)
3593 {
3594 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
3595 {
3596 index = symbol;
3597 initial = constant->getUnionArrayPointer()[0].getIConst();
3598 }
3599 }
3600 }
3601 }
3602 }
3603 }
3604
3605 // Parse comparator and limit value
3606 if(index && node->getCondition())
3607 {
3608 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Alexis Hetu7be70cf2016-05-11 10:56:43 -04003609 TIntermSymbol *left = test ? test->getLeft()->getAsSymbolNode() : nullptr;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003610
Alexis Hetu7be70cf2016-05-11 10:56:43 -04003611 if(left && (left->getId() == index->getId()))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003612 {
3613 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
3614
3615 if(constant)
3616 {
3617 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
3618 {
3619 comparator = test->getOp();
3620 limit = constant->getUnionArrayPointer()[0].getIConst();
3621 }
3622 }
3623 }
3624 }
3625
3626 // Parse increment
3627 if(index && comparator != EOpNull && node->getExpression())
3628 {
3629 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
3630 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
3631
3632 if(binaryTerminal)
3633 {
3634 TOperator op = binaryTerminal->getOp();
3635 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
3636
3637 if(constant)
3638 {
3639 if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
3640 {
3641 int value = constant->getUnionArrayPointer()[0].getIConst();
3642
3643 switch(op)
3644 {
3645 case EOpAddAssign: increment = value; break;
3646 case EOpSubAssign: increment = -value; break;
3647 default: UNIMPLEMENTED();
3648 }
3649 }
3650 }
3651 }
3652 else if(unaryTerminal)
3653 {
3654 TOperator op = unaryTerminal->getOp();
3655
3656 switch(op)
3657 {
3658 case EOpPostIncrement: increment = 1; break;
3659 case EOpPostDecrement: increment = -1; break;
3660 case EOpPreIncrement: increment = 1; break;
3661 case EOpPreDecrement: increment = -1; break;
3662 default: UNIMPLEMENTED();
3663 }
3664 }
3665 }
3666
3667 if(index && comparator != EOpNull && increment != 0)
3668 {
3669 if(comparator == EOpLessThanEqual)
3670 {
3671 comparator = EOpLessThan;
3672 limit += 1;
3673 }
Nicolas Capense3f05552017-05-24 10:45:56 -04003674 else if(comparator == EOpGreaterThanEqual)
3675 {
3676 comparator = EOpLessThan;
3677 limit -= 1;
3678 std::swap(initial, limit);
3679 increment = -increment;
3680 }
3681 else if(comparator == EOpGreaterThan)
3682 {
3683 comparator = EOpLessThan;
3684 std::swap(initial, limit);
3685 increment = -increment;
3686 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003687
3688 if(comparator == EOpLessThan)
3689 {
Nicolas Capens930b7002017-01-06 17:22:13 -05003690 if(!(initial < limit)) // Never loops
Nicolas Capens0bac2852016-05-07 06:09:58 -04003691 {
Nicolas Capens930b7002017-01-06 17:22:13 -05003692 return 0;
3693 }
3694
3695 int iterations = (limit - initial + abs(increment) - 1) / increment; // Ceiling division
3696
3697 if(iterations < 0)
3698 {
3699 return ~0u;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003700 }
3701
3702 return iterations;
3703 }
3704 else UNIMPLEMENTED(); // Falls through
3705 }
3706
3707 return ~0u;
3708 }
3709
3710 bool LoopUnrollable::traverse(TIntermNode *node)
3711 {
3712 loopDepth = 0;
3713 loopUnrollable = true;
3714
3715 node->traverse(this);
3716
3717 return loopUnrollable;
3718 }
3719
3720 bool LoopUnrollable::visitLoop(Visit visit, TIntermLoop *loop)
3721 {
3722 if(visit == PreVisit)
3723 {
3724 loopDepth++;
3725 }
3726 else if(visit == PostVisit)
3727 {
3728 loopDepth++;
3729 }
3730
3731 return true;
3732 }
3733
3734 bool LoopUnrollable::visitBranch(Visit visit, TIntermBranch *node)
3735 {
3736 if(!loopUnrollable)
3737 {
3738 return false;
3739 }
3740
3741 if(!loopDepth)
3742 {
3743 return true;
3744 }
3745
3746 switch(node->getFlowOp())
3747 {
3748 case EOpKill:
3749 case EOpReturn:
3750 break;
3751 case EOpBreak:
3752 case EOpContinue:
3753 loopUnrollable = false;
3754 break;
3755 default: UNREACHABLE(node->getFlowOp());
3756 }
3757
3758 return loopUnrollable;
3759 }
3760
3761 bool LoopUnrollable::visitAggregate(Visit visit, TIntermAggregate *node)
3762 {
3763 return loopUnrollable;
3764 }
3765}