Commit 5ca85ad9 by steve-lunarg

HLSL: allow scalar type keywords as identifiers, and add half type support.

HLSL allows type keywords to also be identifiers, so a sequence such as "float half = 3" is valid, or more bizzarely, something like "float.float = int.uint + bool;" There are places this is not supported. E.g, it's permitted for struct members, but not struct names or functions. Also, vector or matrix types such as "float3" are not permitted as identifiers. This PR adds that support, as well as support for the "half" type. In production shaders, this was seen with variables named "half". The PR attempts to support this without breaking useful grammar errors such as "; expected" at the end of unterminated statements, so it errs on that side at the possible expense of failing to accept valid constructs containing a type keyword identifier. If others are discovered, they can be added. Also, half is now accepted as a valid type, alongside the min*float types.
parent 807a0d9e
hlsl.type.half.frag
Shader version: 450
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:4 Sequence
0:4 move second child to first child (temp mediump float)
0:4 'h0' (temp mediump float)
0:4 Constant:
0:4 0.000000
0:5 Sequence
0:5 move second child to first child (temp mediump 1-component vector of float)
0:5 'h1' (temp mediump 1-component vector of float)
0:5 Constant:
0:5 1.000000
0:6 Sequence
0:6 move second child to first child (temp mediump 2-component vector of float)
0:6 'h2' (temp mediump 2-component vector of float)
0:6 Constant:
0:6 2.000000
0:6 2.000000
0:7 Sequence
0:7 move second child to first child (temp mediump 3-component vector of float)
0:7 'h3' (temp mediump 3-component vector of float)
0:7 Constant:
0:7 3.000000
0:7 3.000000
0:7 3.000000
0:8 Sequence
0:8 move second child to first child (temp mediump 4-component vector of float)
0:8 'h4' (temp mediump 4-component vector of float)
0:8 Constant:
0:8 4.000000
0:8 4.000000
0:8 4.000000
0:8 4.000000
0:10 Sequence
0:10 move second child to first child (temp 4-component vector of float)
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
0:10 Constant:
0:10 0.000000
0:10 0.000000
0:10 0.000000
0:10 0.000000
0:10 Branch: Return
0:? Linker Objects
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
Linked fragment stage:
Shader version: 450
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:4 Sequence
0:4 move second child to first child (temp mediump float)
0:4 'h0' (temp mediump float)
0:4 Constant:
0:4 0.000000
0:5 Sequence
0:5 move second child to first child (temp mediump 1-component vector of float)
0:5 'h1' (temp mediump 1-component vector of float)
0:5 Constant:
0:5 1.000000
0:6 Sequence
0:6 move second child to first child (temp mediump 2-component vector of float)
0:6 'h2' (temp mediump 2-component vector of float)
0:6 Constant:
0:6 2.000000
0:6 2.000000
0:7 Sequence
0:7 move second child to first child (temp mediump 3-component vector of float)
0:7 'h3' (temp mediump 3-component vector of float)
0:7 Constant:
0:7 3.000000
0:7 3.000000
0:7 3.000000
0:8 Sequence
0:8 move second child to first child (temp mediump 4-component vector of float)
0:8 'h4' (temp mediump 4-component vector of float)
0:8 Constant:
0:8 4.000000
0:8 4.000000
0:8 4.000000
0:8 4.000000
0:10 Sequence
0:10 move second child to first child (temp 4-component vector of float)
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
0:10 Constant:
0:10 0.000000
0:10 0.000000
0:10 0.000000
0:10 0.000000
0:10 Branch: Return
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 31
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 28
ExecutionMode 4 OriginUpperLeft
Name 4 "main"
Name 8 "h0"
Name 10 "h1"
Name 14 "h2"
Name 19 "h3"
Name 24 "h4"
Name 28 "@entryPointOutput"
Decorate 8(h0) RelaxedPrecision
Decorate 10(h1) RelaxedPrecision
Decorate 14(h2) RelaxedPrecision
Decorate 19(h3) RelaxedPrecision
Decorate 24(h4) RelaxedPrecision
Decorate 28(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypePointer Function 6(float)
9: 6(float) Constant 0
11: 6(float) Constant 1065353216
12: TypeVector 6(float) 2
13: TypePointer Function 12(fvec2)
15: 6(float) Constant 1073741824
16: 12(fvec2) ConstantComposite 15 15
17: TypeVector 6(float) 3
18: TypePointer Function 17(fvec3)
20: 6(float) Constant 1077936128
21: 17(fvec3) ConstantComposite 20 20 20
22: TypeVector 6(float) 4
23: TypePointer Function 22(fvec4)
25: 6(float) Constant 1082130432
26: 22(fvec4) ConstantComposite 25 25 25 25
27: TypePointer Output 22(fvec4)
28(@entryPointOutput): 27(ptr) Variable Output
29: 22(fvec4) ConstantComposite 9 9 9 9
4(main): 2 Function None 3
5: Label
8(h0): 7(ptr) Variable Function
10(h1): 7(ptr) Variable Function
14(h2): 13(ptr) Variable Function
19(h3): 18(ptr) Variable Function
24(h4): 23(ptr) Variable Function
Store 8(h0) 9
Store 10(h1) 11
Store 14(h2) 16
Store 19(h3) 21
Store 24(h4) 26
Store 28(@entryPointOutput) 29
Return
FunctionEnd
float4 main() : SV_Target0
{
half h0 = 0;
half1 h1 = 1;
half2 h2 = 2;
half3 h3 = 3;
half4 h4 = 4;
return 0.0;
}
struct foo_t {
float float;
};
float fn(float float) { return float; }
float4 main() : SV_Target0
{
float float = 7;
bool bool[2] = { float, float };
int int = bool[1];
uint uint = float + int;
min16float min16float = uint;
min10float min10float = min16float;
half half = 0.5;
{
foo_t float;
float.float = 42;
}
bool[0] = bool[1];
float = float + int + uint + min16float + min10float + (bool[0] ? int : float) + fn(float);
return float;
}
......@@ -221,6 +221,8 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.swizzle.frag", "PixelShaderFunction"},
{"hlsl.templatetypes.frag", "PixelShaderFunction"},
{"hlsl.tx.bracket.frag", "main"},
{"hlsl.type.half.frag", "main"},
{"hlsl.type.identifier.frag", "main"},
{"hlsl.typedef.frag", "PixelShaderFunction"},
{"hlsl.whileLoop.frag", "PixelShaderFunction"},
{"hlsl.void.frag", "PixelShaderFunction"},
......
......@@ -85,21 +85,36 @@ bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
return true;
}
// Even though "sample" is a keyword (for interpolation modifiers), it IS still accepted as
// an identifier. This appears to be a solitary exception: other interp modifier keywords such
// as "linear" or "centroid" NOT valid identifiers. This code special cases "sample",
// so e.g, "int sample;" is accepted.
if (peekTokenClass(EHTokSample)) {
token.string = NewPoolTString("sample");
token.tokenClass = EHTokIdentifier;
token.symbol = nullptr;
idToken = token;
advanceToken();
return true;
// Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
// they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
// valid identifier, nor is "linear". This code special cases the known instances of this, so
// e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
TString* idString = nullptr;
switch (peek()) {
case EHTokSample: idString = NewPoolTString("sample"); break;
case EHTokHalf: idString = NewPoolTString("half"); break;
case EHTokBool: idString = NewPoolTString("bool"); break;
case EHTokFloat: idString = NewPoolTString("float"); break;
case EHTokDouble: idString = NewPoolTString("double"); break;
case EHTokInt: idString = NewPoolTString("int"); break;
case EHTokUint: idString = NewPoolTString("uint"); break;
case EHTokMin16float: idString = NewPoolTString("min16float"); break;
case EHTokMin10float: idString = NewPoolTString("min10float"); break;
case EHTokMin16int: idString = NewPoolTString("min16int"); break;
case EHTokMin12int: idString = NewPoolTString("min12int"); break;
default:
return false;
}
return false;
token.string = idString;
token.tokenClass = EHTokIdentifier;
token.symbol = nullptr;
idToken = token;
advanceToken();
return true;
}
// compilationUnit
......@@ -418,7 +433,15 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
// SEMICOLON
if (! acceptTokenClass(EHTokSemicolon)) {
expected(";");
// This may have been a false detection of what appeared to be a declaration, but
// was actually an assignment such as "float = 4", where "float" is an identifier.
// We put the token back to let further parsing happen for cases where that may
// happen. This errors on the side of caution, and mostly triggers the error.
if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
recedeToken();
else
expected(";");
return false;
}
......@@ -1086,6 +1109,7 @@ bool HlslGrammar::acceptType(TType& type)
// changes, e.g, to use native halfs.
static const TBasicType min16float_bt = EbtFloat;
static const TBasicType min10float_bt = EbtFloat;
static const TBasicType half_bt = EbtFloat;
static const TBasicType min16int_bt = EbtInt;
static const TBasicType min12int_bt = EbtInt;
static const TBasicType min16uint_bt = EbtUint;
......@@ -1255,6 +1279,23 @@ bool HlslGrammar::acceptType(TType& type)
new(&type) TType(EbtBool, EvqTemporary, 4);
break;
case EHTokHalf:
new(&type) TType(half_bt, EvqTemporary, EpqMedium);
break;
case EHTokHalf1:
new(&type) TType(half_bt, EvqTemporary, EpqMedium);
type.makeVector();
break;
case EHTokHalf2:
new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
break;
case EHTokHalf3:
new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
break;
case EHTokHalf4:
new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
break;
case EHTokMin16float:
new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
break;
......@@ -1683,6 +1724,7 @@ bool HlslGrammar::acceptStruct(TType& type)
bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
{
typeList = new TTypeList();
HlslToken idToken;
do {
// success on seeing the RIGHT_BRACE coming up
......@@ -1700,8 +1742,7 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
// struct_declarator COMMA struct_declarator ...
do {
// peek IDENTIFIER
if (! peekTokenClass(EHTokIdentifier)) {
if (! acceptIdentifier(idToken)) {
expected("member name");
return false;
}
......@@ -1709,12 +1750,9 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
// add it to the list of members
TTypeLoc member = { new TType(EbtVoid), token.loc };
member.type->shallowCopy(memberType);
member.type->setFieldName(*token.string);
member.type->setFieldName(*idToken.string);
typeList->push_back(member);
// accept IDENTIFIER
advanceToken();
// array_specifier
TArraySizes* arraySizes = nullptr;
acceptArraySpecifier(arraySizes);
......@@ -2322,7 +2360,9 @@ bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
// arguments
TIntermTyped* arguments = nullptr;
if (! acceptArguments(constructorFunction, arguments)) {
expected("constructor arguments");
// It's possible this is a type keyword used as an identifier. Put the token back
// for later use.
recedeToken();
return false;
}
......
......@@ -169,6 +169,10 @@ void HlslScanContext::fillInKeywordMap()
(*KeywordMap)["uint3"] = EHTokUint3;
(*KeywordMap)["uint4"] = EHTokUint4;
(*KeywordMap)["half1"] = EHTokHalf1;
(*KeywordMap)["half2"] = EHTokHalf2;
(*KeywordMap)["half3"] = EHTokHalf3;
(*KeywordMap)["half4"] = EHTokHalf4;
(*KeywordMap)["min16float1"] = EHTokMin16float1;
(*KeywordMap)["min16float2"] = EHTokMin16float2;
(*KeywordMap)["min16float3"] = EHTokMin16float3;
......@@ -579,6 +583,10 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokUint2:
case EHTokUint3:
case EHTokUint4:
case EHTokHalf1:
case EHTokHalf2:
case EHTokHalf3:
case EHTokHalf4:
case EHTokMin16float1:
case EHTokMin16float2:
case EHTokMin16float3:
......
......@@ -120,6 +120,10 @@ enum EHlslTokenClass {
EHTokUint2,
EHTokUint3,
EHTokUint4,
EHTokHalf1,
EHTokHalf2,
EHTokHalf3,
EHTokHalf4,
EHTokMin16float1,
EHTokMin16float2,
EHTokMin16float3,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment