summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/devinfo.html40
-rw-r--r--docs/news.html15
-rw-r--r--docs/relnotes-7.4.3.html79
-rw-r--r--docs/relnotes-7.4.4.html68
-rw-r--r--docs/relnotes-7.5.html3
-rw-r--r--docs/relnotes.html9
-rw-r--r--progs/demos/fslight.c8
-rw-r--r--scons/dxsdk.py66
-rw-r--r--scons/gallium.py45
-rw-r--r--scons/generic.py8
-rw-r--r--src/gallium/drivers/cell/ppu/cell_screen.c2
-rw-r--r--src/gallium/drivers/softpipe/sp_screen.c2
-rw-r--r--src/gallium/include/pipe/p_defines.h1
-rw-r--r--src/mesa/drivers/dri/intel/intel_context.c11
-rw-r--r--src/mesa/main/mtypes.h1
-rw-r--r--src/mesa/shader/shader_api.c1
-rw-r--r--src/mesa/shader/slang/slang_codegen.c1279
-rw-r--r--src/mesa/shader/slang/slang_codegen.h17
-rw-r--r--src/mesa/shader/slang/slang_compile.c3
-rw-r--r--src/mesa/shader/slang/slang_compile_operation.c68
-rw-r--r--src/mesa/shader/slang/slang_compile_operation.h62
-rw-r--r--src/mesa/shader/slang/slang_compile_variable.h1
-rw-r--r--src/mesa/shader/slang/slang_print.c10
-rw-r--r--src/mesa/state_tracker/st_extensions.c5
24 files changed, 1483 insertions, 321 deletions
diff --git a/docs/devinfo.html b/docs/devinfo.html
index 3cebf5f36d..0fb816749e 100644
--- a/docs/devinfo.html
+++ b/docs/devinfo.html
@@ -123,20 +123,21 @@ These are the instructions for making a new Mesa release.
<H3>Get latest source files</H3>
<p>
-Use "cvs update -dAP " to get the latest Mesa files from CVS.
+Use git to get the latest Mesa files from the git repository, from whatever
+branch is relevant.
</p>
<H3>Verify and update version info</H3>
<p>
-Create/edit the docs/RELNOTES-X.Y file to document what's new in the release.
-Add the new RELNOTES-X.Y file to <a href="relnotes.html">relnotes.html</a>.
-Update the docs/VERSIONS file too.
+Create/edit the docs/relnotes-x.y.html file to document what's new in the release.
+Add the new relnotes-x.y.html file to <a href="relnotes.html">relnotes.html</a>.
</p>
<p>
-Edit the MESA_MAJOR, MESA_MINOR and MESA_TINY version numbers in
+Update the MESA_MAJOR, MESA_MINOR and MESA_TINY version numbers in
configs/default.
+Also update the VERSION line in the top-level Makefile.
</p>
<p>
@@ -144,27 +145,24 @@ Make sure the values in src/mesa/main/version.h are correct.
</p>
<p>
-Edit the top-level Makefile and verify that DIRECTORY, LIB_NAME and
-DEMO_NAME are correct.
-</p>
-
-<p>
Update the docs/news.html file and docs/download.html files.
</p>
<p>
-Check in all updates to CVS.
+Check in all updates to git.
</p>
<p>
-Tag the CVS files with the release name (in the form <b>mesa_X_Y</b>).
+Tag the files with the release name (in the form <b>mesa_X_Y</b>)
+with: <code>git tag -a mesa_X_Y</code>
+Then: <code>git push origin mesa_X_Y</code>
</p>
<H3>Make the tarballs</H3>
<p>
Make a symbolic link from $(DIRECTORY) to 'Mesa'. For example,
-ln -s Mesa Mesa-6.3
+<code>ln -s Mesa Mesa-7.5</code>
This is needed in order to make a correct tar file in the next step.
</p>
@@ -177,7 +175,7 @@ Make the distribution files. From inside the Mesa directory:
<p>
After the tarballs are created, the md5 checksums for the files will
be computed.
-Add them to the docs/news.html file.
+Add them to the docs/relnotes-X.Y.html file.
</p>
<p>
@@ -192,8 +190,20 @@ uploading the tarballs.
</p>
<p>
+Basically, to upload the tarball files with:
+<br>
+<code>
+rsync -avP ssh Mesa*-X.Y.* USERNAME@frs.sourceforge.net:uploads/
+</code>
+</p>
+
+<p>
Update the web site by copying the docs/ directory's files to
-/home/users/b/br/brianp/mesa-www/htdocs/
+/home/users/b/br/brianp/mesa-www/htdocs/ with:
+<br>
+<code>
+sftp USERNAME,mesa3d@web.sourceforge.net
+</code>
</p>
<p>
diff --git a/docs/news.html b/docs/news.html
index 8cf2f91dd0..ee4a86c2a2 100644
--- a/docs/news.html
+++ b/docs/news.html
@@ -11,6 +11,21 @@
<H1>News</H1>
+<h2>June 23, 2009</h2>
+<p>
+<a href="relnotes-7.4.4.html">Mesa 7.4.4</a> is released.
+This is a stable release that fixes a regression in the i915/i965 drivers
+that slipped into the 7.4.3 release.
+</p>
+
+
+<h2>June 19, 2009</h2>
+<p>
+<a href="relnotes-7.4.3.html">Mesa 7.4.3</a> is released.
+This is a stable release fixing bugs since the 7.4.2 release.
+</p>
+
+
<h2>May 15, 2009</h2>
<p>
<a href="relnotes-7.4.2.html">Mesa 7.4.2</a> is released.
diff --git a/docs/relnotes-7.4.3.html b/docs/relnotes-7.4.3.html
new file mode 100644
index 0000000000..35b5dccbb0
--- /dev/null
+++ b/docs/relnotes-7.4.3.html
@@ -0,0 +1,79 @@
+<HTML>
+
+<TITLE>Mesa Release Notes</TITLE>
+
+<head><link rel="stylesheet" type="text/css" href="mesa.css"></head>
+
+<BODY>
+
+<body bgcolor="#eeeeee">
+
+<H1>Mesa 7.4.3 Release Notes / 19 June 2009</H1>
+
+<p>
+Mesa 7.4.3 is a stable development release fixing bugs since the 7.4.2 release.
+</p>
+<p>
+Mesa 7.4.3 implements the OpenGL 2.1 API, but the version reported by
+glGetString(GL_VERSION) depends on the particular driver being used.
+Some drivers don't support all the features required in OpenGL 2.1.
+</p>
+<p>
+See the <a href="install.html">Compiling/Installing page</a> for prerequisites
+for DRI hardware acceleration.
+</p>
+
+
+<h2>MD5 checksums</h2>
+<pre>
+34c5a6c47ed51f31c4fa36e269831352 MesaLib-7.4.3.tar.gz
+70a983ba3deaa8bd63b18bbab283f698 MesaLib-7.4.3.tar.bz2
+34f21b3205b271d575030aa98a2dda51 MesaLib-7.4.3.zip
+56752b7adede212e6097afb10d0c0d59 MesaDemos-7.4.3.tar.gz
+8ffa51c4833b1e298300a005e2d7ca2a MesaDemos-7.4.3.tar.bz2
+0037d24d41400d6fb9800ae55b8c863f MesaDemos-7.4.3.zip
+20e24f6692c0c90e7e3b220f79c4108d MesaGLUT-7.4.3.tar.gz
+03a4beeef74fc5ef0b1d6d04710e5a8a MesaGLUT-7.4.3.tar.bz2
+273788230adbdb9d57371309adedcf5f MesaGLUT-7.4.3.zip
+</pre>
+
+
+<h2>Bug fixes</h2>
+<ul>
+<li>Fixed texture object reference counting bug (bug 21756)
+<li>Allow depth/stencil textures to be attached to GL_STENCIL_ATTACHMENT point
+ (SF bug 2793846)
+<li>Added missing glGet case for GL_VERTEX_ARRAY_BINDING_APPLE
+<li>Fixed some OSMesa build issues
+<li>Fixed a vertex buffer object crash
+<li>Fixed broken glTexImage3D() when image type = GL_BITMAP
+<li>Fixed some GLSL preprocessor bugs
+<li>Fixed framebuffer mem leak in i945/i965 DRI drivers
+<li>Fixed texture coordinate repeat bug in swrast (bug 21872)
+<li>Fixed incorrect viewport clamping (lower bound is zero, not one)
+<li>GLX fix for glean's makeCurrent test case
+</ul>
+
+
+
+<h2>Driver Status</h2>
+
+<pre>
+Driver Status
+---------------------- ----------------------
+DRI drivers varies with the driver
+XMesa/GLX (on Xlib) implements OpenGL 2.1
+OSMesa (off-screen) implements OpenGL 2.1
+Windows/Win32 implements OpenGL 2.1
+Glide (3dfx Voodoo1/2) implements OpenGL 1.3
+SVGA unsupported
+Wind River UGL unsupported
+DJGPP unsupported
+GGI unsupported
+BeOS unsupported
+Allegro unsupported
+D3D unsupported
+</pre>
+
+</body>
+</html>
diff --git a/docs/relnotes-7.4.4.html b/docs/relnotes-7.4.4.html
new file mode 100644
index 0000000000..2a34568a7e
--- /dev/null
+++ b/docs/relnotes-7.4.4.html
@@ -0,0 +1,68 @@
+<HTML>
+
+<TITLE>Mesa Release Notes</TITLE>
+
+<head><link rel="stylesheet" type="text/css" href="mesa.css"></head>
+
+<BODY>
+
+<body bgcolor="#eeeeee">
+
+<H1>Mesa 7.4.4 Release Notes / 23 June 2009</H1>
+
+<p>
+Mesa 7.4.4 is a stable development release fixing bugs since the 7.4.3 release.
+</p>
+<p>
+Mesa 7.4.4 implements the OpenGL 2.1 API, but the version reported by
+glGetString(GL_VERSION) depends on the particular driver being used.
+Some drivers don't support all the features required in OpenGL 2.1.
+</p>
+<p>
+See the <a href="install.html">Compiling/Installing page</a> for prerequisites
+for DRI hardware acceleration.
+</p>
+
+
+<h2>MD5 checksums</h2>
+<pre>
+0b56fe5a88ab0c3c5b2da5068f63f416 MesaLib-7.4.4.tar.gz
+b66528d314c574dccbe0ed963cac5e93 MesaLib-7.4.4.tar.bz2
+2818076f3ba23fa87fdfe4602a637a18 MesaLib-7.4.4.zip
+3e77b208386c47b18165bce5ae317e2c MesaDemos-7.4.4.tar.gz
+628142ec9a54cd28cc027e6ce26cff47 MesaDemos-7.4.4.tar.bz2
+d08a30d30ab7174859aa709cba6c726d MesaDemos-7.4.4.zip
+e6e91ba16e274d40cf3a97ad3218af01 MesaGLUT-7.4.4.tar.gz
+e14bbb52517e8121b31f1387515365ab MesaGLUT-7.4.4.tar.bz2
+f10ed20469753c2b3d68c99854f80fd4 MesaGLUT-7.4.4.zip
+</pre>
+
+
+<h2>Bug fixes</h2>
+<ul>
+<li>Fixed i965/i915 segfault in screen destruction (bug 22408)
+</ul>
+
+
+
+<h2>Driver Status</h2>
+
+<pre>
+Driver Status
+---------------------- ----------------------
+DRI drivers varies with the driver
+XMesa/GLX (on Xlib) implements OpenGL 2.1
+OSMesa (off-screen) implements OpenGL 2.1
+Windows/Win32 implements OpenGL 2.1
+Glide (3dfx Voodoo1/2) implements OpenGL 1.3
+SVGA unsupported
+Wind River UGL unsupported
+DJGPP unsupported
+GGI unsupported
+BeOS unsupported
+Allegro unsupported
+D3D unsupported
+</pre>
+
+</body>
+</html>
diff --git a/docs/relnotes-7.5.html b/docs/relnotes-7.5.html
index 663626cb05..045692113d 100644
--- a/docs/relnotes-7.5.html
+++ b/docs/relnotes-7.5.html
@@ -68,6 +68,8 @@ including GL_ATI_separate_stencil, GL_EXT_stencil_two_side and OpenGL 2.0
<li>GL_EXT_texture_swizzle extension (software drivers, i965 driver)
<li>Updated SPARC assembly optimizations (David S. Miller)
<li>Initial support for separate compilation units in GLSL compiler.
+<li>Increased max number of generic GLSL varying variables to 16 (formerly 8).
+<li>GLSL linker now detects when too many varying variables are used.
</ul>
@@ -75,6 +77,7 @@ including GL_ATI_separate_stencil, GL_EXT_stencil_two_side and OpenGL 2.0
<ul>
<li>Lots of i965 driver bug fixes
<li>Fixed some GLSL preprocessor bugs
+<li>GLSL: continue inside of a for-loop didn't work
</ul>
diff --git a/docs/relnotes.html b/docs/relnotes.html
index ad5b74bad3..35a4c7385f 100644
--- a/docs/relnotes.html
+++ b/docs/relnotes.html
@@ -9,19 +9,14 @@
<H1>Release Notes</H1>
<p>
-Mesa uses an even/odd version number scheme like the Linux kernel.
-Odd numbered versions (such as 6.5) designate new developmental releases.
-Even numbered versions (such as 6.4) designate stable releases.
-</p>
-
-
-<p>
The release notes summarize what's new or changed in each Mesa release.
</p>
<UL>
<LI><A HREF="relnotes-7.6.html">7.6 release notes</A>
<LI><A HREF="relnotes-7.5.html">7.5 release notes</A>
+<LI><A HREF="relnotes-7.4.4.html">7.4.4 release notes</A>
+<LI><A HREF="relnotes-7.4.3.html">7.4.3 release notes</A>
<LI><A HREF="relnotes-7.4.2.html">7.4.2 release notes</A>
<LI><A HREF="relnotes-7.4.1.html">7.4.1 release notes</A>
<LI><A HREF="relnotes-7.4.html">7.4 release notes</A>
diff --git a/progs/demos/fslight.c b/progs/demos/fslight.c
index 41a13cc9f4..f0d76a4a06 100644
--- a/progs/demos/fslight.c
+++ b/progs/demos/fslight.c
@@ -583,10 +583,14 @@ ParseOptions(int argc, char *argv[])
int i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-fs") == 0) {
- FragProgFile = argv[i+1];
+ FragProgFile = argv[++i];
}
else if (strcmp(argv[i], "-vs") == 0) {
- VertProgFile = argv[i+1];
+ VertProgFile = argv[++i];
+ }
+ else {
+ fprintf(stderr, "unknown option %s\n", argv[i]);
+ break;
}
}
}
diff --git a/scons/dxsdk.py b/scons/dxsdk.py
new file mode 100644
index 0000000000..a369e1da10
--- /dev/null
+++ b/scons/dxsdk.py
@@ -0,0 +1,66 @@
+"""dxsdk
+
+Tool-specific initialization for Microsoft DirectX SDK
+
+"""
+
+#
+# Copyright (c) 2009 VMware, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+import os
+import os.path
+
+import SCons.Errors
+import SCons.Util
+
+
+def get_dxsdk_root(env):
+ try:
+ return os.environ['DXSDK_DIR']
+ except KeyError:
+ return None
+
+def get_dxsdk_paths(env):
+ dxsdk_root = get_dxsdk_root(env)
+ if dxsdk_root is None:
+ raise SCons.Errors.InternalError, "DirectX SDK not found"
+
+ if env['machine'] in ('generic', 'x86'):
+ target_cpu = 'x86'
+ elif env['machine'] == 'x86_64':
+ target_cpu = 'x64'
+ else:
+ raise SCons.Errors.InternalError, "Unsupported target machine"
+ include_dir = 'Include'
+
+ env.Append(CPPDEFINES = [('HAVE_DXSDK', '1')])
+ env.Prepend(CPPPATH = [os.path.join(dxsdk_root, 'Include')])
+ env.Prepend(LIBPATH = [os.path.join(dxsdk_root, 'Lib', target_cpu)])
+
+def generate(env):
+ get_dxsdk_paths(env)
+
+def exists(env):
+ return get_dxsdk_root(env) is not None
+
+# vim:set ts=4 sw=4 et:
diff --git a/scons/gallium.py b/scons/gallium.py
index 6e924da303..aed813f027 100644
--- a/scons/gallium.py
+++ b/scons/gallium.py
@@ -319,74 +319,78 @@ def generate(env):
env.Append(CPPDEFINES = cppdefines)
# C compiler options
- cflags = []
+ cflags = [] # C
+ cxxflags = [] # C++
+ ccflags = [] # C & C++
if gcc:
if debug:
- cflags += ['-O0', '-g3']
+ ccflags += ['-O0', '-g3']
elif env['toolchain'] == 'crossmingw':
- cflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
+ ccflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
else:
- cflags += ['-O3', '-g3']
+ ccflags += ['-O3', '-g3']
if env['profile']:
- cflags += ['-pg']
+ ccflags += ['-pg']
if env['machine'] == 'x86':
- cflags += [
+ ccflags += [
'-m32',
#'-march=pentium4',
'-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
#'-mfpmath=sse',
]
if env['machine'] == 'x86_64':
- cflags += ['-m64']
+ ccflags += ['-m64']
# See also:
# - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
- cflags += [
- '-Werror=declaration-after-statement',
+ ccflags += [
'-Wall',
- '-Wmissing-prototypes',
'-Wmissing-field-initializers',
'-Wpointer-arith',
'-Wno-long-long',
'-ffast-math',
- '-std=gnu99',
'-fmessage-length=0', # be nice to Eclipse
]
+ cflags += [
+ '-Werror=declaration-after-statement',
+ '-Wmissing-prototypes',
+ '-std=gnu99',
+ ]
if msvc:
# See also:
# - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
# - cl /?
if debug:
- cflags += [
+ ccflags += [
'/Od', # disable optimizations
'/Oi', # enable intrinsic functions
'/Oy-', # disable frame pointer omission
'/GL-', # disable whole program optimization
]
else:
- cflags += [
+ ccflags += [
'/O2', # optimize for speed
#'/fp:fast', # fast floating point
]
if env['profile']:
- cflags += [
+ ccflags += [
'/Gh', # enable _penter hook function
'/GH', # enable _pexit hook function
]
- cflags += [
+ ccflags += [
'/W3', # warning level
#'/Wp64', # enable 64 bit porting warnings
]
if env['machine'] == 'x86':
- cflags += [
+ ccflags += [
#'/QIfist', # Suppress _ftol
#'/arch:SSE2', # use the SSE2 instructions
]
if platform == 'windows':
- cflags += [
+ ccflags += [
# TODO
]
if platform == 'winddk':
- cflags += [
+ ccflags += [
'/Zl', # omit default library name in .OBJ
'/Zp8', # 8bytes struct member alignment
'/Gy', # separate functions for linker
@@ -405,7 +409,7 @@ def generate(env):
]
if platform == 'wince':
# See also C:\WINCE600\public\common\oak\misc\makefile.def
- cflags += [
+ ccflags += [
'/Zl', # omit default library name in .OBJ
'/GF', # enable read-only string pooling
'/GR-', # disable C++ RTTI
@@ -422,8 +426,9 @@ def generate(env):
# See http://scons.tigris.org/issues/show_bug.cgi?id=1656
env.EnsureSConsVersion(0, 98, 0)
env['PDB'] = '${TARGET.base}.pdb'
+ env.Append(CCFLAGS = ccflags)
env.Append(CFLAGS = cflags)
- env.Append(CXXFLAGS = cflags)
+ env.Append(CXXFLAGS = cxxflags)
if env['platform'] == 'windows' and msvc:
# Choose the appropriate MSVC CRT
diff --git a/scons/generic.py b/scons/generic.py
index 29ddf76d6f..a9c2244a74 100644
--- a/scons/generic.py
+++ b/scons/generic.py
@@ -416,16 +416,18 @@ def generate(env):
# See also:
# - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
ccflags += [
- '-Werror=declaration-after-statement',
'-Wall',
- '-Wmissing-prototypes',
'-Wmissing-field-initializers',
'-Wpointer-arith',
'-Wno-long-long',
'-ffast-math',
- '-std=gnu99',
'-fmessage-length=0', # be nice to Eclipse
]
+ cflags += [
+ '-Werror=declaration-after-statement',
+ '-Wmissing-prototypes',
+ '-std=gnu99',
+ ]
if msvc:
# See also:
# - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
diff --git a/src/gallium/drivers/cell/ppu/cell_screen.c b/src/gallium/drivers/cell/ppu/cell_screen.c
index 512d85d352..bd48ce7005 100644
--- a/src/gallium/drivers/cell/ppu/cell_screen.c
+++ b/src/gallium/drivers/cell/ppu/cell_screen.c
@@ -86,6 +86,8 @@ cell_get_param(struct pipe_screen *screen, int param)
return 1; /* XXX not really true */
case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
return 0; /* XXX to do */
+ case PIPE_CAP_TGSI_CONT_SUPPORTED:
+ return 1;
default:
return 0;
}
diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index 692deeb8fd..be76f1d413 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -87,6 +87,8 @@ softpipe_get_param(struct pipe_screen *screen, int param)
return 8; /* max 128x128x128 */
case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
return 13; /* max 4Kx4K */
+ case PIPE_CAP_TGSI_CONT_SUPPORTED:
+ return 1;
default:
return 0;
}
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 9924046cb2..96030e788d 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -302,6 +302,7 @@ enum pipe_transfer_usage {
#define PIPE_CAP_TEXTURE_MIRROR_CLAMP 24
#define PIPE_CAP_TEXTURE_MIRROR_REPEAT 25
#define PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS 26
+#define PIPE_CAP_TGSI_CONT_SUPPORTED 27
/**
diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c
index a28836a7d8..21d13b862b 100644
--- a/src/mesa/drivers/dri/intel/intel_context.c
+++ b/src/mesa/drivers/dri/intel/intel_context.c
@@ -71,6 +71,8 @@ int INTEL_DEBUG = (0);
#define DRIVER_DATE_GEM "GEM " DRIVER_DATE
+static void intel_flush(GLcontext *ctx, GLboolean needs_mi_flush);
+
static const GLubyte *
intelGetString(GLcontext * ctx, GLenum name)
{
@@ -397,6 +399,15 @@ intel_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
return;
if (!intel->internal_viewport_call && ctx->DrawBuffer->Name == 0) {
+ /* If we're rendering to the fake front buffer, make sure all the pending
+ * drawing has landed on the real front buffer. Otherwise when we
+ * eventually get to DRI2GetBuffersWithFormat the stale real front
+ * buffer contents will get copied to the new fake front buffer.
+ */
+ if (intel->is_front_buffer_rendering) {
+ intel_flush(ctx, GL_FALSE);
+ }
+
intel_update_renderbuffers(driContext, driContext->driDrawablePriv);
if (driContext->driDrawablePriv != driContext->driReadablePriv)
intel_update_renderbuffers(driContext, driContext->driReadablePriv);
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index d1614af736..408b65d308 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2049,6 +2049,7 @@ struct gl_shader_state
struct gl_shader_program *CurrentProgram; /**< The user-bound program */
/** Driver-selectable options: */
GLboolean EmitHighLevelInstructions; /**< IF/ELSE/ENDIF vs. BRA, etc. */
+ GLboolean EmitContReturn; /**< Emit CONT/RET opcodes? */
GLboolean EmitCondCodes; /**< Use condition codes? */
GLboolean EmitComments; /**< Annotated instructions */
void *MemPool;
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index a8390d3094..648fbc186b 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -402,6 +402,7 @@ _mesa_init_shader_state(GLcontext * ctx)
* are generated by the GLSL compiler.
*/
ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
+ ctx->Shader.EmitContReturn = GL_TRUE;
ctx->Shader.EmitCondCodes = GL_FALSE;
ctx->Shader.EmitComments = GL_FALSE;
ctx->Shader.Flags = get_shader_flags();
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 6d693c9027..24e9952386 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -75,6 +75,11 @@ const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256;
static slang_ir_node *
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
+static void
+slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
+ GLuint substCount, slang_variable **substOld,
+ slang_operation **substNew, GLboolean isLHS);
+
/**
* Retrieves type information about an operation.
@@ -326,6 +331,17 @@ sampler_to_texture_index(const slang_type_specifier_type type)
}
+/** helper to build a SLANG_OPER_IDENTIFIER node */
+static void
+slang_operation_identifier(slang_operation *oper,
+ slang_assemble_ctx *A,
+ const char *name)
+{
+ oper->type = SLANG_OPER_IDENTIFIER;
+ oper->a_id = slang_atom_pool_atom(A->atoms, name);
+}
+
+
#define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
/**
@@ -429,6 +445,56 @@ _slang_output_index(const char *name, GLenum target)
}
+/**
+ * Called when we begin code/IR generation for a new while/do/for loop.
+ */
+static void
+push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR)
+{
+ A->LoopOperStack[A->LoopDepth] = loopOper;
+ A->LoopIRStack[A->LoopDepth] = loopIR;
+ A->LoopDepth++;
+}
+
+
+/**
+ * Called when we end code/IR generation for a new while/do/for loop.
+ */
+static void
+pop_loop(slang_assemble_ctx *A)
+{
+ assert(A->LoopDepth > 0);
+ A->LoopDepth--;
+}
+
+
+/**
+ * Return pointer to slang_operation for the loop we're currently inside,
+ * or NULL if not in a loop.
+ */
+static const slang_operation *
+current_loop_oper(const slang_assemble_ctx *A)
+{
+ if (A->LoopDepth > 0)
+ return A->LoopOperStack[A->LoopDepth - 1];
+ else
+ return NULL;
+}
+
+
+/**
+ * Return pointer to slang_ir_node for the loop we're currently inside,
+ * or NULL if not in a loop.
+ */
+static slang_ir_node *
+current_loop_ir(const slang_assemble_ctx *A)
+{
+ if (A->LoopDepth > 0)
+ return A->LoopIRStack[A->LoopDepth - 1];
+ else
+ return NULL;
+}
+
/**********************************************************************/
@@ -636,7 +702,7 @@ new_break(slang_ir_node *loopNode)
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
if (n) {
- /* insert this node at head of linked list */
+ /* insert this node at head of linked list of cont/break instructions */
n->List = loopNode->List;
loopNode->List = n;
}
@@ -648,14 +714,15 @@ new_break(slang_ir_node *loopNode)
* Make new IR_BREAK_IF_TRUE.
*/
static slang_ir_node *
-new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
+new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond)
{
+ slang_ir_node *loopNode = current_loop_ir(A);
slang_ir_node *n;
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
n = new_node1(IR_BREAK_IF_TRUE, cond);
if (n) {
- /* insert this node at head of linked list */
+ /* insert this node at head of linked list of cont/break instructions */
n->List = loopNode->List;
loopNode->List = n;
}
@@ -667,14 +734,16 @@ new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
* Make new IR_CONT_IF_TRUE node.
*/
static slang_ir_node *
-new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
+new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond)
{
+ slang_ir_node *loopNode = current_loop_ir(A);
slang_ir_node *n;
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
n = new_node1(IR_CONT_IF_TRUE, cond);
if (n) {
- /* insert this node at head of linked list */
+ n->Parent = loopNode; /* pointer to containing loop */
+ /* insert this node at head of linked list of cont/break instructions */
n->List = loopNode->List;
loopNode->List = n;
}
@@ -749,6 +818,7 @@ _slang_is_noop(const slang_operation *oper)
/**
* Recursively search tree for a node of the given type.
*/
+#if 0
static slang_operation *
_slang_find_node_type(slang_operation *oper, slang_operation_type type)
{
@@ -762,13 +832,14 @@ _slang_find_node_type(slang_operation *oper, slang_operation_type type)
}
return NULL;
}
+#endif
/**
* Count the number of operations of the given time rooted at 'oper'.
*/
static GLuint
-_slang_count_node_type(slang_operation *oper, slang_operation_type type)
+_slang_count_node_type(const slang_operation *oper, slang_operation_type type)
{
GLuint i, count = 0;
if (oper->type == type) {
@@ -822,6 +893,37 @@ _slang_is_tail_return(const slang_operation *oper)
}
+/**
+ * Generate a variable declaration opeartion.
+ * I.e.: generate AST code for "bool flag = false;"
+ */
+static void
+slang_generate_declaration(slang_assemble_ctx *A,
+ slang_variable_scope *scope,
+ slang_operation *decl,
+ slang_type_specifier_type type,
+ const char *name,
+ GLint initValue)
+{
+ slang_variable *var;
+
+ assert(type == SLANG_SPEC_BOOL ||
+ type == SLANG_SPEC_INT);
+
+ decl->type = SLANG_OPER_VARIABLE_DECL;
+
+ var = slang_variable_scope_grow(scope);
+
+ slang_fully_specified_type_construct(&var->type);
+
+ var->type.specifier.type = type;
+ var->a_name = slang_atom_pool_atom(A->atoms, name);
+ decl->a_id = var->a_name;
+ var->initializer = slang_operation_new(1);
+ slang_operation_literal_bool(var->initializer, initValue);
+}
+
+
static void
slang_resolve_variable(slang_operation *oper)
{
@@ -832,6 +934,159 @@ slang_resolve_variable(slang_operation *oper)
/**
+ * Rewrite AST code for "return expression;".
+ *
+ * We return values from functions by assinging the returned value to
+ * the hidden __retVal variable which is an extra 'out' parameter we add
+ * to the function signature.
+ * This code basically converts "return expr;" into "__retVal = expr; return;"
+ *
+ * \return the new AST code.
+ */
+static slang_operation *
+gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *blockOper, *assignOper;
+
+ assert(oper->type == SLANG_OPER_RETURN);
+
+ if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "illegal return expression");
+ return NULL;
+ }
+
+ blockOper = slang_operation_new(1);
+ blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
+ blockOper->locals->outer_scope = oper->locals->outer_scope;
+ slang_operation_add_children(blockOper, 2);
+
+ if (A->UseReturnFlag) {
+ /* Emit:
+ * {
+ * if (__notRetFlag)
+ * __retVal = expr;
+ * __notRetFlag = 0;
+ * }
+ */
+ {
+ slang_operation *ifOper = slang_oper_child(blockOper, 0);
+ ifOper->type = SLANG_OPER_IF;
+ slang_operation_add_children(ifOper, 3);
+ {
+ slang_operation *cond = slang_oper_child(ifOper, 0);
+ cond->type = SLANG_OPER_IDENTIFIER;
+ cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag");
+ }
+ {
+ slang_operation *elseOper = slang_oper_child(ifOper, 2);
+ elseOper->type = SLANG_OPER_VOID;
+ }
+ assignOper = slang_oper_child(ifOper, 1);
+ }
+ {
+ slang_operation *setOper = slang_oper_child(blockOper, 1);
+ setOper->type = SLANG_OPER_ASSIGN;
+ slang_operation_add_children(setOper, 2);
+ {
+ slang_operation *lhs = slang_oper_child(setOper, 0);
+ lhs->type = SLANG_OPER_IDENTIFIER;
+ lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag");
+ }
+ {
+ slang_operation *rhs = slang_oper_child(setOper, 1);
+ slang_operation_literal_bool(rhs, GL_FALSE);
+ }
+ }
+ }
+ else {
+ /* Emit:
+ * {
+ * __retVal = expr;
+ * return_inlined;
+ * }
+ */
+ assignOper = slang_oper_child(blockOper, 0);
+ {
+ slang_operation *returnOper = slang_oper_child(blockOper, 1);
+ returnOper->type = SLANG_OPER_RETURN_INLINED;
+ assert(returnOper->num_children == 0);
+ }
+ }
+
+ /* __retVal = expression; */
+ assignOper->type = SLANG_OPER_ASSIGN;
+ slang_operation_add_children(assignOper, 2);
+ {
+ slang_operation *lhs = slang_oper_child(assignOper, 0);
+ lhs->type = SLANG_OPER_IDENTIFIER;
+ lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal");
+ }
+ {
+ slang_operation *rhs = slang_oper_child(assignOper, 1);
+ slang_operation_copy(rhs, &oper->children[0]);
+ }
+
+ ///blockOper->locals->outer_scope = oper->locals->outer_scope;
+
+ /*slang_print_tree(blockOper, 0);*/
+
+ return blockOper;
+}
+
+
+/**
+ * Rewrite AST code for "return;" (no expression).
+ */
+static slang_operation *
+gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *newRet;
+
+ assert(oper->type == SLANG_OPER_RETURN);
+
+ if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+ slang_info_log_error(A->log, "return statement requires an expression");
+ return NULL;
+ }
+
+ if (A->UseReturnFlag) {
+ /* Emit:
+ * __notRetFlag = 0;
+ */
+ {
+ newRet = slang_operation_new(1);
+ newRet->locals->outer_scope = oper->locals->outer_scope;
+ newRet->type = SLANG_OPER_ASSIGN;
+ slang_operation_add_children(newRet, 2);
+ {
+ slang_operation *lhs = slang_oper_child(newRet, 0);
+ lhs->type = SLANG_OPER_IDENTIFIER;
+ lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag");
+ }
+ {
+ slang_operation *rhs = slang_oper_child(newRet, 1);
+ slang_operation_literal_bool(rhs, GL_FALSE);
+ }
+ }
+ }
+ else {
+ /* Emit:
+ * return_inlined;
+ */
+ newRet = slang_operation_new(1);
+ newRet->locals->outer_scope = oper->locals->outer_scope;
+ newRet->type = SLANG_OPER_RETURN_INLINED;
+ }
+
+ /*slang_print_tree(newRet, 0);*/
+
+ return newRet;
+}
+
+
+
+
+/**
* Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions.
*/
static void
@@ -866,7 +1121,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
GLuint i;
v = _slang_variable_locate(oper->locals, id, GL_TRUE);
if (!v) {
- _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id);
+ if (_mesa_strcmp((char *) oper->a_id, "__notRetFlag"))
+ _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id);
return;
}
@@ -896,62 +1152,24 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
break;
case SLANG_OPER_RETURN:
- /* do return replacement here too */
- assert(oper->num_children == 0 || oper->num_children == 1);
- if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) {
- /* replace:
- * return expr;
- * with:
- * __retVal = expr;
- * return;
- * then do substitutions on the assignment.
- */
- slang_operation *blockOper, *assignOper, *returnOper;
+ {
+ slang_operation *newReturn;
+ /* generate new 'return' code' */
+ if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID)
+ newReturn = gen_return_without_expression(A, oper);
+ else
+ newReturn = gen_return_with_expression(A, oper);
- /* check if function actually has a return type */
- assert(A->CurFunction);
- if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
- slang_info_log_error(A->log, "illegal return expression");
+ if (!newReturn)
return;
- }
-
- blockOper = slang_operation_new(1);
- blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
- blockOper->num_children = 2;
- blockOper->locals->outer_scope = oper->locals->outer_scope;
- blockOper->children = slang_operation_new(2);
- assignOper = blockOper->children + 0;
- returnOper = blockOper->children + 1;
-
- assignOper->type = SLANG_OPER_ASSIGN;
- assignOper->num_children = 2;
- assignOper->locals->outer_scope = blockOper->locals;
- assignOper->children = slang_operation_new(2);
- assignOper->children[0].type = SLANG_OPER_IDENTIFIER;
- assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal");
- assignOper->children[0].locals->outer_scope = assignOper->locals;
-
- slang_operation_copy(&assignOper->children[1],
- &oper->children[0]);
-
- returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */
- assert(returnOper->num_children == 0);
- /* do substitutions on the "__retVal = expr" sub-tree */
- slang_substitute(A, assignOper,
+ /* do substitutions on the new 'return' code */
+ slang_substitute(A, newReturn,
substCount, substOld, substNew, GL_FALSE);
- /* install new code */
- slang_operation_copy(oper, blockOper);
- slang_operation_destruct(blockOper);
- }
- else {
- /* check if return value was expected */
- assert(A->CurFunction);
- if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
- slang_info_log_error(A->log, "return statement requires an expression");
- return;
- }
+ /* install new 'return' code */
+ slang_operation_copy(oper, newReturn);
+ slang_operation_destruct(newReturn);
}
break;
@@ -1346,12 +1564,74 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun,
}
+/**
+ * Insert declaration for "bool __notRetFlag" in given block operation.
+ * This is used when we can't emit "early" return statements in subroutines.
+ */
+static void
+declare_return_flag(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *decl;
+
+ assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ oper->type == SLANG_OPER_SEQUENCE);
+
+ decl = slang_operation_insert_child(oper, 1);
+
+ slang_generate_declaration(A, oper->locals, decl,
+ SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE);
+
+ /*slang_print_tree(oper, 0);*/
+}
+
+
+/**
+ * Recursively replace instances of the old node type with the new type.
+ */
+static void
+replace_node_type(slang_operation *oper, slang_operation_type oldType,
+ slang_operation_type newType)
+{
+ GLuint i;
+
+ if (oper->type == oldType)
+ oper->type = newType;
+
+ for (i = 0; i < slang_oper_num_children(oper); i++) {
+ replace_node_type(slang_oper_child(oper, i), oldType, newType);
+ }
+}
+
+
+
+/**
+ * Test if the given function body has an "early return". That is, there's
+ * a 'return' statement that's not the very last instruction in the body.
+ */
+static GLboolean
+has_early_return(const slang_operation *funcBody)
+{
+ GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN);
+ if (retCount == 0)
+ return GL_FALSE;
+ else if (retCount == 1 && _slang_is_tail_return(funcBody))
+ return GL_FALSE;
+ else
+ return GL_TRUE;
+}
+
+
+/**
+ * Emit IR code for a function call. This does one of two things:
+ * 1. Inline the function's code
+ * 2. Create an IR for the function's body and create a real call to it.
+ */
static slang_ir_node *
_slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
slang_operation *oper, slang_operation *dest)
{
slang_ir_node *n;
- slang_operation *inlined;
+ slang_operation *instance;
slang_label *prevFuncEndLabel;
char name[200];
@@ -1360,9 +1640,14 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
A->curFuncEndLabel = _slang_label_new(name);
assert(A->curFuncEndLabel);
+ /*
+ * 'instance' is basically a copy of the function's body with various
+ * transformations.
+ */
+
if (slang_is_asm_function(fun) && !dest) {
/* assemble assembly function - tree style */
- inlined = slang_inline_asm_function(A, fun, oper);
+ instance = slang_inline_asm_function(A, fun, oper);
}
else {
/* non-assembly function */
@@ -1371,65 +1656,82 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
* 1. insert the inline code
* 2. Generate a call to the "inline" code as a subroutine
*/
+ const GLboolean earlyReturn = has_early_return(fun->body);
+ if (earlyReturn && !A->EmitContReturn) {
+ A->UseReturnFlag = GL_TRUE;
+ }
- slang_operation *ret = NULL;
-
- inlined = slang_inline_function_call(A, fun, oper, dest);
- if (!inlined)
+ instance = slang_inline_function_call(A, fun, oper, dest);
+ if (!instance)
return NULL;
- ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN);
- if (ret) {
- /* check if this is a "tail" return */
- if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 &&
- _slang_is_tail_return(inlined)) {
- /* The only RETURN is the last stmt in the function, no-op it
- * and inline the function body.
+ if (earlyReturn) {
+ /* The function we're calling has one or more 'return' statements
+ * that prevent us from inlining the function's code.
+ *
+ * In this case, change the function's body type from
+ * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL.
+ * During code emit this will result in a true subroutine call.
+ *
+ * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN.
+ */
+ slang_operation *callOper;
+
+ assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ instance->type == SLANG_OPER_SEQUENCE);
+
+ if (_slang_function_has_return_value(fun) && !dest) {
+ assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL);
+ assert(instance->children[2].type == SLANG_OPER_IDENTIFIER);
+ callOper = &instance->children[1];
+ }
+ else {
+ callOper = instance;
+ }
+
+ if (A->UseReturnFlag) {
+ /* Early returns not supported. Create a _returnFlag variable
+ * that's set upon 'return' and tested elsewhere to no-op any
+ * remaining instructions in the subroutine.
*/
- ret->type = SLANG_OPER_NONE;
+ assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ callOper->type == SLANG_OPER_SEQUENCE);
+ declare_return_flag(A, callOper);
}
else {
- slang_operation *callOper;
- /* The function we're calling has one or more 'return' statements.
- * So, we can't truly inline this function because we need to
- * implement 'return' with RET (and CAL).
- * Nevertheless, we performed "inlining" to make a new instance
- * of the function body to deal with static register allocation.
- *
- * XXX check if there's one 'return' and if it's the very last
- * statement in the function - we can optimize that case.
+ /* We can emit real 'return' statements. If we generated any
+ * 'inline return' statements during function instantiation,
+ * change them back to regular 'return' statements.
*/
- assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
- inlined->type == SLANG_OPER_SEQUENCE);
-
- if (_slang_function_has_return_value(fun) && !dest) {
- assert(inlined->children[0].type == SLANG_OPER_VARIABLE_DECL);
- assert(inlined->children[2].type == SLANG_OPER_IDENTIFIER);
- callOper = &inlined->children[1];
- }
- else {
- callOper = inlined;
- }
- callOper->type = SLANG_OPER_NON_INLINED_CALL;
- callOper->fun = fun;
- callOper->label = _slang_label_new_unique((char*) fun->header.a_name);
+ replace_node_type(instance, SLANG_OPER_RETURN_INLINED,
+ SLANG_OPER_RETURN);
}
+
+ callOper->type = SLANG_OPER_NON_INLINED_CALL;
+ callOper->fun = fun;
+ callOper->label = _slang_label_new_unique((char*) fun->header.a_name);
+ }
+ else {
+ /* If there are any 'return' statements remaining, they're at the
+ * very end of the function and can effectively become no-ops.
+ */
+ replace_node_type(instance, SLANG_OPER_RETURN_INLINED,
+ SLANG_OPER_VOID);
}
}
- if (!inlined)
+ if (!instance)
return NULL;
- /* Replace the function call with the inlined block (or new CALL stmt) */
+ /* Replace the function call with the instance block (or new CALL stmt) */
slang_operation_destruct(oper);
- *oper = *inlined;
- _slang_free(inlined);
+ *oper = *instance;
+ _slang_free(instance);
#if 0
- assert(inlined->locals);
- printf("*** Inlined code for call to %s:\n",
- (char*) fun->header.a_name);
+ assert(instance->locals);
+ printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name);
slang_print_tree(oper, 10);
printf("\n");
#endif
@@ -1445,6 +1747,8 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
n->Comment = _slang_strdup(s);
}
+ A->UseReturnFlag = GL_FALSE;
+
return n;
}
@@ -2337,19 +2641,252 @@ _slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper)
/**
+ * Check if a loop contains a 'continue' statement.
+ * Stop looking if we find a nested loop.
+ */
+static GLboolean
+_slang_loop_contains_continue(const slang_operation *oper)
+{
+ switch (oper->type) {
+ case SLANG_OPER_CONTINUE:
+ return GL_TRUE;
+ case SLANG_OPER_FOR:
+ case SLANG_OPER_DO:
+ case SLANG_OPER_WHILE:
+ /* stop upon finding a nested loop */
+ return GL_FALSE;
+ default:
+ /* recurse */
+ {
+ GLuint i;
+ for (i = 0; i < oper->num_children; i++) {
+ const slang_operation *child = slang_oper_child_const(oper, i);
+ if (_slang_loop_contains_continue(child))
+ return GL_TRUE;
+ }
+ }
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Check if a loop contains a 'continue' or 'break' statement.
+ * Stop looking if we find a nested loop.
+ */
+static GLboolean
+_slang_loop_contains_continue_or_break(const slang_operation *oper)
+{
+ switch (oper->type) {
+ case SLANG_OPER_CONTINUE:
+ case SLANG_OPER_BREAK:
+ return GL_TRUE;
+ case SLANG_OPER_FOR:
+ case SLANG_OPER_DO:
+ case SLANG_OPER_WHILE:
+ /* stop upon finding a nested loop */
+ return GL_FALSE;
+ default:
+ /* recurse */
+ {
+ GLuint i;
+ for (i = 0; i < oper->num_children; i++) {
+ const slang_operation *child = slang_oper_child_const(oper, i);
+ if (_slang_loop_contains_continue_or_break(child))
+ return GL_TRUE;
+ }
+ }
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Replace 'break' and 'continue' statements inside a do and while loops.
+ * This is a recursive helper function used by
+ * _slang_gen_do/while_without_continue().
+ */
+static void
+replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper)
+{
+ switch (oper->type) {
+ case SLANG_OPER_BREAK:
+ /* replace 'break' with "_notBreakFlag = false; break" */
+ {
+ slang_operation *block = oper;
+ block->type = SLANG_OPER_BLOCK_NEW_SCOPE;
+ slang_operation_add_children(block, 2);
+ {
+ slang_operation *assign = slang_oper_child(block, 0);
+ assign->type = SLANG_OPER_ASSIGN;
+ slang_operation_add_children(assign, 2);
+ {
+ slang_operation *lhs = slang_oper_child(assign, 0);
+ slang_operation_identifier(lhs, A, "_notBreakFlag");
+ }
+ {
+ slang_operation *rhs = slang_oper_child(assign, 1);
+ slang_operation_literal_bool(rhs, GL_FALSE);
+ }
+ }
+ {
+ slang_operation *brk = slang_oper_child(block, 1);
+ brk->type = SLANG_OPER_BREAK;
+ assert(!brk->children);
+ }
+ }
+ break;
+ case SLANG_OPER_CONTINUE:
+ /* convert continue into a break */
+ oper->type = SLANG_OPER_BREAK;
+ break;
+ case SLANG_OPER_FOR:
+ case SLANG_OPER_DO:
+ case SLANG_OPER_WHILE:
+ /* stop upon finding a nested loop */
+ break;
+ default:
+ /* recurse */
+ {
+ GLuint i;
+ for (i = 0; i < oper->num_children; i++) {
+ replace_break_and_cont(A, slang_oper_child(oper, i));
+ }
+ }
+ }
+}
+
+
+/**
+ * Transform a while-loop so that continue statements are converted to breaks.
+ * Then do normal IR code generation.
+ *
+ * Before:
+ *
+ * while (LOOPCOND) {
+ * A;
+ * if (IFCOND)
+ * continue;
+ * B;
+ * break;
+ * C;
+ * }
+ *
+ * After:
+ *
+ * {
+ * bool _notBreakFlag = 1;
+ * while (_notBreakFlag && LOOPCOND) {
+ * do {
+ * A;
+ * if (IFCOND) {
+ * break; // was continue
+ * }
+ * B;
+ * _notBreakFlag = 0; // was
+ * break; // break
+ * C;
+ * } while (0)
+ * }
+ * }
+ */
+static slang_ir_node *
+_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *top;
+ slang_operation *innerBody;
+
+ assert(oper->type == SLANG_OPER_WHILE);
+
+ top = slang_operation_new(1);
+ top->type = SLANG_OPER_BLOCK_NEW_SCOPE;
+ top->locals->outer_scope = oper->locals->outer_scope;
+ slang_operation_add_children(top, 2);
+
+ /* declare: bool _notBreakFlag = true */
+ {
+ slang_operation *condDecl = slang_oper_child(top, 0);
+ slang_generate_declaration(A, top->locals, condDecl,
+ SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE);
+ }
+
+ /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */
+ {
+ slang_operation *outerWhile = slang_oper_child(top, 1);
+ outerWhile->type = SLANG_OPER_WHILE;
+ slang_operation_add_children(outerWhile, 2);
+
+ /* _notBreakFlag && LOOPCOND */
+ {
+ slang_operation *cond = slang_oper_child(outerWhile, 0);
+ cond->type = SLANG_OPER_LOGICALAND;
+ slang_operation_add_children(cond, 2);
+ {
+ slang_operation *notBreak = slang_oper_child(cond, 0);
+ slang_operation_identifier(notBreak, A, "_notBreakFlag");
+ }
+ {
+ slang_operation *origCond = slang_oper_child(cond, 1);
+ slang_operation_copy(origCond, slang_oper_child(oper, 0));
+ }
+ }
+
+ /* inner loop */
+ {
+ slang_operation *innerDo = slang_oper_child(outerWhile, 1);
+ innerDo->type = SLANG_OPER_DO;
+ slang_operation_add_children(innerDo, 2);
+
+ /* copy original do-loop body into inner do-loop's body */
+ innerBody = slang_oper_child(innerDo, 0);
+ slang_operation_copy(innerBody, slang_oper_child(oper, 1));
+ innerBody->locals->outer_scope = innerDo->locals;
+
+ /* inner do-loop's condition is constant/false */
+ {
+ slang_operation *constFalse = slang_oper_child(innerDo, 1);
+ slang_operation_literal_bool(constFalse, GL_FALSE);
+ }
+ }
+ }
+
+ /* Finally, in innerBody,
+ * replace "break" with "_notBreakFlag = 0; break"
+ * replace "continue" with "break"
+ */
+ replace_break_and_cont(A, innerBody);
+
+ /*slang_print_tree(top, 0);*/
+
+ return _slang_gen_operation(A, top);
+
+ return NULL;
+}
+
+
+/**
* Generate loop code using high-level IR_LOOP instruction
*/
static slang_ir_node *
-_slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper)
{
/*
* LOOP:
* BREAK if !expr (child[0])
* body code (child[1])
*/
- slang_ir_node *prevLoop, *loop, *breakIf, *body;
+ slang_ir_node *loop, *breakIf, *body;
GLboolean isConst, constTrue;
+ if (!A->EmitContReturn) {
+ /* We don't want to emit CONT instructions. If this while-loop has
+ * a continue, translate it away.
+ */
+ if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) {
+ return _slang_gen_while_without_continue(A, oper);
+ }
+ }
+
/* type-check expression */
if (!_slang_is_boolean(A, &oper->children[0])) {
slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'");
@@ -2364,11 +2901,11 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
return new_node0(IR_NOP);
}
+ /* Begin new loop */
loop = new_loop(NULL);
- /* save old, push new loop */
- prevLoop = A->CurLoop;
- A->CurLoop = loop;
+ /* save loop state */
+ push_loop(A, oper, loop);
if (isConst && constTrue) {
/* while(nonzero constant), no conditional break */
@@ -2377,7 +2914,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
else {
slang_ir_node *cond
= new_cond(new_not(_slang_gen_operation(A, &oper->children[0])));
- breakIf = new_break_if_true(A->CurLoop, cond);
+ breakIf = new_break_if_true(A, cond);
}
body = _slang_gen_operation(A, &oper->children[1]);
loop->Children[0] = new_seq(breakIf, body);
@@ -2386,23 +2923,128 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
/* loop->List is head of linked list of break/continue nodes */
if (!loop->List && isConst && constTrue) {
/* infinite loop detected */
- A->CurLoop = prevLoop; /* clean-up */
+ pop_loop(A);
slang_info_log_error(A->log, "Infinite loop detected!");
return NULL;
}
- /* pop loop, restore prev */
- A->CurLoop = prevLoop;
+ /* restore loop state */
+ pop_loop(A);
return loop;
}
/**
+ * Transform a do-while-loop so that continue statements are converted to breaks.
+ * Then do normal IR code generation.
+ *
+ * Before:
+ *
+ * do {
+ * A;
+ * if (IFCOND)
+ * continue;
+ * B;
+ * break;
+ * C;
+ * } while (LOOPCOND);
+ *
+ * After:
+ *
+ * {
+ * bool _notBreakFlag = 1;
+ * do {
+ * do {
+ * A;
+ * if (IFCOND) {
+ * break; // was continue
+ * }
+ * B;
+ * _notBreakFlag = 0; // was
+ * break; // break
+ * C;
+ * } while (0)
+ * } while (_notBreakFlag && LOOPCOND);
+ * }
+ */
+static slang_ir_node *
+_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *top;
+ slang_operation *innerBody;
+
+ assert(oper->type == SLANG_OPER_DO);
+
+ top = slang_operation_new(1);
+ top->type = SLANG_OPER_BLOCK_NEW_SCOPE;
+ top->locals->outer_scope = oper->locals->outer_scope;
+ slang_operation_add_children(top, 2);
+
+ /* declare: bool _notBreakFlag = true */
+ {
+ slang_operation *condDecl = slang_oper_child(top, 0);
+ slang_generate_declaration(A, top->locals, condDecl,
+ SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE);
+ }
+
+ /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */
+ {
+ slang_operation *outerDo = slang_oper_child(top, 1);
+ outerDo->type = SLANG_OPER_DO;
+ slang_operation_add_children(outerDo, 2);
+
+ /* inner do-loop */
+ {
+ slang_operation *innerDo = slang_oper_child(outerDo, 0);
+ innerDo->type = SLANG_OPER_DO;
+ slang_operation_add_children(innerDo, 2);
+
+ /* copy original do-loop body into inner do-loop's body */
+ innerBody = slang_oper_child(innerDo, 0);
+ slang_operation_copy(innerBody, slang_oper_child(oper, 0));
+ innerBody->locals->outer_scope = innerDo->locals;
+
+ /* inner do-loop's condition is constant/false */
+ {
+ slang_operation *constFalse = slang_oper_child(innerDo, 1);
+ slang_operation_literal_bool(constFalse, GL_FALSE);
+ }
+ }
+
+ /* _notBreakFlag && LOOPCOND */
+ {
+ slang_operation *cond = slang_oper_child(outerDo, 1);
+ cond->type = SLANG_OPER_LOGICALAND;
+ slang_operation_add_children(cond, 2);
+ {
+ slang_operation *notBreak = slang_oper_child(cond, 0);
+ slang_operation_identifier(notBreak, A, "_notBreakFlag");
+ }
+ {
+ slang_operation *origCond = slang_oper_child(cond, 1);
+ slang_operation_copy(origCond, slang_oper_child(oper, 1));
+ }
+ }
+ }
+
+ /* Finally, in innerBody,
+ * replace "break" with "_notBreakFlag = 0; break"
+ * replace "continue" with "break"
+ */
+ replace_break_and_cont(A, innerBody);
+
+ /*slang_print_tree(top, 0);*/
+
+ return _slang_gen_operation(A, top);
+}
+
+
+/**
* Generate IR tree for a do-while loop using high-level LOOP, IF instructions.
*/
static slang_ir_node *
-_slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper)
{
/*
* LOOP:
@@ -2410,9 +3052,18 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
* tail code:
* BREAK if !expr (child[1])
*/
- slang_ir_node *prevLoop, *loop;
+ slang_ir_node *loop;
GLboolean isConst, constTrue;
+ if (!A->EmitContReturn) {
+ /* We don't want to emit CONT instructions. If this do-loop has
+ * a continue, translate it away.
+ */
+ if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) {
+ return _slang_gen_do_without_continue(A, oper);
+ }
+ }
+
/* type-check expression */
if (!_slang_is_boolean(A, &oper->children[1])) {
slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'");
@@ -2421,9 +3072,8 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
loop = new_loop(NULL);
- /* save old, push new loop */
- prevLoop = A->CurLoop;
- A->CurLoop = loop;
+ /* save loop state */
+ push_loop(A, oper, loop);
/* loop body: */
loop->Children[0] = _slang_gen_operation(A, &oper->children[0]);
@@ -2437,13 +3087,13 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
else {
slang_ir_node *cond
= new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
- loop->Children[1] = new_break_if_true(A->CurLoop, cond);
+ loop->Children[1] = new_break_if_true(A, cond);
}
/* XXX we should do infinite loop detection, as above */
- /* pop loop, restore prev */
- A->CurLoop = prevLoop;
+ /* restore loop state */
+ pop_loop(A);
return loop;
}
@@ -2485,9 +3135,14 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
const char *varName;
slang_atom varId;
- assert(oper->type == SLANG_OPER_FOR);
+ if (oper->type != SLANG_OPER_FOR)
+ return GL_FALSE;
+
assert(oper->num_children == 4);
+ if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3)))
+ return GL_FALSE;
+
/* children[0] must be either "int i=constant" or "i=constant" */
if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) {
slang_variable *var;
@@ -2582,20 +3237,6 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
}
-static void
-_unroll_loop_inc(slang_assemble_ctx * A)
-{
- A->UnrollLoop++;
-}
-
-
-static void
-_unroll_loop_dec(slang_assemble_ctx * A)
-{
- A->UnrollLoop--;
-}
-
-
/**
* Unroll a for-loop.
* First we determine the number of iterations to unroll.
@@ -2612,9 +3253,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
slang_ir_node *n, *root = NULL;
slang_atom varId;
- /* Set flag so code generator knows we're unrolling loops */
- _unroll_loop_inc( A );
-
if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) {
/* for (int i=0; ... */
slang_variable *var;
@@ -2637,15 +3275,11 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
/* make a copy of the loop body */
body = slang_operation_new(1);
- if (!body) {
- _unroll_loop_dec( A );
+ if (!body)
return NULL;
- }
- if (!slang_operation_copy(body, &oper->children[3])) {
- _unroll_loop_dec( A );
+ if (!slang_operation_copy(body, &oper->children[3]))
return NULL;
- }
/* in body, replace instances of 'varId' with literal 'iter' */
{
@@ -2656,7 +3290,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
if (!oldVar) {
/* undeclared loop variable */
slang_operation_delete(body);
- _unroll_loop_dec( A );
return NULL;
}
@@ -2671,36 +3304,195 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
/* do IR codegen for body */
n = _slang_gen_operation(A, body);
- if (!n) {
- _unroll_loop_dec( A );
+ if (!n)
return NULL;
- }
root = new_seq(root, n);
slang_operation_delete(body);
}
- _unroll_loop_dec( A );
-
return root;
}
/**
+ * Replace 'continue' statement with 'break' inside a for-loop.
+ * This is a recursive helper function used by _slang_gen_for_without_continue().
+ */
+static void
+replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper)
+{
+ switch (oper->type) {
+ case SLANG_OPER_CONTINUE:
+ oper->type = SLANG_OPER_BREAK;
+ break;
+ case SLANG_OPER_FOR:
+ case SLANG_OPER_DO:
+ case SLANG_OPER_WHILE:
+ /* stop upon finding a nested loop */
+ break;
+ default:
+ /* recurse */
+ {
+ GLuint i;
+ for (i = 0; i < oper->num_children; i++) {
+ replace_continue_with_break(A, slang_oper_child(oper, i));
+ }
+ }
+ }
+}
+
+
+/**
+ * Transform a for-loop so that continue statements are converted to breaks.
+ * Then do normal IR code generation.
+ *
+ * Before:
+ *
+ * for (INIT; LOOPCOND; INCR) {
+ * A;
+ * if (IFCOND) {
+ * continue;
+ * }
+ * B;
+ * }
+ *
+ * After:
+ *
+ * {
+ * bool _condFlag = 1;
+ * for (INIT; _condFlag; ) {
+ * for ( ; _condFlag = LOOPCOND; INCR) {
+ * A;
+ * if (IFCOND) {
+ * break;
+ * }
+ * B;
+ * }
+ * if (_condFlag)
+ * INCR;
+ * }
+ * }
+ */
+static slang_ir_node *
+_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper)
+{
+ slang_operation *top;
+ slang_operation *outerFor, *innerFor, *init, *cond, *incr;
+ slang_operation *lhs, *rhs;
+
+ assert(oper->type == SLANG_OPER_FOR);
+
+ top = slang_operation_new(1);
+ top->type = SLANG_OPER_BLOCK_NEW_SCOPE;
+ top->locals->outer_scope = oper->locals->outer_scope;
+ slang_operation_add_children(top, 2);
+
+ /* declare: bool _condFlag = true */
+ {
+ slang_operation *condDecl = slang_oper_child(top, 0);
+ slang_generate_declaration(A, top->locals, condDecl,
+ SLANG_SPEC_BOOL, "_condFlag", GL_TRUE);
+ }
+
+ /* build outer loop: for (INIT; _condFlag; ) { */
+ outerFor = slang_oper_child(top, 1);
+ outerFor->type = SLANG_OPER_FOR;
+ slang_operation_add_children(outerFor, 4);
+
+ init = slang_oper_child(outerFor, 0);
+ slang_operation_copy(init, slang_oper_child(oper, 0));
+
+ cond = slang_oper_child(outerFor, 1);
+ cond->type = SLANG_OPER_IDENTIFIER;
+ cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag");
+
+ incr = slang_oper_child(outerFor, 2);
+ incr->type = SLANG_OPER_VOID;
+
+ /* body of the outer loop */
+ {
+ slang_operation *block = slang_oper_child(outerFor, 3);
+
+ slang_operation_add_children(block, 2);
+ block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
+
+ /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */
+ {
+ innerFor = slang_oper_child(block, 0);
+
+ /* make copy of orig loop */
+ slang_operation_copy(innerFor, oper);
+ assert(innerFor->type == SLANG_OPER_FOR);
+ innerFor->locals->outer_scope = block->locals;
+
+ init = slang_oper_child(innerFor, 0);
+ init->type = SLANG_OPER_VOID; /* leak? */
+
+ cond = slang_oper_child(innerFor, 1);
+ slang_operation_destruct(cond);
+ cond->type = SLANG_OPER_ASSIGN;
+ cond->locals = _slang_variable_scope_new(innerFor->locals);
+ slang_operation_add_children(cond, 2);
+
+ lhs = slang_oper_child(cond, 0);
+ lhs->type = SLANG_OPER_IDENTIFIER;
+ lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag");
+
+ rhs = slang_oper_child(cond, 1);
+ slang_operation_copy(rhs, slang_oper_child(oper, 1));
+ }
+
+ /* if (_condFlag) INCR; */
+ {
+ slang_operation *ifop = slang_oper_child(block, 1);
+ ifop->type = SLANG_OPER_IF;
+ slang_operation_add_children(ifop, 2);
+
+ /* re-use cond node build above */
+ slang_operation_copy(slang_oper_child(ifop, 0), cond);
+
+ /* incr node from original for-loop operation */
+ slang_operation_copy(slang_oper_child(ifop, 1),
+ slang_oper_child(oper, 2));
+ }
+
+ /* finally, replace "continue" with "break" in the inner for-loop */
+ replace_continue_with_break(A, slang_oper_child(innerFor, 3));
+ }
+
+ return _slang_gen_operation(A, top);
+}
+
+
+
+/**
* Generate IR for a for-loop. Unrolling will be done when possible.
*/
static slang_ir_node *
-_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper)
{
- GLboolean unroll = _slang_can_unroll_for_loop(A, oper);
+ GLboolean unroll;
+
+ if (!A->EmitContReturn) {
+ /* We don't want to emit CONT instructions. If this for-loop has
+ * a continue, translate it away.
+ */
+ if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) {
+ return _slang_gen_for_without_continue(A, oper);
+ }
+ }
+ unroll = _slang_can_unroll_for_loop(A, oper);
if (unroll) {
slang_ir_node *code = _slang_unroll_for_loop(A, oper);
if (code)
return code;
}
+ assert(oper->type == SLANG_OPER_FOR);
+
/* conventional for-loop code generation */
{
/*
@@ -2711,24 +3503,23 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
* tail code:
* incr code (child[2]) // XXX continue here
*/
- slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
+ slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr;
init = _slang_gen_operation(A, &oper->children[0]);
loop = new_loop(NULL);
- /* save old, push new loop */
- prevLoop = A->CurLoop;
- A->CurLoop = loop;
+ /* save loop state */
+ push_loop(A, oper, loop);
cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
- breakIf = new_break_if_true(A->CurLoop, cond);
+ breakIf = new_break_if_true(A, cond);
body = _slang_gen_operation(A, &oper->children[3]);
incr = _slang_gen_operation(A, &oper->children[2]);
loop->Children[0] = new_seq(breakIf, body);
loop->Children[1] = incr; /* tail code */
- /* pop loop, restore prev */
- A->CurLoop = prevLoop;
+ /* restore loop state */
+ pop_loop(A);
return new_seq(init, loop);
}
@@ -2738,18 +3529,22 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
static slang_ir_node *
_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper)
{
- slang_ir_node *n, *loopNode;
+ slang_ir_node *n, *cont, *incr = NULL, *loopNode;
+
assert(oper->type == SLANG_OPER_CONTINUE);
- loopNode = A->CurLoop;
+ loopNode = current_loop_ir(A);
assert(loopNode);
assert(loopNode->Opcode == IR_LOOP);
- n = new_node0(IR_CONT);
- if (n) {
- n->Parent = loopNode;
- /* insert this node at head of linked list */
- n->List = loopNode->List;
- loopNode->List = n;
+
+ cont = new_node0(IR_CONT);
+ if (cont) {
+ cont->Parent = loopNode;
+ /* insert this node at head of linked list of cont/break instructions */
+ cont->List = loopNode->List;
+ loopNode->List = cont;
}
+
+ n = new_seq(incr, cont);
return n;
}
@@ -2819,24 +3614,20 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK)
&& !haveElseClause) {
/* Special case: generate a conditional break */
- if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */
- return NULL;
- ifBody = new_break_if_true(A->CurLoop, cond);
+ ifBody = new_break_if_true(A, cond);
return ifBody;
}
else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE)
- && !haveElseClause) {
+ && !haveElseClause
+ && current_loop_oper(A)
+ && current_loop_oper(A)->type != SLANG_OPER_FOR) {
/* Special case: generate a conditional continue */
- if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */
- return NULL;
- ifBody = new_cont_if_true(A->CurLoop, cond);
+ ifBody = new_cont_if_true(A, cond);
return ifBody;
}
else {
/* general case */
ifBody = _slang_gen_operation(A, &oper->children[1]);
- if (!ifBody)
- return NULL;
if (haveElseClause)
elseBody = _slang_gen_operation(A, &oper->children[2]);
else
@@ -3242,14 +4033,11 @@ _slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper)
select = slang_operation_new(1);
select->type = SLANG_OPER_SELECT;
- select->num_children = 3;
- select->children = slang_operation_new(3);
+ slang_operation_add_children(select, 3);
- slang_operation_copy(&select->children[0], &oper->children[0]);
- slang_operation_copy(&select->children[1], &oper->children[1]);
- select->children[2].type = SLANG_OPER_LITERAL_BOOL;
- ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0); /* false */
- select->children[2].literal_size = 1;
+ slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]);
+ slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]);
+ slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE);
n = _slang_gen_select(A, select);
return n;
@@ -3268,14 +4056,11 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper)
select = slang_operation_new(1);
select->type = SLANG_OPER_SELECT;
- select->num_children = 3;
- select->children = slang_operation_new(3);
+ slang_operation_add_children(select, 3);
- slang_operation_copy(&select->children[0], &oper->children[0]);
- select->children[1].type = SLANG_OPER_LITERAL_BOOL;
- ASSIGN_4V(select->children[1].literal, 1, 1, 1, 1); /* true */
- select->children[1].literal_size = 1;
- slang_operation_copy(&select->children[2], &oper->children[1]);
+ slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]);
+ slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE);
+ slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]);
n = _slang_gen_select(A, select);
return n;
@@ -3288,70 +4073,8 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper)
static slang_ir_node *
_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
{
- const GLboolean haveReturnValue
- = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID);
-
- /* error checking */
- assert(A->CurFunction);
- if (haveReturnValue &&
- A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
- slang_info_log_error(A->log, "illegal return expression");
- return NULL;
- }
- else if (!haveReturnValue &&
- A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
- slang_info_log_error(A->log, "return statement requires an expression");
- return NULL;
- }
-
- if (!haveReturnValue) {
- return new_return(A->curFuncEndLabel);
- }
- else {
- /*
- * Convert from:
- * return expr;
- * To:
- * __retVal = expr;
- * return; // goto __endOfFunction
- */
- slang_operation *assign;
- slang_atom a_retVal;
- slang_ir_node *n;
-
- a_retVal = slang_atom_pool_atom(A->atoms, "__retVal");
- assert(a_retVal);
-
-#if 1 /* DEBUG */
- {
- slang_variable *v =
- _slang_variable_locate(oper->locals, a_retVal, GL_TRUE);
- if (!v) {
- /* trying to return a value in a void-valued function */
- return NULL;
- }
- }
-#endif
-
- assign = slang_operation_new(1);
- assign->type = SLANG_OPER_ASSIGN;
- assign->num_children = 2;
- assign->children = slang_operation_new(2);
- /* lhs (__retVal) */
- assign->children[0].type = SLANG_OPER_IDENTIFIER;
- assign->children[0].a_id = a_retVal;
- assign->children[0].locals->outer_scope = assign->locals;
- /* rhs (expr) */
- /* XXX we might be able to avoid this copy someday */
- slang_operation_copy(&assign->children[1], &oper->children[0]);
-
- /* assemble the new code */
- n = new_seq(_slang_gen_operation(A, assign),
- new_return(A->curFuncEndLabel));
-
- slang_operation_delete(assign);
- return n;
- }
+ assert(oper->type == SLANG_OPER_RETURN);
+ return new_return(A->curFuncEndLabel);
}
@@ -3457,6 +4180,7 @@ _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper)
assert(oper->type == SLANG_OPER_VARIABLE_DECL);
assert(oper->num_children <= 1);
+
/* lookup the variable by name */
var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE);
if (!var)
@@ -3612,6 +4336,9 @@ root_swizzle(const slang_ir_storage *st)
static slang_ir_node *
_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
{
+ slang_operation *pred = NULL;
+ slang_ir_node *n = NULL;
+
if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
/* Check that var is writeable */
slang_variable *var
@@ -3632,6 +4359,17 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
(char *) oper->children[0].a_id);
return NULL;
}
+
+ /* check if we need to predicate this assignment based on __notRetFlag */
+ if ((var->is_global ||
+ var->type.qualifier == SLANG_QUAL_OUT ||
+ var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) {
+ /* create predicate, used below */
+ pred = slang_operation_new(1);
+ pred->type = SLANG_OPER_IDENTIFIER;
+ pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag");
+ pred->locals->outer_scope = oper->locals->outer_scope;
+ }
}
if (oper->children[0].type == SLANG_OPER_IDENTIFIER &&
@@ -3643,14 +4381,12 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
* cases such as "v.x = f();" - would help with typical vertex
* transformation.
*/
- slang_ir_node *n;
n = _slang_gen_function_call_name(A,
(const char *) oper->children[1].a_id,
&oper->children[1], &oper->children[0]);
- return n;
}
else {
- slang_ir_node *n, *lhs, *rhs;
+ slang_ir_node *lhs, *rhs;
/* lhs and rhs type checking */
if (!_slang_assignment_compatible(A,
@@ -3690,12 +4426,21 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
rhs = _slang_gen_swizzle(rhs, newSwizzle);
}
n = new_node2(IR_COPY, lhs, rhs);
- return n;
}
else {
return NULL;
}
}
+
+ if (n && pred) {
+ /* predicate the assignment code on __notRetFlag */
+ slang_ir_node *top, *cond;
+
+ cond = _slang_gen_operation(A, pred);
+ top = new_if(cond, n, NULL);
+ return top;
+ }
+ return n;
}
@@ -4048,16 +4793,14 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
case SLANG_OPER_WHILE:
return _slang_gen_while(A, oper);
case SLANG_OPER_BREAK:
- if (!A->CurLoop) {
- if (!A->UnrollLoop)
- slang_info_log_error(A->log, "'break' not in loop");
+ if (!current_loop_oper(A)) {
+ slang_info_log_error(A->log, "'break' not in loop");
return NULL;
}
- return new_break(A->CurLoop);
+ return new_break(current_loop_ir(A));
case SLANG_OPER_CONTINUE:
- if (!A->CurLoop) {
- if (!A->UnrollLoop)
- slang_info_log_error(A->log, "'continue' not in loop");
+ if (!current_loop_oper(A)) {
+ slang_info_log_error(A->log, "'continue' not in loop");
return NULL;
}
return _slang_gen_continue(A, oper);
@@ -4182,6 +4925,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
return _slang_gen_method_call(A, oper);
case SLANG_OPER_RETURN:
return _slang_gen_return(A, oper);
+ case SLANG_OPER_RETURN_INLINED:
+ return _slang_gen_return(A, oper);
case SLANG_OPER_LABEL:
return new_label(oper->label);
case SLANG_OPER_IDENTIFIER:
@@ -4303,6 +5048,8 @@ _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var,
const GLint totalSize = _slang_array_size(size, arrayLen);
GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
+ var->is_global = GL_TRUE;
+
/* check for sampler2D arrays */
if (texIndex == -1 && var->type.specifier._array)
texIndex = sampler_to_texture_index(var->type.specifier._array->type);
@@ -4601,7 +5348,9 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
assert(A->program->Parameters );
assert(A->program->Varying);
assert(A->vartable);
- A->CurLoop = NULL;
+
+ A->LoopDepth = 0;
+ A->UseReturnFlag = GL_FALSE;
A->CurFunction = fun;
/* fold constant expressions, etc. */
diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h
index d80013ad34..ee3be55a45 100644
--- a/src/mesa/shader/slang/slang_codegen.h
+++ b/src/mesa/shader/slang/slang_codegen.h
@@ -31,6 +31,9 @@
#include "slang_compile.h"
+#define MAX_LOOP_DEPTH 30
+
+
typedef struct slang_assemble_ctx_
{
slang_atom_pool *atoms;
@@ -39,11 +42,19 @@ typedef struct slang_assemble_ctx_
struct gl_sl_pragmas *pragmas;
slang_var_table *vartable;
slang_info_log *log;
- struct slang_label_ *curFuncEndLabel;
- struct slang_ir_node_ *CurLoop;
+
+ /* current loop stack */
+ const slang_operation *LoopOperStack[MAX_LOOP_DEPTH];
+ struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH];
+ GLuint LoopDepth;
+
+ /* current function */
struct slang_function_ *CurFunction;
- GLuint UnrollLoop;
+ struct slang_label_ *curFuncEndLabel;
+ GLboolean UseReturnFlag;
+
GLboolean UnresolvedRefs;
+ GLboolean EmitContReturn;
} slang_assemble_ctx;
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
index d7ad879e97..c1b97c7cb7 100644
--- a/src/mesa/shader/slang/slang_compile.c
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -1953,6 +1953,7 @@ static int
parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
const slang_fully_specified_type * type)
{
+ GET_CURRENT_CONTEXT(ctx); /* a hack */
slang_variable *var;
slang_atom a_name;
@@ -2066,6 +2067,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
A.vartable = O->vartable;
A.log = C->L;
A.curFuncEndLabel = NULL;
+ A.EmitContReturn = ctx->Shader.EmitContReturn;
if (!_slang_codegen_global_variable(&A, var, C->type))
RETURN0;
}
@@ -2430,6 +2432,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
A.program = o.program;
A.pragmas = &shader->Pragmas;
A.vartable = o.vartable;
+ A.EmitContReturn = ctx->Shader.EmitContReturn;
A.log = C->L;
/* main() takes no parameters */
diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c
index e650616880..3e2bdbc91f 100644
--- a/src/mesa/shader/slang/slang_compile_operation.c
+++ b/src/mesa/shader/slang/slang_compile_operation.c
@@ -119,11 +119,13 @@ slang_operation_copy(slang_operation * x, const slang_operation * y)
if (!slang_operation_construct(&z))
return GL_FALSE;
z.type = y->type;
- z.children = (slang_operation *)
- _slang_alloc(y->num_children * sizeof(slang_operation));
- if (z.children == NULL) {
- slang_operation_destruct(&z);
- return GL_FALSE;
+ if (y->num_children > 0) {
+ z.children = (slang_operation *)
+ _slang_alloc(y->num_children * sizeof(slang_operation));
+ if (z.children == NULL) {
+ slang_operation_destruct(&z);
+ return GL_FALSE;
+ }
}
for (z.num_children = 0; z.num_children < y->num_children;
z.num_children++) {
@@ -152,6 +154,15 @@ slang_operation_copy(slang_operation * x, const slang_operation * y)
return GL_FALSE;
}
}
+
+ /* update scoping for children */
+ for (i = 0; i < y->num_children; i++) {
+ if (y->children[i].locals &&
+ y->children[i].locals->outer_scope == y->locals) {
+ z.children[i].locals->outer_scope = z.locals;
+ }
+ }
+
#if 0
z.var = y->var;
z.fun = y->fun;
@@ -198,6 +209,20 @@ slang_operation_delete(slang_operation *oper)
}
+void
+slang_operation_free_children(slang_operation *oper)
+{
+ GLuint i;
+ for (i = 0; i < slang_oper_num_children(oper); i++) {
+ slang_operation *child = slang_oper_child(oper, i);
+ slang_operation_destruct(child);
+ }
+ _slang_free(oper->children);
+ oper->children = NULL;
+ oper->num_children = 0;
+}
+
+
slang_operation *
slang_operation_grow(GLuint *numChildren, slang_operation **children)
{
@@ -263,6 +288,26 @@ slang_operation_insert(GLuint *numElements, slang_operation **array,
}
+/**
+ * Add/insert new child into given node at given position.
+ * \return pointer to the new child node
+ */
+slang_operation *
+slang_operation_insert_child(slang_operation *oper, GLuint pos)
+{
+ slang_operation *newOp;
+
+ newOp = slang_operation_insert(&oper->num_children,
+ &oper->children,
+ pos);
+ if (newOp) {
+ newOp->locals->outer_scope = oper->locals;
+ }
+
+ return newOp;
+}
+
+
void
_slang_operation_swap(slang_operation *oper0, slang_operation *oper1)
{
@@ -272,3 +317,16 @@ _slang_operation_swap(slang_operation *oper0, slang_operation *oper1)
}
+void
+slang_operation_add_children(slang_operation *oper, GLuint num_children)
+{
+ GLuint i;
+ assert(oper->num_children == 0);
+ assert(oper->children == NULL);
+ oper->num_children = num_children;
+ oper->children = slang_operation_new(num_children);
+ for (i = 0; i < num_children; i++) {
+ oper->children[i].locals = _slang_variable_scope_new(oper->locals);
+ }
+}
+
diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h
index 37af5d617c..58f1edeed8 100644
--- a/src/mesa/shader/slang/slang_compile_operation.h
+++ b/src/mesa/shader/slang/slang_compile_operation.h
@@ -42,6 +42,7 @@ typedef enum slang_operation_type_
SLANG_OPER_CONTINUE, /* "continue" statement */
SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */
SLANG_OPER_RETURN, /* "return" [expr] */
+ SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */
SLANG_OPER_LABEL, /* a jump target */
SLANG_OPER_EXPRESSION, /* [expr] */
SLANG_OPER_IF, /* "if" [0] then [1] else [2] */
@@ -150,6 +151,9 @@ slang_operation_new(GLuint count);
extern void
slang_operation_delete(slang_operation *oper);
+extern void
+slang_operation_free_children(slang_operation *oper);
+
extern slang_operation *
slang_operation_grow(GLuint *numChildren, slang_operation **children);
@@ -157,8 +161,66 @@ extern slang_operation *
slang_operation_insert(GLuint *numChildren, slang_operation **children,
GLuint pos);
+extern slang_operation *
+slang_operation_insert_child(slang_operation *oper, GLuint pos);
+
extern void
_slang_operation_swap(slang_operation *oper0, slang_operation *oper1);
+extern void
+slang_operation_add_children(slang_operation *oper, GLuint num_children);
+
+
+/** Return number of children of given node */
+static INLINE GLuint
+slang_oper_num_children(const slang_operation *oper)
+{
+ return oper->num_children;
+}
+
+/** Return child of given operation node */
+static INLINE slang_operation *
+slang_oper_child(slang_operation *oper, GLuint child)
+{
+ assert(child < oper->num_children);
+ return &oper->children[child];
+}
+
+
+/** Return child of given operation node, const version */
+static INLINE const slang_operation *
+slang_oper_child_const(const slang_operation *oper, GLuint child)
+{
+ assert(child < oper->num_children);
+ return &oper->children[child];
+}
+
+
+/** Init oper to a boolean literal. */
+static INLINE void
+slang_operation_literal_bool(slang_operation *oper, GLboolean value)
+{
+ oper->type = SLANG_OPER_LITERAL_BOOL;
+ oper->literal[0] =
+ oper->literal[1] =
+ oper->literal[2] =
+ oper->literal[3] = (float) value;
+ oper->literal_size = 1;
+}
+
+
+/** Init oper to an int literal. */
+static INLINE void
+slang_operation_literal_int(slang_operation *oper, GLint value)
+{
+ oper->type = SLANG_OPER_LITERAL_INT;
+ oper->literal[0] =
+ oper->literal[1] =
+ oper->literal[2] =
+ oper->literal[3] = (float) value;
+ oper->literal_size = 1;
+}
+
+
#endif /* SLANG_COMPILE_OPERATION_H */
diff --git a/src/mesa/shader/slang/slang_compile_variable.h b/src/mesa/shader/slang/slang_compile_variable.h
index a667d91b47..b4585599f2 100644
--- a/src/mesa/shader/slang/slang_compile_variable.h
+++ b/src/mesa/shader/slang/slang_compile_variable.h
@@ -39,6 +39,7 @@ typedef struct slang_variable_
GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */
struct slang_operation_ *initializer; /**< Optional initializer code */
GLuint size; /**< Variable's size in bytes */
+ GLboolean is_global;
GLboolean isTemp; /**< a named temporary (__resultTmp) */
GLboolean declared; /**< for debug */
struct slang_ir_storage_ *store; /**< Storage for this var */
diff --git a/src/mesa/shader/slang/slang_print.c b/src/mesa/shader/slang/slang_print.c
index bf1475f91d..98c7877534 100644
--- a/src/mesa/shader/slang/slang_print.c
+++ b/src/mesa/shader/slang/slang_print.c
@@ -261,6 +261,7 @@ slang_print_tree(const slang_operation *op, int indent)
break;
case SLANG_OPER_BLOCK_NEW_SCOPE:
+ case SLANG_OPER_NON_INLINED_CALL:
spaces(indent);
printf("{{ // new scope locals=%p outer=%p: ",
(void *) op->locals,
@@ -348,6 +349,13 @@ slang_print_tree(const slang_operation *op, int indent)
slang_print_tree(&op->children[0], indent + 3);
break;
+ case SLANG_OPER_RETURN_INLINED:
+ spaces(indent);
+ printf("RETURN_INLINED\n");
+ if (op->num_children > 0)
+ slang_print_tree(&op->children[0], indent + 3);
+ break;
+
case SLANG_OPER_LABEL:
spaces(indent);
printf("LABEL %s\n", (char *) op->a_id);
@@ -478,7 +486,7 @@ slang_print_tree(const slang_operation *op, int indent)
(void *) scope,
(void *) op->locals,
(void *) op->locals->outer_scope);
- assert(scope);
+ /*assert(scope);*/
}
}
break;
diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
index 3cc40ee884..12d9b6b874 100644
--- a/src/mesa/state_tracker/st_extensions.c
+++ b/src/mesa/state_tracker/st_extensions.c
@@ -120,6 +120,11 @@ void st_init_limits(struct st_context *st)
c->MaxDrawBuffers
= CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS),
1, MAX_DRAW_BUFFERS);
+
+ /* Is TGSI_OPCODE_CONT supported? */
+ /* XXX separate query for early function return? */
+ st->ctx->Shader.EmitContReturn =
+ screen->get_param(screen, PIPE_CAP_TGSI_CONT_SUPPORTED);
}