From 1cc1a2813eec42e60c5b4fce41da09bc740c9141 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Fri, 3 Jun 2016 16:55:49 -0600 Subject: [PATCH] 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. --- Test/baseResults/hlsl.cast.frag.out | 86 +++++++++++++++++++++++++++++ Test/hlsl.cast.frag | 4 ++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 42 +++++++++++++- hlsl/hlslScanContext.h | 2 +- hlsl/hlslTokenStream.cpp | 37 ++++++++++++- hlsl/hlslTokenStream.h | 26 +++++++-- 7 files changed, 190 insertions(+), 8 deletions(-) create mode 100755 Test/baseResults/hlsl.cast.frag.out create mode 100644 Test/hlsl.cast.frag diff --git a/Test/baseResults/hlsl.cast.frag.out b/Test/baseResults/hlsl.cast.frag.out new file mode 100755 index 00000000..1e689788 --- /dev/null +++ b/Test/baseResults/hlsl.cast.frag.out @@ -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 diff --git a/Test/hlsl.cast.frag b/Test/hlsl.cast.frag new file mode 100644 index 00000000..c8dc8212 --- /dev/null +++ b/Test/hlsl.cast.frag @@ -0,0 +1,4 @@ +float4 PixelShaderFunction(float4 input) : COLOR0 +{ + return (float4)input + (int4)input + (float4)1.198; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 8f02c6a9..9c0061ed 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -73,6 +73,7 @@ INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, ::testing::ValuesIn(std::vector{ {"hlsl.assoc.frag", "PixelShaderFunction"}, + {"hlsl.cast.frag", "PixelShaderFunction"}, {"hlsl.float1.frag", "PixelShaderFunction"}, {"hlsl.float4.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.frag", "PixelShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index a6387b74..ddb70788 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -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); diff --git a/hlsl/hlslScanContext.h b/hlsl/hlslScanContext.h index 04f24383..d761e3a8 100755 --- a/hlsl/hlslScanContext.h +++ b/hlsl/hlslScanContext.h @@ -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 diff --git a/hlsl/hlslTokenStream.cpp b/hlsl/hlslTokenStream.cpp index cfc1101b..47f779a8 100755 --- a/hlsl/hlslTokenStream.cpp +++ b/hlsl/hlslTokenStream.cpp @@ -37,10 +37,45 @@ 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() { - scanner.tokenize(token); + pushTokenBuffer(token); + if (preTokenStackSize > 0) + token = popPreToken(); + else + scanner.tokenize(token); +} + +void HlslTokenStream::recedeToken() +{ + pushPreToken(token); + token = popTokenBuffer(); } // Return the current token class. diff --git a/hlsl/hlslTokenStream.h b/hlsl/hlslTokenStream.h index 9139df07..83365c4c 100755 --- a/hlsl/hlslTokenStream.h +++ b/hlsl/hlslTokenStream.h @@ -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 + 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