HLSL: 1) Implement lookahead buffers/stacks for token advance/recede, 2) use it for cast operation.

The grammar now accepts type casts, like "(int)x", but that
has to be disambiguated from "(a + b)", needed deeper lookahead
and backing up than what existed so far.
This commit is contained in:
John Kessenich 2016-06-03 16:55:49 -06:00
parent 080cdc1737
commit 1cc1a2813e
7 changed files with 190 additions and 8 deletions

View File

@ -0,0 +1,86 @@
hlsl.cast.frag
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:5 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
0:2 Function Parameters:
0:2 'input' (temp 4-component vector of float)
0:? Sequence
0:3 Branch: Return with expression
0:3 add (temp 4-component vector of float)
0:3 add (temp 4-component vector of float)
0:3 Construct vec4 (temp 4-component vector of float)
0:3 'input' (temp 4-component vector of float)
0:3 Convert int to float (temp 4-component vector of float)
0:3 Convert float to int (temp 4-component vector of int)
0:3 'input' (temp 4-component vector of float)
0:3 Constant:
0:3 1.198000
0:3 1.198000
0:3 1.198000
0:3 1.198000
0:? Linker Objects
Linked fragment stage:
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:5 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
0:2 Function Parameters:
0:2 'input' (temp 4-component vector of float)
0:? Sequence
0:3 Branch: Return with expression
0:3 add (temp 4-component vector of float)
0:3 add (temp 4-component vector of float)
0:3 Construct vec4 (temp 4-component vector of float)
0:3 'input' (temp 4-component vector of float)
0:3 Convert int to float (temp 4-component vector of float)
0:3 Convert float to int (temp 4-component vector of int)
0:3 'input' (temp 4-component vector of float)
0:3 Constant:
0:3 1.198000
0:3 1.198000
0:3 1.198000
0:3 1.198000
0:? Linker Objects
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 26
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "PixelShaderFunction"
ExecutionMode 4 OriginUpperLeft
Source HLSL 450
Name 4 "PixelShaderFunction"
Name 9 "input"
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Function 7(fvec4)
17: TypeInt 32 1
18: TypeVector 17(int) 4
22: 6(float) Constant 1067014160
23: 7(fvec4) ConstantComposite 22 22 22 22
4(PixelShaderFunction): 2 Function None 3
5: Label
9(input): 8(ptr) Variable Function
10: 7(fvec4) Load 9(input)
11: 6(float) CompositeExtract 10 0
12: 6(float) CompositeExtract 10 1
13: 6(float) CompositeExtract 10 2
14: 6(float) CompositeExtract 10 3
15: 7(fvec4) CompositeConstruct 11 12 13 14
16: 7(fvec4) Load 9(input)
19: 18(ivec4) ConvertFToS 16
20: 7(fvec4) ConvertSToF 19
21: 7(fvec4) FAdd 15 20
24: 7(fvec4) FAdd 21 23
ReturnValue 24
FunctionEnd

4
Test/hlsl.cast.frag Normal file
View File

@ -0,0 +1,4 @@
float4 PixelShaderFunction(float4 input) : COLOR0
{
return (float4)input + (int4)input + (float4)1.198;
}

View File

@ -73,6 +73,7 @@ INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileTest,
::testing::ValuesIn(std::vector<FileNameEntryPointPair>{
{"hlsl.assoc.frag", "PixelShaderFunction"},
{"hlsl.cast.frag", "PixelShaderFunction"},
{"hlsl.float1.frag", "PixelShaderFunction"},
{"hlsl.float4.frag", "PixelShaderFunction"},
{"hlsl.intrinsics.frag", "PixelShaderFunction"},

View File

@ -602,7 +602,8 @@ bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel pr
}
// unary_expression
// : + unary_expression
// : (type) unary_expression
// | + unary_expression
// | - unary_expression
// | ! unary_expression
// | ~ unary_expression
@ -612,9 +613,46 @@ bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel pr
//
bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
{
// (type) unary_expression
// Have to look two steps ahead, because this could be, e.g., a
// postfix_expression instead, since that also starts with at "(".
if (acceptTokenClass(EHTokLeftParen)) {
TType castType;
if (acceptType(castType)) {
if (! acceptTokenClass(EHTokRightParen)) {
expected("right parenthesis");
return false;
}
// We've matched "(type)" now, get the expression to cast
TSourceLoc loc = token.loc;
if (! acceptUnaryExpression(node))
return false;
// Hook it up like a constructor
TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
if (constructorFunction == nullptr) {
expected("type that can be constructed");
return false;
}
TIntermTyped* arguments = nullptr;
parseContext.handleFunctionArgument(constructorFunction, arguments, node);
node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
return true;
} else {
// This isn't a type cast, but it still started "(", so if it is a
// unary expression, it can only be a postfix_expression, so try that.
// Back it up first.
recedeToken();
return acceptPostfixExpression(node);
}
}
// peek for "op unary_expression"
TOperator unaryOp = HlslOpMap::preUnary(peek());
// postfix_expression
// postfix_expression (if no unary operator)
if (unaryOp == EOpNull)
return acceptPostfixExpression(node);

View File

@ -57,7 +57,7 @@ struct HlslToken {
HlslToken() : isType(false), string(nullptr), symbol(nullptr) { loc.init(); }
TSourceLoc loc; // location of token in the source
EHlslTokenClass tokenClass; // what kind of token it is
bool isType; // true if the token represents a user type
bool isType; // true if the token represents a type
union { // what data the token holds
glslang::TString *string; // for identifiers
int i; // for literals

View File

@ -37,12 +37,47 @@
namespace glslang {
void HlslTokenStream::pushPreToken(const HlslToken& tok)
{
assert(preTokenStackSize == 0);
preTokenStack = tok;
++preTokenStackSize;
}
HlslToken HlslTokenStream::popPreToken()
{
assert(preTokenStackSize == 1);
--preTokenStackSize;
return preTokenStack;
}
void HlslTokenStream::pushTokenBuffer(const HlslToken& tok)
{
tokenBuffer = tok;
}
HlslToken HlslTokenStream::popTokenBuffer()
{
return tokenBuffer;
}
// Load 'token' with the next token in the stream of tokens.
void HlslTokenStream::advanceToken()
{
pushTokenBuffer(token);
if (preTokenStackSize > 0)
token = popPreToken();
else
scanner.tokenize(token);
}
void HlslTokenStream::recedeToken()
{
pushPreToken(token);
token = popTokenBuffer();
}
// Return the current token class.
EHlslTokenClass HlslTokenStream::peek() const
{

View File

@ -43,20 +43,38 @@ namespace glslang {
class HlslTokenStream {
public:
explicit HlslTokenStream(HlslScanContext& scanner)
: scanner(scanner) { }
: scanner(scanner), preTokenStackSize(0) { }
virtual ~HlslTokenStream() { }
public:
void advanceToken();
void recedeToken();
bool acceptTokenClass(EHlslTokenClass);
EHlslTokenClass peek() const;
bool peekTokenClass(EHlslTokenClass) const;
protected:
HlslToken token; // the current token we are processing
HlslToken token; // the token we are currently looking at, but have not yet accepted
private:
HlslScanContext& scanner; // lexical scanner, to get next token
// Previously scanned tokens, returned for future advances,
// so logically in front of the token stream.
// Is logically a stack; needs last in last out semantics.
// Currently implemented as a stack of size 1.
HlslToken preTokenStack;
int preTokenStackSize;
void pushPreToken(const HlslToken&);
HlslToken popPreToken();
// Previously scanned tokens, not yet return for future advances,
// but available for that.
// Is logically a fifo for normal advances, and a stack for recession.
// Currently implemented with an intrinsic size of 1.
HlslToken tokenBuffer;
void pushTokenBuffer(const HlslToken&);
HlslToken popTokenBuffer();
};
} // end namespace glslang