Add ES 3.0 fragment output link-time test for outputs having or not having location qualifiers.
Also split linker validation into its own file, removed dead "QualifierAlive" files, printed errors for parsing problems with built-in symbols, updated the Windows binary, and added some tests. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23490 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
27b72e42c3
commit
fb57e7cc5e
Binary file not shown.
21
Test/150.vert
Normal file
21
Test/150.vert
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec4 iv4;
|
||||||
|
|
||||||
|
uniform float ps;
|
||||||
|
|
||||||
|
invariant gl_Position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = iv4;
|
||||||
|
gl_PointSize = ps;
|
||||||
|
gl_ClipDistance[2] = iv4.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float gl_ClipDistance[4];
|
||||||
|
|
||||||
|
uniform foob {
|
||||||
|
int a[];
|
||||||
|
};
|
||||||
|
int a[5]; // ERROR, resizing user-block member
|
8
Test/300link.frag
Normal file
8
Test/300link.frag
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 color1;
|
||||||
|
out vec4 color2;
|
||||||
|
|
||||||
|
void main() {}
|
11
Test/300link2.frag
Normal file
11
Test/300link2.frag
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
in vec4 pos;
|
||||||
|
|
||||||
|
layout(location = 1) out vec4 c;
|
||||||
|
layout(location = 5) out vec4 p;
|
||||||
|
layout(location = 9) out vec4 q[2];
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
7
Test/300link3.frag
Normal file
7
Test/300link3.frag
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 color1;
|
||||||
|
|
||||||
|
void main() {}
|
6
Test/410.geom
Normal file
6
Test/410.geom
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#version 410 core
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_ViewportIndex = 7;
|
||||||
|
}
|
33
Test/baseResults/150.vert.out
Normal file
33
Test/baseResults/150.vert.out
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Warning, version 150 is not yet complete; some version-specific features are present, but many are missing.
|
||||||
|
ERROR: 0:13: 'gl_ClipDistance' : undeclared identifier
|
||||||
|
ERROR: 0:13: 'gl_ClipDistance' : left of '[' is not of type array, matrix, or vector
|
||||||
|
ERROR: 0:13: 'assign' : l-value required (can't modify a const)
|
||||||
|
ERROR: 0:16: 'gl_' : reserved built-in name
|
||||||
|
ERROR: 0:21: 'a' : cannot redeclare a user-block member array
|
||||||
|
ERROR: 5 compilation errors. No code generated.
|
||||||
|
|
||||||
|
ERROR: node is still EOpNull!
|
||||||
|
0:9 Function Definition: main( (void)
|
||||||
|
0:9 Function Parameters:
|
||||||
|
0:11 Sequence
|
||||||
|
0:11 move second child to first child (4-component vector of float)
|
||||||
|
0:11 'gl_Position' (invariant gl_Position 4-component vector of float)
|
||||||
|
0:11 'iv4' (in 4-component vector of float)
|
||||||
|
0:12 move second child to first child (float)
|
||||||
|
0:12 'gl_PointSize' (gl_PointSize float)
|
||||||
|
0:12 'ps' (uniform float)
|
||||||
|
0:13 move second child to first child (float)
|
||||||
|
0:13 Constant:
|
||||||
|
0:13 0.000000
|
||||||
|
0:13 direct index (float)
|
||||||
|
0:13 'iv4' (in 4-component vector of float)
|
||||||
|
0:13 Constant:
|
||||||
|
0:13 0 (const int)
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? 'iv4' (in 4-component vector of float)
|
||||||
|
0:? 'ps' (uniform float)
|
||||||
|
0:? 'gl_ClipDistance' (4-element array of float)
|
||||||
|
0:? '__anon__0' (layout(shared ) uniform block)
|
||||||
|
0:? 'gl_VertexID' (gl_VertexId int)
|
||||||
|
0:? 'gl_InstanceID' (gl_InstanceId int)
|
||||||
|
|
15
Test/baseResults/300link.frag.out
Normal file
15
Test/baseResults/300link.frag.out
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
300link.frag
|
||||||
|
|
||||||
|
0:? Sequence
|
||||||
|
0:8 Function Definition: main( (void)
|
||||||
|
0:8 Function Parameters:
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? 'color1' (out highp 4-component vector of float)
|
||||||
|
0:? 'color2' (out highp 4-component vector of float)
|
||||||
|
|
||||||
|
|
||||||
|
Linked fragment stage:
|
||||||
|
|
||||||
|
ERROR: Linking fragment stage: when more than one fragment shader output, all must have location qualifiers
|
||||||
|
|
||||||
|
|
16
Test/baseResults/300link2.frag.out
Normal file
16
Test/baseResults/300link2.frag.out
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
300link2.frag
|
||||||
|
|
||||||
|
0:? Sequence
|
||||||
|
0:9 Function Definition: main( (void)
|
||||||
|
0:9 Function Parameters:
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? 'pos' (smooth in mediump 4-component vector of float)
|
||||||
|
0:? 'c' (layout(location=1 ) out mediump 4-component vector of float)
|
||||||
|
0:? 'p' (layout(location=5 ) out mediump 4-component vector of float)
|
||||||
|
0:? 'q' (layout(location=9 ) out 2-element array of mediump 4-component vector of float)
|
||||||
|
|
||||||
|
|
||||||
|
Linked fragment stage:
|
||||||
|
|
||||||
|
|
||||||
|
|
13
Test/baseResults/300link3.frag.out
Normal file
13
Test/baseResults/300link3.frag.out
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
300link3.frag
|
||||||
|
|
||||||
|
0:? Sequence
|
||||||
|
0:7 Function Definition: main( (void)
|
||||||
|
0:7 Function Parameters:
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? 'color1' (out highp 4-component vector of float)
|
||||||
|
|
||||||
|
|
||||||
|
Linked fragment stage:
|
||||||
|
|
||||||
|
|
||||||
|
|
14
Test/baseResults/410.geom.out
Normal file
14
Test/baseResults/410.geom.out
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Warning, version 410 is not yet complete; some version-specific features are present, but many are missing.
|
||||||
|
ERROR: 0:5: 'gl_ViewportIndex' : undeclared identifier
|
||||||
|
ERROR: 1 compilation errors. No code generated.
|
||||||
|
|
||||||
|
ERROR: node is still EOpNull!
|
||||||
|
0:3 Function Definition: main( (void)
|
||||||
|
0:3 Function Parameters:
|
||||||
|
0:5 Sequence
|
||||||
|
0:5 move second child to first child (float)
|
||||||
|
0:5 'gl_ViewportIndex' (float)
|
||||||
|
0:5 Constant:
|
||||||
|
0:5 7.000000
|
||||||
|
0:? Linker Objects
|
||||||
|
|
@ -38,6 +38,9 @@ runLinkTest mains1.frag mains2.frag noMain1.geom noMain2.geom
|
|||||||
runLinkTest noMain.vert mains.frag
|
runLinkTest noMain.vert mains.frag
|
||||||
runLinkTest link1.frag link2.frag link3.frag
|
runLinkTest link1.frag link2.frag link3.frag
|
||||||
runLinkTest recurse1.vert recurse1.frag recurse2.frag
|
runLinkTest recurse1.vert recurse1.frag recurse2.frag
|
||||||
|
runLinkTest 300link.frag
|
||||||
|
runLinkTest 300link2.frag
|
||||||
|
runLinkTest 300link3.frag
|
||||||
|
|
||||||
#
|
#
|
||||||
# multi-threaded test
|
# multi-threaded test
|
||||||
|
@ -12,6 +12,7 @@ versionsErrors.vert
|
|||||||
120.frag
|
120.frag
|
||||||
130.frag
|
130.frag
|
||||||
140.frag
|
140.frag
|
||||||
|
150.vert
|
||||||
150.geom
|
150.geom
|
||||||
precision.frag
|
precision.frag
|
||||||
precision.vert
|
precision.vert
|
||||||
@ -52,6 +53,7 @@ numeral.frag
|
|||||||
400.geom
|
400.geom
|
||||||
400.tesc
|
400.tesc
|
||||||
400.tese
|
400.tese
|
||||||
|
410.geom
|
||||||
420.tese
|
420.tese
|
||||||
430.comp
|
430.comp
|
||||||
dce.frag
|
dce.frag
|
||||||
|
18
Todo.txt
18
Todo.txt
@ -8,25 +8,25 @@ Link Validation
|
|||||||
Cross-stage linking
|
Cross-stage linking
|
||||||
- type consistency check of uniform and ins <-> outs, both variables and blocks, stage-specific arrayness matching
|
- type consistency check of uniform and ins <-> outs, both variables and blocks, stage-specific arrayness matching
|
||||||
- location/binding/index check
|
- location/binding/index check
|
||||||
- matching initializers for uniforms
|
|
||||||
- mixed es/non-es profiles
|
- mixed es/non-es profiles
|
||||||
- statically consumed input not produced by previous stage
|
- statically consumed input not produced by previous stage
|
||||||
- matching between gl_PerVertex blocks and gl_PerFragment blocks
|
|
||||||
- compute shader not combined with any other stages
|
|
||||||
- give error for sharing a packed block
|
- give error for sharing a packed block
|
||||||
|
- 1.2: matching initializers for uniforms
|
||||||
|
- 1.5: matching between gl_PerVertex blocks and gl_PerFragment blocks
|
||||||
- 1.3: deprecated mixing fixed vertex/fragment stage with programmable fragment/vertex stage.
|
- 1.3: deprecated mixing fixed vertex/fragment stage with programmable fragment/vertex stage.
|
||||||
|
- 4.3: compute shader not combined with any other stages
|
||||||
- 4.3: remove cross-version linking restrictions.
|
- 4.3: remove cross-version linking restrictions.
|
||||||
- 4.3: Allow mismatches in interpolation and auxiliary qualification across stages.
|
- 4.3: Allow mismatches in interpolation and auxiliary qualification across stages.
|
||||||
- 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
|
- 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
|
||||||
Intra-stage linking
|
Intra-stage linking
|
||||||
|
- ES 3.0: location aliasing/overlap (except desktop vertex shader inputs)
|
||||||
|
+ ES 3.0: fragment outputs all have locations, if more than one
|
||||||
+ exactly one main
|
+ exactly one main
|
||||||
+ Non ES: type consistency check of uniforms, globals, ins, and outs
|
+ Non ES: type consistency check of uniforms, globals, ins, and outs
|
||||||
+ Non ES: value checking of global const initializers
|
+ Non ES: value checking of global const initializers
|
||||||
+ Non ES: value checking of uniform initializers
|
+ Non ES: value checking of uniform initializers
|
||||||
+ Non ES: location match
|
+ Non ES: location match
|
||||||
- gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
|
- Non ES: gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
|
||||||
- location aliasing/overlap (except desktop vertex shader inputs)
|
|
||||||
- 1.0: count the number of uniforms and varyings, compare against limits
|
|
||||||
+ recursion for functions
|
+ recursion for functions
|
||||||
- Non ES: block matching
|
- Non ES: block matching
|
||||||
- Non ES: component/binding/index/offset match check
|
- Non ES: component/binding/index/offset match check
|
||||||
@ -46,8 +46,8 @@ Link Validation
|
|||||||
|
|
||||||
Shader Functionality to Implement/Finish
|
Shader Functionality to Implement/Finish
|
||||||
ESSL 2.0 (#version 100)
|
ESSL 2.0 (#version 100)
|
||||||
- implement non-inductive loop limitation detection
|
+ implement non-inductive loop limitation detection
|
||||||
- implement non-inductive array accesses limitation detection
|
+ implement non-inductive array accesses limitation detection
|
||||||
ESSL 3.0
|
ESSL 3.0
|
||||||
- "const" compile-time constant propagation in the front-end has to be complete, for all built-in functions
|
- "const" compile-time constant propagation in the front-end has to be complete, for all built-in functions
|
||||||
GLSL 1.2
|
GLSL 1.2
|
||||||
@ -72,7 +72,7 @@ Shader Functionality to Implement/Finish
|
|||||||
- Built-in uniforms except for depth range parameters
|
- Built-in uniforms except for depth range parameters
|
||||||
- Built-in interface between vertex and fragment: gl_TexCoord, gl_FogFragCoord, and all the color values.
|
- Built-in interface between vertex and fragment: gl_TexCoord, gl_FogFragCoord, and all the color values.
|
||||||
- Built-in two-sided coloring.
|
- Built-in two-sided coloring.
|
||||||
- Fixed functionality for a programmable stage. Supply shaders for all stages currently being used.
|
- Fixed functionality for a programmable stage.
|
||||||
- ftransform(). Use invariant outputs instead.
|
- ftransform(). Use invariant outputs instead.
|
||||||
GLSL 1.5 (Non-ES)
|
GLSL 1.5 (Non-ES)
|
||||||
- Deprecated gl_MaxVaryingComponents
|
- Deprecated gl_MaxVaryingComponents
|
||||||
|
@ -157,6 +157,7 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test</Command>
|
|||||||
<ClCompile Include="glslang\MachineIndependent\InfoSink.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\InfoSink.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\Initialize.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\Initialize.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\limits.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\limits.cpp" />
|
||||||
|
<ClCompile Include="glslang\MachineIndependent\linkValidate.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
|
||||||
@ -171,7 +172,6 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test</Command>
|
|||||||
<ClCompile Include="glslang\MachineIndependent\Intermediate.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\Intermediate.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\ParseHelper.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\ParseHelper.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\QualifierAlive.cpp" />
|
|
||||||
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\ShaderLang.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\ShaderLang.cpp" />
|
||||||
<ClCompile Include="glslang\MachineIndependent\SymbolTable.cpp" />
|
<ClCompile Include="glslang\MachineIndependent\SymbolTable.cpp" />
|
||||||
@ -192,7 +192,6 @@ xcopy /y $(IntDir)$(TargetName)$(TargetExt) Test</Command>
|
|||||||
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h" />
|
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h" />
|
||||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpContext.h" />
|
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpContext.h" />
|
||||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpTokens.h" />
|
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpTokens.h" />
|
||||||
<ClInclude Include="glslang\MachineIndependent\QualifierAlive.h" />
|
|
||||||
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h" />
|
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h" />
|
||||||
<ClInclude Include="glslang\MachineIndependent\localintermediate.h" />
|
<ClInclude Include="glslang\MachineIndependent\localintermediate.h" />
|
||||||
<ClInclude Include="glslang\Include\BaseTypes.h" />
|
<ClInclude Include="glslang\Include\BaseTypes.h" />
|
||||||
|
@ -49,9 +49,6 @@
|
|||||||
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp">
|
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp">
|
||||||
<Filter>Machine Independent</Filter>
|
<Filter>Machine Independent</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="glslang\MachineIndependent\QualifierAlive.cpp">
|
|
||||||
<Filter>Machine Independent</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp">
|
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp">
|
||||||
<Filter>Machine Independent</Filter>
|
<Filter>Machine Independent</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -112,6 +109,9 @@
|
|||||||
<ClCompile Include="glslang\MachineIndependent\limits.cpp">
|
<ClCompile Include="glslang\MachineIndependent\limits.cpp">
|
||||||
<Filter>Machine Independent</Filter>
|
<Filter>Machine Independent</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="glslang\MachineIndependent\linkValidate.cpp">
|
||||||
|
<Filter>Machine Independent</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="glslang\MachineIndependent\Initialize.h">
|
<ClInclude Include="glslang\MachineIndependent\Initialize.h">
|
||||||
@ -120,9 +120,6 @@
|
|||||||
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h">
|
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h">
|
||||||
<Filter>Machine Independent</Filter>
|
<Filter>Machine Independent</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="glslang\MachineIndependent\QualifierAlive.h">
|
|
||||||
<Filter>Machine Independent</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h">
|
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h">
|
||||||
<Filter>Machine Independent</Filter>
|
<Filter>Machine Independent</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "localintermediate.h"
|
#include "localintermediate.h"
|
||||||
#include "QualifierAlive.h"
|
|
||||||
#include "RemoveTree.h"
|
#include "RemoveTree.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
|
|
||||||
@ -928,275 +927,6 @@ void TIntermediate::addToCallGraph(TInfoSink& infoSink, const TString& caller, c
|
|||||||
callGraph.push_front(TCall(caller, callee));
|
callGraph.push_front(TCall(caller, callee));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Merge the information from 'unit' into 'this'
|
|
||||||
//
|
|
||||||
void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
|
|
||||||
{
|
|
||||||
numMains += unit.numMains;
|
|
||||||
numErrors += unit.numErrors;
|
|
||||||
callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
|
|
||||||
|
|
||||||
if ((profile != EEsProfile && unit.profile == EEsProfile) ||
|
|
||||||
(profile == EEsProfile && unit.profile != EEsProfile))
|
|
||||||
error(infoSink, "Cannot mix ES profile with non-ES profile shaders\n");
|
|
||||||
|
|
||||||
if (unit.treeRoot == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (treeRoot == 0) {
|
|
||||||
version = unit.version;
|
|
||||||
treeRoot = unit.treeRoot;
|
|
||||||
return;
|
|
||||||
} else
|
|
||||||
version = std::max(version, unit.version);
|
|
||||||
|
|
||||||
// Get the top-level globals of each level
|
|
||||||
TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
|
|
||||||
TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
|
|
||||||
|
|
||||||
// Get the last members of the sequences, expected to be the linker-object lists
|
|
||||||
assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
|
|
||||||
assert(unitGlobals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
|
|
||||||
TIntermSequence& linkerObjects = globals.back()->getAsAggregate()->getSequence();
|
|
||||||
TIntermSequence& unitLinkerObjects = unitGlobals.back()->getAsAggregate()->getSequence();
|
|
||||||
|
|
||||||
mergeBodies(infoSink, globals, unitGlobals);
|
|
||||||
mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Merge the function bodies and global-level initalizers from unitGlobals into globals.
|
|
||||||
// Will error check duplication of function bodies for the same signature.
|
|
||||||
//
|
|
||||||
void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
|
|
||||||
{
|
|
||||||
// TODO: Performance: Processing in alphabetical order will be faster
|
|
||||||
|
|
||||||
// Error check the global objects, not including the linker objects
|
|
||||||
for (unsigned int child = 0; child < globals.size() - 1; ++child) {
|
|
||||||
for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
|
|
||||||
TIntermAggregate* body = globals[child]->getAsAggregate();
|
|
||||||
TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
|
|
||||||
if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
|
|
||||||
error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
|
|
||||||
infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge the global objects, just in front of the linker objects
|
|
||||||
globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Merge the linker objects from unitLinkerObjects into linkerObjects.
|
|
||||||
// Duplication is expected and filtered out, but contradictions are an error.
|
|
||||||
//
|
|
||||||
void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
|
|
||||||
{
|
|
||||||
// Error check and merge the linker objects (duplicates should not be merged)
|
|
||||||
std::size_t initialNumLinkerObjects = linkerObjects.size();
|
|
||||||
for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
|
|
||||||
bool merge = true;
|
|
||||||
for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
|
|
||||||
TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
|
|
||||||
TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
|
|
||||||
assert(symbol && unitSymbol);
|
|
||||||
if (symbol->getName() == unitSymbol->getName()) {
|
|
||||||
// filter out copy
|
|
||||||
merge = false;
|
|
||||||
|
|
||||||
// but if one has an initializer and the other does not, update
|
|
||||||
// the initializer
|
|
||||||
if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty())
|
|
||||||
symbol->setConstArray(unitSymbol->getConstArray());
|
|
||||||
|
|
||||||
// Check for consistent types/qualification/initializers etc.
|
|
||||||
linkErrorCheck(infoSink, *symbol, *unitSymbol, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (merge)
|
|
||||||
linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Do final link-time error checking of a complete (merged) intermediate representation.
|
|
||||||
// (Most error checking was done during merging).
|
|
||||||
//
|
|
||||||
void TIntermediate::errorCheck(TInfoSink& infoSink)
|
|
||||||
{
|
|
||||||
if (numMains < 1)
|
|
||||||
error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
|
|
||||||
|
|
||||||
checkCallGraphCycles(infoSink);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// See if the call graph contains any static recursion, which is disallowed
|
|
||||||
// by the specification.
|
|
||||||
//
|
|
||||||
void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
|
|
||||||
{
|
|
||||||
// Reset everything, once.
|
|
||||||
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
|
||||||
call->visited = false;
|
|
||||||
call->subGraph = false;
|
|
||||||
call->errorGiven = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration.
|
|
||||||
//
|
|
||||||
|
|
||||||
TCall* newRoot;
|
|
||||||
do {
|
|
||||||
// See if we have unvisited parts of the graph.
|
|
||||||
newRoot = 0;
|
|
||||||
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
|
||||||
if (! call->visited) {
|
|
||||||
newRoot = &(*call);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not, we are done.
|
|
||||||
if (! newRoot)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Otherwise, we found a new subgraph, process it:
|
|
||||||
// See what all can be reached by this new root, and if any of
|
|
||||||
// that is recursive. This is done by marking processed calls as active,
|
|
||||||
// and if a new call is found that is already active, we looped,
|
|
||||||
// thereby detecting recursion.
|
|
||||||
std::list<TCall*> stack;
|
|
||||||
stack.push_back(newRoot);
|
|
||||||
newRoot->subGraph = true;
|
|
||||||
while (! stack.empty()) {
|
|
||||||
// get a caller
|
|
||||||
TCall* call = stack.back();
|
|
||||||
stack.pop_back();
|
|
||||||
|
|
||||||
// Add to the stack all the callees of the last subgraph node popped from the stack.
|
|
||||||
// This algorithm always terminates, because only subGraph == false causes a push
|
|
||||||
// and all pushes change subGraph to true, and nothing changes subGraph to false.
|
|
||||||
for (TGraph::iterator child = callGraph.begin(); child != callGraph.end(); ++child) {
|
|
||||||
if (call->callee == child->caller) {
|
|
||||||
if (child->subGraph) {
|
|
||||||
if (! child->errorGiven) {
|
|
||||||
error(infoSink, "Recursion detected:");
|
|
||||||
infoSink.info << " " << call->callee << " calling " << child->callee << "\n";
|
|
||||||
child->errorGiven = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
child->subGraph = true;
|
|
||||||
stack.push_back(&(*child));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end while, meaning nothing left to process in this subtree
|
|
||||||
|
|
||||||
// Mark all the subGraph nodes as visited, closing out this subgraph.
|
|
||||||
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
|
||||||
if (call->subGraph)
|
|
||||||
call->visited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (newRoot); // redundant loop check; should always exit via the 'break' above
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIntermediate::error(TInfoSink& infoSink, const char* message)
|
|
||||||
{
|
|
||||||
infoSink.info.prefix(EPrefixError);
|
|
||||||
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
|
|
||||||
|
|
||||||
++numErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Compare two global objects from two compilation units and see if they match
|
|
||||||
// well enough. Rules can be different for intra- vs. cross-stage matching.
|
|
||||||
//
|
|
||||||
// This function only does one of intra- or cross-stage matching per call.
|
|
||||||
//
|
|
||||||
// TODO: Linker Functionality: this function is under active development
|
|
||||||
//
|
|
||||||
void TIntermediate::linkErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
|
|
||||||
{
|
|
||||||
bool writeTypeComparison = false;
|
|
||||||
|
|
||||||
// Types have to match
|
|
||||||
if (symbol.getType() != unitSymbol.getType()) {
|
|
||||||
error(infoSink, "Types must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Qualifiers have to (almost) match
|
|
||||||
|
|
||||||
// Storage...
|
|
||||||
if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
|
|
||||||
error(infoSink, "Storage qualifiers must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Precision...
|
|
||||||
if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
|
|
||||||
error(infoSink, "Precision qualifiers must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invariance...
|
|
||||||
if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
|
|
||||||
error(infoSink, "Presence of invariant qualifier must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auxiliary and interpolation...
|
|
||||||
if (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid ||
|
|
||||||
symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth ||
|
|
||||||
symbol.getQualifier().flat != unitSymbol.getQualifier().flat ||
|
|
||||||
symbol.getQualifier().sample != unitSymbol.getQualifier().sample ||
|
|
||||||
symbol.getQualifier().patch != unitSymbol.getQualifier().patch ||
|
|
||||||
symbol.getQualifier().nopersp != unitSymbol.getQualifier().nopersp) {
|
|
||||||
error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory...
|
|
||||||
if (symbol.getQualifier().shared != unitSymbol.getQualifier().shared ||
|
|
||||||
symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent ||
|
|
||||||
symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil ||
|
|
||||||
symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict ||
|
|
||||||
symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly ||
|
|
||||||
symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
|
|
||||||
error(infoSink, "Memory qualifiers must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layouts...
|
|
||||||
if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
|
|
||||||
symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
|
|
||||||
symbol.getQualifier().layoutSlotLocation != unitSymbol.getQualifier().layoutSlotLocation) {
|
|
||||||
error(infoSink, "Layout qualification must match:");
|
|
||||||
writeTypeComparison = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializers have to match, if both are present, and if we don't already know the types don't match
|
|
||||||
if (! writeTypeComparison) {
|
|
||||||
if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) {
|
|
||||||
if (symbol.getConstArray() != unitSymbol.getConstArray()) {
|
|
||||||
error(infoSink, "Initializers must match:");
|
|
||||||
infoSink.info << " " << symbol.getName() << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeTypeComparison)
|
|
||||||
infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
|
|
||||||
unitSymbol.getType().getCompleteString() << "\"\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This deletes the tree.
|
// This deletes the tree.
|
||||||
//
|
//
|
||||||
|
@ -9,12 +9,12 @@ LIBOSDEPENDENT=./../OSDependent/Linux/libOssource.a
|
|||||||
LIBINITIALISATION=./../../OGLCompilersDLL/libInitializeDll.a
|
LIBINITIALISATION=./../../OGLCompilersDLL/libInitializeDll.a
|
||||||
LIBCODEGEN=./../GenericCodeGen/libCodeGen.a
|
LIBCODEGEN=./../GenericCodeGen/libCodeGen.a
|
||||||
OBJECTS= Initialize.o IntermTraverse.o \
|
OBJECTS= Initialize.o IntermTraverse.o \
|
||||||
Intermediate.o ParseHelper.o PoolAlloc.o QualifierAlive.o \
|
Intermediate.o ParseHelper.o PoolAlloc.o \
|
||||||
RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \
|
RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \
|
||||||
InfoSink.o Versions.o Constant.o Scan.o limits.o
|
InfoSink.o Versions.o Constant.o Scan.o limits.o linkValidate.o
|
||||||
|
|
||||||
SRCS= gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \
|
SRCS= gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \
|
||||||
Intermediate.cpp ParseHelper.cpp PoolAlloc.cp QualifierAlive.cpp \
|
Intermediate.cpp ParseHelper.cpp PoolAlloc.cp \
|
||||||
RemoveTree.cpp ShaderLang.cpp SymbolTable.cpp intermOut.cpp \
|
RemoveTree.cpp ShaderLang.cpp SymbolTable.cpp intermOut.cpp \
|
||||||
parseConst.cpp InfoSink.cpp Versions.cpp Constant.cpp Scan.cpp
|
parseConst.cpp InfoSink.cpp Versions.cpp Constant.cpp Scan.cpp
|
||||||
CPPFLAGS=$(DEFINE) $(INCLUDE) -fPIC
|
CPPFLAGS=$(DEFINE) $(INCLUDE) -fPIC
|
||||||
@ -98,7 +98,7 @@ Intermediate.o: localintermediate.h ../Include/intermediate.h
|
|||||||
Intermediate.o: ../Public/ShaderLang.h SymbolTable.h ../Include/Common.h
|
Intermediate.o: ../Public/ShaderLang.h SymbolTable.h ../Include/Common.h
|
||||||
Intermediate.o: ../Include/intermediate.h ../Include/Types.h
|
Intermediate.o: ../Include/intermediate.h ../Include/Types.h
|
||||||
Intermediate.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h
|
Intermediate.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h
|
||||||
Intermediate.o: ../Include/InfoSink.h QualifierAlive.h RemoveTree.h
|
Intermediate.o: ../Include/InfoSink.h RemoveTree.h
|
||||||
ParseHelper.o: ParseHelper.h ../Include/ShHandle.h
|
ParseHelper.o: ParseHelper.h ../Include/ShHandle.h
|
||||||
ParseHelper.o: ../Public/ShaderLang.h ../Include/InfoSink.h
|
ParseHelper.o: ../Public/ShaderLang.h ../Include/InfoSink.h
|
||||||
ParseHelper.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h
|
ParseHelper.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h
|
||||||
@ -109,7 +109,6 @@ ParseHelper.o: localintermediate.h ../Include/intermediate.h
|
|||||||
ParseHelper.o: ../Public/ShaderLang.h
|
ParseHelper.o: ../Public/ShaderLang.h
|
||||||
ParseHelper.o: ../OSDependent/Linux/osinclude.h
|
ParseHelper.o: ../OSDependent/Linux/osinclude.h
|
||||||
ParseHelper.o: ../Include/InitializeGlobals.h ../Include/PoolAlloc.h
|
ParseHelper.o: ../Include/InitializeGlobals.h ../Include/PoolAlloc.h
|
||||||
QualifierAlive.o: ../Include/intermediate.h
|
|
||||||
Scan.o: Scan.h
|
Scan.o: Scan.h
|
||||||
Scan.o: ParseHelper.h SymbolTable.h
|
Scan.o: ParseHelper.h SymbolTable.h
|
||||||
Scan.o: glslang_tab.cpp.h
|
Scan.o: glslang_tab.cpp.h
|
||||||
@ -147,3 +146,4 @@ InfoSink.o: ../Include/InfoSink.h
|
|||||||
Versions.o: ParseHelper.h Versions.h ../Include/ShHandle.h SymbolTable.h localintermediate.h
|
Versions.o: ParseHelper.h Versions.h ../Include/ShHandle.h SymbolTable.h localintermediate.h
|
||||||
Constant.o: localintermediate.h ../Include/intermediate.h ../Public/ShaderLang.h SymbolTable.h Versions.h
|
Constant.o: localintermediate.h ../Include/intermediate.h ../Public/ShaderLang.h SymbolTable.h Versions.h
|
||||||
limits.o: ParseHelper.h
|
limits.o: ParseHelper.h
|
||||||
|
linkValidate.o: localintermediate.h
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
|
||||||
//All rights reserved.
|
|
||||||
//
|
|
||||||
//Redistribution and use in source and binary forms, with or without
|
|
||||||
//modification, are permitted provided that the following conditions
|
|
||||||
//are met:
|
|
||||||
//
|
|
||||||
// Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following
|
|
||||||
// disclaimer in the documentation and/or other materials provided
|
|
||||||
// with the distribution.
|
|
||||||
//
|
|
||||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived
|
|
||||||
// from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
//POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef USE_QUALIFIER_ALIVE
|
|
||||||
|
|
||||||
#include "../Include/intermediate.h"
|
|
||||||
|
|
||||||
namespace glslang {
|
|
||||||
|
|
||||||
class TAliveTraverser : public TIntermTraverser {
|
|
||||||
public:
|
|
||||||
TAliveTraverser(TStorageQualifier q) : TIntermTraverser(), found(false), qualifier(q)
|
|
||||||
{
|
|
||||||
visitSymbol = AliveSymbol;
|
|
||||||
visitSelection = AliveSelection;
|
|
||||||
rightToLeft = true;
|
|
||||||
}
|
|
||||||
bool wasFound() { return found; }
|
|
||||||
protected:
|
|
||||||
bool found;
|
|
||||||
TStorageQualifier qualifier;
|
|
||||||
|
|
||||||
friend void AliveSymbol(TIntermSymbol*, TIntermTraverser*);
|
|
||||||
friend bool AliveSelection(bool, TIntermSelection*, TIntermTraverser*);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Report whether or not a variable of the given qualifier type
|
|
||||||
// is guaranteed written. Not always possible to determine if
|
|
||||||
// it is written conditionally.
|
|
||||||
//
|
|
||||||
// It does not do this well yet, this is just a place holder
|
|
||||||
// that simply determines if it was reference at all, anywhere.
|
|
||||||
//
|
|
||||||
bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
|
|
||||||
{
|
|
||||||
TAliveTraverser it(qualifier);
|
|
||||||
|
|
||||||
if (node)
|
|
||||||
node->traverse(&it);
|
|
||||||
|
|
||||||
return it.wasFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AliveSymbol(TIntermSymbol* node, TIntermTraverser* it)
|
|
||||||
{
|
|
||||||
TAliveTraverser* lit = static_cast<TAliveTraverser*>(it);
|
|
||||||
|
|
||||||
//
|
|
||||||
// If it's what we're looking for, record it.
|
|
||||||
//
|
|
||||||
if (node->getQualifier().storage == lit->qualifier)
|
|
||||||
lit->found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AliveSelection(bool preVisit, TIntermSelection* node, TIntermTraverser* it)
|
|
||||||
{
|
|
||||||
TAliveTraverser* lit = static_cast<TAliveTraverser*>(it);
|
|
||||||
|
|
||||||
if (lit->wasFound())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace glslang
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
|
||||||
//All rights reserved.
|
|
||||||
//
|
|
||||||
//Redistribution and use in source and binary forms, with or without
|
|
||||||
//modification, are permitted provided that the following conditions
|
|
||||||
//are met:
|
|
||||||
//
|
|
||||||
// Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following
|
|
||||||
// disclaimer in the documentation and/or other materials provided
|
|
||||||
// with the distribution.
|
|
||||||
//
|
|
||||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived
|
|
||||||
// from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
//POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace glslang {
|
|
||||||
|
|
||||||
bool QualifierWritten(TIntermNode* root, TStorageQualifier);
|
|
||||||
|
|
||||||
} // end namespace glslang
|
|
@ -145,7 +145,7 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||||||
|
|
||||||
if (! parseContext.parseShaderStrings(ppContext, const_cast<char**>(builtInShaders), builtInLengths, 1) != 0) {
|
if (! parseContext.parseShaderStrings(ppContext, const_cast<char**>(builtInShaders), builtInLengths, 1) != 0) {
|
||||||
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
||||||
printf("Unable to parse built-ins\n");
|
printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
370
glslang/MachineIndependent/linkValidate.cpp
Normal file
370
glslang/MachineIndependent/linkValidate.cpp
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
//
|
||||||
|
//Copyright (C) 2013 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Do link-time merging and validation of intermediate representations.
|
||||||
|
//
|
||||||
|
// Basic model is that during compilation, each compilation unit (shader) is
|
||||||
|
// compiled into one TIntermediate instance. Then, at link time, multiple
|
||||||
|
// units for the same stage can be merged together, which can generate errors.
|
||||||
|
// Then, after all merging, a single instance of TIntermediate represents
|
||||||
|
// the whole stage. A final error check can be done on the resulting stage,
|
||||||
|
// even if no merging was done (i.e., the stage was only one compilation unit).
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "localintermediate.h"
|
||||||
|
#include "../Include/InfoSink.h"
|
||||||
|
|
||||||
|
namespace glslang {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Link-time error emitter.
|
||||||
|
//
|
||||||
|
void TIntermediate::error(TInfoSink& infoSink, const char* message)
|
||||||
|
{
|
||||||
|
infoSink.info.prefix(EPrefixError);
|
||||||
|
infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n";
|
||||||
|
|
||||||
|
++numErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Merge the information from 'unit' into 'this'
|
||||||
|
//
|
||||||
|
void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
|
||||||
|
{
|
||||||
|
numMains += unit.numMains;
|
||||||
|
numErrors += unit.numErrors;
|
||||||
|
callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
|
||||||
|
|
||||||
|
if ((profile != EEsProfile && unit.profile == EEsProfile) ||
|
||||||
|
(profile == EEsProfile && unit.profile != EEsProfile))
|
||||||
|
error(infoSink, "Cannot mix ES profile with non-ES profile shaders\n");
|
||||||
|
|
||||||
|
if (unit.treeRoot == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (treeRoot == 0) {
|
||||||
|
version = unit.version;
|
||||||
|
treeRoot = unit.treeRoot;
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
version = std::max(version, unit.version);
|
||||||
|
|
||||||
|
// Get the top-level globals of each unit
|
||||||
|
TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
|
||||||
|
TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence();
|
||||||
|
|
||||||
|
// Get the linker-object lists
|
||||||
|
TIntermSequence& linkerObjects = findLinkerObjects();
|
||||||
|
TIntermSequence& unitLinkerObjects = unit.findLinkerObjects();
|
||||||
|
|
||||||
|
mergeBodies(infoSink, globals, unitGlobals);
|
||||||
|
mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Merge the function bodies and global-level initalizers from unitGlobals into globals.
|
||||||
|
// Will error check duplication of function bodies for the same signature.
|
||||||
|
//
|
||||||
|
void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
|
||||||
|
{
|
||||||
|
// TODO: Performance: Processing in alphabetical order will be faster
|
||||||
|
|
||||||
|
// Error check the global objects, not including the linker objects
|
||||||
|
for (unsigned int child = 0; child < globals.size() - 1; ++child) {
|
||||||
|
for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
|
||||||
|
TIntermAggregate* body = globals[child]->getAsAggregate();
|
||||||
|
TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
|
||||||
|
if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
|
||||||
|
error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
|
||||||
|
infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the global objects, just in front of the linker objects
|
||||||
|
globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Merge the linker objects from unitLinkerObjects into linkerObjects.
|
||||||
|
// Duplication is expected and filtered out, but contradictions are an error.
|
||||||
|
//
|
||||||
|
void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects)
|
||||||
|
{
|
||||||
|
// Error check and merge the linker objects (duplicates should not be merged)
|
||||||
|
std::size_t initialNumLinkerObjects = linkerObjects.size();
|
||||||
|
for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) {
|
||||||
|
bool merge = true;
|
||||||
|
for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) {
|
||||||
|
TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode();
|
||||||
|
TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode();
|
||||||
|
assert(symbol && unitSymbol);
|
||||||
|
if (symbol->getName() == unitSymbol->getName()) {
|
||||||
|
// filter out copy
|
||||||
|
merge = false;
|
||||||
|
|
||||||
|
// but if one has an initializer and the other does not, update
|
||||||
|
// the initializer
|
||||||
|
if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty())
|
||||||
|
symbol->setConstArray(unitSymbol->getConstArray());
|
||||||
|
|
||||||
|
// Check for consistent types/qualification/initializers etc.
|
||||||
|
mergeErrorCheck(infoSink, *symbol, *unitSymbol, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (merge)
|
||||||
|
linkerObjects.push_back(unitLinkerObjects[unitLinkObj]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compare two global objects from two compilation units and see if they match
|
||||||
|
// well enough. Rules can be different for intra- vs. cross-stage matching.
|
||||||
|
//
|
||||||
|
// This function only does one of intra- or cross-stage matching per call.
|
||||||
|
//
|
||||||
|
// TODO: Linker Functionality: this function is under active development
|
||||||
|
//
|
||||||
|
void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage)
|
||||||
|
{
|
||||||
|
bool writeTypeComparison = false;
|
||||||
|
|
||||||
|
// Types have to match
|
||||||
|
if (symbol.getType() != unitSymbol.getType()) {
|
||||||
|
error(infoSink, "Types must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qualifiers have to (almost) match
|
||||||
|
|
||||||
|
// Storage...
|
||||||
|
if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) {
|
||||||
|
error(infoSink, "Storage qualifiers must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precision...
|
||||||
|
if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) {
|
||||||
|
error(infoSink, "Precision qualifiers must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invariance...
|
||||||
|
if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) {
|
||||||
|
error(infoSink, "Presence of invariant qualifier must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auxiliary and interpolation...
|
||||||
|
if (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid ||
|
||||||
|
symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth ||
|
||||||
|
symbol.getQualifier().flat != unitSymbol.getQualifier().flat ||
|
||||||
|
symbol.getQualifier().sample != unitSymbol.getQualifier().sample ||
|
||||||
|
symbol.getQualifier().patch != unitSymbol.getQualifier().patch ||
|
||||||
|
symbol.getQualifier().nopersp != unitSymbol.getQualifier().nopersp) {
|
||||||
|
error(infoSink, "Interpolation and auxiliary storage qualifiers must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory...
|
||||||
|
if (symbol.getQualifier().shared != unitSymbol.getQualifier().shared ||
|
||||||
|
symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent ||
|
||||||
|
symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil ||
|
||||||
|
symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict ||
|
||||||
|
symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly ||
|
||||||
|
symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) {
|
||||||
|
error(infoSink, "Memory qualifiers must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layouts...
|
||||||
|
if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix ||
|
||||||
|
symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking ||
|
||||||
|
symbol.getQualifier().layoutSlotLocation != unitSymbol.getQualifier().layoutSlotLocation) {
|
||||||
|
error(infoSink, "Layout qualification must match:");
|
||||||
|
writeTypeComparison = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializers have to match, if both are present, and if we don't already know the types don't match
|
||||||
|
if (! writeTypeComparison) {
|
||||||
|
if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) {
|
||||||
|
if (symbol.getConstArray() != unitSymbol.getConstArray()) {
|
||||||
|
error(infoSink, "Initializers must match:");
|
||||||
|
infoSink.info << " " << symbol.getName() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeTypeComparison)
|
||||||
|
infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" <<
|
||||||
|
unitSymbol.getType().getCompleteString() << "\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Do final link-time error checking of a complete (merged) intermediate representation.
|
||||||
|
// (Much error checking was done during merging).
|
||||||
|
//
|
||||||
|
void TIntermediate::errorCheck(TInfoSink& infoSink)
|
||||||
|
{
|
||||||
|
if (numMains < 1)
|
||||||
|
error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
|
||||||
|
|
||||||
|
// recursion checking
|
||||||
|
checkCallGraphCycles(infoSink);
|
||||||
|
|
||||||
|
// overlap/alias/missing I/O, etc.
|
||||||
|
inOutLocationCheck(infoSink);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// See if the call graph contains any static recursion, which is disallowed
|
||||||
|
// by the specification.
|
||||||
|
//
|
||||||
|
void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink)
|
||||||
|
{
|
||||||
|
// Reset everything, once.
|
||||||
|
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
||||||
|
call->visited = false;
|
||||||
|
call->subGraph = false;
|
||||||
|
call->errorGiven = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration.
|
||||||
|
//
|
||||||
|
|
||||||
|
TCall* newRoot;
|
||||||
|
do {
|
||||||
|
// See if we have unvisited parts of the graph.
|
||||||
|
newRoot = 0;
|
||||||
|
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
||||||
|
if (! call->visited) {
|
||||||
|
newRoot = &(*call);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, we are done.
|
||||||
|
if (! newRoot)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Otherwise, we found a new subgraph, process it:
|
||||||
|
// See what all can be reached by this new root, and if any of
|
||||||
|
// that is recursive. This is done by marking processed calls as active,
|
||||||
|
// and if a new call is found that is already active, we looped,
|
||||||
|
// thereby detecting recursion.
|
||||||
|
std::list<TCall*> stack;
|
||||||
|
stack.push_back(newRoot);
|
||||||
|
newRoot->subGraph = true;
|
||||||
|
while (! stack.empty()) {
|
||||||
|
// get a caller
|
||||||
|
TCall* call = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
// Add to the stack all the callees of the last subgraph node popped from the stack.
|
||||||
|
// This algorithm always terminates, because only subGraph == false causes a push
|
||||||
|
// and all pushes change subGraph to true, and nothing changes subGraph to false.
|
||||||
|
for (TGraph::iterator child = callGraph.begin(); child != callGraph.end(); ++child) {
|
||||||
|
if (call->callee == child->caller) {
|
||||||
|
if (child->subGraph) {
|
||||||
|
if (! child->errorGiven) {
|
||||||
|
error(infoSink, "Recursion detected:");
|
||||||
|
infoSink.info << " " << call->callee << " calling " << child->callee << "\n";
|
||||||
|
child->errorGiven = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
child->subGraph = true;
|
||||||
|
stack.push_back(&(*child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end while, meaning nothing left to process in this subtree
|
||||||
|
|
||||||
|
// Mark all the subGraph nodes as visited, closing out this subgraph.
|
||||||
|
for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
|
||||||
|
if (call->subGraph)
|
||||||
|
call->visited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (newRoot); // redundant loop check; should always exit via the 'break' above
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Satisfy rules for location qualifiers on inputs and outputs
|
||||||
|
//
|
||||||
|
void TIntermediate::inOutLocationCheck(TInfoSink& infoSink)
|
||||||
|
{
|
||||||
|
// ES 3.0 requires all outputs to have location qualifiers if there is more than one output
|
||||||
|
bool fragOutHasLocation = false;
|
||||||
|
bool fragOutWithNoLocation = false;
|
||||||
|
int numFragOut = 0;
|
||||||
|
|
||||||
|
// TODO: maps for location collision checking
|
||||||
|
|
||||||
|
TIntermSequence& linkObjects = findLinkerObjects();
|
||||||
|
for (size_t i = 0; i < linkObjects.size(); ++i) {
|
||||||
|
const TType& type = linkObjects[i]->getAsTyped()->getType();
|
||||||
|
const TQualifier& qualifier = type.getQualifier();
|
||||||
|
if (language == EShLangFragment) {
|
||||||
|
if (qualifier.storage == EvqVaryingOut) {
|
||||||
|
++numFragOut;
|
||||||
|
if (qualifier.hasLocation())
|
||||||
|
fragOutHasLocation = true;
|
||||||
|
else
|
||||||
|
fragOutWithNoLocation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile == EEsProfile) {
|
||||||
|
if (numFragOut > 1 && fragOutWithNoLocation)
|
||||||
|
error(infoSink, "when more than one fragment shader output, all must have location qualifiers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TIntermSequence& TIntermediate::findLinkerObjects()
|
||||||
|
{
|
||||||
|
// Get the top-level globals
|
||||||
|
TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence();
|
||||||
|
|
||||||
|
// Get the last member of the sequences, expected to be the linker-object lists
|
||||||
|
assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects);
|
||||||
|
|
||||||
|
return globals.back()->getAsAggregate()->getSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace glslang
|
@ -107,14 +107,16 @@ public:
|
|||||||
void removeTree();
|
void removeTree();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void error(TInfoSink& infoSink, const char*);
|
||||||
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
||||||
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
||||||
void error(TInfoSink& infoSink, const char*);
|
void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
|
||||||
void linkErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
|
|
||||||
void checkCallGraphCycles(TInfoSink&);
|
void checkCallGraphCycles(TInfoSink&);
|
||||||
|
void inOutLocationCheck(TInfoSink&);
|
||||||
|
TIntermSequence& findLinkerObjects();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EShLanguage language;
|
const EShLanguage language;
|
||||||
TIntermNode* treeRoot;
|
TIntermNode* treeRoot;
|
||||||
EProfile profile;
|
EProfile profile;
|
||||||
int version;
|
int version;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user