Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #ifndef COMPILER_OUTPUTASM_H_ |
| 16 | #define COMPILER_OUTPUTASM_H_ |
| 17 | |
| 18 | #include "intermediate.h" |
| 19 | #include "ParseHelper.h" |
| 20 | #include "Shader/PixelShader.hpp" |
| 21 | #include "Shader/VertexShader.hpp" |
| 22 | |
| 23 | #include <list> |
| 24 | #include <set> |
| 25 | #include <map> |
| 26 | |
| 27 | namespace es2 |
| 28 | { |
| 29 | class Shader; |
| 30 | } |
| 31 | |
| 32 | typedef unsigned int GLenum; |
| 33 | |
| 34 | namespace glsl |
| 35 | { |
| 36 | struct BlockMemberInfo |
| 37 | { |
| 38 | BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {} |
| 39 | |
| 40 | BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) |
| 41 | : offset(offset), |
| 42 | arrayStride(arrayStride), |
| 43 | matrixStride(matrixStride), |
| 44 | isRowMajorMatrix(isRowMajorMatrix) |
| 45 | {} |
| 46 | |
| 47 | static BlockMemberInfo getDefaultBlockInfo() |
| 48 | { |
| 49 | return BlockMemberInfo(-1, -1, -1, false); |
| 50 | } |
| 51 | |
| 52 | int offset; |
| 53 | int arrayStride; |
| 54 | int matrixStride; |
| 55 | bool isRowMajorMatrix; |
| 56 | }; |
| 57 | |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 58 | struct ShaderVariable |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 59 | { |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 60 | ShaderVariable(const TType& type, const std::string& name, int registerIndex); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 61 | |
| 62 | GLenum type; |
| 63 | GLenum precision; |
| 64 | std::string name; |
| 65 | int arraySize; |
| 66 | |
| 67 | int registerIndex; |
| 68 | |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 69 | std::vector<ShaderVariable> fields; |
| 70 | }; |
| 71 | |
| 72 | struct Uniform : public ShaderVariable |
| 73 | { |
| 74 | Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo); |
| 75 | |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 76 | int blockId; |
| 77 | BlockMemberInfo blockInfo; |
| 78 | }; |
| 79 | |
| 80 | typedef std::vector<Uniform> ActiveUniforms; |
| 81 | |
| 82 | struct UniformBlock |
| 83 | { |
| 84 | UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize, |
| 85 | TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId); |
| 86 | |
| 87 | std::string name; |
| 88 | unsigned int dataSize; |
| 89 | unsigned int arraySize; |
| 90 | TLayoutBlockStorage layout; |
| 91 | bool isRowMajorLayout; |
| 92 | std::vector<int> fields; |
| 93 | |
| 94 | int registerIndex; |
| 95 | |
| 96 | int blockId; |
| 97 | }; |
| 98 | |
| 99 | class BlockLayoutEncoder |
| 100 | { |
| 101 | public: |
Alexis Hetu | d274253 | 2018-01-23 16:53:41 -0500 | [diff] [blame] | 102 | BlockLayoutEncoder(); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 103 | virtual ~BlockLayoutEncoder() {} |
| 104 | |
| 105 | BlockMemberInfo encodeType(const TType &type); |
| 106 | |
| 107 | size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } |
| 108 | |
| 109 | virtual void enterAggregateType() = 0; |
| 110 | virtual void exitAggregateType() = 0; |
| 111 | |
| 112 | static const size_t BytesPerComponent = 4u; |
| 113 | static const unsigned int ComponentsPerRegister = 4u; |
| 114 | |
| 115 | static size_t getBlockRegister(const BlockMemberInfo &info); |
| 116 | static size_t getBlockRegisterElement(const BlockMemberInfo &info); |
| 117 | |
| 118 | protected: |
| 119 | size_t mCurrentOffset; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 120 | |
| 121 | void nextRegister(); |
| 122 | |
| 123 | virtual void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; |
| 124 | virtual void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; |
| 125 | }; |
| 126 | |
| 127 | // Block layout according to the std140 block layout |
| 128 | // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification |
| 129 | class Std140BlockEncoder : public BlockLayoutEncoder |
| 130 | { |
| 131 | public: |
Alexis Hetu | d274253 | 2018-01-23 16:53:41 -0500 | [diff] [blame] | 132 | Std140BlockEncoder(); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 133 | |
| 134 | void enterAggregateType() override; |
| 135 | void exitAggregateType() override; |
| 136 | |
| 137 | protected: |
| 138 | void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; |
| 139 | void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; |
| 140 | }; |
| 141 | |
| 142 | typedef std::vector<UniformBlock> ActiveUniformBlocks; |
| 143 | |
| 144 | struct Attribute |
| 145 | { |
| 146 | Attribute(); |
Nicolas Capens | 378c434 | 2018-08-07 23:57:21 -0400 | [diff] [blame] | 147 | Attribute(GLenum type, const std::string &name, int arraySize, int layoutLocation, int registerIndex); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 148 | |
| 149 | GLenum type; |
| 150 | std::string name; |
| 151 | int arraySize; |
Nicolas Capens | 378c434 | 2018-08-07 23:57:21 -0400 | [diff] [blame] | 152 | int layoutLocation; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 153 | |
| 154 | int registerIndex; |
| 155 | }; |
| 156 | |
| 157 | typedef std::vector<Attribute> ActiveAttributes; |
| 158 | |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 159 | struct Varying : public ShaderVariable |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 160 | { |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 161 | Varying(const TType& type, const std::string &name, int reg = -1, int col = -1) |
Alexis Hetu | c67e57e | 2018-01-09 16:44:59 -0500 | [diff] [blame] | 162 | : ShaderVariable(type, name, reg), qualifier(type.getQualifier()), column(col) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 163 | { |
| 164 | } |
| 165 | |
| 166 | bool isArray() const |
| 167 | { |
| 168 | return arraySize >= 1; |
| 169 | } |
| 170 | |
| 171 | int size() const // Unify with es2::Uniform? |
| 172 | { |
| 173 | return arraySize > 0 ? arraySize : 1; |
| 174 | } |
| 175 | |
Alexis Hetu | 743913c | 2018-01-04 11:54:55 -0500 | [diff] [blame] | 176 | TQualifier qualifier; |
Alexis Hetu | c67e57e | 2018-01-09 16:44:59 -0500 | [diff] [blame] | 177 | int column; // First register element, assigned during link |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 178 | }; |
| 179 | |
| 180 | typedef std::list<Varying> VaryingList; |
| 181 | |
| 182 | class Shader |
| 183 | { |
| 184 | friend class OutputASM; |
| 185 | public: |
Nico Weber | 226e1c6 | 2019-02-20 09:23:05 -0500 | [diff] [blame] | 186 | virtual ~Shader() {} |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 187 | virtual sw::Shader *getShader() const = 0; |
| 188 | virtual sw::PixelShader *getPixelShader() const; |
| 189 | virtual sw::VertexShader *getVertexShader() const; |
Alexis Hetu | 23f54d7 | 2017-12-05 16:03:51 -0500 | [diff] [blame] | 190 | int getShaderVersion() const { return shaderVersion; } |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 191 | |
| 192 | protected: |
| 193 | VaryingList varyings; |
| 194 | ActiveUniforms activeUniforms; |
Alexis Hetu | 924513c | 2018-01-05 15:48:12 -0500 | [diff] [blame] | 195 | ActiveUniforms activeUniformStructs; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 196 | ActiveAttributes activeAttributes; |
| 197 | ActiveUniformBlocks activeUniformBlocks; |
Alexis Hetu | 23f54d7 | 2017-12-05 16:03:51 -0500 | [diff] [blame] | 198 | int shaderVersion; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 199 | }; |
| 200 | |
| 201 | struct Function |
| 202 | { |
| 203 | Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
| 204 | { |
| 205 | } |
| 206 | |
| 207 | Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
| 208 | { |
| 209 | } |
| 210 | |
| 211 | int label; |
| 212 | TString name; |
| 213 | TIntermSequence *arg; |
| 214 | TIntermTyped *ret; |
| 215 | }; |
| 216 | |
| 217 | typedef sw::Shader::Instruction Instruction; |
| 218 | |
| 219 | class Temporary; |
| 220 | |
| 221 | class OutputASM : public TIntermTraverser |
| 222 | { |
| 223 | public: |
| 224 | explicit OutputASM(TParseContext &context, Shader *shaderObject); |
| 225 | ~OutputASM(); |
| 226 | |
| 227 | void output(); |
| 228 | |
| 229 | void freeTemporary(Temporary *temporary); |
| 230 | |
| 231 | private: |
| 232 | enum Scope |
| 233 | { |
| 234 | GLOBAL, |
| 235 | FUNCTION |
| 236 | }; |
| 237 | |
| 238 | struct TextureFunction |
| 239 | { |
| 240 | TextureFunction(const TString& name); |
| 241 | |
| 242 | enum Method |
| 243 | { |
| 244 | IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) |
| 245 | LOD, |
| 246 | SIZE, // textureSize() |
| 247 | FETCH, |
Alexis Hetu | 4676862 | 2018-01-16 22:09:28 -0500 | [diff] [blame] | 248 | GRAD, |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 249 | }; |
| 250 | |
| 251 | Method method; |
| 252 | bool proj; |
| 253 | bool offset; |
| 254 | }; |
| 255 | |
| 256 | void emitShader(Scope scope); |
| 257 | |
| 258 | // Visit AST nodes and output their code to the body stream |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 259 | void visitSymbol(TIntermSymbol*) override; |
| 260 | bool visitBinary(Visit visit, TIntermBinary*) override; |
| 261 | bool visitUnary(Visit visit, TIntermUnary*) override; |
| 262 | bool visitSelection(Visit visit, TIntermSelection*) override; |
| 263 | bool visitAggregate(Visit visit, TIntermAggregate*) override; |
| 264 | bool visitLoop(Visit visit, TIntermLoop*) override; |
| 265 | bool visitBranch(Visit visit, TIntermBranch*) override; |
| 266 | bool visitSwitch(Visit, TIntermSwitch*) override; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 267 | |
| 268 | sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const; |
| 269 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0); |
| 270 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0 = 0, int index0 = 0, TIntermNode *src1 = 0, int index1 = 0, |
| 271 | TIntermNode *src2 = 0, int index2 = 0, TIntermNode *src3 = 0, int index3 = 0, TIntermNode *src4 = 0, int index4 = 0); |
| 272 | Instruction *emitCast(TIntermTyped *dst, TIntermTyped *src); |
| 273 | Instruction *emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex); |
| 274 | void emitBinary(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0); |
| 275 | void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0); |
| 276 | void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0); |
| 277 | void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0); |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 278 | void source(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index = 0); |
| 279 | void destination(sw::Shader::DestinationParameter ¶meter, TIntermTyped *argument, int index = 0); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 280 | void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0); |
| 281 | void assignLvalue(TIntermTyped *dst, TIntermTyped *src); |
Nicolas Capens | d469de2 | 2017-11-16 10:42:20 -0500 | [diff] [blame] | 282 | void evaluateRvalue(TIntermTyped *node); |
Nicolas Capens | 6986b28 | 2017-11-16 10:38:19 -0500 | [diff] [blame] | 283 | int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node); |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 284 | int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 285 | sw::Shader::ParameterType registerType(TIntermTyped *operand); |
Alexis Hetu | 12b0050 | 2016-05-20 13:01:11 -0400 | [diff] [blame] | 286 | bool hasFlatQualifier(TIntermTyped *operand); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 287 | unsigned int registerIndex(TIntermTyped *operand); |
| 288 | int writeMask(TIntermTyped *destination, int index = 0); |
| 289 | int readSwizzle(TIntermTyped *argument, int size); |
| 290 | bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects |
| 291 | int cost(TIntermNode *expression, int budget); |
| 292 | const Function *findFunction(const TString &name); |
| 293 | |
| 294 | int temporaryRegister(TIntermTyped *temporary); |
| 295 | int varyingRegister(TIntermTyped *varying); |
Alexis Hetu | 4935123 | 2017-11-02 16:00:32 -0400 | [diff] [blame] | 296 | void setPixelShaderInputs(const TType& type, int var, bool flat); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 297 | void declareVarying(TIntermTyped *varying, int reg); |
Alexis Hetu | 4935123 | 2017-11-02 16:00:32 -0400 | [diff] [blame] | 298 | void declareVarying(const TType &type, const TString &name, int registerIndex); |
Alexis Hetu | 930df97 | 2018-01-30 16:54:13 -0500 | [diff] [blame] | 299 | void declareFragmentOutput(TIntermTyped *fragmentOutput); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 300 | int uniformRegister(TIntermTyped *uniform); |
| 301 | int attributeRegister(TIntermTyped *attribute); |
| 302 | int fragmentOutputRegister(TIntermTyped *fragmentOutput); |
| 303 | int samplerRegister(TIntermTyped *sampler); |
| 304 | int samplerRegister(TIntermSymbol *sampler); |
| 305 | bool isSamplerRegister(TIntermTyped *operand); |
Sean Risser | 75841d7 | 2019-04-16 16:19:46 -0400 | [diff] [blame] | 306 | bool arrayExceedsLimits(TIntermTyped *operand); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 307 | |
| 308 | typedef std::vector<TIntermTyped*> VariableArray; |
| 309 | |
| 310 | int lookup(VariableArray &list, TIntermTyped *variable); |
| 311 | int lookup(VariableArray &list, TInterfaceBlock *block); |
| 312 | int blockMemberLookup(const TType &type, const TString &name, int registerIndex); |
Sean Risser | 75841d7 | 2019-04-16 16:19:46 -0400 | [diff] [blame] | 313 | // Returns -1 if it fails to allocate variable. |
Alexis Hetu | da163ed | 2018-01-03 16:36:14 -0500 | [diff] [blame] | 314 | int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 315 | void free(VariableArray &list, TIntermTyped *variable); |
| 316 | |
Alexis Hetu | da163ed | 2018-01-03 16:36:14 -0500 | [diff] [blame] | 317 | void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 318 | |
| 319 | static int dim(TIntermNode *v); |
| 320 | static int dim2(TIntermNode *m); |
Nicolas Capens | ac3f2fa | 2018-05-28 12:25:57 -0400 | [diff] [blame] | 321 | |
| 322 | struct LoopInfo |
| 323 | { |
| 324 | LoopInfo(TIntermLoop *node); |
| 325 | |
| 326 | bool isDeterministic() |
| 327 | { |
| 328 | return (iterations != ~0u); |
| 329 | } |
| 330 | |
| 331 | unsigned int iterations = ~0u; |
| 332 | |
| 333 | TIntermSymbol *index = nullptr; |
| 334 | TOperator comparator = EOpNull; |
| 335 | int initial = 0; |
| 336 | int limit = 0; |
| 337 | int increment = 0; |
| 338 | }; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 339 | |
| 340 | Shader *const shaderObject; |
| 341 | sw::Shader *shader; |
| 342 | sw::PixelShader *pixelShader; |
| 343 | sw::VertexShader *vertexShader; |
| 344 | |
| 345 | VariableArray temporaries; |
| 346 | VariableArray uniforms; |
| 347 | VariableArray varyings; |
| 348 | VariableArray attributes; |
| 349 | VariableArray samplers; |
| 350 | VariableArray fragmentOutputs; |
| 351 | |
| 352 | struct TypedMemberInfo : public BlockMemberInfo |
| 353 | { |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 354 | TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {} |
| 355 | TType type; |
| 356 | }; |
| 357 | struct ArgumentInfo |
| 358 | { |
| 359 | ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) : |
| 360 | typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {} |
| 361 | TypedMemberInfo typedMemberInfo; |
| 362 | int clampedIndex; |
| 363 | int bufferIndex; |
| 364 | }; |
| 365 | int getBlockId(TIntermTyped *argument); |
| 366 | ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index); |
| 367 | |
| 368 | typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap; |
| 369 | std::vector<BlockDefinitionIndexMap> blockDefinitions; |
| 370 | |
| 371 | Scope emitScope; |
| 372 | Scope currentScope; |
| 373 | |
| 374 | int currentFunction; |
| 375 | std::vector<Function> functionArray; |
| 376 | |
| 377 | TQualifier outputQualifier; |
| 378 | |
Nicolas Capens | 4b74373 | 2018-05-28 13:22:07 -0400 | [diff] [blame] | 379 | std::set<int> deterministicVariables; |
| 380 | |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 381 | TParseContext &mContext; |
| 382 | }; |
| 383 | |
| 384 | class LoopUnrollable : public TIntermTraverser |
| 385 | { |
| 386 | public: |
Nicolas Capens | 493fc54 | 2018-05-29 17:11:37 -0400 | [diff] [blame] | 387 | bool traverse(TIntermLoop *loop, int loopIndexId); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 388 | |
| 389 | private: |
Nicolas Capens | ac3f2fa | 2018-05-28 12:25:57 -0400 | [diff] [blame] | 390 | void visitSymbol(TIntermSymbol *node) override; |
| 391 | bool visitBinary(Visit visit, TIntermBinary *node) override; |
| 392 | bool visitUnary(Visit visit, TIntermUnary *node) override; |
| 393 | bool visitBranch(Visit visit, TIntermBranch *node) override; |
Nicolas Capens | ac3f2fa | 2018-05-28 12:25:57 -0400 | [diff] [blame] | 394 | bool visitAggregate(Visit visit, TIntermAggregate *node) override; |
| 395 | |
| 396 | bool loopUnrollable; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 397 | |
Nicolas Capens | ac3f2fa | 2018-05-28 12:25:57 -0400 | [diff] [blame] | 398 | int loopIndexId; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 399 | }; |
| 400 | } |
| 401 | |
| 402 | #endif // COMPILER_OUTPUTASM_H_ |