HLSL: Translate directive [flatten] and [branch] to SPV control mask.

This commit is contained in:
Rex Xu 2017-07-04 23:23:40 +08:00
parent 423fae4858
commit 57e65929e4
15 changed files with 92 additions and 35 deletions

View File

@ -122,6 +122,7 @@ protected:
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier); spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration); spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
spv::ImageFormat TranslateImageFormat(const glslang::TType& type); spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
spv::SelectionControlMask TranslateSelectionControl(glslang::TSelectionControl) const;
spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const; spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) 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*);
@ -741,6 +742,16 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
} }
} }
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(glslang::TSelectionControl selectionControl) const
{
switch (selectionControl) {
case glslang::ESelectionControlNone: return spv::SelectionControlMaskNone;
case glslang::ESelectionControlFlatten: return spv::SelectionControlFlattenMask;
case glslang::ESelectionControlDontFlatten: return spv::SelectionControlDontFlattenMask;
default: return spv::SelectionControlMaskNone;
}
}
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const
{ {
switch (loopControl) { switch (loopControl) {
@ -1941,8 +1952,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
return false; return false;
} }
// Instead, emit control flow... // Instead, emit control flow...
// Don't handle results as temporaries, because there will be two names // Don't handle results as temporaries, because there will be two names
// and better to leave SSA to later passes. // and better to leave SSA to later passes.
spv::Id result = (node->getBasicType() == glslang::EbtVoid) spv::Id result = (node->getBasicType() == glslang::EbtVoid)
@ -1952,8 +1962,11 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
// emit the condition before doing anything with selection // emit the condition before doing anything with selection
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
// Selection control:
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
// make an "if" based on the value created by the condition // make an "if" based on the value created by the condition
spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), builder); spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder);
// emit the "then" statement // emit the "then" statement
if (node->getTrueBlock() != nullptr) { if (node->getTrueBlock() != nullptr) {
@ -1991,6 +2004,9 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType()); spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
// Selection control:
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
// browse the children to sort out code segments // browse the children to sort out code segments
int defaultSegment = -1; int defaultSegment = -1;
std::vector<TIntermNode*> codeSegments; std::vector<TIntermNode*> codeSegments;
@ -2016,7 +2032,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
// make the switch statement // make the switch statement
std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
builder.makeSwitch(selector, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
// emit all the code in the segments // emit all the code in the segments
breakForLoop.push(false); breakForLoop.push(false);
@ -5707,7 +5723,7 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan
leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId); leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
// make an "if" based on the left value // make an "if" based on the left value
spv::Builder::If ifBuilder(leftId, builder); spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder);
// emit right operand as the "then" part of the "if" // emit right operand as the "then" part of the "if"
builder.clearAccessChain(); builder.clearAccessChain();

View File

@ -2009,9 +2009,10 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>&
} }
// Comments in header // Comments in header
Builder::If::If(Id cond, Builder& gb) : Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
builder(gb), builder(gb),
condition(cond), condition(cond),
control(ctrl),
elseBlock(0) elseBlock(0)
{ {
function = &builder.getBuildPoint()->getParent(); function = &builder.getBuildPoint()->getParent();
@ -2052,7 +2053,7 @@ void Builder::If::makeEndIf()
// Go back to the headerBlock and make the flow control split // Go back to the headerBlock and make the flow control split
builder.setBuildPoint(headerBlock); builder.setBuildPoint(headerBlock);
builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone); builder.createSelectionMerge(mergeBlock, control);
if (elseBlock) if (elseBlock)
builder.createConditionalBranch(condition, thenBlock, elseBlock); builder.createConditionalBranch(condition, thenBlock, elseBlock);
else else
@ -2064,7 +2065,7 @@ void Builder::If::makeEndIf()
} }
// Comments in header // Comments in header
void Builder::makeSwitch(Id selector, int numSegments, const std::vector<int>& caseValues, void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
const std::vector<int>& valueIndexToSegment, int defaultSegment, const std::vector<int>& valueIndexToSegment, int defaultSegment,
std::vector<Block*>& segmentBlocks) std::vector<Block*>& segmentBlocks)
{ {
@ -2077,7 +2078,7 @@ void Builder::makeSwitch(Id selector, int numSegments, const std::vector<int>& c
Block* mergeBlock = new Block(getUniqueId(), function); Block* mergeBlock = new Block(getUniqueId(), function);
// make and insert the switch's selection-merge instruction // make and insert the switch's selection-merge instruction
createSelectionMerge(mergeBlock, SelectionControlMaskNone); createSelectionMerge(mergeBlock, control);
// make the switch instruction // make the switch instruction
Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch); Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);

View File

@ -385,7 +385,7 @@ public:
// Helper to use for building nested control flow with if-then-else. // Helper to use for building nested control flow with if-then-else.
class If { class If {
public: public:
If(Id condition, Builder& builder); If(Id condition, unsigned int ctrl, Builder& builder);
~If() {} ~If() {}
void makeBeginElse(); void makeBeginElse();
@ -397,6 +397,7 @@ public:
Builder& builder; Builder& builder;
Id condition; Id condition;
unsigned int control;
Function* function; Function* function;
Block* headerBlock; Block* headerBlock;
Block* thenBlock; Block* thenBlock;
@ -416,7 +417,7 @@ public:
// Returns the right set of basic blocks to start each code segment with, so that the caller's // Returns the right set of basic blocks to start each code segment with, so that the caller's
// recursion stack can hold the memory for it. // recursion stack can hold the memory for it.
// //
void makeSwitch(Id condition, int numSegments, const std::vector<int>& caseValues, void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument
// Add a branch to the innermost switch's merge block. // Add a branch to the innermost switch's merge block.

View File

@ -637,13 +637,15 @@ const char* SelectControlString(int cont)
} }
} }
const int LoopControlCeiling = 2; const int LoopControlCeiling = 4;
const char* LoopControlString(int cont) const char* LoopControlString(int cont)
{ {
switch (cont) { switch (cont) {
case 0: return "Unroll"; case 0: return "Unroll";
case 1: return "DontUnroll"; case 1: return "DontUnroll";
case 2: return "DependencyInfinite";
case 3: return "DependencyLength";
case LoopControlCeiling: case LoopControlCeiling:
default: return "Bad"; default: return "Bad";

View File

@ -90,7 +90,7 @@ gl_FragCoord origin is upper left
11(@PixelShaderFunction(vf4;): 2 Function None 9 11(@PixelShaderFunction(vf4;): 2 Function None 9
10(input): 8(ptr) FunctionParameter 10(input): 8(ptr) FunctionParameter
12: Label 12: Label
SelectionMerge 16 None SelectionMerge 16 DontFlatten
BranchConditional 14 15 16 BranchConditional 14 15 16
15: Label 15: Label
Branch 16 Branch 16

View File

@ -319,7 +319,7 @@ gl_FragCoord origin is upper left
48: 7(fvec4) Load 10(input) 48: 7(fvec4) Load 10(input)
49: 16(bvec4) FOrdEqual 47 48 49: 16(bvec4) FOrdEqual 47 48
50: 15(bool) All 49 50: 15(bool) All 49
SelectionMerge 52 None SelectionMerge 52 Flatten
BranchConditional 50 51 52 BranchConditional 50 51 52
51: Label 51: Label
53: 7(fvec4) Load 10(input) 53: 7(fvec4) Load 10(input)

View File

@ -399,7 +399,7 @@ gl_FragCoord origin is upper left
Branch 25 Branch 25
25: Label 25: Label
36: 9(int) Load 13(c) 36: 9(int) Load 13(c)
SelectionMerge 40 None SelectionMerge 40 DontFlatten
Switch 36 39 Switch 36 39
case 1: 37 case 1: 37
case 2: 38 case 2: 38

View File

@ -18,7 +18,7 @@ float4 PixelShaderFunction(float4 input, int c, int d) : COLOR0
break; break;
} }
switch (c) { [branch] switch (c) {
case 1: case 1:
++input; ++input;
break; break;

View File

@ -861,6 +861,15 @@ protected:
TType type; TType type;
}; };
//
// Selection control hints
//
enum TSelectionControl {
ESelectionControlNone,
ESelectionControlFlatten,
ESelectionControlDontFlatten,
};
// //
// Loop control hints // Loop control hints
// //
@ -1285,19 +1294,22 @@ protected:
class TIntermSelection : public TIntermTyped { class TIntermSelection : public TIntermTyped {
public: public:
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB) {} TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
virtual TIntermTyped* getCondition() const { return condition; } virtual TIntermTyped* getCondition() const { return condition; }
virtual TIntermNode* getTrueBlock() const { return trueBlock; } virtual TIntermNode* getTrueBlock() const { return trueBlock; }
virtual TIntermNode* getFalseBlock() const { return falseBlock; } virtual TIntermNode* getFalseBlock() const { return falseBlock; }
virtual TIntermSelection* getAsSelectionNode() { return this; } virtual TIntermSelection* getAsSelectionNode() { return this; }
virtual const TIntermSelection* getAsSelectionNode() const { return this; } virtual const TIntermSelection* getAsSelectionNode() const { return this; }
void setSelectionControl(TSelectionControl c) { control = c; }
TSelectionControl getSelectionControl() const { return control; }
protected: protected:
TIntermTyped* condition; TIntermTyped* condition;
TIntermNode* trueBlock; TIntermNode* trueBlock;
TIntermNode* falseBlock; TIntermNode* falseBlock;
TSelectionControl control; // selection control hint
}; };
// //
@ -1308,15 +1320,18 @@ protected:
// //
class TIntermSwitch : public TIntermNode { class TIntermSwitch : public TIntermNode {
public: public:
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { } TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), control(ESelectionControlNone) { }
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
virtual TIntermNode* getCondition() const { return condition; } virtual TIntermNode* getCondition() const { return condition; }
virtual TIntermAggregate* getBody() const { return body; } virtual TIntermAggregate* getBody() const { return body; }
virtual TIntermSwitch* getAsSwitchNode() { return this; } virtual TIntermSwitch* getAsSwitchNode() { return this; }
virtual const TIntermSwitch* getAsSwitchNode() const { return this; } virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
void setSelectionControl(TSelectionControl c) { control = c; }
TSelectionControl getSelectionControl() const { return control; }
protected: protected:
TIntermTyped* condition; TIntermTyped* condition;
TIntermAggregate* body; TIntermAggregate* body;
TSelectionControl control; // selection control hint
}; };
enum TVisit enum TVisit

View File

@ -1614,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
// //
// Returns the selection node created. // Returns the selection node created.
// //
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc) TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc, TSelectionControl control)
{ {
// //
// Don't prune the false path for compile-time constants; it's needed // Don't prune the false path for compile-time constants; it's needed
@ -1623,6 +1623,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair no
TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
node->setLoc(loc); node->setLoc(loc);
node->setSelectionControl(control);
return node; return node;
} }
@ -1665,12 +1666,12 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
// //
// Returns the selection node created, or nullptr if one could not be. // Returns the selection node created, or nullptr if one could not be.
// //
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc) TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc, TSelectionControl control)
{ {
// If it's void, go to the if-then-else selection() // If it's void, go to the if-then-else selection()
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) { if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
TIntermNodePair pair = { trueBlock, falseBlock }; TIntermNodePair pair = { trueBlock, falseBlock };
return addSelection(cond, pair, loc); return addSelection(cond, pair, loc, control);
} }
// //

View File

@ -276,8 +276,8 @@ public:
TIntermAggregate* makeAggregate(const TSourceLoc&); TIntermAggregate* makeAggregate(const TSourceLoc&);
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
bool areAllChildConst(TIntermAggregate* aggrNode); bool areAllChildConst(TIntermAggregate* aggrNode);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&); TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const; TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;

View File

@ -3201,10 +3201,10 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
return acceptScopedCompoundStatement(statement); return acceptScopedCompoundStatement(statement);
case EHTokIf: case EHTokIf:
return acceptSelectionStatement(statement); return acceptSelectionStatement(statement, attributes);
case EHTokSwitch: case EHTokSwitch:
return acceptSwitchStatement(statement); return acceptSwitchStatement(statement, attributes);
case EHTokFor: case EHTokFor:
case EHTokDo: case EHTokDo:
@ -3317,10 +3317,12 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
// : IF LEFT_PAREN expression RIGHT_PAREN statement // : IF LEFT_PAREN expression RIGHT_PAREN statement
// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement // : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
// //
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributeMap& attributes)
{ {
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
// IF // IF
if (! acceptTokenClass(EHTokIf)) if (! acceptTokenClass(EHTokIf))
return false; return false;
@ -3358,7 +3360,7 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
} }
// Put the pieces together // Put the pieces together
statement = intermediate.addSelection(condition, thenElse, loc); statement = intermediate.addSelection(condition, thenElse, loc, control);
parseContext.popScope(); parseContext.popScope();
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
@ -3368,10 +3370,13 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
// switch_statement // switch_statement
// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement // : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
// //
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributeMap& attributes)
{ {
// SWITCH // SWITCH
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
if (! acceptTokenClass(EHTokSwitch)) if (! acceptTokenClass(EHTokSwitch))
return false; return false;
@ -3391,7 +3396,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
--parseContext.controlFlowNestingLevel; --parseContext.controlFlowNestingLevel;
if (statementOkay) if (statementOkay)
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr); statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, control);
parseContext.popSwitchSequence(); parseContext.popSwitchSequence();
parseContext.popScope(); parseContext.popScope();

View File

@ -116,8 +116,8 @@ namespace glslang {
bool acceptStatement(TIntermNode*&); bool acceptStatement(TIntermNode*&);
bool acceptNestedStatement(TIntermNode*&); bool acceptNestedStatement(TIntermNode*&);
void acceptAttributes(TAttributeMap&); void acceptAttributes(TAttributeMap&);
bool acceptSelectionStatement(TIntermNode*&); bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&);
bool acceptSwitchStatement(TIntermNode*&); bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&);
bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&); bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
bool acceptJumpStatement(TIntermNode*&); bool acceptJumpStatement(TIntermNode*&);
bool acceptCaseLabel(TIntermNode*&); bool acceptCaseLabel(TIntermNode*&);

View File

@ -8273,6 +8273,19 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
return true; return true;
} }
//
// Selection hints
//
TSelectionControl HlslParseContext::handleSelectionControl(const TAttributeMap& attributes) const
{
if (attributes.contains(EatFlatten))
return ESelectionControlFlatten;
else if (attributes.contains(EatBranch))
return ESelectionControlDontFlatten;
else
return ESelectionControlNone;
}
// //
// Loop hints // Loop hints
// //
@ -8286,7 +8299,6 @@ TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes
return ELoopControlNone; return ELoopControlNone;
} }
// //
// Updating default qualifier for the case of a declaration with just a qualifier, // Updating default qualifier for the case of a declaration with just a qualifier,
// no type, block, or identifier. // no type, block, or identifier.
@ -8425,7 +8437,7 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn
// Turn the top-level node sequence built up of wrapupSwitchSubsequence // Turn the top-level node sequence built up of wrapupSwitchSubsequence
// into a switch node. // into a switch node.
// //
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermAggregate* lastStatements) TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermAggregate* lastStatements, TSelectionControl control)
{ {
wrapupSwitchSubsequence(lastStatements, nullptr); wrapupSwitchSubsequence(lastStatements, nullptr);
@ -8452,6 +8464,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
TIntermSwitch* switchNode = new TIntermSwitch(expression, body); TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
switchNode->setLoc(loc); switchNode->setLoc(loc);
switchNode->setSelectionControl(control);
return switchNode; return switchNode;
} }

View File

@ -159,7 +159,7 @@ public:
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, TSelectionControl control);
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
@ -198,6 +198,9 @@ public:
bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry); bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry); bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
// Determine selection control from attributes
TSelectionControl handleSelectionControl(const TAttributeMap& attributes) const;
// Determine loop control from attributes // Determine loop control from attributes
TLoopControl handleLoopControl(const TAttributeMap& attributes) const; TLoopControl handleLoopControl(const TAttributeMap& attributes) const;