spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
- spv::SelectionControlMask TranslateSelectionControl(glslang::TSelectionControl) const;
- spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const;
+ spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
+ spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
+ spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&) const;
spv::StorageClass TranslateStorageClass(const glslang::TType&);
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&);
}
}
-spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(glslang::TSelectionControl selectionControl) const
+spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const
{
- switch (selectionControl) {
- case glslang::ESelectionControlNone: return spv::SelectionControlMaskNone;
- case glslang::ESelectionControlFlatten: return spv::SelectionControlFlattenMask;
- case glslang::ESelectionControlDontFlatten: return spv::SelectionControlDontFlattenMask;
- default: return spv::SelectionControlMaskNone;
- }
+ if (selectionNode.getFlatten())
+ return spv::SelectionControlFlattenMask;
+ if (selectionNode.getDontFlatten())
+ return spv::SelectionControlDontFlattenMask;
+ return spv::SelectionControlMaskNone;
}
-spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const
+spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const
{
- switch (loopControl) {
- case glslang::ELoopControlNone: return spv::LoopControlMaskNone;
- case glslang::ELoopControlUnroll: return spv::LoopControlUnrollMask;
- case glslang::ELoopControlDontUnroll: return spv::LoopControlDontUnrollMask;
- // TODO: DependencyInfinite
- // TODO: DependencyLength
- default: return spv::LoopControlMaskNone;
- }
+ if (switchNode.getFlatten())
+ return spv::SelectionControlFlattenMask;
+ if (switchNode.getDontFlatten())
+ return spv::SelectionControlDontFlattenMask;
+ return spv::SelectionControlMaskNone;
+}
+
+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.
node->getCondition()->traverse(this);
// 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
spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder);
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
// Selection control:
- const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
+ const spv::SelectionControlMask control = TranslateSwitchControl(*node);
// browse the children to sort out code segments
int defaultSegment = -1;
builder.createBranch(&blocks.head);
// Loop control:
- const spv::LoopControlMask control = TranslateLoopControl(node->getLoopControl());
+ const spv::LoopControlMask control = TranslateLoopControl(*node);
// TODO: dependency length
hlsl.numthreads.comp
Shader version: 500
-local_size = (4, 4, 2)
+local_size = (1, 4, 8)
0:? Sequence
0:4 Function Definition: main(vu3; ( temp void)
0:4 Function Parameters:
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 '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:? Sequence
0:9 move second child to first child ( temp 3-component vector of uint)
0:? 'tid' ( temp 3-component vector of uint)
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:? Linker Objects
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
Shader version: 500
-local_size = (4, 4, 2)
+local_size = (1, 4, 8)
0:? Sequence
0:4 Function Definition: main(vu3; ( temp void)
0:4 Function Parameters:
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 '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:? Sequence
0:9 move second child to first child ( temp 3-component vector of uint)
0:? 'tid' ( temp 3-component vector of uint)
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:? Linker Objects
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
- EntryPoint GLCompute 4 "main_aux1" 18
- ExecutionMode 4 LocalSize 4 4 2
+ EntryPoint GLCompute 4 "main_aux2" 18
+ ExecutionMode 4 LocalSize 1 4 8
Source HLSL 500
- Name 4 "main_aux1"
+ Name 4 "main_aux2"
Name 11 "main(vu3;"
Name 10 "tid"
- Name 14 "@main_aux1(vu3;"
+ Name 14 "@main_aux2(vu3;"
Name 13 "tid"
Name 16 "tid"
Name 18 "tid"
9: TypeFunction 2 8(ptr)
17: TypePointer Input 7(ivec3)
18(tid): 17(ptr) Variable Input
- 4(main_aux1): 2 Function None 3
+ 4(main_aux2): 2 Function None 3
5: Label
16(tid): 8(ptr) Variable Function
20(param): 8(ptr) Variable Function
Store 16(tid) 19
21: 7(ivec3) Load 16(tid)
Store 20(param) 21
- 22: 2 FunctionCall 14(@main_aux1(vu3;) 20(param)
+ 22: 2 FunctionCall 14(@main_aux2(vu3;) 20(param)
Return
FunctionEnd
11(main(vu3;): 2 Function None 9
12: Label
Return
FunctionEnd
-14(@main_aux1(vu3;): 2 Function None 9
+14(@main_aux2(vu3;): 2 Function None 9
13(tid): 8(ptr) FunctionParameter
15: Label
Return
{
}
-[numTHreaDs(4,4,2)] // case insensitive
-void main_aux1(uint3 tid : SV_DispatchThreadID )
+[numthreads(1,4,8)]
+void main_aux2(uint3 tid : SV_DispatchThreadID )
{
}
-[numthreads(1,4,8)]
-void main_aux2(uint3 tid : SV_DispatchThreadID );
-
set(SOURCES
MachineIndependent/glslang.y
MachineIndependent/glslang_tab.cpp
+ MachineIndependent/attribute.cpp
MachineIndependent/Constant.cpp
MachineIndependent/iomapper.cpp
MachineIndependent/InfoSink.cpp
Include/revision.h
Include/ShHandle.h
Include/Types.h
+ MachineIndependent/attribute.h
MachineIndependent/glslang_tab.cpp.h
MachineIndependent/gl_types.h
MachineIndependent/Initialize.h
#ifndef _CONSTANT_UNION_INCLUDED_
#define _CONSTANT_UNION_INCLUDED_
+#include "../Include/Common.h"
+#include "../Include/BaseTypes.h"
+
namespace glslang {
class TConstUnion {
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; }
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:
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.
//
test(aTest),
terminal(aTerminal),
first(testFirst),
- control(ELoopControlNone)
+ unroll(false),
+ dontUnroll(false)
{ }
- 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; }
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
};
//
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
};
//
//
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
//
// 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
TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
node->setLoc(loc);
- node->setSelectionControl(control);
return node;
}
//
// 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);
}
//
//
// 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;
}
//
// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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_
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;
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&);
{"hlsl.matrixindex.frag", "main"},
{"hlsl.nonstaticMemberFunction.frag", "main"},
{"hlsl.numericsuffixes.frag", "main"},
- {"hlsl.numthreads.comp", "main_aux1"},
+ {"hlsl.numthreads.comp", "main_aux2"},
{"hlsl.overload.frag", "PixelShaderFunction"},
{"hlsl.opaque-type-bug.frag", "main"},
{"hlsl.params.default.frag", "main"},
//
#include "hlslAttributes.h"
-#include <cstdlib>
-#include <cctype>
-#include <algorithm>
+#include "hlslParseHelper.h"
namespace glslang {
// Map the given string to an attribute enum from TAttributeType,
// 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
- if (lowernameSpace == "vk") {
- if (lowername == "input_attachment_index")
+ if (nameSpace == "vk") {
+ if (name == "input_attachment_index")
return EatInputAttachment;
- else if (lowername == "location")
+ else if (name == "location")
return EatLocation;
- else if (lowername == "binding")
+ else if (name == "binding")
return EatBinding;
- else if (lowername == "global_cbuffer_binding")
+ else if (name == "global_cbuffer_binding")
return EatGlobalBinding;
- else if (lowername == "builtin")
+ else if (name == "builtin")
return EatBuiltIn;
- else if (lowername == "constant_id")
+ else if (name == "constant_id")
return EatConstantId;
- else if (lowername == "push_constant")
+ else if (name == "push_constant")
return EatPushConstant;
- } else if (lowernameSpace.size() > 0)
+ } else if (nameSpace.size() > 0)
return EatNone;
// handle names with no namespace
- if (lowername == "allow_uav_condition")
+ if (name == "allow_uav_condition")
return EatAllow_uav_condition;
- else if (lowername == "branch")
+ else if (name == "branch")
return EatBranch;
- else if (lowername == "call")
+ else if (name == "call")
return EatCall;
- else if (lowername == "domain")
+ else if (name == "domain")
return EatDomain;
- else if (lowername == "earlydepthstencil")
+ else if (name == "earlydepthstencil")
return EatEarlyDepthStencil;
- else if (lowername == "fastopt")
+ else if (name == "fastopt")
return EatFastOpt;
- else if (lowername == "flatten")
+ else if (name == "flatten")
return EatFlatten;
- else if (lowername == "forcecase")
+ else if (name == "forcecase")
return EatForceCase;
- else if (lowername == "instance")
+ else if (name == "instance")
return EatInstance;
- else if (lowername == "maxtessfactor")
+ else if (name == "maxtessfactor")
return EatMaxTessFactor;
- else if (lowername == "maxvertexcount")
+ else if (name == "maxvertexcount")
return EatMaxVertexCount;
- else if (lowername == "numthreads")
+ else if (name == "numthreads")
return EatNumThreads;
- else if (lowername == "outputcontrolpoints")
+ else if (name == "outputcontrolpoints")
return EatOutputControlPoints;
- else if (lowername == "outputtopology")
+ else if (name == "outputtopology")
return EatOutputTopology;
- else if (lowername == "partitioning")
+ else if (name == "partitioning")
return EatPartitioning;
- else if (lowername == "patchconstantfunc")
+ else if (name == "patchconstantfunc")
return EatPatchConstantFunc;
- else if (lowername == "unroll")
+ else if (name == "unroll")
return EatUnroll;
- else if (lowername == "loop")
+ else if (name == "loop")
return EatLoop;
else
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
#include <unordered_map>
#include <functional>
-#include "hlslScanContext.h"
-#include "../glslang/Include/Common.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
- };
-}
-
-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
+#include "../glslang/MachineIndependent/attribute.h"
+#include "../glslang/MachineIndependent/SymbolTable.h"
+#include "hlslScanContext.h"
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 {
public:
TFunctionDeclarator() : function(nullptr), body(nullptr) { }
TSourceLoc loc;
TFunction* function;
- TAttributeMap attributes;
+ TAttributes attributes;
TVector<HlslToken>* body;
};
} // end namespace glslang
-
#endif // HLSLATTRIBUTES_H_
if (peekTokenClass(EHTokLeftParen)) {
// 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.
parseContext.renameShaderFunction(fullName);
parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
}
} 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())
declaredType.getQualifier().storage = EvqUniform;
bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
{
node = nullptr;
- TAttributeMap attributes;
+ TAttributes attributes;
// fully_specified_type
TType type;
if (! acceptFullySpecifiedType(type, attributes))
return false;
+ if (attributes.size() > 0)
+ parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
+
// filter out type casts
if (peekTokenClass(EHTokLeftParen)) {
recedeToken();
// : 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;
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
TQualifier qualifier;
parseContext.mergeQualifiers(type.getQualifier(), qualifier);
// merge in the attributes
- parseContext.transferTypeAttributes(attributes, type);
+ parseContext.transferTypeAttributes(token.loc, attributes, type);
// further, it can create an anonymous instance of the block
// (cbuffer and tbuffer don't consume the next identifier, and
qualifier.builtIn = type.getQualifier().builtIn;
type.getQualifier() = qualifier;
-
- // merge in the attributes
- parseContext.transferTypeAttributes(attributes, type);
}
return true;
// struct_declaration
// attributes
- TAttributeMap attributes;
+ TAttributes attributes;
acceptAttributes(attributes);
bool declarator_list = false;
expected("member type");
return false;
}
+
+ // merge in the attributes
+ parseContext.transferTypeAttributes(token.loc, attributes, memberType);
// struct_declarator COMMA struct_declarator ...
bool functionDefinitionAccepted = false;
bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
{
// attributes
- TAttributeMap attributes;
+ TAttributes attributes;
acceptAttributes(attributes);
// fully_specified_type
if (! acceptFullySpecifiedType(*type, attributes))
return false;
+ // merge in the attributes
+ parseContext.transferTypeAttributes(token.loc, attributes, *type);
+
// identifier
HlslToken idToken;
acceptIdentifier(idToken);
statement = nullptr;
// attributes
- TAttributeMap attributes;
+ TAttributes attributes;
acceptAttributes(attributes);
// attributed_statement
// | PATCHCONSTANTFUNC
// | 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
// numthreads, which is used to set the CS local size.
return;
}
- // Add any values we found into the attribute map. This accepts
- // (and ignores) values not mapping to a known TAttributeType;
- attributes.setAttribute(nameSpace, attributeToken.string, expressions);
+ // Add any values we found into the attribute map.
+ if (attributeToken.string != nullptr) {
+ 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);
}
// : IF LEFT_PAREN expression RIGHT_PAREN 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;
- const TSelectionControl control = parseContext.handleSelectionControl(attributes);
-
// IF
if (! acceptTokenClass(EHTokIf))
return false;
}
// 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.controlFlowNestingLevel;
// switch_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
TSourceLoc loc = token.loc;
- const TSelectionControl control = parseContext.handleSelectionControl(attributes);
-
if (! acceptTokenClass(EHTokSwitch))
return false;
--parseContext.controlFlowNestingLevel;
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.popScope();
// | 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.
-bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
+bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
{
TSourceLoc loc = token.loc;
TIntermTyped* condition = nullptr;
// WHILE or DO or FOR
advanceToken();
-
- const TLoopControl control = parseContext.handleLoopControl(attributes);
+ TIntermLoop* loopNode = nullptr;
switch (loop) {
case EHTokWhile:
// so that something declared in the condition is scoped to the lifetime
parseContext.popScope();
--parseContext.controlFlowNestingLevel;
- statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
-
- return true;
+ loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
+ statement = loopNode;
+ break;
case EHTokDo:
parseContext.nestLooping(); // this only needs to work right if no errors
parseContext.unnestLooping();
--parseContext.controlFlowNestingLevel;
- statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
-
- return true;
+ loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
+ statement = loopNode;
+ break;
case EHTokFor:
{
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.unnestLooping();
--parseContext.controlFlowNestingLevel;
- return true;
+ break;
}
default:
return false;
}
+
+ parseContext.handleLoopAttributes(loc, loopNode, attributes);
+ return true;
}
// jump_statement
namespace glslang {
- class TAttributeMap;
class TFunctionDeclarator;
// Should just be the grammar aspect of HLSL.
bool acceptControlDeclaration(TIntermNode*& node);
bool acceptSamplerDeclarationDX9(TType&);
bool acceptSamplerState();
- bool acceptFullySpecifiedType(TType&, const TAttributeMap&);
- bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributeMap&, bool forbidDeclarators = false);
+ bool acceptFullySpecifiedType(TType&, const TAttributes&);
+ bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false);
bool acceptQualifier(TQualifier&);
bool acceptLayoutQualifierList(TQualifier&);
bool acceptType(TType&);
bool acceptScopedCompoundStatement(TIntermNode*&);
bool acceptStatement(TIntermNode*&);
bool acceptNestedStatement(TIntermNode*&);
- void acceptAttributes(TAttributeMap&);
- bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&);
- bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&);
- bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
+ void acceptAttributes(TAttributes&);
+ bool acceptSelectionStatement(TIntermNode*&, const TAttributes&);
+ bool acceptSwitchStatement(TIntermNode*&, const TAttributes&);
+ bool acceptIterationStatement(TIntermNode*&, const TAttributes&);
bool acceptJumpStatement(TIntermNode*&);
bool acceptCaseLabel(TIntermNode*&);
bool acceptDefaultLabel(TIntermNode*&);
// Returns an aggregate of parameter-symbol nodes.
//
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
- const TAttributeMap& attributes,
+ const TAttributes& attributes,
TIntermNode*& entryPointTree)
{
currentCaller = function.getMangledName();
}
// 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
- const TIntermAggregate* numThreads = attributes[EatNumThreads];
- if (numThreads != nullptr) {
- const TIntermSequence& sequence = numThreads->getSequence();
-
- for (int lid = 0; lid < int(sequence.size()); ++lid)
- intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
- }
-
- // MaxVertexCount
- if (attributes.contains(EatMaxVertexCount)) {
- int maxVertexCount;
-
- if (! attributes.getInt(EatMaxVertexCount, maxVertexCount)) {
- error(loc, "invalid maxvertexcount", "", "");
- } else {
- if (! intermediate.setVertices(maxVertexCount))
- error(loc, "cannot change previously set maxvertexcount attribute", "", "");
- }
- }
-
- // Handle [patchconstantfunction("...")]
- if (attributes.contains(EatPatchConstantFunc)) {
- TString pcfName;
- if (! attributes.getString(EatPatchConstantFunc, pcfName, 0, false)) {
- error(loc, "invalid patch constant function", "", "");
- } else {
- patchConstantFunctionName = pcfName;
+ for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+ switch (it->name) {
+ case EatNumThreads:
+ {
+ const TIntermSequence& sequence = it->args->getSequence();
+ for (int lid = 0; lid < int(sequence.size()); ++lid)
+ intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+ break;
}
- }
+ case EatMaxVertexCount:
+ {
+ int maxVertexCount;
- // Handle [domain("...")]
- if (attributes.contains(EatDomain)) {
- TString domainStr;
- if (! attributes.getString(EatDomain, domainStr)) {
- error(loc, "invalid domain", "", "");
- } else {
- TLayoutGeometry domain = ElgNone;
-
- if (domainStr == "tri") {
- domain = ElgTriangles;
- } else if (domainStr == "quad") {
- domain = ElgQuads;
- } else if (domainStr == "isoline") {
- domain = ElgIsolines;
+ if (! it->getInt(maxVertexCount)) {
+ error(loc, "invalid maxvertexcount", "", "");
} else {
- error(loc, "unsupported domain type", domainStr.c_str(), "");
+ if (! intermediate.setVertices(maxVertexCount))
+ error(loc, "cannot change previously set maxvertexcount attribute", "", "");
}
-
- if (language == EShLangTessEvaluation) {
- if (! intermediate.setInputPrimitive(domain))
- error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+ break;
+ }
+ case EatPatchConstantFunc:
+ {
+ TString pcfName;
+ if (! it->getString(pcfName, 0, false)) {
+ error(loc, "invalid patch constant function", "", "");
} else {
- if (! intermediate.setOutputPrimitive(domain))
- error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+ patchConstantFunctionName = pcfName;
}
+ break;
}
- }
-
- // Handle [outputtopology("...")]
- if (attributes.contains(EatOutputTopology)) {
- TString topologyStr;
- if (! attributes.getString(EatOutputTopology, topologyStr)) {
- error(loc, "invalid outputtopology", "", "");
- } else {
- TVertexOrder vertexOrder = EvoNone;
- TLayoutGeometry primitive = ElgNone;
-
- if (topologyStr == "point") {
- intermediate.setPointMode();
- } else if (topologyStr == "line") {
- primitive = ElgIsolines;
- } else if (topologyStr == "triangle_cw") {
- vertexOrder = EvoCw;
- primitive = ElgTriangles;
- } else if (topologyStr == "triangle_ccw") {
- vertexOrder = EvoCcw;
- primitive = ElgTriangles;
+ case EatDomain:
+ {
+ // Handle [domain("...")]
+ TString domainStr;
+ if (! it->getString(domainStr)) {
+ error(loc, "invalid domain", "", "");
} else {
- error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
- }
+ TLayoutGeometry domain = ElgNone;
+
+ if (domainStr == "tri") {
+ domain = ElgTriangles;
+ } else if (domainStr == "quad") {
+ domain = ElgQuads;
+ } else if (domainStr == "isoline") {
+ domain = ElgIsolines;
+ } else {
+ error(loc, "unsupported domain type", domainStr.c_str(), "");
+ }
- if (vertexOrder != EvoNone) {
- if (! intermediate.setVertexOrder(vertexOrder)) {
- error(loc, "cannot change previously set outputtopology",
- TQualifier::getVertexOrderString(vertexOrder), "");
+ if (language == EShLangTessEvaluation) {
+ if (! intermediate.setInputPrimitive(domain))
+ error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+ } else {
+ if (! intermediate.setOutputPrimitive(domain))
+ error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
}
}
- if (primitive != ElgNone)
- intermediate.setOutputPrimitive(primitive);
+ break;
}
- }
-
- // Handle [partitioning("...")]
- if (attributes.contains(EatPartitioning)) {
- TString partitionStr;
- if (! attributes.getString(EatPartitioning, partitionStr)) {
- error(loc, "invalid partitioning", "", "");
- } else {
- TVertexSpacing partitioning = EvsNone;
-
- if (partitionStr == "integer") {
- partitioning = EvsEqual;
- } else if (partitionStr == "fractional_even") {
- partitioning = EvsFractionalEven;
- } else if (partitionStr == "fractional_odd") {
- partitioning = EvsFractionalOdd;
- //} else if (partition == "pow2") { // TODO: currently nothing to map this to.
+ case EatOutputTopology:
+ {
+ // Handle [outputtopology("...")]
+ TString topologyStr;
+ if (! it->getString(topologyStr)) {
+ error(loc, "invalid outputtopology", "", "");
} else {
- error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
- }
+ TVertexOrder vertexOrder = EvoNone;
+ TLayoutGeometry primitive = ElgNone;
+
+ if (topologyStr == "point") {
+ intermediate.setPointMode();
+ } else if (topologyStr == "line") {
+ primitive = ElgIsolines;
+ } else if (topologyStr == "triangle_cw") {
+ vertexOrder = EvoCw;
+ primitive = ElgTriangles;
+ } else if (topologyStr == "triangle_ccw") {
+ vertexOrder = EvoCcw;
+ primitive = ElgTriangles;
+ } else {
+ error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
+ }
- if (! intermediate.setVertexSpacing(partitioning))
- error(loc, "cannot change previously set partitioning",
- TQualifier::getVertexSpacingString(partitioning), "");
+ if (vertexOrder != EvoNone) {
+ if (! intermediate.setVertexOrder(vertexOrder)) {
+ error(loc, "cannot change previously set outputtopology",
+ TQualifier::getVertexOrderString(vertexOrder), "");
+ }
+ }
+ if (primitive != ElgNone)
+ intermediate.setOutputPrimitive(primitive);
+ }
+ break;
}
- }
+ case EatPartitioning:
+ {
+ // Handle [partitioning("...")]
+ TString partitionStr;
+ if (! it->getString(partitionStr)) {
+ error(loc, "invalid partitioning", "", "");
+ } else {
+ TVertexSpacing partitioning = EvsNone;
+
+ if (partitionStr == "integer") {
+ partitioning = EvsEqual;
+ } else if (partitionStr == "fractional_even") {
+ partitioning = EvsFractionalEven;
+ } else if (partitionStr == "fractional_odd") {
+ partitioning = EvsFractionalOdd;
+ //} else if (partition == "pow2") { // TODO: currently nothing to map this to.
+ } else {
+ error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
+ }
- // Handle [outputcontrolpoints("...")]
- if (attributes.contains(EatOutputControlPoints)) {
- int ctrlPoints;
- if (! attributes.getInt(EatOutputControlPoints, ctrlPoints)) {
- error(loc, "invalid outputcontrolpoints", "", "");
- } else {
- if (! intermediate.setVertices(ctrlPoints)) {
- error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
+ if (! intermediate.setVertexSpacing(partitioning))
+ error(loc, "cannot change previously set partitioning",
+ TQualifier::getVertexSpacingString(partitioning), "");
+ }
+ break;
+ }
+ case EatOutputControlPoints:
+ {
+ // Handle [outputcontrolpoints("...")]
+ int ctrlPoints;
+ if (! it->getInt(ctrlPoints)) {
+ error(loc, "invalid outputcontrolpoints", "", "");
+ } else {
+ if (! intermediate.setVertices(ctrlPoints)) {
+ 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
// 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)
return;
- // location
int value;
- if (attributes.getInt(EatLocation, value))
- type.getQualifier().layoutLocation = value;
-
- // binding
- if (attributes.getInt(EatBinding, value)) {
- type.getQualifier().layoutBinding = value;
- type.getQualifier().layoutSet = 0;
- }
-
- // set
- if (attributes.getInt(EatBinding, value, 1))
- type.getQualifier().layoutSet = value;
-
- // global cbuffer binding
- if (attributes.getInt(EatGlobalBinding, value))
- globalUniformBinding = value;
-
- // global cbuffer binding
- if (attributes.getInt(EatGlobalBinding, value, 1))
- globalUniformSet = value;
-
- // input attachment
- if (attributes.getInt(EatInputAttachment, value))
- type.getQualifier().layoutAttachment = value;
-
- // PointSize built-in
TString builtInString;
- if (attributes.getString(EatBuiltIn, builtInString, 0, false)) {
- if (builtInString == "PointSize")
- type.getQualifier().builtIn = EbvPointSize;
- }
-
- // push_constant
- if (attributes.contains(EatPushConstant))
- type.getQualifier().layoutPushConstant = true;
-
- // specialization constant
- if (attributes.getInt(EatConstantId, value)) {
- TSourceLoc loc;
- loc.init();
- setSpecConstantId(loc, type.getQualifier(), value);
+ for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+ switch (it->name) {
+ case EatLocation:
+ // location
+ if (it->getInt(value))
+ type.getQualifier().layoutLocation = value;
+ break;
+ case EatBinding:
+ // binding
+ if (it->getInt(value)) {
+ type.getQualifier().layoutBinding = value;
+ type.getQualifier().layoutSet = 0;
+ }
+ // set
+ if (it->getInt(value, 1))
+ type.getQualifier().layoutSet = value;
+ break;
+ case EatGlobalBinding:
+ // global cbuffer binding
+ if (it->getInt(value))
+ globalUniformBinding = value;
+ // global cbuffer binding
+ if (it->getInt(value, 1))
+ globalUniformSet = value;
+ break;
+ case EatInputAttachment:
+ // input attachment
+ if (it->getInt(value))
+ type.getQualifier().layoutAttachment = value;
+ break;
+ case EatBuiltIn:
+ // PointSize built-in
+ if (it->getString(builtInString, 0, false)) {
+ if (builtInString == "PointSize")
+ type.getQualifier().builtIn = EbvPointSize;
+ }
+ break;
+ case EatPushConstant:
+ // push_constant
+ type.getQualifier().layoutPushConstant = true;
+ break;
+ case EatConstantId:
+ // specialization constant
+ if (it->getInt(value)) {
+ TSourceLoc loc;
+ loc.init();
+ setSpecConstantId(loc, type.getQualifier(), value);
+ }
+ break;
+ default:
+ if (! allowEntry)
+ warn(loc, "attribute does not apply to a type", "", "");
+ break;
+ }
}
}
// a subtree that creates the entry point.
//
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.
const auto isDsPcfInput = [this](const TType& type) {
}
//
-// 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))
- return ESelectionControlFlatten;
- else if (attributes.contains(EatBranch))
- return ESelectionControlDontFlatten;
- else
- return ESelectionControlNone;
+ 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 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
//
-TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const
+void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
+ const TAttributes& attributes)
{
- if (attributes.contains(EatUnroll))
- return ELoopControlUnroll;
- else if (attributes.contains(EatLoop))
- return ELoopControlDontUnroll;
- else
- return ELoopControlNone;
+ if (loop == nullptr)
+ return;
+
+ for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+ switch (it->name) {
+ case EatUnroll:
+ loop->setUnroll();
+ break;
+ case EatLoop:
+ loop->setDontUnroll();
+ break;
+ default:
+ warn(loc, "attribute does not apply to a loop", "", "");
+ break;
+ }
+ }
}
//
// into a switch node.
//
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
- TIntermAggregate* lastStatements, TSelectionControl control)
+ TIntermAggregate* lastStatements, const TAttributes& attributes)
{
wrapupSwitchSubsequence(lastStatements, nullptr);
TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
switchNode->setLoc(loc);
- switchNode->setSelectionControl(control);
+ handleSwitchAttributes(loc, switchNode, attributes);
return switchNode;
}
#include "../glslang/MachineIndependent/parseVersions.h"
#include "../glslang/MachineIndependent/ParseHelper.h"
+#include "../glslang/MachineIndependent/attribute.h"
#include <array>
namespace glslang {
-class TAttributeMap; // forward declare
class TFunctionDeclarator;
class HlslParseContext : public TParseContextBase {
bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field);
void assignToInterface(TVariable& variable);
void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
- TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
- TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
- void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
- void transferTypeAttributes(const TAttributeMap&, TType&);
+ TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree);
+ TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&);
+ void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&);
+ void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false);
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
void remapNonEntryPointIO(TFunction& function);
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
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);
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
// 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
- TLoopControl handleLoopControl(const TAttributeMap& attributes) const;
+ void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes);
// Share struct buffer deep types
void shareStructBufferType(TType&);
// Obtain the sampler return type of the given sampler in retType.
void getTextureReturnType(const TSampler& sampler, TType& retType) const;
+ TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const;
+
protected:
struct TFlattenData {
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),