Merge pull request #1232 from KhronosGroup/control-flow-attributes
Control flow attributes
This commit is contained in:
commit
98e733cb58
42 changed files with 3765 additions and 2890 deletions
|
|
@ -9,6 +9,7 @@ endif(WIN32)
|
|||
set(SOURCES
|
||||
MachineIndependent/glslang.y
|
||||
MachineIndependent/glslang_tab.cpp
|
||||
MachineIndependent/attribute.cpp
|
||||
MachineIndependent/Constant.cpp
|
||||
MachineIndependent/iomapper.cpp
|
||||
MachineIndependent/InfoSink.cpp
|
||||
|
|
@ -51,6 +52,7 @@ set(HEADERS
|
|||
Include/revision.h
|
||||
Include/ShHandle.h
|
||||
Include/Types.h
|
||||
MachineIndependent/attribute.h
|
||||
MachineIndependent/glslang_tab.cpp.h
|
||||
MachineIndependent/gl_types.h
|
||||
MachineIndependent/Initialize.h
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ inline TString* NewPoolTString(const char* s)
|
|||
return new(memory) TString(s);
|
||||
}
|
||||
|
||||
template<class T> inline T* NewPoolObject(T)
|
||||
template<class T> inline T* NewPoolObject(T*)
|
||||
{
|
||||
return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@
|
|||
#ifndef _CONSTANT_UNION_INCLUDED_
|
||||
#define _CONSTANT_UNION_INCLUDED_
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/BaseTypes.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TConstUnion {
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ public:
|
|||
virtual glslang::TIntermMethod* getAsMethodNode() { return 0; }
|
||||
virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; }
|
||||
virtual glslang::TIntermBranch* getAsBranchNode() { return 0; }
|
||||
virtual glslang::TIntermLoop* getAsLoopNode() { return 0; }
|
||||
virtual glslang::TIntermLoop* getAsLoopNode() { return 0; }
|
||||
|
||||
virtual const glslang::TIntermTyped* getAsTyped() const { return 0; }
|
||||
virtual const glslang::TIntermOperator* getAsOperator() const { return 0; }
|
||||
|
|
@ -832,7 +832,7 @@ public:
|
|||
virtual const glslang::TIntermMethod* getAsMethodNode() const { return 0; }
|
||||
virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return 0; }
|
||||
virtual const glslang::TIntermBranch* getAsBranchNode() const { return 0; }
|
||||
virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; }
|
||||
virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; }
|
||||
virtual ~TIntermNode() { }
|
||||
|
||||
protected:
|
||||
|
|
@ -885,24 +885,6 @@ protected:
|
|||
TType type;
|
||||
};
|
||||
|
||||
//
|
||||
// Selection control hints
|
||||
//
|
||||
enum TSelectionControl {
|
||||
ESelectionControlNone,
|
||||
ESelectionControlFlatten,
|
||||
ESelectionControlDontFlatten,
|
||||
};
|
||||
|
||||
//
|
||||
// Loop control hints
|
||||
//
|
||||
enum TLoopControl {
|
||||
ELoopControlNone,
|
||||
ELoopControlUnroll,
|
||||
ELoopControlDontUnroll,
|
||||
};
|
||||
|
||||
//
|
||||
// Handle for, do-while, and while loops.
|
||||
//
|
||||
|
|
@ -913,26 +895,36 @@ public:
|
|||
test(aTest),
|
||||
terminal(aTerminal),
|
||||
first(testFirst),
|
||||
control(ELoopControlNone)
|
||||
unroll(false),
|
||||
dontUnroll(false),
|
||||
dependency(0)
|
||||
{ }
|
||||
|
||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||
virtual const TIntermLoop* getAsLoopNode() const { return this; }
|
||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||
virtual const TIntermLoop* getAsLoopNode() const { return this; }
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
TIntermNode* getBody() const { return body; }
|
||||
TIntermTyped* getTest() const { return test; }
|
||||
TIntermTyped* getTerminal() const { return terminal; }
|
||||
bool testFirst() const { return first; }
|
||||
|
||||
void setLoopControl(TLoopControl c) { control = c; }
|
||||
TLoopControl getLoopControl() const { return control; }
|
||||
void setUnroll() { unroll = true; }
|
||||
void setDontUnroll() { dontUnroll = true; }
|
||||
bool getUnroll() const { return unroll; }
|
||||
bool getDontUnroll() const { return dontUnroll; }
|
||||
|
||||
static const unsigned int dependencyInfinite = 0xFFFFFFFF;
|
||||
void setLoopDependency(int d) { dependency = d; }
|
||||
int getLoopDependency() const { return dependency; }
|
||||
|
||||
protected:
|
||||
TIntermNode* body; // code to loop over
|
||||
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
|
||||
TIntermTyped* terminal; // exists for for-loops
|
||||
bool first; // true for while and for, not for do-while
|
||||
TLoopControl control; // loop control hint
|
||||
bool unroll; // true if unroll requested
|
||||
bool dontUnroll; // true if request to not unroll
|
||||
unsigned int dependency; // loop dependency hint; 0 means not set or unknown
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -1343,22 +1335,29 @@ protected:
|
|||
class TIntermSelection : public TIntermTyped {
|
||||
public:
|
||||
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
|
||||
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
|
||||
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
|
||||
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
|
||||
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
virtual TIntermTyped* getCondition() const { return condition; }
|
||||
virtual TIntermNode* getTrueBlock() const { return trueBlock; }
|
||||
virtual TIntermNode* getFalseBlock() const { return falseBlock; }
|
||||
virtual TIntermSelection* getAsSelectionNode() { return this; }
|
||||
virtual const TIntermSelection* getAsSelectionNode() const { return this; }
|
||||
void setSelectionControl(TSelectionControl c) { control = c; }
|
||||
TSelectionControl getSelectionControl() const { return control; }
|
||||
|
||||
void setFlatten() { flatten = true; }
|
||||
void setDontFlatten() { dontFlatten = true; }
|
||||
bool getFlatten() const { return flatten; }
|
||||
bool getDontFlatten() const { return dontFlatten; }
|
||||
|
||||
protected:
|
||||
TIntermTyped* condition;
|
||||
TIntermNode* trueBlock;
|
||||
TIntermNode* falseBlock;
|
||||
TSelectionControl control; // selection control hint
|
||||
bool flatten; // true if flatten requested
|
||||
bool dontFlatten; // true if requested to not flatten
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -1369,18 +1368,24 @@ protected:
|
|||
//
|
||||
class TIntermSwitch : public TIntermNode {
|
||||
public:
|
||||
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), control(ESelectionControlNone) { }
|
||||
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
virtual TIntermNode* getCondition() const { return condition; }
|
||||
virtual TIntermAggregate* getBody() const { return body; }
|
||||
virtual TIntermSwitch* getAsSwitchNode() { return this; }
|
||||
virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
|
||||
void setSelectionControl(TSelectionControl c) { control = c; }
|
||||
TSelectionControl getSelectionControl() const { return control; }
|
||||
|
||||
void setFlatten() { flatten = true; }
|
||||
void setDontFlatten() { dontFlatten = true; }
|
||||
bool getFlatten() const { return flatten; }
|
||||
bool getDontFlatten() const { return dontFlatten; }
|
||||
|
||||
protected:
|
||||
TIntermTyped* condition;
|
||||
TIntermAggregate* body;
|
||||
TSelectionControl control; // selection control hint
|
||||
bool flatten; // true if flatten requested
|
||||
bool dontFlatten; // true if requested to not flatten
|
||||
};
|
||||
|
||||
enum TVisit
|
||||
|
|
|
|||
|
|
@ -1614,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
|
|||
//
|
||||
// Returns the selection node created.
|
||||
//
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc, TSelectionControl control)
|
||||
TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
|
||||
{
|
||||
//
|
||||
// Don't prune the false path for compile-time constants; it's needed
|
||||
|
|
@ -1623,7 +1623,6 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair no
|
|||
|
||||
TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
|
||||
node->setLoc(loc);
|
||||
node->setSelectionControl(control);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
|
@ -1666,12 +1665,13 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
|
|||
//
|
||||
// Returns the selection node created, or nullptr if one could not be.
|
||||
//
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc, TSelectionControl control)
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock,
|
||||
const TSourceLoc& loc)
|
||||
{
|
||||
// If it's void, go to the if-then-else selection()
|
||||
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
|
||||
TIntermNodePair pair = { trueBlock, falseBlock };
|
||||
return addSelection(cond, pair, loc, control);
|
||||
return addSelection(cond, pair, loc);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1909,11 +1909,11 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
|
|||
//
|
||||
// Create while and do-while loop nodes.
|
||||
//
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
|
||||
const TSourceLoc& loc)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
|
@ -1921,11 +1921,11 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
|
|||
//
|
||||
// Create a for-loop sequence.
|
||||
//
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
|
||||
TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
// make a sequence of the initializer and statement, but try to reuse the
|
||||
// aggregate already created for whatever is in the initializer, if there is one
|
||||
|
|
|
|||
|
|
@ -44,13 +44,15 @@
|
|||
#ifndef _PARSER_HELPER_INCLUDED_
|
||||
#define _PARSER_HELPER_INCLUDED_
|
||||
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
|
||||
#include "parseVersions.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "localintermediate.h"
|
||||
#include "Scan.h"
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
#include "attribute.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
|
|
@ -409,6 +411,17 @@ public:
|
|||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
|
||||
|
||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||
TAttributeType attributeFromName(const TString& name) const;
|
||||
TAttributes* makeAttributes(const TString& identifier) const;
|
||||
TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const;
|
||||
TAttributes* mergeAttributes(TAttributes*, TAttributes*) const;
|
||||
|
||||
// Determine selection control from attributes
|
||||
void handleSelectionAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
|
||||
// Determine loop control from attributes
|
||||
void handleLoopAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
|
||||
protected:
|
||||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "../Include/Types.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "ParseHelper.h"
|
||||
#include "attribute.h"
|
||||
#include "glslang_tab.cpp.h"
|
||||
#include "ScanContext.h"
|
||||
#include "Scan.h"
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ void TParseVersions::initializeExtensionBehavior()
|
|||
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_control_flow_attributes] = EBhDisable;
|
||||
|
||||
// #line and #include
|
||||
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
||||
|
|
@ -328,6 +329,7 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||
"#define GL_EXT_shader_image_load_formatted 1\n"
|
||||
"#define GL_EXT_post_depth_coverage 1\n"
|
||||
"#define GL_EXT_control_flow_attributes 1\n"
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
"#define GL_AMD_shader_ballot 1\n"
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_lo
|
|||
const char* const E_GL_EXT_device_group = "GL_EXT_device_group";
|
||||
const char* const E_GL_EXT_multiview = "GL_EXT_multiview";
|
||||
const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage";
|
||||
const char* const E_GL_EXT_control_flow_attributes = "GL_EXT_control_flow_attributes";
|
||||
|
||||
// Arrays of extensions for the above viewportEXTs duplications
|
||||
|
||||
|
|
|
|||
257
glslang/MachineIndependent/attribute.cpp
Normal file
257
glslang/MachineIndependent/attribute.cpp
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
//
|
||||
// Copyright (C) 2017 LunarG, Inc.
|
||||
// Copyright (C) 2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google, Inc., nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "attribute.h"
|
||||
#include "../Include/intermediate.h"
|
||||
#include "ParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeArgs::getInt(int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
||||
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
}
|
||||
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
||||
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = *stringConst->getSConst();
|
||||
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// How many arguments were supplied?
|
||||
int TAttributeArgs::size() const
|
||||
{
|
||||
return args == nullptr ? 0 : (int)args->getSequence().size();
|
||||
}
|
||||
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
||||
{
|
||||
if (args == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (argNum >= args->getSequence().size())
|
||||
return nullptr;
|
||||
|
||||
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
}
|
||||
|
||||
// Implementation of TParseContext parts of attributes
|
||||
TAttributeType TParseContext::attributeFromName(const TString& name) const
|
||||
{
|
||||
if (name == "branch" || name == "dont_flatten")
|
||||
return EatBranch;
|
||||
else if (name == "flatten")
|
||||
return EatFlatten;
|
||||
else if (name == "unroll")
|
||||
return EatUnroll;
|
||||
else if (name == "loop" || name == "dont_unroll")
|
||||
return EatLoop;
|
||||
else if (name == "dependency_infinite")
|
||||
return EatDependencyInfinite;
|
||||
else if (name == "dependency_length")
|
||||
return EatDependencyLength;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
|
||||
// Make an initial leaf for the grammar from a no-argument attribute
|
||||
TAttributes* TParseContext::makeAttributes(const TString& identifier) const
|
||||
{
|
||||
TAttributes *attributes = nullptr;
|
||||
attributes = NewPoolObject(attributes);
|
||||
TAttributeArgs args = { attributeFromName(identifier), nullptr };
|
||||
attributes->push_back(args);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// Make an initial leaf for the grammar from a one-argument attribute
|
||||
TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
|
||||
{
|
||||
TAttributes *attributes = nullptr;
|
||||
attributes = NewPoolObject(attributes);
|
||||
|
||||
// for now, node is always a simple single expression, but other code expects
|
||||
// a list, so make it so
|
||||
TIntermAggregate* agg = intermediate.makeAggregate(node);
|
||||
TAttributeArgs args = { attributeFromName(identifier), agg };
|
||||
attributes->push_back(args);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// Merge two sets of attributes into a single set.
|
||||
// The second argument is destructively consumed.
|
||||
TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
|
||||
{
|
||||
attr1->splice(attr1->end(), *attr2);
|
||||
return attr1;
|
||||
}
|
||||
|
||||
//
|
||||
// Selection attributes
|
||||
//
|
||||
void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermSelection* selection = node->getAsSelectionNode();
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a selection", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Switch attributes
|
||||
//
|
||||
void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermSwitch* selection = node->getAsSwitchNode();
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a switch", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop attributes
|
||||
//
|
||||
void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermLoop* loop = node->getAsLoopNode();
|
||||
if (loop == nullptr) {
|
||||
// the actual loop might be part of a sequence
|
||||
TIntermAggregate* agg = node->getAsAggregate();
|
||||
if (agg == nullptr)
|
||||
return;
|
||||
for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
|
||||
loop = (*it)->getAsLoopNode();
|
||||
if (loop != nullptr)
|
||||
break;
|
||||
}
|
||||
if (loop == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->name != EatDependencyLength && it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
int value;
|
||||
switch (it->name) {
|
||||
case EatUnroll:
|
||||
loop->setUnroll();
|
||||
break;
|
||||
case EatLoop:
|
||||
loop->setDontUnroll();
|
||||
break;
|
||||
case EatDependencyInfinite:
|
||||
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
|
||||
break;
|
||||
case EatDependencyLength:
|
||||
if (it->size() == 1 && it->getInt(value)) {
|
||||
if (value <= 0)
|
||||
error(node->getLoc(), "must be positive", "dependency_length", "");
|
||||
loop->setLoopDependency(value);
|
||||
} else
|
||||
warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace glslang
|
||||
102
glslang/MachineIndependent/attribute.h
Normal file
102
glslang/MachineIndependent/attribute.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Copyright (C) 2017 LunarG, Inc.
|
||||
// Copyright (C) 2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _ATTRIBUTE_INCLUDED_
|
||||
#define _ATTRIBUTE_INCLUDED_
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ConstantUnion.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
enum TAttributeType {
|
||||
EatNone,
|
||||
EatAllow_uav_condition,
|
||||
EatBranch,
|
||||
EatCall,
|
||||
EatDomain,
|
||||
EatEarlyDepthStencil,
|
||||
EatFastOpt,
|
||||
EatFlatten,
|
||||
EatForceCase,
|
||||
EatInstance,
|
||||
EatMaxTessFactor,
|
||||
EatNumThreads,
|
||||
EatMaxVertexCount,
|
||||
EatOutputControlPoints,
|
||||
EatOutputTopology,
|
||||
EatPartitioning,
|
||||
EatPatchConstantFunc,
|
||||
EatPatchSize,
|
||||
EatUnroll,
|
||||
EatLoop,
|
||||
EatBinding,
|
||||
EatGlobalBinding,
|
||||
EatLocation,
|
||||
EatInputAttachment,
|
||||
EatBuiltIn,
|
||||
EatPushConstant,
|
||||
EatConstantId,
|
||||
EatDependencyInfinite,
|
||||
EatDependencyLength
|
||||
};
|
||||
|
||||
class TIntermAggregate;
|
||||
|
||||
struct TAttributeArgs {
|
||||
TAttributeType name;
|
||||
const TIntermAggregate* args;
|
||||
|
||||
// Obtain attribute as integer
|
||||
// Return false if it cannot be obtained
|
||||
bool getInt(int& value, int argNum = 0) const;
|
||||
|
||||
// Obtain attribute as string, with optional to-lower transform
|
||||
// Return false if it cannot be obtained
|
||||
bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||
|
||||
// How many arguments were provided to the attribute?
|
||||
int size() const;
|
||||
|
||||
protected:
|
||||
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
|
||||
};
|
||||
|
||||
typedef TList<TAttributeArgs> TAttributes;
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _ATTRIBUTE_INCLUDED_
|
||||
|
|
@ -58,6 +58,7 @@ Jutta Degener, 1995
|
|||
#include "SymbolTable.h"
|
||||
#include "ParseHelper.h"
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "attribute.h"
|
||||
|
||||
using namespace glslang;
|
||||
|
||||
|
|
@ -86,6 +87,7 @@ using namespace glslang;
|
|||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
glslang::TAttributes* attributes;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
|
|
@ -218,12 +220,12 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
|||
%type <interm.intermNode> translation_unit function_definition
|
||||
%type <interm.intermNode> statement simple_statement
|
||||
%type <interm.intermNode> statement_list switch_statement_list compound_statement
|
||||
%type <interm.intermNode> declaration_statement selection_statement expression_statement
|
||||
%type <interm.intermNode> switch_statement case_label
|
||||
%type <interm.intermNode> declaration_statement selection_statement selection_statement_nonattributed expression_statement
|
||||
%type <interm.intermNode> switch_statement switch_statement_nonattributed case_label
|
||||
%type <interm.intermNode> declaration external_declaration
|
||||
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
||||
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
||||
%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_scoped
|
||||
%type <interm.intermNode> iteration_statement iteration_statement_nonattributed jump_statement statement_no_new_scope statement_scoped
|
||||
%type <interm> single_declaration init_declarator_list
|
||||
|
||||
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
||||
|
|
@ -246,6 +248,8 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
|||
|
||||
%type <interm.identifierList> identifier_list
|
||||
|
||||
%type <interm.attributes> attribute attribute_list single_attribute
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
|
||||
|
|
@ -2673,6 +2677,15 @@ expression_statement
|
|||
;
|
||||
|
||||
selection_statement
|
||||
: selection_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute selection_statement_nonattributed {
|
||||
parseContext.handleSelectionAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
selection_statement_nonattributed
|
||||
: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
|
||||
parseContext.boolCheck($1.loc, $3);
|
||||
$$ = parseContext.intermediate.addSelection($3, $5, $1.loc);
|
||||
|
|
@ -2709,6 +2722,15 @@ condition
|
|||
;
|
||||
|
||||
switch_statement
|
||||
: switch_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute switch_statement_nonattributed {
|
||||
parseContext.handleSwitchAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
switch_statement_nonattributed
|
||||
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
|
||||
// start new switch sequence on the switch stack
|
||||
++parseContext.controlFlowNestingLevel;
|
||||
|
|
@ -2762,6 +2784,15 @@ case_label
|
|||
;
|
||||
|
||||
iteration_statement
|
||||
: iteration_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute iteration_statement_nonattributed {
|
||||
parseContext.handleLoopAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
iteration_statement_nonattributed
|
||||
: WHILE LEFT_PAREN {
|
||||
if (! parseContext.limits.whileLoops)
|
||||
parseContext.error($1.loc, "while loops not available", "limitation", "");
|
||||
|
|
@ -2920,4 +2951,26 @@ function_definition
|
|||
}
|
||||
;
|
||||
|
||||
attribute
|
||||
: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET {
|
||||
$$ = $3;
|
||||
parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute");
|
||||
}
|
||||
|
||||
attribute_list
|
||||
: single_attribute {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute_list COMMA single_attribute {
|
||||
$$ = parseContext.mergeAttributes($1, $3);
|
||||
}
|
||||
|
||||
single_attribute
|
||||
: IDENTIFIER {
|
||||
$$ = parseContext.makeAttributes(*$1.string);
|
||||
}
|
||||
| IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN {
|
||||
$$ = parseContext.makeAttributes(*$1.string, $3);
|
||||
}
|
||||
|
||||
%%
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -348,7 +348,7 @@ extern int yydebug;
|
|||
typedef union YYSTYPE YYSTYPE;
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 68 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
#line 69 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
|
|
@ -370,6 +370,7 @@ union YYSTYPE
|
|||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
glslang::TAttributes* attributes;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
|
|
@ -382,7 +383,7 @@ union YYSTYPE
|
|||
};
|
||||
} interm;
|
||||
|
||||
#line 386 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
#line 387 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
};
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
|
|
|||
|
|
@ -817,7 +817,13 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node
|
|||
OutputTreeText(out, node, depth);
|
||||
|
||||
out.debug << "Test condition and select";
|
||||
out.debug << " (" << node->getCompleteString() << ")\n";
|
||||
out.debug << " (" << node->getCompleteString() << ")";
|
||||
|
||||
if (node->getFlatten())
|
||||
out.debug << ": Flatten";
|
||||
if (node->getDontFlatten())
|
||||
out.debug << ": DontFlatten";
|
||||
out.debug << "\n";
|
||||
|
||||
++depth;
|
||||
|
||||
|
|
@ -979,7 +985,17 @@ bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
|
|||
out.debug << "Loop with condition ";
|
||||
if (! node->testFirst())
|
||||
out.debug << "not ";
|
||||
out.debug << "tested first\n";
|
||||
out.debug << "tested first";
|
||||
|
||||
if (node->getUnroll())
|
||||
out.debug << ": Unroll";
|
||||
if (node->getDontUnroll())
|
||||
out.debug << ": DontUnroll";
|
||||
if (node->getLoopDependency()) {
|
||||
out.debug << ": Dependency ";
|
||||
out.debug << node->getLoopDependency();
|
||||
}
|
||||
out.debug << "\n";
|
||||
|
||||
++depth;
|
||||
|
||||
|
|
@ -1040,7 +1056,13 @@ bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
|
|||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "switch\n";
|
||||
out.debug << "switch";
|
||||
|
||||
if (node->getFlatten())
|
||||
out.debug << ": Flatten";
|
||||
if (node->getDontFlatten())
|
||||
out.debug << ": DontFlatten";
|
||||
out.debug << "\n";
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "condition\n";
|
||||
|
|
|
|||
|
|
@ -420,8 +420,8 @@ public:
|
|||
TIntermAggregate* makeAggregate(const TSourceLoc&);
|
||||
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
|
||||
bool areAllChildConst(TIntermAggregate* aggrNode);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
|
||||
TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
|
||||
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
|
||||
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
|
||||
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
|
||||
|
|
@ -439,8 +439,9 @@ public:
|
|||
TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
|
||||
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
|
||||
const TSourceLoc&, TIntermLoop*&);
|
||||
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
|
||||
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
|
||||
template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue