mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
GLSL: Implement GL_EXT_control_flow_attributes.
See https://github.com/KhronosGroup/GLSL/pull/11.
This commit is contained in:
parent
e18fd20d5c
commit
a2858d9bdd
@ -131,7 +131,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&) const;
|
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, unsigned int& dependencyLength) 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&);
|
||||||
@ -767,7 +767,9 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const g
|
|||||||
return spv::SelectionControlMaskNone;
|
return spv::SelectionControlMaskNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode) const
|
// return a non-0 dependency if the dependency argument must be set
|
||||||
|
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
|
||||||
|
unsigned int& dependencyLength) const
|
||||||
{
|
{
|
||||||
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
||||||
|
|
||||||
@ -775,6 +777,12 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang:
|
|||||||
control = control | spv::LoopControlDontUnrollMask;
|
control = control | spv::LoopControlDontUnrollMask;
|
||||||
if (loopNode.getUnroll())
|
if (loopNode.getUnroll())
|
||||||
control = control | spv::LoopControlUnrollMask;
|
control = control | spv::LoopControlUnrollMask;
|
||||||
|
if (loopNode.getLoopDependency() == glslang::TIntermLoop::dependencyInfinite)
|
||||||
|
control = control | spv::LoopControlDependencyInfiniteMask;
|
||||||
|
else if (loopNode.getLoopDependency() > 0) {
|
||||||
|
control = control | spv::LoopControlDependencyLengthMask;
|
||||||
|
dependencyLength = loopNode.getLoopDependency();
|
||||||
|
}
|
||||||
|
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
@ -2137,9 +2145,8 @@ 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);
|
unsigned int dependencyLength = glslang::TIntermLoop::dependencyInfinite;
|
||||||
|
const spv::LoopControlMask control = TranslateLoopControl(*node, dependencyLength);
|
||||||
// TODO: dependency length
|
|
||||||
|
|
||||||
// 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
|
||||||
@ -2149,7 +2156,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
|||||||
// including merges of its own.
|
// including merges of its own.
|
||||||
builder.setLine(node->getLoc().line);
|
builder.setLine(node->getLoc().line);
|
||||||
builder.setBuildPoint(&blocks.head);
|
builder.setBuildPoint(&blocks.head);
|
||||||
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control);
|
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, dependencyLength);
|
||||||
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);
|
||||||
|
@ -2573,12 +2573,15 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
|
|||||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
|
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
|
||||||
|
unsigned int dependencyLength)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
merge->addImmediateOperand(dependencyLength);
|
||||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,7 +561,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);
|
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, unsigned int dependencyLength);
|
||||||
|
|
||||||
// Sets to generate opcode for specialization constants.
|
// Sets to generate opcode for specialization constants.
|
||||||
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
||||||
|
@ -2558,6 +2558,7 @@ void Parameterize()
|
|||||||
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'");
|
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'");
|
||||||
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'");
|
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'");
|
||||||
InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
|
InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
|
||||||
|
InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, "");
|
||||||
|
|
||||||
InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'");
|
InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'");
|
||||||
InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
|
InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
|
||||||
|
@ -15,3 +15,18 @@ void main()
|
|||||||
b1 = allInvocations(b1);
|
b1 = allInvocations(b1);
|
||||||
b1 = allInvocationsEqual(b1);
|
b1 = allInvocationsEqual(b1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void attExtBad()
|
||||||
|
{
|
||||||
|
// ERRORs, not enabled
|
||||||
|
[[dependency_length(1+3)]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[flatten]] if (true) { } else { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#extension GL_EXT_control_flow_attributes : enable
|
||||||
|
|
||||||
|
void attExt()
|
||||||
|
{
|
||||||
|
[[dependency_length(-3)]] do { } while(true); // ERROR, not positive
|
||||||
|
[[dependency_length(0)]] do { } while(true); // ERROR, not positive
|
||||||
|
}
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
460.frag
|
460.frag
|
||||||
|
ERROR: 0:22: 'attribute' : required extension not requested: GL_EXT_control_flow_attributes
|
||||||
|
ERROR: 0:23: 'attribute' : required extension not requested: GL_EXT_control_flow_attributes
|
||||||
|
ERROR: 0:30: 'dependency_length' : must be positive
|
||||||
|
ERROR: 0:31: 'dependency_length' : must be positive
|
||||||
|
ERROR: 4 compilation errors. No code generated.
|
||||||
|
|
||||||
|
|
||||||
Shader version: 460
|
Shader version: 460
|
||||||
0:? Sequence
|
Requested GL_EXT_control_flow_attributes
|
||||||
|
ERROR: node is still EOpNull!
|
||||||
0:10 Function Definition: main( ( global void)
|
0:10 Function Definition: main( ( global void)
|
||||||
0:10 Function Parameters:
|
0:10 Function Parameters:
|
||||||
0:12 Sequence
|
0:12 Sequence
|
||||||
@ -21,6 +29,43 @@ Shader version: 460
|
|||||||
0:16 'b1' ( temp bool)
|
0:16 'b1' ( temp bool)
|
||||||
0:16 allInvocationsEqual ( global bool)
|
0:16 allInvocationsEqual ( global bool)
|
||||||
0:16 'b1' ( temp bool)
|
0:16 'b1' ( temp bool)
|
||||||
|
0:19 Function Definition: attExtBad( ( global void)
|
||||||
|
0:19 Function Parameters:
|
||||||
|
0:22 Sequence
|
||||||
|
0:22 Sequence
|
||||||
|
0:22 Sequence
|
||||||
|
0:22 move second child to first child ( temp int)
|
||||||
|
0:22 'i' ( temp int)
|
||||||
|
0:22 Constant:
|
||||||
|
0:22 0 (const int)
|
||||||
|
0:22 Loop with condition tested first
|
||||||
|
0:22 Loop Condition
|
||||||
|
0:22 Compare Less Than ( temp bool)
|
||||||
|
0:22 'i' ( temp int)
|
||||||
|
0:22 Constant:
|
||||||
|
0:22 8 (const int)
|
||||||
|
0:22 No loop body
|
||||||
|
0:22 Loop Terminal Expression
|
||||||
|
0:22 Pre-Increment ( temp int)
|
||||||
|
0:22 'i' ( temp int)
|
||||||
|
0:23 Test condition and select ( temp void)
|
||||||
|
0:23 Condition
|
||||||
|
0:23 Constant:
|
||||||
|
0:23 true (const bool)
|
||||||
|
0:23 true case is null
|
||||||
|
0:28 Function Definition: attExt( ( global void)
|
||||||
|
0:28 Function Parameters:
|
||||||
|
0:30 Sequence
|
||||||
|
0:30 Loop with condition not tested first
|
||||||
|
0:30 Loop Condition
|
||||||
|
0:30 Constant:
|
||||||
|
0:30 true (const bool)
|
||||||
|
0:30 No loop body
|
||||||
|
0:31 Loop with condition not tested first
|
||||||
|
0:31 Loop Condition
|
||||||
|
0:31 Constant:
|
||||||
|
0:31 true (const bool)
|
||||||
|
0:31 No loop body
|
||||||
0:? Linker Objects
|
0:? Linker Objects
|
||||||
0:? 's' ( smooth in structure{ global float f, global 4-component vector of float v})
|
0:? 's' ( smooth in structure{ global float f, global 4-component vector of float v})
|
||||||
|
|
||||||
@ -29,7 +74,8 @@ Linked fragment stage:
|
|||||||
|
|
||||||
|
|
||||||
Shader version: 460
|
Shader version: 460
|
||||||
0:? Sequence
|
Requested GL_EXT_control_flow_attributes
|
||||||
|
ERROR: node is still EOpNull!
|
||||||
0:10 Function Definition: main( ( global void)
|
0:10 Function Definition: main( ( global void)
|
||||||
0:10 Function Parameters:
|
0:10 Function Parameters:
|
||||||
0:12 Sequence
|
0:12 Sequence
|
||||||
|
238
Test/baseResults/spv.controlFlowAttributes.frag.out
Executable file
238
Test/baseResults/spv.controlFlowAttributes.frag.out
Executable file
@ -0,0 +1,238 @@
|
|||||||
|
spv.controlFlowAttributes.frag
|
||||||
|
WARNING: 0:20: '' : attribute with arguments not recognized, skipping
|
||||||
|
WARNING: 0:21: '' : attribute with arguments not recognized, skipping
|
||||||
|
WARNING: 0:22: '' : attribute with arguments not recognized, skipping
|
||||||
|
WARNING: 0:23: 'dependency_length' : expected a single integer argument
|
||||||
|
WARNING: 0:24: '' : attribute with arguments not recognized, skipping
|
||||||
|
WARNING: 0:25: '' : attribute with arguments not recognized, skipping
|
||||||
|
WARNING: 0:26: '' : attribute with arguments not recognized, skipping
|
||||||
|
|
||||||
|
// Module Version 10000
|
||||||
|
// Generated by (magic number): 80003
|
||||||
|
// Id's are bound by 118
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint Fragment 4 "main"
|
||||||
|
ExecutionMode 4 OriginUpperLeft
|
||||||
|
Source GLSL 450
|
||||||
|
SourceExtension "GL_EXT_control_flow_attributes"
|
||||||
|
Name 4 "main"
|
||||||
|
Name 8 "i"
|
||||||
|
Name 36 "i"
|
||||||
|
Name 47 "cond"
|
||||||
|
Name 60 "i"
|
||||||
|
Name 79 "i"
|
||||||
|
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
|
||||||
|
31: 17(bool) ConstantTrue
|
||||||
|
46: TypePointer Private 17(bool)
|
||||||
|
47(cond): 46(ptr) Variable Private
|
||||||
|
54: 17(bool) ConstantFalse
|
||||||
|
55: 6(int) Constant 3
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
8(i): 7(ptr) Variable Function
|
||||||
|
36(i): 7(ptr) Variable Function
|
||||||
|
60(i): 7(ptr) Variable Function
|
||||||
|
79(i): 7(ptr) Variable Function
|
||||||
|
Store 8(i) 9
|
||||||
|
Branch 10
|
||||||
|
10: Label
|
||||||
|
LoopMerge 12 13 Unroll
|
||||||
|
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 DontUnroll
|
||||||
|
Branch 23
|
||||||
|
23: Label
|
||||||
|
Branch 25
|
||||||
|
25: Label
|
||||||
|
Branch 22
|
||||||
|
24: Label
|
||||||
|
Branch 26
|
||||||
|
26: Label
|
||||||
|
LoopMerge 28 29 DontUnroll
|
||||||
|
Branch 30
|
||||||
|
30: Label
|
||||||
|
BranchConditional 31 27 28
|
||||||
|
27: Label
|
||||||
|
Branch 29
|
||||||
|
29: Label
|
||||||
|
Branch 26
|
||||||
|
28: Label
|
||||||
|
Branch 32
|
||||||
|
32: Label
|
||||||
|
LoopMerge 34 35 DependencyInfinite
|
||||||
|
Branch 33
|
||||||
|
33: Label
|
||||||
|
Branch 35
|
||||||
|
35: Label
|
||||||
|
BranchConditional 31 32 34
|
||||||
|
34: Label
|
||||||
|
Store 36(i) 9
|
||||||
|
Branch 37
|
||||||
|
37: Label
|
||||||
|
LoopMerge 39 40 DependencyLength 4
|
||||||
|
Branch 41
|
||||||
|
41: Label
|
||||||
|
42: 6(int) Load 36(i)
|
||||||
|
43: 17(bool) SLessThan 42 16
|
||||||
|
BranchConditional 43 38 39
|
||||||
|
38: Label
|
||||||
|
Branch 40
|
||||||
|
40: Label
|
||||||
|
44: 6(int) Load 36(i)
|
||||||
|
45: 6(int) IAdd 44 20
|
||||||
|
Store 36(i) 45
|
||||||
|
Branch 37
|
||||||
|
39: Label
|
||||||
|
48: 17(bool) Load 47(cond)
|
||||||
|
SelectionMerge 50 Flatten
|
||||||
|
BranchConditional 48 49 50
|
||||||
|
49: Label
|
||||||
|
Branch 50
|
||||||
|
50: Label
|
||||||
|
51: 17(bool) Load 47(cond)
|
||||||
|
SelectionMerge 53 DontFlatten
|
||||||
|
BranchConditional 51 52 53
|
||||||
|
52: Label
|
||||||
|
Store 47(cond) 54
|
||||||
|
Branch 53
|
||||||
|
53: Label
|
||||||
|
SelectionMerge 57 DontFlatten
|
||||||
|
Switch 55 57
|
||||||
|
case 3: 56
|
||||||
|
56: Label
|
||||||
|
Branch 57
|
||||||
|
57: Label
|
||||||
|
Store 60(i) 9
|
||||||
|
Branch 61
|
||||||
|
61: Label
|
||||||
|
LoopMerge 63 64 None
|
||||||
|
Branch 65
|
||||||
|
65: Label
|
||||||
|
66: 6(int) Load 60(i)
|
||||||
|
67: 17(bool) SLessThan 66 16
|
||||||
|
BranchConditional 67 62 63
|
||||||
|
62: Label
|
||||||
|
Branch 64
|
||||||
|
64: Label
|
||||||
|
68: 6(int) Load 60(i)
|
||||||
|
69: 6(int) IAdd 68 20
|
||||||
|
Store 60(i) 69
|
||||||
|
Branch 61
|
||||||
|
63: Label
|
||||||
|
Branch 70
|
||||||
|
70: Label
|
||||||
|
LoopMerge 72 73 None
|
||||||
|
Branch 74
|
||||||
|
74: Label
|
||||||
|
BranchConditional 31 71 72
|
||||||
|
71: Label
|
||||||
|
Branch 73
|
||||||
|
73: Label
|
||||||
|
Branch 70
|
||||||
|
72: Label
|
||||||
|
Branch 75
|
||||||
|
75: Label
|
||||||
|
LoopMerge 77 78 None
|
||||||
|
Branch 76
|
||||||
|
76: Label
|
||||||
|
Branch 78
|
||||||
|
78: Label
|
||||||
|
BranchConditional 31 75 77
|
||||||
|
77: Label
|
||||||
|
Store 79(i) 9
|
||||||
|
Branch 80
|
||||||
|
80: Label
|
||||||
|
LoopMerge 82 83 None
|
||||||
|
Branch 84
|
||||||
|
84: Label
|
||||||
|
85: 6(int) Load 79(i)
|
||||||
|
86: 17(bool) SLessThan 85 16
|
||||||
|
BranchConditional 86 81 82
|
||||||
|
81: Label
|
||||||
|
Branch 83
|
||||||
|
83: Label
|
||||||
|
87: 6(int) Load 79(i)
|
||||||
|
88: 6(int) IAdd 87 20
|
||||||
|
Store 79(i) 88
|
||||||
|
Branch 80
|
||||||
|
82: Label
|
||||||
|
89: 17(bool) Load 47(cond)
|
||||||
|
SelectionMerge 91 None
|
||||||
|
BranchConditional 89 90 91
|
||||||
|
90: Label
|
||||||
|
Branch 91
|
||||||
|
91: Label
|
||||||
|
92: 17(bool) Load 47(cond)
|
||||||
|
SelectionMerge 94 None
|
||||||
|
BranchConditional 92 93 94
|
||||||
|
93: Label
|
||||||
|
Store 47(cond) 54
|
||||||
|
Branch 94
|
||||||
|
94: Label
|
||||||
|
SelectionMerge 96 None
|
||||||
|
Switch 55 96
|
||||||
|
case 3: 95
|
||||||
|
95: Label
|
||||||
|
Branch 96
|
||||||
|
96: Label
|
||||||
|
Branch 99
|
||||||
|
99: Label
|
||||||
|
LoopMerge 101 102 Unroll DontUnroll DependencyLength 2
|
||||||
|
Branch 103
|
||||||
|
103: Label
|
||||||
|
104: 17(bool) Load 47(cond)
|
||||||
|
BranchConditional 104 100 101
|
||||||
|
100: Label
|
||||||
|
Branch 102
|
||||||
|
102: Label
|
||||||
|
Branch 99
|
||||||
|
101: Label
|
||||||
|
SelectionMerge 106 DontFlatten
|
||||||
|
Switch 55 106
|
||||||
|
case 3: 105
|
||||||
|
105: Label
|
||||||
|
Branch 106
|
||||||
|
106: Label
|
||||||
|
109: 17(bool) Load 47(cond)
|
||||||
|
SelectionMerge 111 Flatten
|
||||||
|
BranchConditional 109 110 111
|
||||||
|
110: Label
|
||||||
|
Branch 111
|
||||||
|
111: Label
|
||||||
|
Branch 112
|
||||||
|
112: Label
|
||||||
|
LoopMerge 114 115 DependencyInfinite
|
||||||
|
Branch 116
|
||||||
|
116: Label
|
||||||
|
117: 17(bool) Load 47(cond)
|
||||||
|
BranchConditional 117 113 114
|
||||||
|
113: Label
|
||||||
|
Branch 115
|
||||||
|
115: Label
|
||||||
|
Branch 112
|
||||||
|
114: Label
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
39
Test/spv.controlFlowAttributes.frag
Normal file
39
Test/spv.controlFlowAttributes.frag
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
#extension GL_EXT_control_flow_attributes : enable
|
||||||
|
|
||||||
|
bool cond;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
[[unroll]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[loop]] for (;;) { }
|
||||||
|
[[dont_unroll]] while(true) { }
|
||||||
|
[[dependency_infinite]] do { } while(true);
|
||||||
|
[[dependency_length(1+3)]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[flatten]] if (cond) { } else { }
|
||||||
|
[[branch]] if (cond) cond = false;
|
||||||
|
[[dont_flatten]] switch(3) { } // dropped
|
||||||
|
[[dont_flatten]] switch(3) { case 3: break; }
|
||||||
|
|
||||||
|
// warnings on all these
|
||||||
|
[[unroll(2)]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[dont_unroll(-2)]] while(true) { }
|
||||||
|
[[dependency_infinite(3)]] do { } while(true);
|
||||||
|
[[dependency_length]] for (int i = 0; i < 8; ++i) { }
|
||||||
|
[[flatten(3)]] if (cond) { } else { }
|
||||||
|
[[branch(5.2)]] if (cond) cond = false;
|
||||||
|
[[dont_flatten(3 + 7)]] switch(3) { case 3: break; }
|
||||||
|
|
||||||
|
// other valid uses
|
||||||
|
[[ unroll, dont_unroll, dependency_length(2) ]] while(cond) { }
|
||||||
|
[ [ dont_flatten , branch ] ] switch(3) { case 3: break; }
|
||||||
|
[
|
||||||
|
// attribute
|
||||||
|
[
|
||||||
|
// here
|
||||||
|
flatten
|
||||||
|
]
|
||||||
|
] if (cond) { } else { }
|
||||||
|
[[ dependency_length(2), dependency_infinite ]] while(cond) { }
|
||||||
|
}
|
@ -155,7 +155,7 @@ inline TString* NewPoolTString(const char* s)
|
|||||||
return new(memory) TString(s);
|
return new(memory) TString(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> inline T* NewPoolObject(T)
|
template<class T> inline T* NewPoolObject(T*)
|
||||||
{
|
{
|
||||||
return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
|
return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
|
||||||
}
|
}
|
||||||
|
@ -896,7 +896,8 @@ public:
|
|||||||
terminal(aTerminal),
|
terminal(aTerminal),
|
||||||
first(testFirst),
|
first(testFirst),
|
||||||
unroll(false),
|
unroll(false),
|
||||||
dontUnroll(false)
|
dontUnroll(false),
|
||||||
|
dependency(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||||
@ -912,6 +913,10 @@ public:
|
|||||||
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;
|
||||||
|
void setLoopDependency(int d) { dependency = d; }
|
||||||
|
int getLoopDependency() const { return dependency; }
|
||||||
|
|
||||||
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
|
||||||
@ -919,6 +924,7 @@ protected:
|
|||||||
bool first; // true for while and for, not for do-while
|
bool first; // true for while and for, not for do-while
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -44,13 +44,15 @@
|
|||||||
#ifndef _PARSER_HELPER_INCLUDED_
|
#ifndef _PARSER_HELPER_INCLUDED_
|
||||||
#define _PARSER_HELPER_INCLUDED_
|
#define _PARSER_HELPER_INCLUDED_
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "parseVersions.h"
|
#include "parseVersions.h"
|
||||||
#include "../Include/ShHandle.h"
|
#include "../Include/ShHandle.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "localintermediate.h"
|
#include "localintermediate.h"
|
||||||
#include "Scan.h"
|
#include "Scan.h"
|
||||||
#include <cstdarg>
|
#include "attribute.h"
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
@ -409,6 +411,17 @@ public:
|
|||||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
|
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
|
||||||
|
|
||||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||||
|
TAttributeType attributeFromName(const TString& name) const;
|
||||||
|
TAttributes* makeAttributes(const TString& identifier) const;
|
||||||
|
TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const;
|
||||||
|
TAttributes* mergeAttributes(TAttributes*, TAttributes*) const;
|
||||||
|
|
||||||
|
// Determine selection control from attributes
|
||||||
|
void handleSelectionAttributes(const TAttributes& attributes, TIntermNode*);
|
||||||
|
void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*);
|
||||||
|
|
||||||
|
// Determine loop control from attributes
|
||||||
|
void handleLoopAttributes(const TAttributes& attributes, TIntermNode*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "../Include/Types.h"
|
#include "../Include/Types.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "ParseHelper.h"
|
#include "ParseHelper.h"
|
||||||
|
#include "attribute.h"
|
||||||
#include "glslang_tab.cpp.h"
|
#include "glslang_tab.cpp.h"
|
||||||
#include "ScanContext.h"
|
#include "ScanContext.h"
|
||||||
#include "Scan.h"
|
#include "Scan.h"
|
||||||
|
@ -188,6 +188,7 @@ void TParseVersions::initializeExtensionBehavior()
|
|||||||
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
|
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
|
||||||
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
|
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
|
||||||
extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable;
|
extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable;
|
||||||
|
extensionBehavior[E_GL_EXT_control_flow_attributes] = EBhDisable;
|
||||||
|
|
||||||
// #line and #include
|
// #line and #include
|
||||||
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
||||||
@ -328,6 +329,7 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||||||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||||
"#define GL_EXT_shader_image_load_formatted 1\n"
|
"#define GL_EXT_shader_image_load_formatted 1\n"
|
||||||
"#define GL_EXT_post_depth_coverage 1\n"
|
"#define GL_EXT_post_depth_coverage 1\n"
|
||||||
|
"#define GL_EXT_control_flow_attributes 1\n"
|
||||||
|
|
||||||
#ifdef AMD_EXTENSIONS
|
#ifdef AMD_EXTENSIONS
|
||||||
"#define GL_AMD_shader_ballot 1\n"
|
"#define GL_AMD_shader_ballot 1\n"
|
||||||
|
@ -146,6 +146,7 @@ const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_lo
|
|||||||
const char* const E_GL_EXT_device_group = "GL_EXT_device_group";
|
const char* const E_GL_EXT_device_group = "GL_EXT_device_group";
|
||||||
const char* const E_GL_EXT_multiview = "GL_EXT_multiview";
|
const char* const E_GL_EXT_multiview = "GL_EXT_multiview";
|
||||||
const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage";
|
const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage";
|
||||||
|
const char* const E_GL_EXT_control_flow_attributes = "GL_EXT_control_flow_attributes";
|
||||||
|
|
||||||
// Arrays of extensions for the above viewportEXTs duplications
|
// Arrays of extensions for the above viewportEXTs duplications
|
||||||
|
|
||||||
|
@ -40,47 +40,218 @@
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
// extract integers out of attribute arguments stored in attribute aggregate
|
// extract integers out of attribute arguments stored in attribute aggregate
|
||||||
bool TAttributeArgs::getInt(int& value, int argNum) const
|
bool TAttributeArgs::getInt(int& value, int argNum) const
|
||||||
{
|
{
|
||||||
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
||||||
|
|
||||||
if (intConst == nullptr)
|
if (intConst == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
value = intConst->getIConst();
|
value = intConst->getIConst();
|
||||||
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
|
||||||
{
|
{
|
||||||
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
||||||
|
|
||||||
if (stringConst == nullptr)
|
if (stringConst == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
value = *stringConst->getSConst();
|
value = *stringConst->getSConst();
|
||||||
|
|
||||||
// Convenience.
|
// Convenience.
|
||||||
if (convertToLower)
|
if (convertToLower)
|
||||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Helper to get attribute const union. Returns nullptr on failure.
|
// How many arguments were supplied?
|
||||||
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
int TAttributeArgs::size() const
|
||||||
{
|
{
|
||||||
if (argNum >= args->getSequence().size())
|
return args == nullptr ? 0 : (int)args->getSequence().size();
|
||||||
return nullptr;
|
}
|
||||||
|
|
||||||
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
// Helper to get attribute const union. Returns nullptr on failure.
|
||||||
if (constVal == nullptr || constVal->getType() != basicType)
|
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
||||||
return nullptr;
|
{
|
||||||
|
if (args == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return constVal;
|
if (argNum >= args->getSequence().size())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||||
|
if (constVal == nullptr || constVal->getType() != basicType)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return constVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of TParseContext parts of attributes
|
||||||
|
TAttributeType TParseContext::attributeFromName(const TString& name) const
|
||||||
|
{
|
||||||
|
if (name == "branch" || name == "dont_flatten")
|
||||||
|
return EatBranch;
|
||||||
|
else if (name == "flatten")
|
||||||
|
return EatFlatten;
|
||||||
|
else if (name == "unroll")
|
||||||
|
return EatUnroll;
|
||||||
|
else if (name == "loop" || name == "dont_unroll")
|
||||||
|
return EatLoop;
|
||||||
|
else if (name == "dependency_infinite")
|
||||||
|
return EatDependencyInfinite;
|
||||||
|
else if (name == "dependency_length")
|
||||||
|
return EatDependencyLength;
|
||||||
|
else
|
||||||
|
return EatNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an initial leaf for the grammar from a no-argument attribute
|
||||||
|
TAttributes* TParseContext::makeAttributes(const TString& identifier) const
|
||||||
|
{
|
||||||
|
TAttributes *attributes = nullptr;
|
||||||
|
attributes = NewPoolObject(attributes);
|
||||||
|
TAttributeArgs args = { attributeFromName(identifier), nullptr };
|
||||||
|
attributes->push_back(args);
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an initial leaf for the grammar from a one-argument attribute
|
||||||
|
TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
|
||||||
|
{
|
||||||
|
TAttributes *attributes = nullptr;
|
||||||
|
attributes = NewPoolObject(attributes);
|
||||||
|
|
||||||
|
// for now, node is always a simple single expression, but other code expects
|
||||||
|
// a list, so make it so
|
||||||
|
TIntermAggregate* agg = intermediate.makeAggregate(node);
|
||||||
|
TAttributeArgs args = { attributeFromName(identifier), agg };
|
||||||
|
attributes->push_back(args);
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge two sets of attributes into a single set.
|
||||||
|
// The second argument is destructively consumed.
|
||||||
|
TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
|
||||||
|
{
|
||||||
|
attr1->splice(attr1->end(), *attr2);
|
||||||
|
return attr1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Selection attributes
|
||||||
|
//
|
||||||
|
void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||||
|
{
|
||||||
|
TIntermSelection* selection = node->getAsSelectionNode();
|
||||||
|
if (selection == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||||
|
if (it->size() > 0) {
|
||||||
|
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (it->name) {
|
||||||
|
case EatFlatten:
|
||||||
|
selection->setFlatten();
|
||||||
|
break;
|
||||||
|
case EatBranch:
|
||||||
|
selection->setDontFlatten();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warn(node->getLoc(), "attribute does not apply to a selection", "", "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Switch attributes
|
||||||
|
//
|
||||||
|
void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||||
|
{
|
||||||
|
TIntermSwitch* selection = node->getAsSwitchNode();
|
||||||
|
if (selection == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||||
|
if (it->size() > 0) {
|
||||||
|
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (it->name) {
|
||||||
|
case EatFlatten:
|
||||||
|
selection->setFlatten();
|
||||||
|
break;
|
||||||
|
case EatBranch:
|
||||||
|
selection->setDontFlatten();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warn(node->getLoc(), "attribute does not apply to a switch", "", "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Loop attributes
|
||||||
|
//
|
||||||
|
void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||||
|
{
|
||||||
|
TIntermLoop* loop = node->getAsLoopNode();
|
||||||
|
if (loop == nullptr) {
|
||||||
|
// the actual loop might be part of a sequence
|
||||||
|
TIntermAggregate* agg = node->getAsAggregate();
|
||||||
|
if (agg == nullptr)
|
||||||
|
return;
|
||||||
|
for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
|
||||||
|
loop = (*it)->getAsLoopNode();
|
||||||
|
if (loop != nullptr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (loop == nullptr)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||||
|
if (it->name != EatDependencyLength && it->size() > 0) {
|
||||||
|
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value;
|
||||||
|
switch (it->name) {
|
||||||
|
case EatUnroll:
|
||||||
|
loop->setUnroll();
|
||||||
|
break;
|
||||||
|
case EatLoop:
|
||||||
|
loop->setDontUnroll();
|
||||||
|
break;
|
||||||
|
case EatDependencyInfinite:
|
||||||
|
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
|
||||||
|
break;
|
||||||
|
case EatDependencyLength:
|
||||||
|
if (it->size() == 1 && it->getInt(value)) {
|
||||||
|
if (value <= 0)
|
||||||
|
error(node->getLoc(), "must be positive", "dependency_length", "");
|
||||||
|
loop->setLoopDependency(value);
|
||||||
|
} else
|
||||||
|
warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
@ -69,14 +69,16 @@ namespace glslang {
|
|||||||
EatInputAttachment,
|
EatInputAttachment,
|
||||||
EatBuiltIn,
|
EatBuiltIn,
|
||||||
EatPushConstant,
|
EatPushConstant,
|
||||||
EatConstantId
|
EatConstantId,
|
||||||
|
EatDependencyInfinite,
|
||||||
|
EatDependencyLength
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIntermAggregate;
|
class TIntermAggregate;
|
||||||
|
|
||||||
struct TAttributeArgs {
|
struct TAttributeArgs {
|
||||||
TAttributeType name;
|
TAttributeType name;
|
||||||
TIntermAggregate* args;
|
const TIntermAggregate* args;
|
||||||
|
|
||||||
// Obtain attribute as integer
|
// Obtain attribute as integer
|
||||||
// Return false if it cannot be obtained
|
// Return false if it cannot be obtained
|
||||||
@ -86,6 +88,9 @@ namespace glslang {
|
|||||||
// Return false if it cannot be obtained
|
// Return false if it cannot be obtained
|
||||||
bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
|
bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||||
|
|
||||||
|
// How many arguments were provided to the attribute?
|
||||||
|
int size() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
|
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
|
||||||
};
|
};
|
||||||
|
@ -58,6 +58,7 @@ Jutta Degener, 1995
|
|||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "ParseHelper.h"
|
#include "ParseHelper.h"
|
||||||
#include "../Public/ShaderLang.h"
|
#include "../Public/ShaderLang.h"
|
||||||
|
#include "attribute.h"
|
||||||
|
|
||||||
using namespace glslang;
|
using namespace glslang;
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ using namespace glslang;
|
|||||||
TIntermNode* intermNode;
|
TIntermNode* intermNode;
|
||||||
glslang::TIntermNodePair nodePair;
|
glslang::TIntermNodePair nodePair;
|
||||||
glslang::TIntermTyped* intermTypedNode;
|
glslang::TIntermTyped* intermTypedNode;
|
||||||
|
glslang::TAttributes* attributes;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
glslang::TPublicType type;
|
glslang::TPublicType type;
|
||||||
@ -218,12 +220,12 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
|||||||
%type <interm.intermNode> translation_unit function_definition
|
%type <interm.intermNode> translation_unit function_definition
|
||||||
%type <interm.intermNode> statement simple_statement
|
%type <interm.intermNode> statement simple_statement
|
||||||
%type <interm.intermNode> statement_list switch_statement_list compound_statement
|
%type <interm.intermNode> statement_list switch_statement_list compound_statement
|
||||||
%type <interm.intermNode> declaration_statement selection_statement expression_statement
|
%type <interm.intermNode> declaration_statement selection_statement selection_statement_nonattributed expression_statement
|
||||||
%type <interm.intermNode> switch_statement case_label
|
%type <interm.intermNode> switch_statement switch_statement_nonattributed case_label
|
||||||
%type <interm.intermNode> declaration external_declaration
|
%type <interm.intermNode> declaration external_declaration
|
||||||
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
||||||
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
||||||
%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_scoped
|
%type <interm.intermNode> iteration_statement iteration_statement_nonattributed jump_statement statement_no_new_scope statement_scoped
|
||||||
%type <interm> single_declaration init_declarator_list
|
%type <interm> single_declaration init_declarator_list
|
||||||
|
|
||||||
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
||||||
@ -246,6 +248,8 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
|||||||
|
|
||||||
%type <interm.identifierList> identifier_list
|
%type <interm.identifierList> identifier_list
|
||||||
|
|
||||||
|
%type <interm.attributes> attribute attribute_list single_attribute
|
||||||
|
|
||||||
%start translation_unit
|
%start translation_unit
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -2673,6 +2677,15 @@ expression_statement
|
|||||||
;
|
;
|
||||||
|
|
||||||
selection_statement
|
selection_statement
|
||||||
|
: selection_statement_nonattributed {
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| attribute selection_statement_nonattributed {
|
||||||
|
parseContext.handleSelectionAttributes(*$1, $2);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
|
||||||
|
selection_statement_nonattributed
|
||||||
: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
|
: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
|
||||||
parseContext.boolCheck($1.loc, $3);
|
parseContext.boolCheck($1.loc, $3);
|
||||||
$$ = parseContext.intermediate.addSelection($3, $5, $1.loc);
|
$$ = parseContext.intermediate.addSelection($3, $5, $1.loc);
|
||||||
@ -2709,6 +2722,15 @@ condition
|
|||||||
;
|
;
|
||||||
|
|
||||||
switch_statement
|
switch_statement
|
||||||
|
: switch_statement_nonattributed {
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| attribute switch_statement_nonattributed {
|
||||||
|
parseContext.handleSwitchAttributes(*$1, $2);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_statement_nonattributed
|
||||||
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
|
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
|
||||||
// start new switch sequence on the switch stack
|
// start new switch sequence on the switch stack
|
||||||
++parseContext.controlFlowNestingLevel;
|
++parseContext.controlFlowNestingLevel;
|
||||||
@ -2762,6 +2784,15 @@ case_label
|
|||||||
;
|
;
|
||||||
|
|
||||||
iteration_statement
|
iteration_statement
|
||||||
|
: iteration_statement_nonattributed {
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| attribute iteration_statement_nonattributed {
|
||||||
|
parseContext.handleLoopAttributes(*$1, $2);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
|
||||||
|
iteration_statement_nonattributed
|
||||||
: WHILE LEFT_PAREN {
|
: WHILE LEFT_PAREN {
|
||||||
if (! parseContext.limits.whileLoops)
|
if (! parseContext.limits.whileLoops)
|
||||||
parseContext.error($1.loc, "while loops not available", "limitation", "");
|
parseContext.error($1.loc, "while loops not available", "limitation", "");
|
||||||
@ -2920,4 +2951,26 @@ function_definition
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
attribute
|
||||||
|
: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET {
|
||||||
|
$$ = $3;
|
||||||
|
parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_list
|
||||||
|
: single_attribute {
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| attribute_list COMMA single_attribute {
|
||||||
|
$$ = parseContext.mergeAttributes($1, $3);
|
||||||
|
}
|
||||||
|
|
||||||
|
single_attribute
|
||||||
|
: IDENTIFIER {
|
||||||
|
$$ = parseContext.makeAttributes(*$1.string);
|
||||||
|
}
|
||||||
|
| IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN {
|
||||||
|
$$ = parseContext.makeAttributes(*$1.string, $3);
|
||||||
|
}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -348,7 +348,7 @@ extern int yydebug;
|
|||||||
typedef union YYSTYPE YYSTYPE;
|
typedef union YYSTYPE YYSTYPE;
|
||||||
union YYSTYPE
|
union YYSTYPE
|
||||||
{
|
{
|
||||||
#line 68 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
#line 69 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
glslang::TSourceLoc loc;
|
glslang::TSourceLoc loc;
|
||||||
@ -370,6 +370,7 @@ union YYSTYPE
|
|||||||
TIntermNode* intermNode;
|
TIntermNode* intermNode;
|
||||||
glslang::TIntermNodePair nodePair;
|
glslang::TIntermNodePair nodePair;
|
||||||
glslang::TIntermTyped* intermTypedNode;
|
glslang::TIntermTyped* intermTypedNode;
|
||||||
|
glslang::TAttributes* attributes;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
glslang::TPublicType type;
|
glslang::TPublicType type;
|
||||||
@ -382,7 +383,7 @@ union YYSTYPE
|
|||||||
};
|
};
|
||||||
} interm;
|
} interm;
|
||||||
|
|
||||||
#line 386 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
#line 387 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||||
};
|
};
|
||||||
# define YYSTYPE_IS_TRIVIAL 1
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
# define YYSTYPE_IS_DECLARED 1
|
# define YYSTYPE_IS_DECLARED 1
|
||||||
|
@ -235,6 +235,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
"spv.branch-return.vert",
|
"spv.branch-return.vert",
|
||||||
"spv.builtInXFB.vert",
|
"spv.builtInXFB.vert",
|
||||||
"spv.conditionalDiscard.frag",
|
"spv.conditionalDiscard.frag",
|
||||||
|
"spv.controlFlowAttributes.frag",
|
||||||
"spv.conversion.frag",
|
"spv.conversion.frag",
|
||||||
"spv.dataOut.frag",
|
"spv.dataOut.frag",
|
||||||
"spv.dataOutIndirect.frag",
|
"spv.dataOutIndirect.frag",
|
||||||
|
@ -8868,7 +8868,7 @@ void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwit
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Loop hints
|
// Loop attributes
|
||||||
//
|
//
|
||||||
void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
|
void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
|
||||||
const TAttributes& attributes)
|
const TAttributes& attributes)
|
||||||
|
Loading…
Reference in New Issue
Block a user