Commit a3a5cc6a by Olli Etuaho

Expose the IntermNode tree generated in the compiler for testing

This refactoring makes it possible for tests to access the IntermNode tree produced by compilation by calling compileTree(). Removing ParseContext usage from OutputHLSL has the additional benefit of better separation between parsing and output. BUG=angle:916 Change-Id: Ib40954832316328772a5c1dcbbe6b46b238e4e65 Reviewed-on: https://chromium-review.googlesource.com/249723Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 73edef0a
......@@ -125,7 +125,8 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
maxCallStackDepth(0),
fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(type)
builtInFunctionEmulator(type),
mSourcePath(NULL)
{
}
......@@ -158,15 +159,19 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
return true;
}
bool TCompiler::compile(const char* const shaderStrings[],
size_t numStrings,
int compileOptions)
TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions)
{
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
size_t numStrings, int compileOptions)
{
TScopedPoolAllocator scopedAlloc(&allocator);
clearResults();
if (numStrings == 0)
return true;
ASSERT(numStrings > 0);
ASSERT(GetGlobalPoolAllocator());
// Reset the extension behavior for each compilation unit.
ResetExtensionBehavior(extensionBehavior);
......@@ -176,11 +181,10 @@ bool TCompiler::compile(const char* const shaderStrings[],
compileOptions |= SH_VALIDATE_LOOP_INDEXING;
// First string is path of source file if flag is set. The actual source follows.
const char* sourcePath = NULL;
size_t firstSource = 0;
if (compileOptions & SH_SOURCE_PATH)
{
sourcePath = shaderStrings[0];
mSourcePath = shaderStrings[0];
++firstSource;
}
......@@ -188,7 +192,7 @@ bool TCompiler::compile(const char* const shaderStrings[],
TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
shaderType, shaderSpec, compileOptions, true,
sourcePath, infoSink, debugShaderPrecision);
infoSink, debugShaderPrecision);
parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
SetGlobalParseContext(&parseContext);
......@@ -210,6 +214,8 @@ bool TCompiler::compile(const char* const shaderStrings[],
success = false;
}
TIntermNode *root = NULL;
if (success)
{
mPragma = parseContext.pragma();
......@@ -218,7 +224,7 @@ bool TCompiler::compile(const char* const shaderStrings[],
symbolTable.setGlobalInvariant();
}
TIntermNode* root = parseContext.treeRoot;
root = parseContext.treeRoot;
success = intermediate.postProcess(root);
// Disallow expressions deemed too complex.
......@@ -305,18 +311,37 @@ bool TCompiler::compile(const char* const shaderStrings[],
RegenerateStructNames gen(symbolTable, shaderVersion);
root->traverse(&gen);
}
if (success && (compileOptions & SH_INTERMEDIATE_TREE))
intermediate.outputTree(root);
if (success && (compileOptions & SH_OBJECT_CODE))
translate(root);
}
// Cleanup. The IntermNode tree doesn't need to be deleted here, since the
// memory will be freed in a big chunk by the PoolAllocator.
SetGlobalParseContext(NULL);
return success;
if (success)
return root;
return NULL;
}
bool TCompiler::compile(const char* const shaderStrings[],
size_t numStrings, int compileOptions)
{
if (numStrings == 0)
return true;
TScopedPoolAllocator scopedAlloc(&allocator);
TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
if (root)
{
if (compileOptions & SH_INTERMEDIATE_TREE)
TIntermediate::outputTree(root, infoSink.info);
if (compileOptions & SH_OBJECT_CODE)
translate(root, compileOptions);
// The IntermNode tree doesn't need to be deleted here, since the
// memory will be freed in a big chunk by the PoolAllocator.
return true;
}
return false;
}
bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
......@@ -424,6 +449,8 @@ void TCompiler::clearResults()
builtInFunctionEmulator.Cleanup();
nameMap.clear();
mSourcePath = NULL;
}
bool TCompiler::detectCallDepth(TIntermNode* inputRoot, TInfoSink& inputInfoSink, bool limitCallStackDepth)
......@@ -602,6 +629,11 @@ const TExtensionBehavior& TCompiler::getExtensionBehavior() const
return extensionBehavior;
}
const char *TCompiler::getSourcePath() const
{
return mSourcePath;
}
const ShBuiltInResources& TCompiler::getResources() const
{
return compileResources;
......
......@@ -61,9 +61,15 @@ class TCompiler : public TShHandleBase
virtual TCompiler* getAsCompiler() { return this; }
bool Init(const ShBuiltInResources& resources);
// compileTreeForTesting should be used only when tests require access to
// the AST. Users of this function need to manually manage the global pool
// allocator. Returns NULL whenever there are compilation errors.
TIntermNode *compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
bool compile(const char* const shaderStrings[],
size_t numStrings,
int compileOptions);
size_t numStrings, int compileOptions);
// Get results of the last compilation.
int getShaderVersion() const { return shaderVersion; }
......@@ -105,7 +111,7 @@ class TCompiler : public TShHandleBase
// Collect info for all attribs, uniforms, varyings.
void collectVariables(TIntermNode* root);
// Translate to object code.
virtual void translate(TIntermNode* root) = 0;
virtual void translate(TIntermNode *root, int compileOptions) = 0;
// Returns true if, after applying the packing rules in the GLSL 1.017 spec
// Appendix A, section 7, the shader does not use too many uniforms.
bool enforcePackingRestrictions();
......@@ -130,6 +136,7 @@ class TCompiler : public TShHandleBase
bool limitExpressionComplexity(TIntermNode* root);
// Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const;
const char *getSourcePath() const;
const TPragma& getPragma() const { return mPragma; }
void writePragma();
......@@ -145,6 +152,9 @@ class TCompiler : public TShHandleBase
std::vector<sh::InterfaceBlock> interfaceBlocks;
private:
TIntermNode *compileTreeImpl(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
sh::GLenum shaderType;
ShShaderSpec shaderSpec;
ShShaderOutput outputType;
......@@ -170,6 +180,7 @@ class TCompiler : public TShHandleBase
// Results of compilation.
int shaderVersion;
TInfoSink infoSink; // Output sink.
const char *mSourcePath; // Path of source file or NULL
// name hashing.
ShHashFunction64 hashFunction;
......
......@@ -36,6 +36,7 @@ class TIntermTyped;
class TIntermSymbol;
class TIntermLoop;
class TInfoSink;
class TInfoSinkBase;
class TIntermRaw;
//
......
......@@ -55,7 +55,8 @@ class TIntermediate
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
bool postProcess(TIntermNode *);
void outputTree(TIntermNode *);
static void outputTree(TIntermNode *, TInfoSinkBase &);
private:
void operator=(TIntermediate &); // prevent assignments
......
......@@ -95,12 +95,21 @@ bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
return false;
}
OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath, ShShaderOutput outputType,
int numRenderTargets, const std::vector<Uniform> &uniforms,
int compileOptions)
: TIntermTraverser(true, true, true),
mContext(context),
mOutputType(parentTranslator->getOutputType())
mShaderType(shaderType),
mShaderVersion(shaderVersion),
mExtensionBehavior(extensionBehavior),
mSourcePath(sourcePath),
mOutputType(outputType),
mNumRenderTargets(numRenderTargets),
mCompileOptions(compileOptions)
{
mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
mUnfoldShortCircuit = new UnfoldShortCircuit(this);
mInsideFunction = false;
mUsesFragColor = false;
......@@ -116,9 +125,6 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
mUsesDiscardRewriting = false;
mUsesNestedBreak = false;
const ShBuiltInResources &resources = parentTranslator->getResources();
mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
mUniqueIndex = 0;
mContainsLoopDiscontinuity = false;
......@@ -130,11 +136,11 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
mExcessiveLoopIndex = NULL;
mStructureHLSL = new StructureHLSL;
mUniformHLSL = new UniformHLSL(mStructureHLSL, parentTranslator);
mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
if (mOutputType == SH_HLSL9_OUTPUT)
{
if (mContext.shaderType == GL_FRAGMENT_SHADER)
if (mShaderType == GL_FRAGMENT_SHADER)
{
// Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
mUniformHLSL->reserveUniformRegisters(3);
......@@ -157,26 +163,26 @@ OutputHLSL::~OutputHLSL()
SafeDelete(mUniformHLSL);
}
void OutputHLSL::output()
void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
{
mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
mContainsAnyLoop = containsAnyLoop(mContext.treeRoot);
const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
mContainsLoopDiscontinuity = mShaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(treeRoot);
mContainsAnyLoop = containsAnyLoop(treeRoot);
const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
makeFlaggedStructMaps(flaggedStructs);
// Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
// use a vertex attribute as a condition, and some related computation in the else block.
if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == GL_VERTEX_SHADER)
if (mOutputType == SH_HLSL9_OUTPUT && mShaderType == GL_VERTEX_SHADER)
{
RewriteElseBlocks(mContext.treeRoot);
RewriteElseBlocks(treeRoot);
}
BuiltInFunctionEmulatorHLSL builtInFunctionEmulator;
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot);
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
// Output the body and footer first to determine what has to go in the header
mInfoSinkStack.push(&mBody);
mContext.treeRoot->traverse(this);
treeRoot->traverse(this);
mInfoSinkStack.pop();
mInfoSinkStack.push(&mFooter);
......@@ -190,10 +196,9 @@ void OutputHLSL::output()
header(&builtInFunctionEmulator);
mInfoSinkStack.pop();
TInfoSinkBase& sink = mContext.infoSink().obj;
sink << mHeader.c_str();
sink << mBody.c_str();
sink << mFooter.c_str();
objSink << mHeader.c_str();
objSink << mBody.c_str();
objSink << mFooter.c_str();
builtInFunctionEmulator.Cleanup();
}
......@@ -353,16 +358,16 @@ void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulat
"#define FLATTEN\n"
"#endif\n";
if (mContext.shaderType == GL_FRAGMENT_SHADER)
if (mShaderType == GL_FRAGMENT_SHADER)
{
TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
out << "// Varyings\n";
out << varyings;
out << "\n";
if (mContext.getShaderVersion() >= 300)
if (mShaderVersion >= 300)
{
for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
{
......@@ -2051,7 +2056,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional
if (lod0 || mContext.shaderType == GL_VERTEX_SHADER)
if (lod0 || mShaderType == GL_VERTEX_SHADER)
{
if (bias)
{
......@@ -2180,7 +2185,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
// however flattening all the ifs in branch heavy shaders made D3D error too.
// As a temporary workaround we flatten the ifs only if there is at least a loop
// present somewhere in the shader.
if (mContext.shaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop)
if (mShaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop)
{
out << "FLATTEN ";
}
......@@ -2649,16 +2654,16 @@ void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TStr
void OutputHLSL::outputLineDirective(int line)
{
if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
{
TInfoSinkBase &out = getInfoSink();
out << "\n";
out << "#line " << line;
if (mContext.sourcePath)
if (mSourcePath)
{
out << " \"" << mContext.sourcePath << "\"";
out << " \"" << mSourcePath << "\"";
}
out << "\n";
......
......@@ -29,10 +29,15 @@ typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
class OutputHLSL : public TIntermTraverser
{
public:
OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator);
OutputHLSL(sh::GLenum shaderType, int shaderVersion,
const TExtensionBehavior &extensionBehavior,
const char *sourcePath, ShShaderOutput outputType,
int numRenderTargets, const std::vector<Uniform> &uniforms,
int compileOptions);
~OutputHLSL();
void output();
void output(TIntermNode *treeRoot, TInfoSinkBase &objSink);
const std::map<std::string, unsigned int> &getInterfaceBlockRegisterMap() const;
const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
......@@ -76,8 +81,13 @@ class OutputHLSL : public TIntermTraverser
// Returns the function name
TString addStructEqualityFunction(const TStructure &structure);
TParseContext &mContext;
sh::GLenum mShaderType;
int mShaderVersion;
const TExtensionBehavior &mExtensionBehavior;
const char *mSourcePath;
const ShShaderOutput mOutputType;
int mCompileOptions;
UnfoldShortCircuit *mUnfoldShortCircuit;
bool mInsideFunction;
......
......@@ -25,13 +25,12 @@ struct TMatrixFields {
// they can be passed to the parser without needing a global.
//
struct TParseContext {
TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is, bool debugShaderPrecisionSupported) :
TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, TInfoSink& is, bool debugShaderPrecisionSupported) :
intermediate(interm),
symbolTable(symt),
shaderType(type),
shaderSpec(spec),
compileOptions(options),
sourcePath(sourcePath),
treeRoot(0),
loopNestingLevel(0),
structNestingLevel(0),
......@@ -51,7 +50,6 @@ struct TParseContext {
ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
int shaderVersion;
int compileOptions;
const char* sourcePath; // Path of source file or NULL.
TIntermNode* treeRoot; // root of parse tree being created
int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // incremented while parsing a struct declaration
......
......@@ -14,7 +14,7 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_ESSL_OUTPUT) {
}
void TranslatorESSL::translate(TIntermNode* root) {
void TranslatorESSL::translate(TIntermNode *root, int) {
TInfoSinkBase& sink = getInfoSink().obj;
writePragma();
......
......@@ -14,7 +14,7 @@ public:
TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
protected:
virtual void translate(TIntermNode* root);
virtual void translate(TIntermNode *root, int compileOptions);
private:
void writeExtensionBehavior();
......
......@@ -15,7 +15,7 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_GLSL_OUTPUT) {
}
void TranslatorGLSL::translate(TIntermNode* root) {
void TranslatorGLSL::translate(TIntermNode *root, int) {
TInfoSinkBase& sink = getInfoSink().obj;
// Write GLSL version.
......
......@@ -15,7 +15,7 @@ class TranslatorGLSL : public TCompiler
TranslatorGLSL(sh::GLenum type, ShShaderSpec spec);
protected:
virtual void translate(TIntermNode *root);
virtual void translate(TIntermNode *root, int compileOptions);
private:
void writeVersion(TIntermNode *root);
......
......@@ -6,7 +6,6 @@
#include "compiler/translator/TranslatorHLSL.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/OutputHLSL.h"
TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
......@@ -14,12 +13,15 @@ TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutpu
{
}
void TranslatorHLSL::translate(TIntermNode *root)
void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
{
TParseContext& parseContext = *GetGlobalParseContext();
sh::OutputHLSL outputHLSL(parseContext, this);
const ShBuiltInResources &resources = getResources();
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
outputHLSL.output();
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions);
outputHLSL.output(root, getInfoSink().obj);
mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap();
mUniformRegisterMap = outputHLSL.getUniformRegisterMap();
......
......@@ -22,7 +22,7 @@ class TranslatorHLSL : public TCompiler
unsigned int getUniformRegister(const std::string &uniformName) const;
protected:
virtual void translate(TIntermNode* root);
virtual void translate(TIntermNode *root, int compileOptions);
std::map<std::string, unsigned int> mInterfaceBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap;
......
......@@ -16,7 +16,7 @@
namespace sh
{
UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
UnfoldShortCircuit::UnfoldShortCircuit(OutputHLSL *outputHLSL) : mOutputHLSL(outputHLSL)
{
mTemporaryIndex = 0;
}
......
......@@ -19,7 +19,7 @@ class OutputHLSL;
class UnfoldShortCircuit : public TIntermTraverser
{
public:
UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL);
UnfoldShortCircuit(OutputHLSL *outputHLSL);
void traverse(TIntermNode *node);
bool visitBinary(Visit visit, TIntermBinary*);
......@@ -29,7 +29,6 @@ class UnfoldShortCircuit : public TIntermTraverser
int getNextTemporaryIndex();
protected:
TParseContext &mContext;
OutputHLSL *const mOutputHLSL;
int mTemporaryIndex;
......
......@@ -11,7 +11,6 @@
#include "common/utilities.h"
#include "compiler/translator/StructureHLSL.h"
#include "compiler/translator/TranslatorHLSL.h"
#include "compiler/translator/UtilsHLSL.h"
#include "compiler/translator/blocklayout.h"
#include "compiler/translator/util.h"
......@@ -61,13 +60,13 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
return DecoratePrivate(interfaceBlock.name()) + "_type";
}
UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator)
UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector<Uniform> &uniforms)
: mUniformRegister(0),
mInterfaceBlockRegister(0),
mSamplerRegister(0),
mStructureHLSL(structureHLSL),
mOutputType(translator->getOutputType()),
mUniforms(translator->getUniforms())
mOutputType(outputType),
mUniforms(uniforms)
{}
void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
......
......@@ -19,7 +19,7 @@ class StructureHLSL;
class UniformHLSL
{
public:
UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator);
UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector<Uniform> &uniforms);
void reserveUniformRegisters(unsigned int registerCount);
void reserveInterfaceBlockRegisters(unsigned int registerCount);
......
......@@ -613,14 +613,13 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
//
// This function is the one to call externally to start the traversal.
// Individual functions can be initialized to 0 to skip processing of that
// type of node. It's children will still be processed.
// type of node. Its children will still be processed.
//
void TIntermediate::outputTree(TIntermNode *root)
void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
{
if (root == NULL)
return;
TOutputTraverser it(infoSink);
TOutputTraverser it(mInfoSink.info);
ASSERT(root);
root->traverse(&it);
}
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