GLSL: Implement GL_EXT_control_flow_attributes.

See https://github.com/KhronosGroup/GLSL/pull/11.
This commit is contained in:
John Kessenich 2018-01-31 08:11:18 -07:00
parent e18fd20d5c
commit a2858d9bdd
21 changed files with 3120 additions and 2405 deletions

View file

@ -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;
}

View file

@ -896,7 +896,8 @@ public:
terminal(aTerminal),
first(testFirst),
unroll(false),
dontUnroll(false)
dontUnroll(false),
dependency(0)
{ }
virtual TIntermLoop* getAsLoopNode() { return this; }
@ -912,6 +913,10 @@ public:
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
@ -919,6 +924,7 @@ protected:
bool first; // true for while and for, not for do-while
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
};
//

View file

@ -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);

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -40,47 +40,218 @@
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);
// 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;
if (intConst == nullptr)
return false;
value = intConst->getIConst();
return true;
};
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);
// 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;
if (stringConst == nullptr)
return false;
value = *stringConst->getSConst();
value = *stringConst->getSConst();
// Convenience.
if (convertToLower)
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
// Convenience.
if (convertToLower)
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
return true;
};
return true;
}
// Helper to get attribute const union. Returns nullptr on failure.
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
{
if (argNum >= args->getSequence().size())
return nullptr;
// How many arguments were supplied?
int TAttributeArgs::size() const
{
return args == nullptr ? 0 : (int)args->getSequence().size();
}
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
if (constVal == nullptr || constVal->getType() != basicType)
return nullptr;
// Helper to get attribute const union. Returns nullptr on failure.
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
{
if (args == nullptr)
return nullptr;
return constVal;
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

View file

@ -69,14 +69,16 @@ namespace glslang {
EatInputAttachment,
EatBuiltIn,
EatPushConstant,
EatConstantId
EatConstantId,
EatDependencyInfinite,
EatDependencyLength
};
class TIntermAggregate;
struct TAttributeArgs {
TAttributeType name;
TIntermAggregate* args;
const TIntermAggregate* args;
// Obtain attribute as integer
// Return false if it cannot be obtained
@ -86,6 +88,9 @@ namespace glslang {
// 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;
};

View file

@ -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

View file

@ -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