Commit 9cbc07c3 by Olli Etuaho Committed by Commit Bot

Simplify AST transformations that need to find main

Share code for finding the main function from the AST between InitializeVariables, DeferGlobalInitializers, EmulateGLFragColorBroadcast and UseInterfaceBlockFields. This makes InitializeVariables simpler in particular, as it doesn't need an AST traverser anymore. BUG=angleproject:2033 TEST=angle_unittests, WebGL conformance tests Change-Id: I14c994bbde58a904f6684d2f0b72bd8004f70902 Reviewed-on: https://chromium-review.googlesource.com/501166Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 995c2ed2
......@@ -52,6 +52,8 @@
'compiler/translator/ExpandIntegerPowExpressions.cpp',
'compiler/translator/ExpandIntegerPowExpressions.h',
'compiler/translator/ExtensionBehavior.h',
'compiler/translator/FindMain.cpp',
'compiler/translator/FindMain.h',
'compiler/translator/FindSymbolNode.cpp',
'compiler/translator/FindSymbolNode.h',
'compiler/translator/FlagStd140Structs.cpp',
......
......@@ -903,7 +903,7 @@ bool TCompiler::enforcePackingRestrictions()
return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
}
void TCompiler::initializeGLPosition(TIntermNode *root)
void TCompiler::initializeGLPosition(TIntermBlock *root)
{
InitVariableList list;
sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
......@@ -912,7 +912,7 @@ void TCompiler::initializeGLPosition(TIntermNode *root)
InitializeVariables(root, list, symbolTable);
}
void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
{
sh::InterfaceBlockList list;
......@@ -928,7 +928,7 @@ void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
sh::UseInterfaceBlockFields(root, list, symbolTable);
}
void TCompiler::initializeOutputVariables(TIntermNode *root)
void TCompiler::initializeOutputVariables(TIntermBlock *root)
{
InitVariableList list;
if (shaderType == GL_VERTEX_SHADER)
......
......@@ -146,15 +146,15 @@ class TCompiler : public TShHandleBase
// Insert statements to reference all members in unused uniform blocks with standard and shared
// layout. This is to work around a Mac driver that treats unused standard/shared
// uniform blocks as inactive.
void useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root);
void useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root);
// Insert statements to initialize output variables in the beginning of main().
// This is to avoid undefined behaviors.
void initializeOutputVariables(TIntermNode *root);
void initializeOutputVariables(TIntermBlock *root);
// Insert gl_Position = vec4(0,0,0,0) to the beginning of main().
// It is to work around a Linux driver bug where missing this causes compile failure
// while spec says it is allowed.
// This function should only be applied to vertex shaders.
void initializeGLPosition(TIntermNode *root);
void initializeGLPosition(TIntermBlock *root);
// Return true if the maximum expression complexity is below the limit.
bool limitExpressionComplexity(TIntermNode *root);
// Get built-in extensions with default behavior.
......
......@@ -12,6 +12,7 @@
#include "compiler/translator/DeferGlobalInitializers.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
......@@ -116,19 +117,14 @@ void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
root->getSequence()->push_back(functionDefinition);
// Insert call into main function
for (TIntermNode *node : *root->getSequence())
{
TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain())
{
TIntermAggregate *functionCallNode = CreateInternalFunctionCallNode(
TType(EbtVoid), functionName, initFunctionId, nullptr);
TIntermBlock *mainBody = nodeFunction->getBody();
ASSERT(mainBody != nullptr);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), functionCallNode);
}
}
TIntermFunctionDefinition *main = FindMain(root);
ASSERT(main != nullptr);
TIntermAggregate *functionCallNode =
CreateInternalFunctionCallNode(TType(EbtVoid), functionName, initFunctionId, nullptr);
TIntermBlock *mainBody = main->getBody();
ASSERT(mainBody != nullptr);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), functionCallNode);
}
} // namespace
......
......@@ -12,6 +12,8 @@
//
#include "compiler/translator/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
namespace sh
......@@ -25,25 +27,22 @@ class GLFragColorBroadcastTraverser : public TIntermTraverser
public:
GLFragColorBroadcastTraverser(int maxDrawBuffers)
: TIntermTraverser(true, false, false),
mMainSequence(nullptr),
mGLFragColorUsed(false),
mMaxDrawBuffers(maxDrawBuffers)
{
}
void broadcastGLFragColor();
void broadcastGLFragColor(TIntermBlock *root);
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
protected:
void visitSymbol(TIntermSymbol *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
TIntermBinary *constructGLFragDataNode(int index) const;
TIntermBinary *constructGLFragDataAssignNode(int index) const;
private:
TIntermSequence *mMainSequence;
bool mGLFragColorUsed;
int mMaxDrawBuffers;
};
......@@ -77,40 +76,27 @@ void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
}
}
bool GLFragColorBroadcastTraverser::visitFunctionDefinition(Visit visit,
TIntermFunctionDefinition *node)
{
ASSERT(visit == PreVisit);
if (node->getFunctionSymbolInfo()->isMain())
{
TIntermBlock *body = node->getBody();
ASSERT(body);
mMainSequence = body->getSequence();
}
return true;
}
void GLFragColorBroadcastTraverser::broadcastGLFragColor()
void GLFragColorBroadcastTraverser::broadcastGLFragColor(TIntermBlock *root)
{
ASSERT(mMaxDrawBuffers > 1);
if (!mGLFragColorUsed)
{
return;
}
ASSERT(mMainSequence);
TIntermSequence *mainSequence = FindMain(root)->getBody()->getSequence();
// Now insert statements
// gl_FragData[1] = gl_FragData[0];
// ...
// gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
{
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
mainSequence->insert(mainSequence->end(), constructGLFragDataAssignNode(colorIndex));
}
}
} // namespace anonymous
void EmulateGLFragColorBroadcast(TIntermNode *root,
void EmulateGLFragColorBroadcast(TIntermBlock *root,
int maxDrawBuffers,
std::vector<sh::OutputVariable> *outputVariables)
{
......@@ -120,7 +106,7 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
if (traverser.isGLFragColorUsed())
{
traverser.updateTree();
traverser.broadcastGLFragColor();
traverser.broadcastGLFragColor(root);
for (auto &var : *outputVariables)
{
if (var.name == "gl_FragColor")
......
......@@ -15,12 +15,12 @@
namespace sh
{
struct OutputVariable;
class TIntermNode;
class TIntermBlock;
// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function,
// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0].
// If gl_FragColor is in outputVariables, it is replaced by gl_FragData.
void EmulateGLFragColorBroadcast(TIntermNode *root,
void EmulateGLFragColorBroadcast(TIntermBlock *root,
int maxDrawBuffers,
std::vector<OutputVariable> *outputVariables);
}
......
//
// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FindMain.cpp: Find the main() function definition in a given AST.
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
namespace sh
{
TIntermFunctionDefinition *FindMain(TIntermBlock *root)
{
for (TIntermNode *node : *root->getSequence())
{
TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain())
{
return nodeFunction;
}
}
return nullptr;
}
} // namespace sh
//
// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FindMain.h: Find the main() function definition in a given AST.
#ifndef COMPILER_TRANSLATOR_FINDMAIN_H_
#define COMPILER_TRANSLATOR_FINDMAIN_H_
namespace sh
{
class TIntermBlock;
class TIntermFunctionDefinition;
TIntermFunctionDefinition *FindMain(TIntermBlock *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_FINDMAIN_H_
\ No newline at end of file
......@@ -8,6 +8,7 @@
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
......@@ -18,54 +19,11 @@ namespace sh
namespace
{
class VariableInitializer : public TIntermTraverser
void InsertInitCode(TIntermSequence *sequence,
const InitVariableList &variables,
const TSymbolTable &symbolTable)
{
public:
VariableInitializer(const InitVariableList &vars, const TSymbolTable &symbolTable)
: TIntermTraverser(true, false, false),
mVariables(vars),
mSymbolTable(symbolTable),
mCodeInserted(false)
{
ASSERT(mSymbolTable.atGlobalLevel());
}
protected:
bool visitBinary(Visit, TIntermBinary *node) override { return false; }
bool visitUnary(Visit, TIntermUnary *node) override { return false; }
bool visitIfElse(Visit, TIntermIfElse *node) override { return false; }
bool visitLoop(Visit, TIntermLoop *node) override { return false; }
bool visitBranch(Visit, TIntermBranch *node) override { return false; }
bool visitAggregate(Visit, TIntermAggregate *node) override { return false; }
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
const InitVariableList &mVariables;
const TSymbolTable &mSymbolTable;
bool mCodeInserted;
};
// VariableInitializer implementation.
bool VariableInitializer::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
// Function definition.
ASSERT(visit == PreVisit);
if (node->getFunctionSymbolInfo()->isMain())
{
TIntermBlock *body = node->getBody();
insertInitCode(body->getSequence());
mCodeInserted = true;
}
return false;
}
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
for (const auto &var : mVariables)
for (const auto &var : variables)
{
TString name = TString(var.name.c_str());
......@@ -102,7 +60,7 @@ void VariableInitializer::insertInitCode(TIntermSequence *sequence)
}
else if (var.isStruct())
{
TVariable *structInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
TVariable *structInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
ASSERT(structInfo);
TIntermSymbol *symbol = new TIntermSymbol(0, name, structInfo->getType());
......@@ -125,12 +83,14 @@ void VariableInitializer::insertInitCode(TIntermSequence *sequence)
} // namespace anonymous
void InitializeVariables(TIntermNode *root,
void InitializeVariables(TIntermBlock *root,
const InitVariableList &vars,
const TSymbolTable &symbolTable)
{
VariableInitializer initializer(vars, symbolTable);
root->traverse(&initializer);
TIntermFunctionDefinition *main = FindMain(root);
ASSERT(main != nullptr);
TIntermBlock *body = main->getBody();
InsertInitCode(body->getSequence(), vars, symbolTable);
}
} // namespace sh
......@@ -11,7 +11,7 @@
namespace sh
{
class TIntermNode;
class TIntermBlock;
class TSymbolTable;
typedef std::vector<sh::ShaderVariable> InitVariableList;
......@@ -23,7 +23,7 @@ typedef std::vector<sh::ShaderVariable> InitVariableList;
// 2. initializing ESSL 3.00 shaders' output variables (which might be structs).
// Specifically, it's not feasible to make it work for local variables because if their
// types are structs, we can't look into TSymbolTable to find the TType data.
void InitializeVariables(TIntermNode *root,
void InitializeVariables(TIntermBlock *root,
const InitVariableList &vars,
const TSymbolTable &symbolTable);
} // namespace sh
......
......@@ -10,6 +10,7 @@
#include "compiler/translator/UseInterfaceBlockFields.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
......@@ -20,47 +21,9 @@ namespace sh
namespace
{
class UseUniformBlockMembers : public TIntermTraverser
{
public:
UseUniformBlockMembers(const InterfaceBlockList &blocks, const TSymbolTable &symbolTable)
: TIntermTraverser(true, false, false),
mBlocks(blocks),
mSymbolTable(symbolTable),
mCodeInserted(false)
{
ASSERT(mSymbolTable.atGlobalLevel());
}
protected:
bool visitAggregate(Visit visit, TIntermAggregate *node) override { return !mCodeInserted; }
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
private:
void insertUseCode(TIntermSequence *sequence);
void AddFieldUseStatements(const ShaderVariable &var, TIntermSequence *sequence);
const InterfaceBlockList &mBlocks;
const TSymbolTable &mSymbolTable;
bool mCodeInserted;
};
bool UseUniformBlockMembers::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
ASSERT(visit == PreVisit);
if (node->getFunctionSymbolInfo()->isMain())
{
TIntermBlock *body = node->getBody();
ASSERT(body);
insertUseCode(body->getSequence());
mCodeInserted = true;
return false;
}
return !mCodeInserted;
}
void UseUniformBlockMembers::AddFieldUseStatements(const ShaderVariable &var,
TIntermSequence *sequence)
void AddFieldUseStatements(const ShaderVariable &var,
TIntermSequence *sequence,
const TSymbolTable &symbolTable)
{
TString name = TString(var.name.c_str());
if (var.isArray())
......@@ -75,7 +38,7 @@ void UseUniformBlockMembers::AddFieldUseStatements(const ShaderVariable &var,
TType basicType;
if (var.isStruct())
{
TVariable *structInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
TVariable *structInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
ASSERT(structInfo);
const TType &structType = structInfo->getType();
type = &structType;
......@@ -103,21 +66,23 @@ void UseUniformBlockMembers::AddFieldUseStatements(const ShaderVariable &var,
}
}
void UseUniformBlockMembers::insertUseCode(TIntermSequence *sequence)
void InsertUseCode(TIntermSequence *sequence,
const InterfaceBlockList &blocks,
const TSymbolTable &symbolTable)
{
for (const auto &block : mBlocks)
for (const auto &block : blocks)
{
if (block.instanceName.empty())
{
for (const auto &var : block.fields)
{
AddFieldUseStatements(var, sequence);
AddFieldUseStatements(var, sequence, symbolTable);
}
}
else if (block.arraySize > 0)
{
TString name = TString(block.instanceName.c_str());
TVariable *ubInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
TVariable *ubInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
ASSERT(ubInfo);
TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, ubInfo->getType());
for (unsigned int i = 0; i < block.arraySize; ++i)
......@@ -136,7 +101,7 @@ void UseUniformBlockMembers::insertUseCode(TIntermSequence *sequence)
else
{
TString name = TString(block.instanceName.c_str());
TVariable *ubInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
TVariable *ubInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
ASSERT(ubInfo);
TIntermSymbol *blockSymbol = new TIntermSymbol(0, name, ubInfo->getType());
for (unsigned int i = 0; i < block.fields.size(); ++i)
......@@ -152,12 +117,14 @@ void UseUniformBlockMembers::insertUseCode(TIntermSequence *sequence)
} // namespace anonymous
void UseInterfaceBlockFields(TIntermNode *root,
void UseInterfaceBlockFields(TIntermBlock *root,
const InterfaceBlockList &blocks,
const TSymbolTable &symbolTable)
{
UseUniformBlockMembers useUniformBlock(blocks, symbolTable);
root->traverse(&useUniformBlock);
TIntermFunctionDefinition *main = FindMain(root);
TIntermBlock *mainBody = main->getBody();
ASSERT(mainBody);
InsertUseCode(mainBody->getSequence(), blocks, symbolTable);
}
} // namespace sh
......@@ -13,15 +13,15 @@
#include <GLSLANG/ShaderLang.h>
class TIntermNode;
namespace sh
{
class TIntermBlock;
class TSymbolTable;
using InterfaceBlockList = std::vector<sh::InterfaceBlock>;
void UseInterfaceBlockFields(TIntermNode *root,
void UseInterfaceBlockFields(TIntermBlock *root,
const InterfaceBlockList &blocks,
const TSymbolTable &symbolTable);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment