IntermNode_util.cpp (15649B)
1 // 2 // Copyright 2017 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly 7 // meant to be used in AST transforms. 8 9 #include "compiler/translator/tree_util/IntermNode_util.h" 10 11 #include "compiler/translator/FunctionLookup.h" 12 #include "compiler/translator/SymbolTable.h" 13 14 namespace sh 15 { 16 17 namespace 18 { 19 20 const TFunction *LookUpBuiltInFunction(const char *name, 21 const TIntermSequence *arguments, 22 const TSymbolTable &symbolTable, 23 int shaderVersion) 24 { 25 const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments); 26 const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion); 27 if (symbol) 28 { 29 ASSERT(symbol->isFunction()); 30 return static_cast<const TFunction *>(symbol); 31 } 32 return nullptr; 33 } 34 35 } // anonymous namespace 36 37 TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func) 38 { 39 return new TIntermFunctionPrototype(&func); 40 } 41 42 TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, 43 TIntermBlock *functionBody) 44 { 45 return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody); 46 } 47 48 TIntermTyped *CreateZeroNode(const TType &type) 49 { 50 TType constType(type); 51 constType.setQualifier(EvqConst); 52 53 if (!type.isArray() && type.getBasicType() != EbtStruct) 54 { 55 size_t size = constType.getObjectSize(); 56 TConstantUnion *u = new TConstantUnion[size]; 57 for (size_t i = 0; i < size; ++i) 58 { 59 switch (type.getBasicType()) 60 { 61 case EbtFloat: 62 u[i].setFConst(0.0f); 63 break; 64 case EbtInt: 65 u[i].setIConst(0); 66 break; 67 case EbtUInt: 68 u[i].setUConst(0u); 69 break; 70 case EbtBool: 71 u[i].setBConst(false); 72 break; 73 default: 74 // CreateZeroNode is called by ParseContext that keeps parsing even when an 75 // error occurs, so it is possible for CreateZeroNode to be called with 76 // non-basic types. This happens only on error condition but CreateZeroNode 77 // needs to return a value with the correct type to continue the type check. 78 // That's why we handle non-basic type by setting whatever value, we just need 79 // the type to be right. 80 u[i].setIConst(42); 81 break; 82 } 83 } 84 85 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); 86 return node; 87 } 88 89 TIntermSequence arguments; 90 91 if (type.isArray()) 92 { 93 TType elementType(type); 94 elementType.toArrayElementType(); 95 96 size_t arraySize = type.getOutermostArraySize(); 97 for (size_t i = 0; i < arraySize; ++i) 98 { 99 arguments.push_back(CreateZeroNode(elementType)); 100 } 101 } 102 else 103 { 104 ASSERT(type.getBasicType() == EbtStruct); 105 106 const TStructure *structure = type.getStruct(); 107 for (const auto &field : structure->fields()) 108 { 109 arguments.push_back(CreateZeroNode(*field->type())); 110 } 111 } 112 113 return TIntermAggregate::CreateConstructor(constType, &arguments); 114 } 115 116 TIntermConstantUnion *CreateFloatNode(float value, TPrecision precision) 117 { 118 TConstantUnion *u = new TConstantUnion[1]; 119 u[0].setFConst(value); 120 121 TType type(EbtFloat, precision, EvqConst, 1); 122 return new TIntermConstantUnion(u, type); 123 } 124 125 TIntermConstantUnion *CreateVecNode(const float values[], 126 unsigned int vecSize, 127 TPrecision precision) 128 { 129 TConstantUnion *u = new TConstantUnion[vecSize]; 130 for (unsigned int channel = 0; channel < vecSize; ++channel) 131 { 132 u[channel].setFConst(values[channel]); 133 } 134 135 TType type(EbtFloat, precision, EvqConst, static_cast<uint8_t>(vecSize)); 136 return new TIntermConstantUnion(u, type); 137 } 138 139 TIntermConstantUnion *CreateUVecNode(const unsigned int values[], 140 unsigned int vecSize, 141 TPrecision precision) 142 { 143 TConstantUnion *u = new TConstantUnion[vecSize]; 144 for (unsigned int channel = 0; channel < vecSize; ++channel) 145 { 146 u[channel].setUConst(values[channel]); 147 } 148 149 TType type(EbtUInt, precision, EvqConst, static_cast<uint8_t>(vecSize)); 150 return new TIntermConstantUnion(u, type); 151 } 152 153 TIntermConstantUnion *CreateIndexNode(int index) 154 { 155 TConstantUnion *u = new TConstantUnion[1]; 156 u[0].setIConst(index); 157 158 TType type(EbtInt, EbpHigh, EvqConst, 1); 159 return new TIntermConstantUnion(u, type); 160 } 161 162 TIntermConstantUnion *CreateUIntNode(unsigned int value) 163 { 164 TConstantUnion *u = new TConstantUnion[1]; 165 u[0].setUConst(value); 166 167 TType type(EbtUInt, EbpHigh, EvqConst, 1); 168 return new TIntermConstantUnion(u, type); 169 } 170 171 TIntermConstantUnion *CreateBoolNode(bool value) 172 { 173 TConstantUnion *u = new TConstantUnion[1]; 174 u[0].setBConst(value); 175 176 TType type(EbtBool, EbpUndefined, EvqConst, 1); 177 return new TIntermConstantUnion(u, type); 178 } 179 180 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type) 181 { 182 ASSERT(symbolTable != nullptr); 183 // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created 184 // variable. This might need to be done in other places as well. 185 return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal); 186 } 187 188 TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier) 189 { 190 ASSERT(symbolTable != nullptr); 191 if (type->getQualifier() == qualifier) 192 { 193 return CreateTempVariable(symbolTable, type); 194 } 195 TType *typeWithQualifier = new TType(*type); 196 typeWithQualifier->setQualifier(qualifier); 197 return CreateTempVariable(symbolTable, typeWithQualifier); 198 } 199 200 TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable) 201 { 202 ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal); 203 ASSERT(tempVariable->getType().getQualifier() == EvqTemporary || 204 tempVariable->getType().getQualifier() == EvqConst || 205 tempVariable->getType().getQualifier() == EvqGlobal); 206 return new TIntermSymbol(tempVariable); 207 } 208 209 TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable) 210 { 211 TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); 212 tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable)); 213 return tempDeclaration; 214 } 215 216 TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable, 217 TIntermTyped *initializer) 218 { 219 ASSERT(initializer != nullptr); 220 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); 221 TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); 222 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer); 223 tempDeclaration->appendDeclarator(tempInit); 224 return tempDeclaration; 225 } 226 227 TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode) 228 { 229 ASSERT(rightNode != nullptr); 230 TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); 231 return new TIntermBinary(EOpAssign, tempSymbol, rightNode); 232 } 233 234 TVariable *DeclareTempVariable(TSymbolTable *symbolTable, 235 const TType *type, 236 TQualifier qualifier, 237 TIntermDeclaration **declarationOut) 238 { 239 TVariable *variable = CreateTempVariable(symbolTable, type, qualifier); 240 *declarationOut = CreateTempDeclarationNode(variable); 241 return variable; 242 } 243 244 TVariable *DeclareTempVariable(TSymbolTable *symbolTable, 245 TIntermTyped *initializer, 246 TQualifier qualifier, 247 TIntermDeclaration **declarationOut) 248 { 249 TVariable *variable = 250 CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier); 251 *declarationOut = CreateTempInitDeclarationNode(variable, initializer); 252 return variable; 253 } 254 255 std::pair<const TVariable *, const TVariable *> DeclareStructure( 256 TIntermBlock *root, 257 TSymbolTable *symbolTable, 258 TFieldList *fieldList, 259 TQualifier qualifier, 260 const TMemoryQualifier &memoryQualifier, 261 uint32_t arraySize, 262 const ImmutableString &structTypeName, 263 const ImmutableString *structInstanceName) 264 { 265 TStructure *structure = 266 new TStructure(symbolTable, structTypeName, fieldList, SymbolType::AngleInternal); 267 268 auto makeStructureType = [&](bool isStructSpecifier) { 269 TType *structureType = new TType(structure, isStructSpecifier); 270 structureType->setQualifier(qualifier); 271 structureType->setMemoryQualifier(memoryQualifier); 272 if (arraySize > 0) 273 { 274 structureType->makeArray(arraySize); 275 } 276 return structureType; 277 }; 278 279 TIntermSequence insertSequence; 280 281 TVariable *typeVar = new TVariable(symbolTable, kEmptyImmutableString, makeStructureType(true), 282 SymbolType::Empty); 283 insertSequence.push_back(new TIntermDeclaration{typeVar}); 284 285 TVariable *instanceVar = nullptr; 286 if (structInstanceName) 287 { 288 instanceVar = new TVariable(symbolTable, *structInstanceName, makeStructureType(false), 289 SymbolType::AngleInternal); 290 insertSequence.push_back(new TIntermDeclaration{instanceVar}); 291 } 292 293 size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root); 294 root->insertChildNodes(firstFunctionIndex, insertSequence); 295 296 return {typeVar, instanceVar}; 297 } 298 299 const TVariable *DeclareInterfaceBlock(TIntermBlock *root, 300 TSymbolTable *symbolTable, 301 TFieldList *fieldList, 302 TQualifier qualifier, 303 const TLayoutQualifier &layoutQualifier, 304 const TMemoryQualifier &memoryQualifier, 305 uint32_t arraySize, 306 const ImmutableString &blockTypeName, 307 const ImmutableString &blockVariableName) 308 { 309 // Define an interface block. 310 TInterfaceBlock *interfaceBlock = new TInterfaceBlock( 311 symbolTable, blockTypeName, fieldList, layoutQualifier, SymbolType::AngleInternal); 312 313 // Turn the inteface block into a declaration. 314 TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier); 315 interfaceBlockType->setMemoryQualifier(memoryQualifier); 316 if (arraySize > 0) 317 { 318 interfaceBlockType->makeArray(arraySize); 319 } 320 321 TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration; 322 TVariable *interfaceBlockVar = 323 new TVariable(symbolTable, blockVariableName, interfaceBlockType, 324 blockVariableName.empty() ? SymbolType::Empty : SymbolType::AngleInternal); 325 TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar); 326 interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator); 327 328 // Insert the declarations before the first function. 329 TIntermSequence insertSequence; 330 insertSequence.push_back(interfaceBlockDecl); 331 332 size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root); 333 root->insertChildNodes(firstFunctionIndex, insertSequence); 334 335 return interfaceBlockVar; 336 } 337 338 TIntermBlock *EnsureBlock(TIntermNode *node) 339 { 340 if (node == nullptr) 341 return nullptr; 342 TIntermBlock *blockNode = node->getAsBlock(); 343 if (blockNode != nullptr) 344 return blockNode; 345 346 blockNode = new TIntermBlock(); 347 blockNode->setLine(node->getLine()); 348 blockNode->appendStatement(node); 349 return blockNode; 350 } 351 352 TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable) 353 { 354 const TSymbol *symbol = symbolTable.findGlobal(name); 355 ASSERT(symbol && symbol->isVariable()); 356 return new TIntermSymbol(static_cast<const TVariable *>(symbol)); 357 } 358 359 TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name, 360 const TSymbolTable &symbolTable, 361 int shaderVersion) 362 { 363 const TVariable *var = 364 static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion)); 365 ASSERT(var); 366 return new TIntermSymbol(var); 367 } 368 369 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, 370 TIntermSequence *arguments, 371 const TSymbolTable &symbolTable, 372 int shaderVersion) 373 { 374 const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion); 375 ASSERT(fn); 376 TOperator op = fn->getBuiltInOp(); 377 if (BuiltInGroup::IsMath(op) && arguments->size() == 1) 378 { 379 return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn); 380 } 381 return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments); 382 } 383 384 TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, 385 const std::initializer_list<TIntermNode *> &arguments, 386 const TSymbolTable &symbolTable, 387 int shaderVersion) 388 { 389 TIntermSequence argSequence(arguments); 390 return CreateBuiltInFunctionCallNode(name, &argSequence, symbolTable, shaderVersion); 391 } 392 393 TIntermTyped *CreateBuiltInUnaryFunctionCallNode(const char *name, 394 TIntermTyped *argument, 395 const TSymbolTable &symbolTable, 396 int shaderVersion) 397 { 398 return CreateBuiltInFunctionCallNode(name, {argument}, symbolTable, shaderVersion); 399 } 400 401 int GetESSLOrGLSLVersion(ShShaderSpec spec, int esslVersion, int glslVersion) 402 { 403 return IsDesktopGLSpec(spec) ? glslVersion : esslVersion; 404 } 405 406 // Returns true if a block ends in a branch (break, continue, return, etc). This is only correct 407 // after PruneNoOps, because it expects empty blocks after a branch to have been already pruned, 408 // i.e. a block can only end in a branch if its last statement is a branch or is a block ending in 409 // branch. 410 bool EndsInBranch(TIntermBlock *block) 411 { 412 while (block != nullptr) 413 { 414 // Get the last statement of the block. 415 TIntermSequence &statements = *block->getSequence(); 416 if (statements.empty()) 417 { 418 return false; 419 } 420 421 TIntermNode *lastStatement = statements.back(); 422 423 // If it's a branch itself, we have the answer. 424 if (lastStatement->getAsBranchNode()) 425 { 426 return true; 427 } 428 429 // Otherwise, see if it's a block that ends in a branch 430 block = lastStatement->getAsBlock(); 431 } 432 433 return false; 434 } 435 436 } // namespace sh