SPV 1.4: Implement the 5 new loop controls.
This commit is contained in:
parent
0c1e71a123
commit
1f4d04687b
@ -135,7 +135,7 @@ protected:
|
|||||||
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
|
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
|
||||||
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
|
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
|
||||||
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
|
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
|
||||||
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, unsigned int& dependencyLength) const;
|
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
|
||||||
spv::StorageClass TranslateStorageClass(const glslang::TType&);
|
spv::StorageClass TranslateStorageClass(const glslang::TType&);
|
||||||
void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
|
void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
|
||||||
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
|
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
|
||||||
@ -1055,7 +1055,7 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const g
|
|||||||
|
|
||||||
// return a non-0 dependency if the dependency argument must be set
|
// return a non-0 dependency if the dependency argument must be set
|
||||||
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
|
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
|
||||||
unsigned int& dependencyLength) const
|
std::vector<unsigned int>& operands) const
|
||||||
{
|
{
|
||||||
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
||||||
|
|
||||||
@ -1067,7 +1067,29 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang:
|
|||||||
control = control | spv::LoopControlDependencyInfiniteMask;
|
control = control | spv::LoopControlDependencyInfiniteMask;
|
||||||
else if (loopNode.getLoopDependency() > 0) {
|
else if (loopNode.getLoopDependency() > 0) {
|
||||||
control = control | spv::LoopControlDependencyLengthMask;
|
control = control | spv::LoopControlDependencyLengthMask;
|
||||||
dependencyLength = loopNode.getLoopDependency();
|
operands.push_back((unsigned int)loopNode.getLoopDependency());
|
||||||
|
}
|
||||||
|
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
|
||||||
|
if (loopNode.getMinIterations() > 0) {
|
||||||
|
control = control | spv::LoopControlMinIterationsMask;
|
||||||
|
operands.push_back(loopNode.getMinIterations());
|
||||||
|
}
|
||||||
|
if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {
|
||||||
|
control = control | spv::LoopControlMaxIterationsMask;
|
||||||
|
operands.push_back(loopNode.getMaxIterations());
|
||||||
|
}
|
||||||
|
if (loopNode.getIterationMultiple() > 1) {
|
||||||
|
control = control | spv::LoopControlIterationMultipleMask;
|
||||||
|
operands.push_back(loopNode.getIterationMultiple());
|
||||||
|
}
|
||||||
|
if (loopNode.getPeelCount() > 0) {
|
||||||
|
control = control | spv::LoopControlPeelCountMask;
|
||||||
|
operands.push_back(loopNode.getPeelCount());
|
||||||
|
}
|
||||||
|
if (loopNode.getPartialCount() > 0) {
|
||||||
|
control = control | spv::LoopControlPartialCountMask;
|
||||||
|
operands.push_back(loopNode.getPartialCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return control;
|
return control;
|
||||||
@ -2841,8 +2863,8 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
|||||||
builder.createBranch(&blocks.head);
|
builder.createBranch(&blocks.head);
|
||||||
|
|
||||||
// Loop control:
|
// Loop control:
|
||||||
unsigned int dependencyLength = glslang::TIntermLoop::dependencyInfinite;
|
std::vector<unsigned int> operands;
|
||||||
const spv::LoopControlMask control = TranslateLoopControl(*node, dependencyLength);
|
const spv::LoopControlMask control = TranslateLoopControl(*node, operands);
|
||||||
|
|
||||||
// Spec requires back edges to target header blocks, and every header block
|
// Spec requires back edges to target header blocks, and every header block
|
||||||
// must dominate its merge block. Make a header block first to ensure these
|
// must dominate its merge block. Make a header block first to ensure these
|
||||||
@ -2852,7 +2874,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
|||||||
// including merges of its own.
|
// including merges of its own.
|
||||||
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
||||||
builder.setBuildPoint(&blocks.head);
|
builder.setBuildPoint(&blocks.head);
|
||||||
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, dependencyLength);
|
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
|
||||||
if (node->testFirst() && node->getTest()) {
|
if (node->testFirst() && node->getTest()) {
|
||||||
spv::Block& test = builder.makeNewBlock();
|
spv::Block& test = builder.makeNewBlock();
|
||||||
builder.createBranch(&test);
|
builder.createBranch(&test);
|
||||||
|
@ -2956,14 +2956,14 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
|
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
|
||||||
unsigned int dependencyLength)
|
const std::vector<unsigned int>& operands)
|
||||||
{
|
{
|
||||||
Instruction* merge = new Instruction(OpLoopMerge);
|
Instruction* merge = new Instruction(OpLoopMerge);
|
||||||
merge->addIdOperand(mergeBlock->getId());
|
merge->addIdOperand(mergeBlock->getId());
|
||||||
merge->addIdOperand(continueBlock->getId());
|
merge->addIdOperand(continueBlock->getId());
|
||||||
merge->addImmediateOperand(control);
|
merge->addImmediateOperand(control);
|
||||||
if ((control & LoopControlDependencyLengthMask) != 0)
|
for (int op = 0; op < (int)operands.size(); ++op)
|
||||||
merge->addImmediateOperand(dependencyLength);
|
merge->addImmediateOperand(operands[op]);
|
||||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,7 +662,7 @@ public:
|
|||||||
|
|
||||||
void createBranch(Block* block);
|
void createBranch(Block* block);
|
||||||
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
||||||
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, unsigned int dependencyLength);
|
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, const std::vector<unsigned int>& operands);
|
||||||
|
|
||||||
// Sets to generate opcode for specialization constants.
|
// Sets to generate opcode for specialization constants.
|
||||||
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
||||||
|
@ -674,15 +674,20 @@ const char* SelectControlString(int cont)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int LoopControlCeiling = 4;
|
const int LoopControlCeiling = LoopControlPartialCountShift + 1;
|
||||||
|
|
||||||
const char* LoopControlString(int cont)
|
const char* LoopControlString(int cont)
|
||||||
{
|
{
|
||||||
switch (cont) {
|
switch (cont) {
|
||||||
case 0: return "Unroll";
|
case LoopControlUnrollShift: return "Unroll";
|
||||||
case 1: return "DontUnroll";
|
case LoopControlDontUnrollShift: return "DontUnroll";
|
||||||
case 2: return "DependencyInfinite";
|
case LoopControlDependencyInfiniteShift: return "DependencyInfinite";
|
||||||
case 3: return "DependencyLength";
|
case LoopControlDependencyLengthShift: return "DependencyLength";
|
||||||
|
case LoopControlMinIterationsShift: return "MinIterations";
|
||||||
|
case LoopControlMaxIterationsShift: return "MaxIterations";
|
||||||
|
case LoopControlIterationMultipleShift: return "IterationMultiple";
|
||||||
|
case LoopControlPeelCountShift: return "PeelCount";
|
||||||
|
case LoopControlPartialCountShift: return "PartialCount";
|
||||||
|
|
||||||
case LoopControlCeiling:
|
case LoopControlCeiling:
|
||||||
default: return "Bad";
|
default: return "Bad";
|
||||||
|
@ -56,7 +56,7 @@ ERROR: node is still EOpNull!
|
|||||||
0:28 Function Definition: attExt( ( global void)
|
0:28 Function Definition: attExt( ( global void)
|
||||||
0:28 Function Parameters:
|
0:28 Function Parameters:
|
||||||
0:30 Sequence
|
0:30 Sequence
|
||||||
0:30 Loop with condition not tested first: Dependency -3
|
0:30 Loop with condition not tested first
|
||||||
0:30 Loop Condition
|
0:30 Loop Condition
|
||||||
0:30 Constant:
|
0:30 Constant:
|
||||||
0:30 true (const bool)
|
0:30 true (const bool)
|
||||||
|
110
Test/baseResults/spv.1.4.LoopControl.frag.out
Normal file
110
Test/baseResults/spv.1.4.LoopControl.frag.out
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
spv.1.4.LoopControl.frag
|
||||||
|
WARNING: 0:15: 'min_iterations' : expected a single integer argument
|
||||||
|
WARNING: 0:15: 'max_iterations' : expected a single integer argument
|
||||||
|
|
||||||
|
Validation failed
|
||||||
|
// Module Version 10400
|
||||||
|
// Generated by (magic number): 80007
|
||||||
|
// Id's are bound by 54
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint Fragment 4 "main" 53
|
||||||
|
ExecutionMode 4 OriginUpperLeft
|
||||||
|
Source GLSL 450
|
||||||
|
SourceExtension "GL_EXT_control_flow_attributes"
|
||||||
|
Name 4 "main"
|
||||||
|
Name 8 "i"
|
||||||
|
Name 32 "i"
|
||||||
|
Name 42 "i"
|
||||||
|
Name 53 "cond"
|
||||||
|
2: TypeVoid
|
||||||
|
3: TypeFunction 2
|
||||||
|
6: TypeInt 32 1
|
||||||
|
7: TypePointer Function 6(int)
|
||||||
|
9: 6(int) Constant 0
|
||||||
|
16: 6(int) Constant 8
|
||||||
|
17: TypeBool
|
||||||
|
20: 6(int) Constant 1
|
||||||
|
27: 17(bool) ConstantTrue
|
||||||
|
52: TypePointer Private 17(bool)
|
||||||
|
53(cond): 52(ptr) Variable Private
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
8(i): 7(ptr) Variable Function
|
||||||
|
32(i): 7(ptr) Variable Function
|
||||||
|
42(i): 7(ptr) Variable Function
|
||||||
|
Store 8(i) 9
|
||||||
|
Branch 10
|
||||||
|
10: Label
|
||||||
|
LoopMerge 12 13 MinIterations MaxIterations 3 7
|
||||||
|
Branch 14
|
||||||
|
14: Label
|
||||||
|
15: 6(int) Load 8(i)
|
||||||
|
18: 17(bool) SLessThan 15 16
|
||||||
|
BranchConditional 18 11 12
|
||||||
|
11: Label
|
||||||
|
Branch 13
|
||||||
|
13: Label
|
||||||
|
19: 6(int) Load 8(i)
|
||||||
|
21: 6(int) IAdd 19 20
|
||||||
|
Store 8(i) 21
|
||||||
|
Branch 10
|
||||||
|
12: Label
|
||||||
|
Branch 22
|
||||||
|
22: Label
|
||||||
|
LoopMerge 24 25 IterationMultiple 2
|
||||||
|
Branch 26
|
||||||
|
26: Label
|
||||||
|
BranchConditional 27 23 24
|
||||||
|
23: Label
|
||||||
|
Branch 25
|
||||||
|
25: Label
|
||||||
|
Branch 22
|
||||||
|
24: Label
|
||||||
|
Branch 28
|
||||||
|
28: Label
|
||||||
|
LoopMerge 30 31 PeelCount 5
|
||||||
|
Branch 29
|
||||||
|
29: Label
|
||||||
|
Branch 31
|
||||||
|
31: Label
|
||||||
|
BranchConditional 27 28 30
|
||||||
|
30: Label
|
||||||
|
Store 32(i) 9
|
||||||
|
Branch 33
|
||||||
|
33: Label
|
||||||
|
LoopMerge 35 36 PartialCount 4
|
||||||
|
Branch 37
|
||||||
|
37: Label
|
||||||
|
38: 6(int) Load 32(i)
|
||||||
|
39: 17(bool) SLessThan 38 16
|
||||||
|
BranchConditional 39 34 35
|
||||||
|
34: Label
|
||||||
|
Branch 36
|
||||||
|
36: Label
|
||||||
|
40: 6(int) Load 32(i)
|
||||||
|
41: 6(int) IAdd 40 20
|
||||||
|
Store 32(i) 41
|
||||||
|
Branch 33
|
||||||
|
35: Label
|
||||||
|
Store 42(i) 9
|
||||||
|
Branch 43
|
||||||
|
43: Label
|
||||||
|
LoopMerge 45 46 None
|
||||||
|
Branch 47
|
||||||
|
47: Label
|
||||||
|
48: 6(int) Load 42(i)
|
||||||
|
49: 17(bool) SLessThan 48 16
|
||||||
|
BranchConditional 49 44 45
|
||||||
|
44: Label
|
||||||
|
Branch 46
|
||||||
|
46: Label
|
||||||
|
50: 6(int) Load 42(i)
|
||||||
|
51: 6(int) IAdd 50 20
|
||||||
|
Store 42(i) 51
|
||||||
|
Branch 43
|
||||||
|
45: Label
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
@ -1,7 +1,7 @@
|
|||||||
spv.controlFlowAttributes.frag
|
spv.controlFlowAttributes.frag
|
||||||
WARNING: 0:20: '' : attribute with arguments not recognized, skipping
|
WARNING: 0:20: 'unroll' : expected no arguments
|
||||||
WARNING: 0:21: '' : attribute with arguments not recognized, skipping
|
WARNING: 0:21: 'dont_unroll' : expected no arguments
|
||||||
WARNING: 0:22: '' : attribute with arguments not recognized, skipping
|
WARNING: 0:22: 'dependency_infinite' : expected no arguments
|
||||||
WARNING: 0:23: 'dependency_length' : expected a single integer argument
|
WARNING: 0:23: 'dependency_length' : expected a single integer argument
|
||||||
WARNING: 0:24: '' : attribute with arguments not recognized, skipping
|
WARNING: 0:24: '' : attribute with arguments not recognized, skipping
|
||||||
WARNING: 0:25: '' : attribute with arguments not recognized, skipping
|
WARNING: 0:25: '' : attribute with arguments not recognized, skipping
|
||||||
|
19
Test/spv.1.4.LoopControl.frag
Normal file
19
Test/spv.1.4.LoopControl.frag
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
#extension GL_EXT_control_flow_attributes : enable
|
||||||
|
|
||||||
|
bool cond;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
[[min_iterations(3), max_iterations(7)]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[iteration_multiple(2)]] while(true) { }
|
||||||
|
[[peel_count(5)]] do { } while(true);
|
||||||
|
[[partial_count(4)]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
|
||||||
|
// warnings on all these
|
||||||
|
[[min_iterations, max_iterations]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
//[[iteration_multiple(0)]] while(true) { }
|
||||||
|
//[[peel_count]] do { } while(true);
|
||||||
|
//[[partial_count]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
}
|
@ -1116,7 +1116,12 @@ public:
|
|||||||
first(testFirst),
|
first(testFirst),
|
||||||
unroll(false),
|
unroll(false),
|
||||||
dontUnroll(false),
|
dontUnroll(false),
|
||||||
dependency(0)
|
dependency(0),
|
||||||
|
minIterations(0),
|
||||||
|
maxIterations(iterationsInfinite),
|
||||||
|
iterationMultiple(1),
|
||||||
|
peelCount(0),
|
||||||
|
partialCount(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||||
@ -1128,14 +1133,36 @@ public:
|
|||||||
bool testFirst() const { return first; }
|
bool testFirst() const { return first; }
|
||||||
|
|
||||||
void setUnroll() { unroll = true; }
|
void setUnroll() { unroll = true; }
|
||||||
void setDontUnroll() { dontUnroll = true; }
|
void setDontUnroll() {
|
||||||
|
dontUnroll = true;
|
||||||
|
peelCount = 0;
|
||||||
|
partialCount = 0;
|
||||||
|
}
|
||||||
bool getUnroll() const { return unroll; }
|
bool getUnroll() const { return unroll; }
|
||||||
bool getDontUnroll() const { return dontUnroll; }
|
bool getDontUnroll() const { return dontUnroll; }
|
||||||
|
|
||||||
static const unsigned int dependencyInfinite = 0xFFFFFFFF;
|
static const unsigned int dependencyInfinite = 0xFFFFFFFF;
|
||||||
|
static const unsigned int iterationsInfinite = 0xFFFFFFFF;
|
||||||
void setLoopDependency(int d) { dependency = d; }
|
void setLoopDependency(int d) { dependency = d; }
|
||||||
int getLoopDependency() const { return dependency; }
|
int getLoopDependency() const { return dependency; }
|
||||||
|
|
||||||
|
void setMinIterations(unsigned int v) { minIterations = v; }
|
||||||
|
unsigned int getMinIterations() const { return minIterations; }
|
||||||
|
void setMaxIterations(unsigned int v) { maxIterations = v; }
|
||||||
|
unsigned int getMaxIterations() const { return maxIterations; }
|
||||||
|
void setIterationMultiple(unsigned int v) { iterationMultiple = v; }
|
||||||
|
unsigned int getIterationMultiple() const { return iterationMultiple; }
|
||||||
|
void setPeelCount(unsigned int v) {
|
||||||
|
peelCount = v;
|
||||||
|
dontUnroll = false;
|
||||||
|
}
|
||||||
|
unsigned int getPeelCount() const { return peelCount; }
|
||||||
|
void setPartialCount(unsigned int v) {
|
||||||
|
partialCount = v;
|
||||||
|
dontUnroll = false;
|
||||||
|
}
|
||||||
|
unsigned int getPartialCount() const { return partialCount; }
|
||||||
|
|
||||||
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
|
||||||
@ -1144,6 +1171,11 @@ protected:
|
|||||||
bool unroll; // true if unroll requested
|
bool unroll; // true if unroll requested
|
||||||
bool dontUnroll; // true if request to not unroll
|
bool dontUnroll; // true if request to not unroll
|
||||||
unsigned int dependency; // loop dependency hint; 0 means not set or unknown
|
unsigned int dependency; // loop dependency hint; 0 means not set or unknown
|
||||||
|
unsigned int minIterations; // as per the SPIR-V specification
|
||||||
|
unsigned int maxIterations; // as per the SPIR-V specification
|
||||||
|
unsigned int iterationMultiple; // as per the SPIR-V specification
|
||||||
|
unsigned int peelCount; // as per the SPIR-V specification
|
||||||
|
unsigned int partialCount; // as per the SPIR-V specification
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -52,6 +52,7 @@ bool TAttributeArgs::getInt(int& value, int argNum) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||||
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
||||||
@ -110,6 +111,16 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const
|
|||||||
return EatDependencyInfinite;
|
return EatDependencyInfinite;
|
||||||
else if (name == "dependency_length")
|
else if (name == "dependency_length")
|
||||||
return EatDependencyLength;
|
return EatDependencyLength;
|
||||||
|
else if (name == "min_iterations")
|
||||||
|
return EatMinIterations;
|
||||||
|
else if (name == "max_iterations")
|
||||||
|
return EatMaxIterations;
|
||||||
|
else if (name == "iteration_multiple")
|
||||||
|
return EatIterationMultiple;
|
||||||
|
else if (name == "peel_count")
|
||||||
|
return EatPeelCount;
|
||||||
|
else if (name == "partial_count")
|
||||||
|
return EatPartialCount;
|
||||||
else
|
else
|
||||||
return EatNone;
|
return EatNone;
|
||||||
}
|
}
|
||||||
@ -225,29 +236,101 @@ void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermN
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||||
if (it->name != EatDependencyLength && it->size() > 0) {
|
|
||||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int value;
|
const auto noArgument = [&](const char* feature) {
|
||||||
|
if (it->size() > 0) {
|
||||||
|
warn(node->getLoc(), "expected no arguments", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto positiveSignedArgument = [&](const char* feature, int& value) {
|
||||||
|
if (it->size() == 1 && it->getInt(value)) {
|
||||||
|
if (value <= 0) {
|
||||||
|
error(node->getLoc(), "must be positive", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(node->getLoc(), "expected a single integer argument", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto unsignedArgument = [&](const char* feature, unsigned int& uiValue) {
|
||||||
|
int value;
|
||||||
|
if (!(it->size() == 1 && it->getInt(value))) {
|
||||||
|
warn(node->getLoc(), "expected a single integer argument", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uiValue = (unsigned int)value;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto positiveUnsignedArgument = [&](const char* feature, unsigned int& uiValue) {
|
||||||
|
int value;
|
||||||
|
if (it->size() == 1 && it->getInt(value)) {
|
||||||
|
if (value == 0) {
|
||||||
|
error(node->getLoc(), "must be greater than or equal to 1", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(node->getLoc(), "expected a single integer argument", feature, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uiValue = (unsigned int)value;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto spirv14 = [&](const char* feature) {
|
||||||
|
if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4)
|
||||||
|
warn(node->getLoc(), "attribute requires a SPIR-V 1.4 target-env", feature, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
unsigned uiValue = 0;
|
||||||
switch (it->name) {
|
switch (it->name) {
|
||||||
case EatUnroll:
|
case EatUnroll:
|
||||||
loop->setUnroll();
|
if (noArgument("unroll"))
|
||||||
|
loop->setUnroll();
|
||||||
break;
|
break;
|
||||||
case EatLoop:
|
case EatLoop:
|
||||||
loop->setDontUnroll();
|
if (noArgument("dont_unroll"))
|
||||||
|
loop->setDontUnroll();
|
||||||
break;
|
break;
|
||||||
case EatDependencyInfinite:
|
case EatDependencyInfinite:
|
||||||
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
|
if (noArgument("dependency_infinite"))
|
||||||
|
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
|
||||||
break;
|
break;
|
||||||
case EatDependencyLength:
|
case EatDependencyLength:
|
||||||
if (it->size() == 1 && it->getInt(value)) {
|
if (positiveSignedArgument("dependency_length", value))
|
||||||
if (value <= 0)
|
|
||||||
error(node->getLoc(), "must be positive", "dependency_length", "");
|
|
||||||
loop->setLoopDependency(value);
|
loop->setLoopDependency(value);
|
||||||
} else
|
break;
|
||||||
warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
|
case EatMinIterations:
|
||||||
|
spirv14("min_iterations");
|
||||||
|
if (unsignedArgument("min_iterations", uiValue))
|
||||||
|
loop->setMinIterations(uiValue);
|
||||||
|
break;
|
||||||
|
case EatMaxIterations:
|
||||||
|
spirv14("max_iterations");
|
||||||
|
if (unsignedArgument("max_iterations", uiValue))
|
||||||
|
loop->setMaxIterations(uiValue);
|
||||||
|
break;
|
||||||
|
case EatIterationMultiple:
|
||||||
|
spirv14("iteration_multiple");
|
||||||
|
if (positiveUnsignedArgument("iteration_multiple", uiValue))
|
||||||
|
loop->setIterationMultiple(uiValue);
|
||||||
|
break;
|
||||||
|
case EatPeelCount:
|
||||||
|
spirv14("peel_count");
|
||||||
|
if (unsignedArgument("peel_count", uiValue))
|
||||||
|
loop->setPeelCount(uiValue);
|
||||||
|
break;
|
||||||
|
case EatPartialCount:
|
||||||
|
spirv14("partial_count");
|
||||||
|
if (unsignedArgument("partial_count", uiValue))
|
||||||
|
loop->setPartialCount(uiValue);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
|
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
|
||||||
|
@ -71,7 +71,12 @@ namespace glslang {
|
|||||||
EatPushConstant,
|
EatPushConstant,
|
||||||
EatConstantId,
|
EatConstantId,
|
||||||
EatDependencyInfinite,
|
EatDependencyInfinite,
|
||||||
EatDependencyLength
|
EatDependencyLength,
|
||||||
|
EatMinIterations,
|
||||||
|
EatMaxIterations,
|
||||||
|
EatIterationMultiple,
|
||||||
|
EatPeelCount,
|
||||||
|
EatPartialCount
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIntermAggregate;
|
class TIntermAggregate;
|
||||||
|
@ -467,6 +467,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
::testing::ValuesIn(std::vector<std::string>({
|
::testing::ValuesIn(std::vector<std::string>({
|
||||||
"spv.1.4.OpEntryPoint.frag",
|
"spv.1.4.OpEntryPoint.frag",
|
||||||
"spv.1.4.OpSelect.frag",
|
"spv.1.4.OpSelect.frag",
|
||||||
|
"spv.1.4.LoopControl.frag",
|
||||||
})),
|
})),
|
||||||
FileNameAsCustomTestSuffix
|
FileNameAsCustomTestSuffix
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user