mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
HLSL: implement [unroll] and [loop] attributes
This adds infrastructure suitable for any front end to create SPIR-V loop control flags. The only current front end doing so is HLSL. [unroll] turns into spv::LoopControlUnrollMask [loop] turns into spv::LoopControlDontUnrollMask no specification means spv::LoopControlMaskNone
This commit is contained in:
parent
de1cc06c1d
commit
f1709e7146
@ -122,6 +122,7 @@ protected:
|
||||
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
|
||||
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
|
||||
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
|
||||
spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const;
|
||||
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
|
||||
spv::Id getSampledType(const glslang::TSampler&);
|
||||
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
|
||||
@ -767,6 +768,18 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
|
||||
}
|
||||
}
|
||||
|
||||
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const
|
||||
{
|
||||
switch (loopControl) {
|
||||
case glslang::ELoopControlNone: return spv::LoopControlMaskNone;
|
||||
case glslang::ELoopControlUnroll: return spv::LoopControlUnrollMask;
|
||||
case glslang::ELoopControlDontUnroll: return spv::LoopControlDontUnrollMask;
|
||||
// TODO: DependencyInfinite
|
||||
// TODO: DependencyLength
|
||||
default: return spv::LoopControlMaskNone;
|
||||
}
|
||||
}
|
||||
|
||||
// Return whether or not the given type is something that should be tied to a
|
||||
// descriptor set.
|
||||
bool IsDescriptorResource(const glslang::TType& type)
|
||||
@ -1960,6 +1973,12 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
||||
{
|
||||
auto blocks = builder.makeNewLoop();
|
||||
builder.createBranch(&blocks.head);
|
||||
|
||||
// Loop control:
|
||||
const spv::LoopControlMask control = TranslateLoopControl(node->getLoopControl());
|
||||
|
||||
// TODO: dependency length
|
||||
|
||||
// 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
|
||||
// conditions are met. By definition, it will contain OpLoopMerge, followed
|
||||
@ -1967,7 +1986,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
||||
// instructions in it, since the body/test may have arbitrary instructions,
|
||||
// including merges of its own.
|
||||
builder.setBuildPoint(&blocks.head);
|
||||
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone);
|
||||
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control);
|
||||
if (node->testFirst() && node->getTest()) {
|
||||
spv::Block& test = builder.makeNewBlock();
|
||||
builder.createBranch(&test);
|
||||
|
@ -132,7 +132,7 @@ local_size = (4, 6, 8)
|
||||
Store 13(x) 14
|
||||
Branch 15
|
||||
15: Label
|
||||
LoopMerge 17 18 None
|
||||
LoopMerge 17 18 Unroll
|
||||
Branch 19
|
||||
19: Label
|
||||
20: 11(int) Load 13(x)
|
||||
|
@ -194,7 +194,7 @@ gl_FragCoord origin is upper left
|
||||
12: Label
|
||||
Branch 13
|
||||
13: Label
|
||||
LoopMerge 15 16 None
|
||||
LoopMerge 15 16 Unroll
|
||||
Branch 14
|
||||
14: Label
|
||||
Branch 16
|
||||
@ -203,7 +203,7 @@ gl_FragCoord origin is upper left
|
||||
15: Label
|
||||
Branch 19
|
||||
19: Label
|
||||
LoopMerge 21 22 None
|
||||
LoopMerge 21 22 Unroll
|
||||
Branch 20
|
||||
20: Label
|
||||
Branch 22
|
||||
|
@ -338,7 +338,7 @@ gl_FragCoord origin is upper left
|
||||
23: Label
|
||||
Branch 25
|
||||
25: Label
|
||||
LoopMerge 27 28 None
|
||||
LoopMerge 27 28 Unroll
|
||||
Branch 29
|
||||
29: Label
|
||||
30: 7(fvec4) Load 10(input)
|
||||
|
233
Test/baseResults/hlsl.loopattr.frag.out
Normal file
233
Test/baseResults/hlsl.loopattr.frag.out
Normal file
@ -0,0 +1,233 @@
|
||||
hlsl.loopattr.frag
|
||||
Shader version: 500
|
||||
gl_FragCoord origin is upper left
|
||||
0:? Sequence
|
||||
0:3 Function Definition: @main( ( temp 4-component vector of float)
|
||||
0:3 Function Parameters:
|
||||
0:? Sequence
|
||||
0:5 Sequence
|
||||
0:5 move second child to first child ( temp int)
|
||||
0:5 'x' ( temp int)
|
||||
0:5 Constant:
|
||||
0:5 0 (const int)
|
||||
0:5 Loop with condition tested first
|
||||
0:5 Loop Condition
|
||||
0:5 Compare Less Than ( temp bool)
|
||||
0:5 'x' ( temp int)
|
||||
0:5 Constant:
|
||||
0:5 5 (const int)
|
||||
0:5 No loop body
|
||||
0:5 Loop Terminal Expression
|
||||
0:5 Pre-Increment ( temp int)
|
||||
0:5 'x' ( temp int)
|
||||
0:8 Sequence
|
||||
0:8 move second child to first child ( temp int)
|
||||
0:8 'y' ( temp int)
|
||||
0:8 Constant:
|
||||
0:8 0 (const int)
|
||||
0:8 Loop with condition tested first
|
||||
0:8 Loop Condition
|
||||
0:8 Compare Less Than ( temp bool)
|
||||
0:8 'y' ( temp int)
|
||||
0:8 Constant:
|
||||
0:8 5 (const int)
|
||||
0:8 No loop body
|
||||
0:8 Loop Terminal Expression
|
||||
0:8 Pre-Increment ( temp int)
|
||||
0:8 'y' ( temp int)
|
||||
0:11 Sequence
|
||||
0:11 move second child to first child ( temp int)
|
||||
0:11 'z' ( temp int)
|
||||
0:11 Constant:
|
||||
0:11 0 (const int)
|
||||
0:11 Loop with condition tested first
|
||||
0:11 Loop Condition
|
||||
0:11 Compare Less Than ( temp bool)
|
||||
0:11 'z' ( temp int)
|
||||
0:11 Constant:
|
||||
0:11 5 (const int)
|
||||
0:11 No loop body
|
||||
0:11 Loop Terminal Expression
|
||||
0:11 Pre-Increment ( temp int)
|
||||
0:11 'z' ( temp int)
|
||||
0:13 Branch: Return with expression
|
||||
0:13 Constant:
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:3 Function Definition: main( ( temp void)
|
||||
0:3 Function Parameters:
|
||||
0:? Sequence
|
||||
0:3 move second child to first child ( temp 4-component vector of float)
|
||||
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
|
||||
0:3 Function Call: @main( ( temp 4-component vector of float)
|
||||
0:? Linker Objects
|
||||
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
|
||||
|
||||
|
||||
Linked fragment stage:
|
||||
|
||||
|
||||
Shader version: 500
|
||||
gl_FragCoord origin is upper left
|
||||
0:? Sequence
|
||||
0:3 Function Definition: @main( ( temp 4-component vector of float)
|
||||
0:3 Function Parameters:
|
||||
0:? Sequence
|
||||
0:5 Sequence
|
||||
0:5 move second child to first child ( temp int)
|
||||
0:5 'x' ( temp int)
|
||||
0:5 Constant:
|
||||
0:5 0 (const int)
|
||||
0:5 Loop with condition tested first
|
||||
0:5 Loop Condition
|
||||
0:5 Compare Less Than ( temp bool)
|
||||
0:5 'x' ( temp int)
|
||||
0:5 Constant:
|
||||
0:5 5 (const int)
|
||||
0:5 No loop body
|
||||
0:5 Loop Terminal Expression
|
||||
0:5 Pre-Increment ( temp int)
|
||||
0:5 'x' ( temp int)
|
||||
0:8 Sequence
|
||||
0:8 move second child to first child ( temp int)
|
||||
0:8 'y' ( temp int)
|
||||
0:8 Constant:
|
||||
0:8 0 (const int)
|
||||
0:8 Loop with condition tested first
|
||||
0:8 Loop Condition
|
||||
0:8 Compare Less Than ( temp bool)
|
||||
0:8 'y' ( temp int)
|
||||
0:8 Constant:
|
||||
0:8 5 (const int)
|
||||
0:8 No loop body
|
||||
0:8 Loop Terminal Expression
|
||||
0:8 Pre-Increment ( temp int)
|
||||
0:8 'y' ( temp int)
|
||||
0:11 Sequence
|
||||
0:11 move second child to first child ( temp int)
|
||||
0:11 'z' ( temp int)
|
||||
0:11 Constant:
|
||||
0:11 0 (const int)
|
||||
0:11 Loop with condition tested first
|
||||
0:11 Loop Condition
|
||||
0:11 Compare Less Than ( temp bool)
|
||||
0:11 'z' ( temp int)
|
||||
0:11 Constant:
|
||||
0:11 5 (const int)
|
||||
0:11 No loop body
|
||||
0:11 Loop Terminal Expression
|
||||
0:11 Pre-Increment ( temp int)
|
||||
0:11 'z' ( temp int)
|
||||
0:13 Branch: Return with expression
|
||||
0:13 Constant:
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:13 0.000000
|
||||
0:3 Function Definition: main( ( temp void)
|
||||
0:3 Function Parameters:
|
||||
0:? Sequence
|
||||
0:3 move second child to first child ( temp 4-component vector of float)
|
||||
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
|
||||
0:3 Function Call: @main( ( temp 4-component vector of float)
|
||||
0:? Linker Objects
|
||||
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
|
||||
|
||||
// Module Version 10000
|
||||
// Generated by (magic number): 80001
|
||||
// Id's are bound by 54
|
||||
|
||||
Capability Shader
|
||||
1: ExtInstImport "GLSL.std.450"
|
||||
MemoryModel Logical GLSL450
|
||||
EntryPoint Fragment 4 "main" 52
|
||||
ExecutionMode 4 OriginUpperLeft
|
||||
Source HLSL 500
|
||||
Name 4 "main"
|
||||
Name 9 "@main("
|
||||
Name 13 "x"
|
||||
Name 27 "y"
|
||||
Name 37 "z"
|
||||
Name 52 "@entryPointOutput"
|
||||
Decorate 52(@entryPointOutput) Location 0
|
||||
2: TypeVoid
|
||||
3: TypeFunction 2
|
||||
6: TypeFloat 32
|
||||
7: TypeVector 6(float) 4
|
||||
8: TypeFunction 7(fvec4)
|
||||
11: TypeInt 32 1
|
||||
12: TypePointer Function 11(int)
|
||||
14: 11(int) Constant 0
|
||||
21: 11(int) Constant 5
|
||||
22: TypeBool
|
||||
25: 11(int) Constant 1
|
||||
47: 6(float) Constant 0
|
||||
48: 7(fvec4) ConstantComposite 47 47 47 47
|
||||
51: TypePointer Output 7(fvec4)
|
||||
52(@entryPointOutput): 51(ptr) Variable Output
|
||||
4(main): 2 Function None 3
|
||||
5: Label
|
||||
53: 7(fvec4) FunctionCall 9(@main()
|
||||
Store 52(@entryPointOutput) 53
|
||||
Return
|
||||
FunctionEnd
|
||||
9(@main(): 7(fvec4) Function None 8
|
||||
10: Label
|
||||
13(x): 12(ptr) Variable Function
|
||||
27(y): 12(ptr) Variable Function
|
||||
37(z): 12(ptr) Variable Function
|
||||
Store 13(x) 14
|
||||
Branch 15
|
||||
15: Label
|
||||
LoopMerge 17 18 Unroll
|
||||
Branch 19
|
||||
19: Label
|
||||
20: 11(int) Load 13(x)
|
||||
23: 22(bool) SLessThan 20 21
|
||||
BranchConditional 23 16 17
|
||||
16: Label
|
||||
Branch 18
|
||||
18: Label
|
||||
24: 11(int) Load 13(x)
|
||||
26: 11(int) IAdd 24 25
|
||||
Store 13(x) 26
|
||||
Branch 15
|
||||
17: Label
|
||||
Store 27(y) 14
|
||||
Branch 28
|
||||
28: Label
|
||||
LoopMerge 30 31 DontUnroll
|
||||
Branch 32
|
||||
32: Label
|
||||
33: 11(int) Load 27(y)
|
||||
34: 22(bool) SLessThan 33 21
|
||||
BranchConditional 34 29 30
|
||||
29: Label
|
||||
Branch 31
|
||||
31: Label
|
||||
35: 11(int) Load 27(y)
|
||||
36: 11(int) IAdd 35 25
|
||||
Store 27(y) 36
|
||||
Branch 28
|
||||
30: Label
|
||||
Store 37(z) 14
|
||||
Branch 38
|
||||
38: Label
|
||||
LoopMerge 40 41 None
|
||||
Branch 42
|
||||
42: Label
|
||||
43: 11(int) Load 37(z)
|
||||
44: 22(bool) SLessThan 43 21
|
||||
BranchConditional 44 39 40
|
||||
39: Label
|
||||
Branch 41
|
||||
41: Label
|
||||
45: 11(int) Load 37(z)
|
||||
46: 11(int) IAdd 45 25
|
||||
Store 37(z) 46
|
||||
Branch 38
|
||||
40: Label
|
||||
ReturnValue 48
|
||||
FunctionEnd
|
@ -171,7 +171,7 @@ gl_FragCoord origin is upper left
|
||||
28: Label
|
||||
Branch 32
|
||||
32: Label
|
||||
LoopMerge 34 35 None
|
||||
LoopMerge 34 35 Unroll
|
||||
Branch 36
|
||||
36: Label
|
||||
BranchConditional 31 33 34
|
||||
|
14
Test/hlsl.loopattr.frag
Normal file
14
Test/hlsl.loopattr.frag
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
float4 main() : SV_Target0
|
||||
{
|
||||
// Unroll hint
|
||||
[unroll(5) ] for (int x=0; x<5; ++x);
|
||||
|
||||
// Don't unroll hint
|
||||
[loop] for (int y=0; y<5; ++y);
|
||||
|
||||
// No hint
|
||||
for (int z=0; z<5; ++z);
|
||||
|
||||
return 0;
|
||||
}
|
@ -758,6 +758,15 @@ protected:
|
||||
TType type;
|
||||
};
|
||||
|
||||
//
|
||||
// Loop control hints
|
||||
//
|
||||
enum TLoopControl {
|
||||
ELoopControlNone,
|
||||
ELoopControlUnroll,
|
||||
ELoopControlDontUnroll,
|
||||
};
|
||||
|
||||
//
|
||||
// Handle for, do-while, and while loops.
|
||||
//
|
||||
@ -767,17 +776,25 @@ public:
|
||||
body(aBody),
|
||||
test(aTest),
|
||||
terminal(aTerminal),
|
||||
first(testFirst) { }
|
||||
first(testFirst),
|
||||
control(ELoopControlNone)
|
||||
{ }
|
||||
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
TIntermNode* getBody() const { return body; }
|
||||
TIntermTyped* getTest() const { return test; }
|
||||
TIntermTyped* getTerminal() const { return terminal; }
|
||||
bool testFirst() const { return first; }
|
||||
|
||||
void setLoopControl(TLoopControl c) { control = c; }
|
||||
TLoopControl getLoopControl() const { return control; }
|
||||
|
||||
protected:
|
||||
TIntermNode* body; // code to loop over
|
||||
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
|
||||
TIntermTyped* terminal; // exists for for-loops
|
||||
bool first; // true for while and for, not for do-while
|
||||
TLoopControl control; // loop control hint
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -1630,10 +1630,11 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
|
||||
//
|
||||
// Create while and do-while loop nodes.
|
||||
//
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -1641,10 +1642,11 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
|
||||
//
|
||||
// Create a for-loop sequence.
|
||||
//
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
// make a sequence of the initializer and statement
|
||||
TIntermAggregate* loopSequence = makeAggregate(initializer, loc);
|
||||
|
@ -283,8 +283,8 @@ public:
|
||||
TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
|
||||
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
|
||||
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
|
||||
template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
|
||||
|
@ -175,6 +175,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{"hlsl.logical.binary.vec.frag", "main"},
|
||||
{"hlsl.logicalConvert.frag", "main"},
|
||||
{"hlsl.logical.unary.frag", "main"},
|
||||
{"hlsl.loopattr.frag", "main"},
|
||||
{"hlsl.namespace.frag", "main"},
|
||||
{"hlsl.nonint-index.frag", "main"},
|
||||
{"hlsl.matNx1.frag", "main"},
|
||||
|
@ -80,6 +80,8 @@ namespace glslang {
|
||||
return EatPatchConstantFunc;
|
||||
else if (lowername == "unroll")
|
||||
return EatUnroll;
|
||||
else if (lowername == "loop")
|
||||
return EatLoop;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
@ -107,4 +109,10 @@ namespace glslang {
|
||||
return (entry == attributes.end()) ? nullptr : entry->second;
|
||||
}
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool TAttributeMap::contains(TAttributeType attr) const
|
||||
{
|
||||
return attributes.find(attr) != attributes.end();
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
@ -62,6 +62,7 @@ namespace glslang {
|
||||
EatPatchConstantFunc,
|
||||
EatPatchSize,
|
||||
EatUnroll,
|
||||
EatLoop,
|
||||
};
|
||||
}
|
||||
|
||||
@ -86,6 +87,9 @@ namespace glslang {
|
||||
// Const lookup: search for (but do not modify) the attribute in the map.
|
||||
const TIntermAggregate* operator[](TAttributeType) const;
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool contains(TAttributeType) const;
|
||||
|
||||
protected:
|
||||
// Find an attribute enum given its name.
|
||||
static TAttributeType attributeFromName(const TString&);
|
||||
|
@ -3127,7 +3127,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
|
||||
case EHTokFor:
|
||||
case EHTokDo:
|
||||
case EHTokWhile:
|
||||
return acceptIterationStatement(statement);
|
||||
return acceptIterationStatement(statement, attributes);
|
||||
|
||||
case EHTokContinue:
|
||||
case EHTokBreak:
|
||||
@ -3336,7 +3336,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
|
||||
// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
|
||||
//
|
||||
// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
{
|
||||
TSourceLoc loc = token.loc;
|
||||
TIntermTyped* condition = nullptr;
|
||||
@ -3347,6 +3347,8 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
|
||||
// WHILE or DO or FOR
|
||||
advanceToken();
|
||||
|
||||
const TLoopControl control = parseContext.handleLoopControl(attributes);
|
||||
|
||||
switch (loop) {
|
||||
case EHTokWhile:
|
||||
// so that something declared in the condition is scoped to the lifetime
|
||||
@ -3370,7 +3372,7 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
|
||||
parseContext.unnestLooping();
|
||||
parseContext.popScope();
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
|
||||
statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
|
||||
|
||||
return true;
|
||||
|
||||
@ -3402,7 +3404,7 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
|
||||
|
||||
parseContext.unnestLooping();
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, 0, false, loc);
|
||||
statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
|
||||
|
||||
return true;
|
||||
|
||||
@ -3451,7 +3453,7 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
|
||||
return false;
|
||||
}
|
||||
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
|
||||
|
||||
parseContext.popScope();
|
||||
parseContext.unnestLooping();
|
||||
|
@ -116,7 +116,7 @@ namespace glslang {
|
||||
void acceptAttributes(TAttributeMap&);
|
||||
bool acceptSelectionStatement(TIntermNode*&);
|
||||
bool acceptSwitchStatement(TIntermNode*&);
|
||||
bool acceptIterationStatement(TIntermNode*&);
|
||||
bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
|
||||
bool acceptJumpStatement(TIntermNode*&);
|
||||
bool acceptCaseLabel(TIntermNode*&);
|
||||
bool acceptDefaultLabel(TIntermNode*&);
|
||||
|
@ -7568,6 +7568,20 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Loop hints
|
||||
//
|
||||
TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const
|
||||
{
|
||||
if (attributes.contains(EatUnroll))
|
||||
return ELoopControlUnroll;
|
||||
else if (attributes.contains(EatLoop))
|
||||
return ELoopControlDontUnroll;
|
||||
else
|
||||
return ELoopControlNone;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Updating default qualifier for the case of a declaration with just a qualifier,
|
||||
// no type, block, or identifier.
|
||||
|
@ -192,6 +192,9 @@ public:
|
||||
bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||
|
||||
// Determine loop control from attributes
|
||||
TLoopControl handleLoopControl(const TAttributeMap& attributes) const;
|
||||
|
||||
// Potentially rename shader entry point function
|
||||
void renameShaderFunction(const TString*& name) const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user