HLSL: Refactor attribute implementation.

- make it sharable with GLSL
- correct the case insensitivity
- remove the map; queries are not needed, all entries need processing
- make it easier to build bottom up (will help GLSL parsing)
- support semantic checking and reporting
- allow front-end dependent semantics and attribute name mapping
This commit is contained in:
John Kessenich 2018-01-30 11:01:39 -07:00
parent e349af7e20
commit e18fd20d5c
17 changed files with 638 additions and 500 deletions

View File

@ -129,8 +129,9 @@ protected:
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier); spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration); spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
spv::ImageFormat TranslateImageFormat(const glslang::TType& type); spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
spv::SelectionControlMask TranslateSelectionControl(glslang::TSelectionControl) const; spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const; spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&) const;
spv::StorageClass TranslateStorageClass(const glslang::TType&); spv::StorageClass TranslateStorageClass(const glslang::TType&);
spv::Id createSpvVariable(const glslang::TIntermSymbol*); spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&); spv::Id getSampledType(const glslang::TSampler&);
@ -748,26 +749,34 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
} }
} }
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(glslang::TSelectionControl selectionControl) const spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const
{ {
switch (selectionControl) { if (selectionNode.getFlatten())
case glslang::ESelectionControlNone: return spv::SelectionControlMaskNone; return spv::SelectionControlFlattenMask;
case glslang::ESelectionControlFlatten: return spv::SelectionControlFlattenMask; if (selectionNode.getDontFlatten())
case glslang::ESelectionControlDontFlatten: return spv::SelectionControlDontFlattenMask; return spv::SelectionControlDontFlattenMask;
default: return spv::SelectionControlMaskNone; return spv::SelectionControlMaskNone;
}
} }
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const
{ {
switch (loopControl) { if (switchNode.getFlatten())
case glslang::ELoopControlNone: return spv::LoopControlMaskNone; return spv::SelectionControlFlattenMask;
case glslang::ELoopControlUnroll: return spv::LoopControlUnrollMask; if (switchNode.getDontFlatten())
case glslang::ELoopControlDontUnroll: return spv::LoopControlDontUnrollMask; return spv::SelectionControlDontFlattenMask;
// TODO: DependencyInfinite return spv::SelectionControlMaskNone;
// TODO: DependencyLength
default: return spv::LoopControlMaskNone;
} }
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode) const
{
spv::LoopControlMask control = spv::LoopControlMaskNone;
if (loopNode.getDontUnroll())
control = control | spv::LoopControlDontUnrollMask;
if (loopNode.getUnroll())
control = control | spv::LoopControlUnrollMask;
return control;
} }
// Translate glslang type to SPIR-V storage class. // Translate glslang type to SPIR-V storage class.
@ -2026,7 +2035,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
// Selection control: // Selection control:
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl()); const spv::SelectionControlMask control = TranslateSelectionControl(*node);
// make an "if" based on the value created by the condition // make an "if" based on the value created by the condition
spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder); spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder);
@ -2068,7 +2077,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType()); spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
// Selection control: // Selection control:
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl()); const spv::SelectionControlMask control = TranslateSwitchControl(*node);
// browse the children to sort out code segments // browse the children to sort out code segments
int defaultSegment = -1; int defaultSegment = -1;
@ -2128,7 +2137,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
builder.createBranch(&blocks.head); builder.createBranch(&blocks.head);
// Loop control: // Loop control:
const spv::LoopControlMask control = TranslateLoopControl(node->getLoopControl()); const spv::LoopControlMask control = TranslateLoopControl(*node);
// TODO: dependency length // TODO: dependency length

View File

@ -1,20 +1,20 @@
hlsl.numthreads.comp hlsl.numthreads.comp
Shader version: 500 Shader version: 500
local_size = (4, 4, 2) local_size = (1, 4, 8)
0:? Sequence 0:? Sequence
0:4 Function Definition: main(vu3; ( temp void) 0:4 Function Definition: main(vu3; ( temp void)
0:4 Function Parameters: 0:4 Function Parameters:
0:4 'tid' ( in 3-component vector of uint) 0:4 'tid' ( in 3-component vector of uint)
0:9 Function Definition: @main_aux1(vu3; ( temp void) 0:9 Function Definition: @main_aux2(vu3; ( temp void)
0:9 Function Parameters: 0:9 Function Parameters:
0:9 'tid' ( in 3-component vector of uint) 0:9 'tid' ( in 3-component vector of uint)
0:9 Function Definition: main_aux1( ( temp void) 0:9 Function Definition: main_aux2( ( temp void)
0:9 Function Parameters: 0:9 Function Parameters:
0:? Sequence 0:? Sequence
0:9 move second child to first child ( temp 3-component vector of uint) 0:9 move second child to first child ( temp 3-component vector of uint)
0:? 'tid' ( temp 3-component vector of uint) 0:? 'tid' ( temp 3-component vector of uint)
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID) 0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
0:9 Function Call: @main_aux1(vu3; ( temp void) 0:9 Function Call: @main_aux2(vu3; ( temp void)
0:? 'tid' ( temp 3-component vector of uint) 0:? 'tid' ( temp 3-component vector of uint)
0:? Linker Objects 0:? Linker Objects
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID) 0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
@ -24,21 +24,21 @@ Linked compute stage:
Shader version: 500 Shader version: 500
local_size = (4, 4, 2) local_size = (1, 4, 8)
0:? Sequence 0:? Sequence
0:4 Function Definition: main(vu3; ( temp void) 0:4 Function Definition: main(vu3; ( temp void)
0:4 Function Parameters: 0:4 Function Parameters:
0:4 'tid' ( in 3-component vector of uint) 0:4 'tid' ( in 3-component vector of uint)
0:9 Function Definition: @main_aux1(vu3; ( temp void) 0:9 Function Definition: @main_aux2(vu3; ( temp void)
0:9 Function Parameters: 0:9 Function Parameters:
0:9 'tid' ( in 3-component vector of uint) 0:9 'tid' ( in 3-component vector of uint)
0:9 Function Definition: main_aux1( ( temp void) 0:9 Function Definition: main_aux2( ( temp void)
0:9 Function Parameters: 0:9 Function Parameters:
0:? Sequence 0:? Sequence
0:9 move second child to first child ( temp 3-component vector of uint) 0:9 move second child to first child ( temp 3-component vector of uint)
0:? 'tid' ( temp 3-component vector of uint) 0:? 'tid' ( temp 3-component vector of uint)
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID) 0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
0:9 Function Call: @main_aux1(vu3; ( temp void) 0:9 Function Call: @main_aux2(vu3; ( temp void)
0:? 'tid' ( temp 3-component vector of uint) 0:? 'tid' ( temp 3-component vector of uint)
0:? Linker Objects 0:? Linker Objects
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID) 0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
@ -50,13 +50,13 @@ local_size = (4, 4, 2)
Capability Shader Capability Shader
1: ExtInstImport "GLSL.std.450" 1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450 MemoryModel Logical GLSL450
EntryPoint GLCompute 4 "main_aux1" 18 EntryPoint GLCompute 4 "main_aux2" 18
ExecutionMode 4 LocalSize 4 4 2 ExecutionMode 4 LocalSize 1 4 8
Source HLSL 500 Source HLSL 500
Name 4 "main_aux1" Name 4 "main_aux2"
Name 11 "main(vu3;" Name 11 "main(vu3;"
Name 10 "tid" Name 10 "tid"
Name 14 "@main_aux1(vu3;" Name 14 "@main_aux2(vu3;"
Name 13 "tid" Name 13 "tid"
Name 16 "tid" Name 16 "tid"
Name 18 "tid" Name 18 "tid"
@ -70,7 +70,7 @@ local_size = (4, 4, 2)
9: TypeFunction 2 8(ptr) 9: TypeFunction 2 8(ptr)
17: TypePointer Input 7(ivec3) 17: TypePointer Input 7(ivec3)
18(tid): 17(ptr) Variable Input 18(tid): 17(ptr) Variable Input
4(main_aux1): 2 Function None 3 4(main_aux2): 2 Function None 3
5: Label 5: Label
16(tid): 8(ptr) Variable Function 16(tid): 8(ptr) Variable Function
20(param): 8(ptr) Variable Function 20(param): 8(ptr) Variable Function
@ -78,7 +78,7 @@ local_size = (4, 4, 2)
Store 16(tid) 19 Store 16(tid) 19
21: 7(ivec3) Load 16(tid) 21: 7(ivec3) Load 16(tid)
Store 20(param) 21 Store 20(param) 21
22: 2 FunctionCall 14(@main_aux1(vu3;) 20(param) 22: 2 FunctionCall 14(@main_aux2(vu3;) 20(param)
Return Return
FunctionEnd FunctionEnd
11(main(vu3;): 2 Function None 9 11(main(vu3;): 2 Function None 9
@ -86,7 +86,7 @@ local_size = (4, 4, 2)
12: Label 12: Label
Return Return
FunctionEnd FunctionEnd
14(@main_aux1(vu3;): 2 Function None 9 14(@main_aux2(vu3;): 2 Function None 9
13(tid): 8(ptr) FunctionParameter 13(tid): 8(ptr) FunctionParameter
15: Label 15: Label
Return Return

View File

@ -4,11 +4,8 @@ void main(uint3 tid : SV_DispatchThreadID )
{ {
} }
[numTHreaDs(4,4,2)] // case insensitive [numthreads(1,4,8)]
void main_aux1(uint3 tid : SV_DispatchThreadID ) void main_aux2(uint3 tid : SV_DispatchThreadID )
{ {
} }
[numthreads(1,4,8)]
void main_aux2(uint3 tid : SV_DispatchThreadID );

View File

@ -9,6 +9,7 @@ endif(WIN32)
set(SOURCES set(SOURCES
MachineIndependent/glslang.y MachineIndependent/glslang.y
MachineIndependent/glslang_tab.cpp MachineIndependent/glslang_tab.cpp
MachineIndependent/attribute.cpp
MachineIndependent/Constant.cpp MachineIndependent/Constant.cpp
MachineIndependent/iomapper.cpp MachineIndependent/iomapper.cpp
MachineIndependent/InfoSink.cpp MachineIndependent/InfoSink.cpp
@ -51,6 +52,7 @@ set(HEADERS
Include/revision.h Include/revision.h
Include/ShHandle.h Include/ShHandle.h
Include/Types.h Include/Types.h
MachineIndependent/attribute.h
MachineIndependent/glslang_tab.cpp.h MachineIndependent/glslang_tab.cpp.h
MachineIndependent/gl_types.h MachineIndependent/gl_types.h
MachineIndependent/Initialize.h MachineIndependent/Initialize.h

View File

@ -37,6 +37,9 @@
#ifndef _CONSTANT_UNION_INCLUDED_ #ifndef _CONSTANT_UNION_INCLUDED_
#define _CONSTANT_UNION_INCLUDED_ #define _CONSTANT_UNION_INCLUDED_
#include "../Include/Common.h"
#include "../Include/BaseTypes.h"
namespace glslang { namespace glslang {
class TConstUnion { class TConstUnion {

View File

@ -885,24 +885,6 @@ protected:
TType type; 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. // Handle for, do-while, and while loops.
// //
@ -913,7 +895,8 @@ public:
test(aTest), test(aTest),
terminal(aTerminal), terminal(aTerminal),
first(testFirst), first(testFirst),
control(ELoopControlNone) unroll(false),
dontUnroll(false)
{ } { }
virtual TIntermLoop* getAsLoopNode() { return this; } virtual TIntermLoop* getAsLoopNode() { return this; }
@ -924,15 +907,18 @@ public:
TIntermTyped* getTerminal() const { return terminal; } TIntermTyped* getTerminal() const { return terminal; }
bool testFirst() const { return first; } bool testFirst() const { return first; }
void setLoopControl(TLoopControl c) { control = c; } void setUnroll() { unroll = true; }
TLoopControl getLoopControl() const { return control; } void setDontUnroll() { dontUnroll = true; }
bool getUnroll() const { return unroll; }
bool getDontUnroll() const { return dontUnroll; }
protected: protected:
TIntermNode* body; // code to loop over TIntermNode* body; // code to loop over
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
TIntermTyped* terminal; // exists for for-loops TIntermTyped* terminal; // exists for for-loops
bool first; // true for while and for, not for do-while 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
}; };
// //
@ -1343,22 +1329,29 @@ protected:
class TIntermSelection : public TIntermTyped { class TIntermSelection : public TIntermTyped {
public: public:
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : 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) : 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 void traverse(TIntermTraverser*);
virtual TIntermTyped* getCondition() const { return condition; } virtual TIntermTyped* getCondition() const { return condition; }
virtual TIntermNode* getTrueBlock() const { return trueBlock; } virtual TIntermNode* getTrueBlock() const { return trueBlock; }
virtual TIntermNode* getFalseBlock() const { return falseBlock; } virtual TIntermNode* getFalseBlock() const { return falseBlock; }
virtual TIntermSelection* getAsSelectionNode() { return this; } virtual TIntermSelection* getAsSelectionNode() { return this; }
virtual const TIntermSelection* getAsSelectionNode() const { 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: protected:
TIntermTyped* condition; TIntermTyped* condition;
TIntermNode* trueBlock; TIntermNode* trueBlock;
TIntermNode* falseBlock; TIntermNode* falseBlock;
TSelectionControl control; // selection control hint bool flatten; // true if flatten requested
bool dontFlatten; // true if requested to not flatten
}; };
// //
@ -1369,18 +1362,24 @@ protected:
// //
class TIntermSwitch : public TIntermNode { class TIntermSwitch : public TIntermNode {
public: 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 void traverse(TIntermTraverser*);
virtual TIntermNode* getCondition() const { return condition; } virtual TIntermNode* getCondition() const { return condition; }
virtual TIntermAggregate* getBody() const { return body; } virtual TIntermAggregate* getBody() const { return body; }
virtual TIntermSwitch* getAsSwitchNode() { return this; } virtual TIntermSwitch* getAsSwitchNode() { return this; }
virtual const TIntermSwitch* getAsSwitchNode() const { 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: protected:
TIntermTyped* condition; TIntermTyped* condition;
TIntermAggregate* body; TIntermAggregate* body;
TSelectionControl control; // selection control hint bool flatten; // true if flatten requested
bool dontFlatten; // true if requested to not flatten
}; };
enum TVisit enum TVisit

View File

@ -1614,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
// //
// Returns the selection node created. // 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 // 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); TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
node->setLoc(loc); node->setLoc(loc);
node->setSelectionControl(control);
return node; 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. // 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 it's void, go to the if-then-else selection()
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) { if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
TIntermNodePair pair = { trueBlock, falseBlock }; 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. // 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); TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
node->setLoc(loc); node->setLoc(loc);
node->setLoopControl(control);
return node; return node;
} }
@ -1921,11 +1921,11 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
// //
// Create a for-loop sequence. // 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->setLoc(loc);
node->setLoopControl(control);
// make a sequence of the initializer and statement, but try to reuse the // 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 // aggregate already created for whatever is in the initializer, if there is one

View File

@ -0,0 +1,86 @@
//
// 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;
};
// 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;
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
if (constVal == nullptr || constVal->getType() != basicType)
return nullptr;
return constVal;
}
} // end namespace glslang

View File

@ -0,0 +1,97 @@
//
// 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
};
class TIntermAggregate;
struct TAttributeArgs {
TAttributeType name;
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;
protected:
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
};
typedef TList<TAttributeArgs> TAttributes;
} // end namespace glslang
#endif // _ATTRIBUTE_INCLUDED_

View File

@ -420,8 +420,8 @@ public:
TIntermAggregate* makeAggregate(const TSourceLoc&); TIntermAggregate* makeAggregate(const TSourceLoc&);
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
bool areAllChildConst(TIntermAggregate* aggrNode); bool areAllChildConst(TIntermAggregate* aggrNode);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone); TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone); TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&); TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const; 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; TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const; TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false); bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermLoop* addLoop(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&, TLoopControl = ELoopControlNone); TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
const TSourceLoc&, TIntermLoop*&);
TIntermBranch* addBranch(TOperator, const TSourceLoc&); TIntermBranch* addBranch(TOperator, const TSourceLoc&);
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&); template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);

View File

@ -247,7 +247,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.matrixindex.frag", "main"}, {"hlsl.matrixindex.frag", "main"},
{"hlsl.nonstaticMemberFunction.frag", "main"}, {"hlsl.nonstaticMemberFunction.frag", "main"},
{"hlsl.numericsuffixes.frag", "main"}, {"hlsl.numericsuffixes.frag", "main"},
{"hlsl.numthreads.comp", "main_aux1"}, {"hlsl.numthreads.comp", "main_aux2"},
{"hlsl.overload.frag", "PixelShaderFunction"}, {"hlsl.overload.frag", "PixelShaderFunction"},
{"hlsl.opaque-type-bug.frag", "main"}, {"hlsl.opaque-type-bug.frag", "main"},
{"hlsl.params.default.frag", "main"}, {"hlsl.params.default.frag", "main"},

View File

@ -34,157 +34,73 @@
// //
#include "hlslAttributes.h" #include "hlslAttributes.h"
#include <cstdlib> #include "hlslParseHelper.h"
#include <cctype>
#include <algorithm>
namespace glslang { namespace glslang {
// Map the given string to an attribute enum from TAttributeType, // Map the given string to an attribute enum from TAttributeType,
// or EatNone if invalid. // or EatNone if invalid.
TAttributeType TAttributeMap::attributeFromName(const TString& nameSpace, const TString& name) TAttributeType HlslParseContext::attributeFromName(const TString& nameSpace, const TString& name) const
{ {
// These are case insensitive.
TString lowername(name);
std::transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
TString lowernameSpace(nameSpace);
std::transform(lowernameSpace.begin(), lowernameSpace.end(), lowernameSpace.begin(), ::tolower);
// handle names within a namespace // handle names within a namespace
if (lowernameSpace == "vk") { if (nameSpace == "vk") {
if (lowername == "input_attachment_index") if (name == "input_attachment_index")
return EatInputAttachment; return EatInputAttachment;
else if (lowername == "location") else if (name == "location")
return EatLocation; return EatLocation;
else if (lowername == "binding") else if (name == "binding")
return EatBinding; return EatBinding;
else if (lowername == "global_cbuffer_binding") else if (name == "global_cbuffer_binding")
return EatGlobalBinding; return EatGlobalBinding;
else if (lowername == "builtin") else if (name == "builtin")
return EatBuiltIn; return EatBuiltIn;
else if (lowername == "constant_id") else if (name == "constant_id")
return EatConstantId; return EatConstantId;
else if (lowername == "push_constant") else if (name == "push_constant")
return EatPushConstant; return EatPushConstant;
} else if (lowernameSpace.size() > 0) } else if (nameSpace.size() > 0)
return EatNone; return EatNone;
// handle names with no namespace // handle names with no namespace
if (lowername == "allow_uav_condition") if (name == "allow_uav_condition")
return EatAllow_uav_condition; return EatAllow_uav_condition;
else if (lowername == "branch") else if (name == "branch")
return EatBranch; return EatBranch;
else if (lowername == "call") else if (name == "call")
return EatCall; return EatCall;
else if (lowername == "domain") else if (name == "domain")
return EatDomain; return EatDomain;
else if (lowername == "earlydepthstencil") else if (name == "earlydepthstencil")
return EatEarlyDepthStencil; return EatEarlyDepthStencil;
else if (lowername == "fastopt") else if (name == "fastopt")
return EatFastOpt; return EatFastOpt;
else if (lowername == "flatten") else if (name == "flatten")
return EatFlatten; return EatFlatten;
else if (lowername == "forcecase") else if (name == "forcecase")
return EatForceCase; return EatForceCase;
else if (lowername == "instance") else if (name == "instance")
return EatInstance; return EatInstance;
else if (lowername == "maxtessfactor") else if (name == "maxtessfactor")
return EatMaxTessFactor; return EatMaxTessFactor;
else if (lowername == "maxvertexcount") else if (name == "maxvertexcount")
return EatMaxVertexCount; return EatMaxVertexCount;
else if (lowername == "numthreads") else if (name == "numthreads")
return EatNumThreads; return EatNumThreads;
else if (lowername == "outputcontrolpoints") else if (name == "outputcontrolpoints")
return EatOutputControlPoints; return EatOutputControlPoints;
else if (lowername == "outputtopology") else if (name == "outputtopology")
return EatOutputTopology; return EatOutputTopology;
else if (lowername == "partitioning") else if (name == "partitioning")
return EatPartitioning; return EatPartitioning;
else if (lowername == "patchconstantfunc") else if (name == "patchconstantfunc")
return EatPatchConstantFunc; return EatPatchConstantFunc;
else if (lowername == "unroll") else if (name == "unroll")
return EatUnroll; return EatUnroll;
else if (lowername == "loop") else if (name == "loop")
return EatLoop; return EatLoop;
else else
return EatNone; return EatNone;
} }
// Look up entry, inserting if it's not there, and if name is a valid attribute name
// as known by attributeFromName.
TAttributeType TAttributeMap::setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value)
{
if (name == nullptr)
return EatNone;
const TAttributeType attr = attributeFromName(nameSpace, *name);
if (attr != EatNone)
attributes[attr] = value;
return attr;
}
// Look up entry (const version), and return aggregate node. This cannot change the map.
const TIntermAggregate* TAttributeMap::operator[](TAttributeType attr) const
{
const auto entry = attributes.find(attr);
return (entry == attributes.end()) ? nullptr : entry->second;
}
// True if entry exists in map (even if value is nullptr)
bool TAttributeMap::contains(TAttributeType attr) const
{
return attributes.find(attr) != attributes.end();
}
// extract integers out of attribute arguments stored in attribute aggregate
bool TAttributeMap::getInt(TAttributeType attr, int& value, int argNum) const
{
const TConstUnion* intConst = getConstUnion(attr, 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 TAttributeMap::getString(TAttributeType attr, TString& value, int argNum, bool convertToLower) const
{
const TConstUnion* stringConst = getConstUnion(attr, EbtString, argNum);
if (stringConst == nullptr)
return false;
value = *stringConst->getSConst();
// Convenience.
if (convertToLower)
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
return true;
};
// Helper to get attribute const union. Returns nullptr on failure.
const TConstUnion* TAttributeMap::getConstUnion(TAttributeType attr, TBasicType basicType, int argNum) const
{
const TIntermAggregate* attrAgg = (*this)[attr];
if (attrAgg == nullptr)
return nullptr;
if (argNum >= int(attrAgg->getSequence().size()))
return nullptr;
const TConstUnion* constVal = &attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
if (constVal == nullptr || constVal->getType() != basicType)
return nullptr;
return constVal;
}
} // end namespace glslang } // end namespace glslang

View File

@ -38,93 +38,22 @@
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
#include "../glslang/MachineIndependent/attribute.h"
#include "../glslang/MachineIndependent/SymbolTable.h"
#include "hlslScanContext.h" #include "hlslScanContext.h"
#include "../glslang/Include/Common.h"
namespace glslang { 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
};
}
namespace std {
// Allow use of TAttributeType enum in hash_map without calling code having to cast.
template <> struct hash<glslang::TAttributeType> {
std::size_t operator()(glslang::TAttributeType attr) const {
return std::hash<int>()(int(attr));
}
};
} // end namespace std
namespace glslang {
class TIntermAggregate;
class TAttributeMap {
public:
int size() const { return (int)attributes.size(); }
// Search for and potentially add the attribute into the map. Return the
// attribute type enum for it, if found, else EatNone.
TAttributeType setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value);
// Const lookup: search for (but do not modify) the attribute in the map.
const TIntermAggregate* operator[](TAttributeType) const;
// True if entry exists in map (even if value is nullptr)
bool contains(TAttributeType) const;
// Obtain attribute as integer
bool getInt(TAttributeType attr, int& value, int argNum = 0) const;
// Obtain attribute as string, with optional to-lower transform
bool getString(TAttributeType attr, TString& value, int argNum = 0, bool convertToLower = true) const;
protected:
// Helper to get attribute const union
const TConstUnion* getConstUnion(TAttributeType attr, TBasicType, int argNum) const;
// Find an attribute enum given its name.
static TAttributeType attributeFromName(const TString& nameSpace, const TString& name);
std::unordered_map<TAttributeType, TIntermAggregate*> attributes;
};
class TFunctionDeclarator { class TFunctionDeclarator {
public: public:
TFunctionDeclarator() : function(nullptr), body(nullptr) { } TFunctionDeclarator() : function(nullptr), body(nullptr) { }
TSourceLoc loc; TSourceLoc loc;
TFunction* function; TFunction* function;
TAttributeMap attributes; TAttributes attributes;
TVector<HlslToken>* body; TVector<HlslToken>* body;
}; };
} // end namespace glslang } // end namespace glslang
#endif // HLSLATTRIBUTES_H_ #endif // HLSLATTRIBUTES_H_

View File

@ -396,6 +396,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
if (peekTokenClass(EHTokLeftParen)) { if (peekTokenClass(EHTokLeftParen)) {
// looks like function parameters // looks like function parameters
// merge in the attributes into the return type
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true);
// Potentially rename shader entry point function. No-op most of the time. // Potentially rename shader entry point function. No-op most of the time.
parseContext.renameShaderFunction(fullName); parseContext.renameShaderFunction(fullName);
@ -423,7 +426,13 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true); parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
} }
} else { } else {
// A variable declaration. Fix the storage qualifier if it's a global. // A variable declaration.
// merge in the attributes, the first time around, into the shared type
if (! declarator_list)
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType);
// Fix the storage qualifier if it's a global.
if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
declaredType.getQualifier().storage = EvqUniform; declaredType.getQualifier().storage = EvqUniform;
@ -536,13 +545,16 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node) bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
{ {
node = nullptr; node = nullptr;
TAttributeMap attributes; TAttributes attributes;
// fully_specified_type // fully_specified_type
TType type; TType type;
if (! acceptFullySpecifiedType(type, attributes)) if (! acceptFullySpecifiedType(type, attributes))
return false; return false;
if (attributes.size() > 0)
parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
// filter out type casts // filter out type casts
if (peekTokenClass(EHTokLeftParen)) { if (peekTokenClass(EHTokLeftParen)) {
recedeToken(); recedeToken();
@ -578,12 +590,12 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
// : type_specifier // : type_specifier
// | type_qualifier type_specifier // | type_qualifier type_specifier
// //
bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributeMap& attributes) bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes)
{ {
TIntermNode* nodeList = nullptr; TIntermNode* nodeList = nullptr;
return acceptFullySpecifiedType(type, nodeList, attributes); return acceptFullySpecifiedType(type, nodeList, attributes);
} }
bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributeMap& attributes, bool forbidDeclarators) bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators)
{ {
// type_qualifier // type_qualifier
TQualifier qualifier; TQualifier qualifier;
@ -608,7 +620,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
parseContext.mergeQualifiers(type.getQualifier(), qualifier); parseContext.mergeQualifiers(type.getQualifier(), qualifier);
// merge in the attributes // merge in the attributes
parseContext.transferTypeAttributes(attributes, type); parseContext.transferTypeAttributes(token.loc, attributes, type);
// further, it can create an anonymous instance of the block // further, it can create an anonymous instance of the block
// (cbuffer and tbuffer don't consume the next identifier, and // (cbuffer and tbuffer don't consume the next identifier, and
@ -633,9 +645,6 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
qualifier.builtIn = type.getQualifier().builtIn; qualifier.builtIn = type.getQualifier().builtIn;
type.getQualifier() = qualifier; type.getQualifier() = qualifier;
// merge in the attributes
parseContext.transferTypeAttributes(attributes, type);
} }
return true; return true;
@ -2335,7 +2344,7 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
// struct_declaration // struct_declaration
// attributes // attributes
TAttributeMap attributes; TAttributes attributes;
acceptAttributes(attributes); acceptAttributes(attributes);
bool declarator_list = false; bool declarator_list = false;
@ -2347,6 +2356,9 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
return false; return false;
} }
// merge in the attributes
parseContext.transferTypeAttributes(token.loc, attributes, memberType);
// struct_declarator COMMA struct_declarator ... // struct_declarator COMMA struct_declarator ...
bool functionDefinitionAccepted = false; bool functionDefinitionAccepted = false;
do { do {
@ -2542,7 +2554,7 @@ bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTy
bool HlslGrammar::acceptParameterDeclaration(TFunction& function) bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
{ {
// attributes // attributes
TAttributeMap attributes; TAttributes attributes;
acceptAttributes(attributes); acceptAttributes(attributes);
// fully_specified_type // fully_specified_type
@ -2550,6 +2562,9 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
if (! acceptFullySpecifiedType(*type, attributes)) if (! acceptFullySpecifiedType(*type, attributes))
return false; return false;
// merge in the attributes
parseContext.transferTypeAttributes(token.loc, attributes, *type);
// identifier // identifier
HlslToken idToken; HlslToken idToken;
acceptIdentifier(idToken); acceptIdentifier(idToken);
@ -3386,7 +3401,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
statement = nullptr; statement = nullptr;
// attributes // attributes
TAttributeMap attributes; TAttributes attributes;
acceptAttributes(attributes); acceptAttributes(attributes);
// attributed_statement // attributed_statement
@ -3458,7 +3473,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
// | PATCHCONSTANTFUNC // | PATCHCONSTANTFUNC
// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN // | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
// //
void HlslGrammar::acceptAttributes(TAttributeMap& attributes) void HlslGrammar::acceptAttributes(TAttributes& attributes)
{ {
// For now, accept the [ XXX(X) ] syntax, but drop all but // For now, accept the [ XXX(X) ] syntax, but drop all but
// numthreads, which is used to set the CS local size. // numthreads, which is used to set the CS local size.
@ -3529,9 +3544,16 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
return; return;
} }
// Add any values we found into the attribute map. This accepts // Add any values we found into the attribute map.
// (and ignores) values not mapping to a known TAttributeType; if (attributeToken.string != nullptr) {
attributes.setAttribute(nameSpace, attributeToken.string, expressions); TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string);
if (attributeType == EatNone)
parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), "");
else {
TAttributeArgs attributeArgs = { attributeType, expressions };
attributes.push_back(attributeArgs);
}
}
} while (true); } while (true);
} }
@ -3539,12 +3561,10 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
// : IF LEFT_PAREN expression RIGHT_PAREN statement // : IF LEFT_PAREN expression RIGHT_PAREN statement
// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement // : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
// //
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributeMap& attributes) bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes)
{ {
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
// IF // IF
if (! acceptTokenClass(EHTokIf)) if (! acceptTokenClass(EHTokIf))
return false; return false;
@ -3582,7 +3602,9 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
} }
// Put the pieces together // Put the pieces together
statement = intermediate.addSelection(condition, thenElse, loc, control); statement = intermediate.addSelection(condition, thenElse, loc);
parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes);
parseContext.popScope(); parseContext.popScope();
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
@ -3592,13 +3614,11 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
// switch_statement // switch_statement
// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement // : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
// //
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributeMap& attributes) bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes)
{ {
// SWITCH // SWITCH
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
if (! acceptTokenClass(EHTokSwitch)) if (! acceptTokenClass(EHTokSwitch))
return false; return false;
@ -3618,7 +3638,8 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
if (statementOkay) if (statementOkay)
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, control); statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr,
attributes);
parseContext.popSwitchSequence(); parseContext.popSwitchSequence();
parseContext.popScope(); parseContext.popScope();
@ -3632,7 +3653,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement // | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
// //
// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen. // Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes) bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
{ {
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
TIntermTyped* condition = nullptr; TIntermTyped* condition = nullptr;
@ -3643,8 +3664,7 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
// WHILE or DO or FOR // WHILE or DO or FOR
advanceToken(); advanceToken();
const TLoopControl control = parseContext.handleLoopControl(attributes); TIntermLoop* loopNode = nullptr;
switch (loop) { switch (loop) {
case EHTokWhile: case EHTokWhile:
// so that something declared in the condition is scoped to the lifetime // so that something declared in the condition is scoped to the lifetime
@ -3670,9 +3690,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
parseContext.popScope(); parseContext.popScope();
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control); loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
statement = loopNode;
return true; break;
case EHTokDo: case EHTokDo:
parseContext.nestLooping(); // this only needs to work right if no errors parseContext.nestLooping(); // this only needs to work right if no errors
@ -3703,9 +3723,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
parseContext.unnestLooping(); parseContext.unnestLooping();
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
statement = intermediate.addLoop(statement, condition, 0, false, loc, control); loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
statement = loopNode;
return true; break;
case EHTokFor: case EHTokFor:
{ {
@ -3747,18 +3767,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
return false; return false;
} }
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control); statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode);
parseContext.popScope(); parseContext.popScope();
parseContext.unnestLooping(); parseContext.unnestLooping();
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
return true; break;
} }
default: default:
return false; return false;
} }
parseContext.handleLoopAttributes(loc, loopNode, attributes);
return true;
} }
// jump_statement // jump_statement

View File

@ -43,7 +43,6 @@
namespace glslang { namespace glslang {
class TAttributeMap;
class TFunctionDeclarator; class TFunctionDeclarator;
// Should just be the grammar aspect of HLSL. // Should just be the grammar aspect of HLSL.
@ -71,8 +70,8 @@ namespace glslang {
bool acceptControlDeclaration(TIntermNode*& node); bool acceptControlDeclaration(TIntermNode*& node);
bool acceptSamplerDeclarationDX9(TType&); bool acceptSamplerDeclarationDX9(TType&);
bool acceptSamplerState(); bool acceptSamplerState();
bool acceptFullySpecifiedType(TType&, const TAttributeMap&); bool acceptFullySpecifiedType(TType&, const TAttributes&);
bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributeMap&, bool forbidDeclarators = false); bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false);
bool acceptQualifier(TQualifier&); bool acceptQualifier(TQualifier&);
bool acceptLayoutQualifierList(TQualifier&); bool acceptLayoutQualifierList(TQualifier&);
bool acceptType(TType&); bool acceptType(TType&);
@ -117,10 +116,10 @@ namespace glslang {
bool acceptScopedCompoundStatement(TIntermNode*&); bool acceptScopedCompoundStatement(TIntermNode*&);
bool acceptStatement(TIntermNode*&); bool acceptStatement(TIntermNode*&);
bool acceptNestedStatement(TIntermNode*&); bool acceptNestedStatement(TIntermNode*&);
void acceptAttributes(TAttributeMap&); void acceptAttributes(TAttributes&);
bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&); bool acceptSelectionStatement(TIntermNode*&, const TAttributes&);
bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&); bool acceptSwitchStatement(TIntermNode*&, const TAttributes&);
bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&); bool acceptIterationStatement(TIntermNode*&, const TAttributes&);
bool acceptJumpStatement(TIntermNode*&); bool acceptJumpStatement(TIntermNode*&);
bool acceptCaseLabel(TIntermNode*&); bool acceptCaseLabel(TIntermNode*&);
bool acceptDefaultLabel(TIntermNode*&); bool acceptDefaultLabel(TIntermNode*&);

View File

@ -1620,7 +1620,7 @@ void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc,
// Returns an aggregate of parameter-symbol nodes. // Returns an aggregate of parameter-symbol nodes.
// //
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function, TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
const TAttributeMap& attributes, const TAttributes& attributes,
TIntermNode*& entryPointTree) TIntermNode*& entryPointTree)
{ {
currentCaller = function.getMangledName(); currentCaller = function.getMangledName();
@ -1717,43 +1717,44 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
} }
// Handle all [attrib] attribute for the shader entry point // Handle all [attrib] attribute for the shader entry point
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes) void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes)
{ {
// Handle entry-point function attributes for (auto it = attributes.begin(); it != attributes.end(); ++it) {
const TIntermAggregate* numThreads = attributes[EatNumThreads]; switch (it->name) {
if (numThreads != nullptr) { case EatNumThreads:
const TIntermSequence& sequence = numThreads->getSequence(); {
const TIntermSequence& sequence = it->args->getSequence();
for (int lid = 0; lid < int(sequence.size()); ++lid) for (int lid = 0; lid < int(sequence.size()); ++lid)
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst()); intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
break;
} }
case EatMaxVertexCount:
// MaxVertexCount {
if (attributes.contains(EatMaxVertexCount)) {
int maxVertexCount; int maxVertexCount;
if (! attributes.getInt(EatMaxVertexCount, maxVertexCount)) { if (! it->getInt(maxVertexCount)) {
error(loc, "invalid maxvertexcount", "", ""); error(loc, "invalid maxvertexcount", "", "");
} else { } else {
if (! intermediate.setVertices(maxVertexCount)) if (! intermediate.setVertices(maxVertexCount))
error(loc, "cannot change previously set maxvertexcount attribute", "", ""); error(loc, "cannot change previously set maxvertexcount attribute", "", "");
} }
break;
} }
case EatPatchConstantFunc:
// Handle [patchconstantfunction("...")] {
if (attributes.contains(EatPatchConstantFunc)) {
TString pcfName; TString pcfName;
if (! attributes.getString(EatPatchConstantFunc, pcfName, 0, false)) { if (! it->getString(pcfName, 0, false)) {
error(loc, "invalid patch constant function", "", ""); error(loc, "invalid patch constant function", "", "");
} else { } else {
patchConstantFunctionName = pcfName; patchConstantFunctionName = pcfName;
} }
break;
} }
case EatDomain:
{
// Handle [domain("...")] // Handle [domain("...")]
if (attributes.contains(EatDomain)) {
TString domainStr; TString domainStr;
if (! attributes.getString(EatDomain, domainStr)) { if (! it->getString(domainStr)) {
error(loc, "invalid domain", "", ""); error(loc, "invalid domain", "", "");
} else { } else {
TLayoutGeometry domain = ElgNone; TLayoutGeometry domain = ElgNone;
@ -1776,12 +1777,13 @@ void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const T
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), ""); error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
} }
} }
break;
} }
case EatOutputTopology:
{
// Handle [outputtopology("...")] // Handle [outputtopology("...")]
if (attributes.contains(EatOutputTopology)) {
TString topologyStr; TString topologyStr;
if (! attributes.getString(EatOutputTopology, topologyStr)) { if (! it->getString(topologyStr)) {
error(loc, "invalid outputtopology", "", ""); error(loc, "invalid outputtopology", "", "");
} else { } else {
TVertexOrder vertexOrder = EvoNone; TVertexOrder vertexOrder = EvoNone;
@ -1810,12 +1812,13 @@ void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const T
if (primitive != ElgNone) if (primitive != ElgNone)
intermediate.setOutputPrimitive(primitive); intermediate.setOutputPrimitive(primitive);
} }
break;
} }
case EatPartitioning:
{
// Handle [partitioning("...")] // Handle [partitioning("...")]
if (attributes.contains(EatPartitioning)) {
TString partitionStr; TString partitionStr;
if (! attributes.getString(EatPartitioning, partitionStr)) { if (! it->getString(partitionStr)) {
error(loc, "invalid partitioning", "", ""); error(loc, "invalid partitioning", "", "");
} else { } else {
TVertexSpacing partitioning = EvsNone; TVertexSpacing partitioning = EvsNone;
@ -1835,72 +1838,97 @@ void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const T
error(loc, "cannot change previously set partitioning", error(loc, "cannot change previously set partitioning",
TQualifier::getVertexSpacingString(partitioning), ""); TQualifier::getVertexSpacingString(partitioning), "");
} }
break;
} }
case EatOutputControlPoints:
{
// Handle [outputcontrolpoints("...")] // Handle [outputcontrolpoints("...")]
if (attributes.contains(EatOutputControlPoints)) {
int ctrlPoints; int ctrlPoints;
if (! attributes.getInt(EatOutputControlPoints, ctrlPoints)) { if (! it->getInt(ctrlPoints)) {
error(loc, "invalid outputcontrolpoints", "", ""); error(loc, "invalid outputcontrolpoints", "", "");
} else { } else {
if (! intermediate.setVertices(ctrlPoints)) { if (! intermediate.setVertices(ctrlPoints)) {
error(loc, "cannot change previously set outputcontrolpoints attribute", "", ""); error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
} }
} }
break;
}
case EatBuiltIn:
case EatLocation:
// tolerate these because of dual use of entrypoint and type attributes
break;
default:
warn(loc, "attribute does not apply to entry point", "", "");
break;
}
} }
} }
// Update the given type with any type-like attribute information in the // Update the given type with any type-like attribute information in the
// attributes. // attributes.
void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, TType& type) void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type,
bool allowEntry)
{ {
if (attributes.size() == 0) if (attributes.size() == 0)
return; return;
// location
int value; int value;
if (attributes.getInt(EatLocation, value)) TString builtInString;
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
switch (it->name) {
case EatLocation:
// location
if (it->getInt(value))
type.getQualifier().layoutLocation = value; type.getQualifier().layoutLocation = value;
break;
case EatBinding:
// binding // binding
if (attributes.getInt(EatBinding, value)) { if (it->getInt(value)) {
type.getQualifier().layoutBinding = value; type.getQualifier().layoutBinding = value;
type.getQualifier().layoutSet = 0; type.getQualifier().layoutSet = 0;
} }
// set // set
if (attributes.getInt(EatBinding, value, 1)) if (it->getInt(value, 1))
type.getQualifier().layoutSet = value; type.getQualifier().layoutSet = value;
break;
case EatGlobalBinding:
// global cbuffer binding // global cbuffer binding
if (attributes.getInt(EatGlobalBinding, value)) if (it->getInt(value))
globalUniformBinding = value; globalUniformBinding = value;
// global cbuffer binding // global cbuffer binding
if (attributes.getInt(EatGlobalBinding, value, 1)) if (it->getInt(value, 1))
globalUniformSet = value; globalUniformSet = value;
break;
case EatInputAttachment:
// input attachment // input attachment
if (attributes.getInt(EatInputAttachment, value)) if (it->getInt(value))
type.getQualifier().layoutAttachment = value; type.getQualifier().layoutAttachment = value;
break;
case EatBuiltIn:
// PointSize built-in // PointSize built-in
TString builtInString; if (it->getString(builtInString, 0, false)) {
if (attributes.getString(EatBuiltIn, builtInString, 0, false)) {
if (builtInString == "PointSize") if (builtInString == "PointSize")
type.getQualifier().builtIn = EbvPointSize; type.getQualifier().builtIn = EbvPointSize;
} }
break;
case EatPushConstant:
// push_constant // push_constant
if (attributes.contains(EatPushConstant))
type.getQualifier().layoutPushConstant = true; type.getQualifier().layoutPushConstant = true;
break;
case EatConstantId:
// specialization constant // specialization constant
if (attributes.getInt(EatConstantId, value)) { if (it->getInt(value)) {
TSourceLoc loc; TSourceLoc loc;
loc.init(); loc.init();
setSpecConstantId(loc, type.getQualifier(), value); setSpecConstantId(loc, type.getQualifier(), value);
} }
break;
default:
if (! allowEntry)
warn(loc, "attribute does not apply to a type", "", "");
break;
}
}
} }
// //
@ -1936,7 +1964,7 @@ void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, T
// a subtree that creates the entry point. // a subtree that creates the entry point.
// //
TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction, TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction,
const TAttributeMap& attributes) const TAttributes& attributes)
{ {
// Return true if this is a tessellation patch constant function input to a domain shader. // Return true if this is a tessellation patch constant function input to a domain shader.
const auto isDsPcfInput = [this](const TType& type) { const auto isDsPcfInput = [this](const TType& type) {
@ -8792,29 +8820,75 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
} }
// //
// Selection hints // Selection attributes
// //
TSelectionControl HlslParseContext::handleSelectionControl(const TAttributeMap& attributes) const void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection,
const TAttributes& attributes)
{ {
if (attributes.contains(EatFlatten)) if (selection == nullptr)
return ESelectionControlFlatten; return;
else if (attributes.contains(EatBranch))
return ESelectionControlDontFlatten; for (auto it = attributes.begin(); it != attributes.end(); ++it) {
else switch (it->name) {
return ESelectionControlNone; case EatFlatten:
selection->setFlatten();
break;
case EatBranch:
selection->setDontFlatten();
break;
default:
warn(loc, "attribute does not apply to a selection", "", "");
break;
}
}
}
//
// Switch attributes
//
void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection,
const TAttributes& attributes)
{
if (selection == nullptr)
return;
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
switch (it->name) {
case EatFlatten:
selection->setFlatten();
break;
case EatBranch:
selection->setDontFlatten();
break;
default:
warn(loc, "attribute does not apply to a switch", "", "");
break;
}
}
} }
// //
// Loop hints // Loop hints
// //
TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
const TAttributes& attributes)
{ {
if (attributes.contains(EatUnroll)) if (loop == nullptr)
return ELoopControlUnroll; return;
else if (attributes.contains(EatLoop))
return ELoopControlDontUnroll; for (auto it = attributes.begin(); it != attributes.end(); ++it) {
else switch (it->name) {
return ELoopControlNone; case EatUnroll:
loop->setUnroll();
break;
case EatLoop:
loop->setDontUnroll();
break;
default:
warn(loc, "attribute does not apply to a loop", "", "");
break;
}
}
} }
// //
@ -8959,7 +9033,7 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn
// into a switch node. // into a switch node.
// //
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
TIntermAggregate* lastStatements, TSelectionControl control) TIntermAggregate* lastStatements, const TAttributes& attributes)
{ {
wrapupSwitchSubsequence(lastStatements, nullptr); wrapupSwitchSubsequence(lastStatements, nullptr);
@ -8986,7 +9060,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
TIntermSwitch* switchNode = new TIntermSwitch(expression, body); TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
switchNode->setLoc(loc); switchNode->setLoc(loc);
switchNode->setSelectionControl(control); handleSwitchAttributes(loc, switchNode, attributes);
return switchNode; return switchNode;
} }

View File

@ -38,12 +38,12 @@
#include "../glslang/MachineIndependent/parseVersions.h" #include "../glslang/MachineIndependent/parseVersions.h"
#include "../glslang/MachineIndependent/ParseHelper.h" #include "../glslang/MachineIndependent/ParseHelper.h"
#include "../glslang/MachineIndependent/attribute.h"
#include <array> #include <array>
namespace glslang { namespace glslang {
class TAttributeMap; // forward declare
class TFunctionDeclarator; class TFunctionDeclarator;
class HlslParseContext : public TParseContextBase { class HlslParseContext : public TParseContextBase {
@ -80,10 +80,10 @@ public:
bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field); bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field);
void assignToInterface(TVariable& variable); void assignToInterface(TVariable& variable);
void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree);
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&); TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&);
void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&); void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&);
void transferTypeAttributes(const TAttributeMap&, TType&); void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false);
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node); void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs); void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
void remapNonEntryPointIO(TFunction& function); void remapNonEntryPointIO(TFunction& function);
@ -163,7 +163,7 @@ public:
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, TSelectionControl control); TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&);
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
@ -203,10 +203,11 @@ public:
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry); bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
// Determine selection control from attributes // Determine selection control from attributes
TSelectionControl handleSelectionControl(const TAttributeMap& attributes) const; void handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection*, const TAttributes& attributes);
void handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch*, const TAttributes& attributes);
// Determine loop control from attributes // Determine loop control from attributes
TLoopControl handleLoopControl(const TAttributeMap& attributes) const; void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes);
// Share struct buffer deep types // Share struct buffer deep types
void shareStructBufferType(TType&); void shareStructBufferType(TType&);
@ -217,6 +218,8 @@ public:
// Obtain the sampler return type of the given sampler in retType. // Obtain the sampler return type of the given sampler in retType.
void getTextureReturnType(const TSampler& sampler, TType& retType) const; void getTextureReturnType(const TSampler& sampler, TType& retType) const;
TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const;
protected: protected:
struct TFlattenData { struct TFlattenData {
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd), TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),