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::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) 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::Id createSpvVariable(const glslang::TIntermSymbol*);
|
||||
spv::Id getSampledType(const glslang::TSampler&);
|
||||
@ -767,7 +767,9 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const g
|
||||
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;
|
||||
|
||||
@ -775,6 +777,12 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang:
|
||||
control = control | spv::LoopControlDontUnrollMask;
|
||||
if (loopNode.getUnroll())
|
||||
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;
|
||||
}
|
||||
@ -2137,9 +2145,8 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
||||
builder.createBranch(&blocks.head);
|
||||
|
||||
// Loop control:
|
||||
const spv::LoopControlMask control = TranslateLoopControl(*node);
|
||||
|
||||
// TODO: dependency length
|
||||
unsigned int dependencyLength = glslang::TIntermLoop::dependencyInfinite;
|
||||
const spv::LoopControlMask control = TranslateLoopControl(*node, dependencyLength);
|
||||
|
||||
// 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
|
||||
@ -2149,7 +2156,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
||||
// including merges of its own.
|
||||
builder.setLine(node->getLoc().line);
|
||||
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()) {
|
||||
spv::Block& test = builder.makeNewBlock();
|
||||
builder.createBranch(&test);
|
||||
|
@ -2573,12 +2573,15 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
|
||||
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);
|
||||
merge->addIdOperand(mergeBlock->getId());
|
||||
merge->addIdOperand(continueBlock->getId());
|
||||
merge->addImmediateOperand(control);
|
||||
if ((control & LoopControlDependencyLengthMask) != 0)
|
||||
merge->addImmediateOperand(dependencyLength);
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
|
||||
}
|
||||
|
||||
|
@ -561,7 +561,7 @@ public:
|
||||
|
||||
void createBranch(Block* block);
|
||||
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.
|
||||
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
||||
|
@ -2558,6 +2558,7 @@ void Parameterize()
|
||||
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'");
|
||||
InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'");
|
||||
InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
|
||||
InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, "");
|
||||
|
||||
InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'");
|
||||
InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");
|
||||
|
@ -15,3 +15,18 @@ void main()
|
||||
b1 = allInvocations(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
|
||||
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
|
||||
0:? Sequence
|
||||
Requested GL_EXT_control_flow_attributes
|
||||
ERROR: node is still EOpNull!
|
||||
0:10 Function Definition: main( ( global void)
|
||||
0:10 Function Parameters:
|
||||
0:12 Sequence
|
||||
@ -21,6 +29,43 @@ Shader version: 460
|
||||
0:16 'b1' ( temp bool)
|
||||
0:16 allInvocationsEqual ( global 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:? 's' ( smooth in structure{ global float f, global 4-component vector of float v})
|
||||
|
||||
@ -29,7 +74,8 @@ Linked fragment stage:
|
||||
|
||||
|
||||
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 Parameters:
|
||||
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);
|
||||
}
|
||||
|
||||
template<class T> inline T* NewPoolObject(T)
|
||||
template<class T> inline T* NewPoolObject(T*)
|
||||
{
|
||||
return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
|
||||
}
|
||||
|
@ -896,7 +896,8 @@ public:
|
||||
terminal(aTerminal),
|
||||
first(testFirst),
|
||||
unroll(false),
|
||||
dontUnroll(false)
|
||||
dontUnroll(false),
|
||||
dependency(0)
|
||||
{ }
|
||||
|
||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||
@ -912,6 +913,10 @@ public:
|
||||
bool getUnroll() const { return unroll; }
|
||||
bool getDontUnroll() const { return dontUnroll; }
|
||||
|
||||
static const unsigned int dependencyInfinite = 0xFFFFFFFF;
|
||||
void setLoopDependency(int d) { dependency = d; }
|
||||
int getLoopDependency() const { return dependency; }
|
||||
|
||||
protected:
|
||||
TIntermNode* body; // code to loop over
|
||||
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
|
||||
@ -919,6 +924,7 @@ protected:
|
||||
bool first; // true for while and for, not for do-while
|
||||
bool unroll; // true if unroll requested
|
||||
bool dontUnroll; // true if request to not unroll
|
||||
unsigned int dependency; // loop dependency hint; 0 means not set or unknown
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -44,13 +44,15 @@
|
||||
#ifndef _PARSER_HELPER_INCLUDED_
|
||||
#define _PARSER_HELPER_INCLUDED_
|
||||
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
|
||||
#include "parseVersions.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "localintermediate.h"
|
||||
#include "Scan.h"
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
#include "attribute.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
@ -409,6 +411,17 @@ public:
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
|
||||
|
||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||
TAttributeType attributeFromName(const TString& name) const;
|
||||
TAttributes* makeAttributes(const TString& identifier) const;
|
||||
TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const;
|
||||
TAttributes* mergeAttributes(TAttributes*, TAttributes*) const;
|
||||
|
||||
// Determine selection control from attributes
|
||||
void handleSelectionAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
|
||||
// Determine loop control from attributes
|
||||
void handleLoopAttributes(const TAttributes& attributes, TIntermNode*);
|
||||
|
||||
protected:
|
||||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "../Include/Types.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "ParseHelper.h"
|
||||
#include "attribute.h"
|
||||
#include "glslang_tab.cpp.h"
|
||||
#include "ScanContext.h"
|
||||
#include "Scan.h"
|
||||
|
@ -188,6 +188,7 @@ void TParseVersions::initializeExtensionBehavior()
|
||||
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_control_flow_attributes] = EBhDisable;
|
||||
|
||||
// #line and #include
|
||||
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
||||
@ -328,6 +329,7 @@ void TParseVersions::getPreamble(std::string& preamble)
|
||||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||
"#define GL_EXT_shader_image_load_formatted 1\n"
|
||||
"#define GL_EXT_post_depth_coverage 1\n"
|
||||
"#define GL_EXT_control_flow_attributes 1\n"
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
"#define GL_AMD_shader_ballot 1\n"
|
||||
|
@ -146,6 +146,7 @@ const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_lo
|
||||
const char* const E_GL_EXT_device_group = "GL_EXT_device_group";
|
||||
const char* const E_GL_EXT_multiview = "GL_EXT_multiview";
|
||||
const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage";
|
||||
const char* const E_GL_EXT_control_flow_attributes = "GL_EXT_control_flow_attributes";
|
||||
|
||||
// Arrays of extensions for the above viewportEXTs duplications
|
||||
|
||||
|
@ -40,47 +40,218 @@
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeArgs::getInt(int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeArgs::getInt(int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
||||
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
};
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
}
|
||||
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
||||
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = *stringConst->getSConst();
|
||||
value = *stringConst->getSConst();
|
||||
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
||||
{
|
||||
if (argNum >= args->getSequence().size())
|
||||
return nullptr;
|
||||
// How many arguments were supplied?
|
||||
int TAttributeArgs::size() const
|
||||
{
|
||||
return args == nullptr ? 0 : (int)args->getSequence().size();
|
||||
}
|
||||
|
||||
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
||||
{
|
||||
if (args == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
if (argNum >= args->getSequence().size())
|
||||
return nullptr;
|
||||
|
||||
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
}
|
||||
|
||||
// Implementation of TParseContext parts of attributes
|
||||
TAttributeType TParseContext::attributeFromName(const TString& name) const
|
||||
{
|
||||
if (name == "branch" || name == "dont_flatten")
|
||||
return EatBranch;
|
||||
else if (name == "flatten")
|
||||
return EatFlatten;
|
||||
else if (name == "unroll")
|
||||
return EatUnroll;
|
||||
else if (name == "loop" || name == "dont_unroll")
|
||||
return EatLoop;
|
||||
else if (name == "dependency_infinite")
|
||||
return EatDependencyInfinite;
|
||||
else if (name == "dependency_length")
|
||||
return EatDependencyLength;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
|
||||
// Make an initial leaf for the grammar from a no-argument attribute
|
||||
TAttributes* TParseContext::makeAttributes(const TString& identifier) const
|
||||
{
|
||||
TAttributes *attributes = nullptr;
|
||||
attributes = NewPoolObject(attributes);
|
||||
TAttributeArgs args = { attributeFromName(identifier), nullptr };
|
||||
attributes->push_back(args);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// Make an initial leaf for the grammar from a one-argument attribute
|
||||
TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
|
||||
{
|
||||
TAttributes *attributes = nullptr;
|
||||
attributes = NewPoolObject(attributes);
|
||||
|
||||
// for now, node is always a simple single expression, but other code expects
|
||||
// a list, so make it so
|
||||
TIntermAggregate* agg = intermediate.makeAggregate(node);
|
||||
TAttributeArgs args = { attributeFromName(identifier), agg };
|
||||
attributes->push_back(args);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// Merge two sets of attributes into a single set.
|
||||
// The second argument is destructively consumed.
|
||||
TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
|
||||
{
|
||||
attr1->splice(attr1->end(), *attr2);
|
||||
return attr1;
|
||||
}
|
||||
|
||||
//
|
||||
// Selection attributes
|
||||
//
|
||||
void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermSelection* selection = node->getAsSelectionNode();
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a selection", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Switch attributes
|
||||
//
|
||||
void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermSwitch* selection = node->getAsSwitchNode();
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a switch", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop attributes
|
||||
//
|
||||
void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
|
||||
{
|
||||
TIntermLoop* loop = node->getAsLoopNode();
|
||||
if (loop == nullptr) {
|
||||
// the actual loop might be part of a sequence
|
||||
TIntermAggregate* agg = node->getAsAggregate();
|
||||
if (agg == nullptr)
|
||||
return;
|
||||
for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
|
||||
loop = (*it)->getAsLoopNode();
|
||||
if (loop != nullptr)
|
||||
break;
|
||||
}
|
||||
if (loop == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->name != EatDependencyLength && it->size() > 0) {
|
||||
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
int value;
|
||||
switch (it->name) {
|
||||
case EatUnroll:
|
||||
loop->setUnroll();
|
||||
break;
|
||||
case EatLoop:
|
||||
loop->setDontUnroll();
|
||||
break;
|
||||
case EatDependencyInfinite:
|
||||
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
|
||||
break;
|
||||
case EatDependencyLength:
|
||||
if (it->size() == 1 && it->getInt(value)) {
|
||||
if (value <= 0)
|
||||
error(node->getLoc(), "must be positive", "dependency_length", "");
|
||||
loop->setLoopDependency(value);
|
||||
} else
|
||||
warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
|
||||
break;
|
||||
default:
|
||||
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace glslang
|
||||
|
@ -69,14 +69,16 @@ namespace glslang {
|
||||
EatInputAttachment,
|
||||
EatBuiltIn,
|
||||
EatPushConstant,
|
||||
EatConstantId
|
||||
EatConstantId,
|
||||
EatDependencyInfinite,
|
||||
EatDependencyLength
|
||||
};
|
||||
|
||||
class TIntermAggregate;
|
||||
|
||||
struct TAttributeArgs {
|
||||
TAttributeType name;
|
||||
TIntermAggregate* args;
|
||||
const TIntermAggregate* args;
|
||||
|
||||
// Obtain attribute as integer
|
||||
// Return false if it cannot be obtained
|
||||
@ -86,6 +88,9 @@ namespace glslang {
|
||||
// Return false if it cannot be obtained
|
||||
bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||
|
||||
// How many arguments were provided to the attribute?
|
||||
int size() const;
|
||||
|
||||
protected:
|
||||
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
|
||||
};
|
||||
|
@ -58,6 +58,7 @@ Jutta Degener, 1995
|
||||
#include "SymbolTable.h"
|
||||
#include "ParseHelper.h"
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "attribute.h"
|
||||
|
||||
using namespace glslang;
|
||||
|
||||
@ -86,6 +87,7 @@ using namespace glslang;
|
||||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
glslang::TAttributes* attributes;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
@ -218,12 +220,12 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
||||
%type <interm.intermNode> translation_unit function_definition
|
||||
%type <interm.intermNode> statement simple_statement
|
||||
%type <interm.intermNode> statement_list switch_statement_list compound_statement
|
||||
%type <interm.intermNode> declaration_statement selection_statement expression_statement
|
||||
%type <interm.intermNode> switch_statement case_label
|
||||
%type <interm.intermNode> declaration_statement selection_statement selection_statement_nonattributed expression_statement
|
||||
%type <interm.intermNode> switch_statement switch_statement_nonattributed case_label
|
||||
%type <interm.intermNode> declaration external_declaration
|
||||
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
||||
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
||||
%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_scoped
|
||||
%type <interm.intermNode> iteration_statement iteration_statement_nonattributed jump_statement statement_no_new_scope statement_scoped
|
||||
%type <interm> single_declaration init_declarator_list
|
||||
|
||||
%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
|
||||
@ -246,6 +248,8 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
||||
|
||||
%type <interm.identifierList> identifier_list
|
||||
|
||||
%type <interm.attributes> attribute attribute_list single_attribute
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
|
||||
@ -2673,6 +2677,15 @@ expression_statement
|
||||
;
|
||||
|
||||
selection_statement
|
||||
: selection_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute selection_statement_nonattributed {
|
||||
parseContext.handleSelectionAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
selection_statement_nonattributed
|
||||
: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
|
||||
parseContext.boolCheck($1.loc, $3);
|
||||
$$ = parseContext.intermediate.addSelection($3, $5, $1.loc);
|
||||
@ -2709,6 +2722,15 @@ condition
|
||||
;
|
||||
|
||||
switch_statement
|
||||
: switch_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute switch_statement_nonattributed {
|
||||
parseContext.handleSwitchAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
switch_statement_nonattributed
|
||||
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
|
||||
// start new switch sequence on the switch stack
|
||||
++parseContext.controlFlowNestingLevel;
|
||||
@ -2762,6 +2784,15 @@ case_label
|
||||
;
|
||||
|
||||
iteration_statement
|
||||
: iteration_statement_nonattributed {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute iteration_statement_nonattributed {
|
||||
parseContext.handleLoopAttributes(*$1, $2);
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
iteration_statement_nonattributed
|
||||
: WHILE LEFT_PAREN {
|
||||
if (! parseContext.limits.whileLoops)
|
||||
parseContext.error($1.loc, "while loops not available", "limitation", "");
|
||||
@ -2920,4 +2951,26 @@ function_definition
|
||||
}
|
||||
;
|
||||
|
||||
attribute
|
||||
: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET {
|
||||
$$ = $3;
|
||||
parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute");
|
||||
}
|
||||
|
||||
attribute_list
|
||||
: single_attribute {
|
||||
$$ = $1;
|
||||
}
|
||||
| attribute_list COMMA single_attribute {
|
||||
$$ = parseContext.mergeAttributes($1, $3);
|
||||
}
|
||||
|
||||
single_attribute
|
||||
: IDENTIFIER {
|
||||
$$ = parseContext.makeAttributes(*$1.string);
|
||||
}
|
||||
| IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN {
|
||||
$$ = parseContext.makeAttributes(*$1.string, $3);
|
||||
}
|
||||
|
||||
%%
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -348,7 +348,7 @@ extern int yydebug;
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 68 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
#line 69 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
@ -370,6 +370,7 @@ union YYSTYPE
|
||||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
glslang::TAttributes* attributes;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
@ -382,7 +383,7 @@ union YYSTYPE
|
||||
};
|
||||
} interm;
|
||||
|
||||
#line 386 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
#line 387 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
};
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
@ -235,6 +235,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"spv.branch-return.vert",
|
||||
"spv.builtInXFB.vert",
|
||||
"spv.conditionalDiscard.frag",
|
||||
"spv.controlFlowAttributes.frag",
|
||||
"spv.conversion.frag",
|
||||
"spv.dataOut.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,
|
||||
const TAttributes& attributes)
|
||||
|
Loading…
Reference in New Issue
Block a user