Implement unbound varibility for struct types.

Now, if a struct member has an explicit 'uniform' or 'varying'
qualifier, then that member has that variability, regardless of
the variability of the struct's variability.  Members without
'uniform' or 'varying' have unbound variability, and in turn
inherit the variability of the struct.

As a result of this, now structs can properly be 'varying' by default,
just like all the other types, while still having sensible semantics.
This commit is contained in:
Matt Pharr
2012-02-20 12:20:51 -08:00
parent 6d7ff7eba2
commit f81acbfe80
59 changed files with 744 additions and 322 deletions

View File

@@ -92,7 +92,8 @@ Contents:
* `Reference Types`_
* `Enumeration Types`_
* `Short Vector Types`_
* `Struct and Array Types`_
* `Array Types`_
* `Struct Types`_
+ `Declarations and Initializers`_
+ `Expressions`_
@@ -859,7 +860,9 @@ A variable that is declared with the ``uniform`` qualifier represents a
single value that is shared across the entire gang. (In contrast, the
default variability qualifier for variables in ``ispc``, ``varying``,
represents a variable that has a distinct storage location for each program
instance in the gang.)
instance in the gang.) (Though see the discussion in `Struct Types`_ for
some subtleties related to ``uniform`` and ``varying`` when used with
structures.)
It is an error to try to assign a ``varying`` value to a ``uniform``
variable, though ``uniform`` values can be assigned to ``uniform``
@@ -1832,20 +1835,19 @@ expressions:
int8<2> bar = ...;
foo.yz = bar; // Error: can't assign to left-hand side of expression
Struct and Array Types
----------------------
More complex data structures can be built using ``struct`` and arrays.
Array Types
-----------
Arrays of any type can be declared just as in C and C++:
::
struct Foo {
float time;
int flags[10];
};
float a[10];
uniform int * varying b[20];
Like in C, multidimensional arrays can be specified; the following declares
an array of 5 arrays of 15 floats.
Multidimensional arrays can be specified as arrays of arrays; the following
declares an array of 5 arrays of 15 floats.
::
@@ -1860,6 +1862,27 @@ that functions can be declared to take "unsized arrays" as parameters:
void foo(float array[], int length);
Finally, the name of an array will be automatically implicitly converted to
a uniform pointer to the array type if needed:
::
int a[10];
int * uniform ap = a;
Struct Types
------------
Aggregate data structures can be built using ``struct``.
::
struct Foo {
float time;
int flags[10];
};
As in C++, after a ``struct`` is declared, an instance can be created using
the ``struct``'s name:
@@ -1873,6 +1896,60 @@ Alternatively, ``struct`` can be used before the structure name:
struct Foo f;
Members in a structure declaration may each have ``uniform`` or ``varying``
qualifiers, or may have no rate qualifier, in which case their variability
is initially "unbound".
::
struct Bar {
uniform int a;
varying int b;
int c;
};
In the declaration above, the variability of ``c`` is unbound. The
variability of struct members that are unbound is resolved when a struct is
defined; if the ``struct`` is ``uniform``, then unbound members are
``uniform``, and if the ``struct`` is ``varying``, then unbound members are
varying.
::
Bar vb;
uniform Bar ub;
Here, ``b`` is a ``varying Bar`` (since ``varying`` is the default
variability). If ``Bar`` is defined as above, then ``vb.a`` is still a
``uniform int``, since its varaibility was bound in the original
declaration of the ``Bar`` type. Similarly, ``vb.b`` is ``varying``. The
variability fo ``vb.c`` is ``varying``, since ``vb`` is ``varying``.
(Similarly, ``ub.a`` is ``uniform``, ``ub.b`` is ``varying``, and ``ub.c``
is ``uniform``.)
In most cases, it's worthwhile to declare ``struct`` members with unbound
variability so that all have the same variability for both ``uniform`` and
``varying`` structs. In particular, if a ``struct`` has a member with
bound ``uniform`` type, it's not possible to index into an array of the
struct type with a ``varying`` index. Consider the following example:
::
struct Foo { uniform int a; };
uniform Foo f[...] = ...;
int index = ...;
Foo fv = f[index]; // ERROR
Here, the ``Foo`` type has a member with bound ``uniform`` variability.
Because ``index`` has a different value for each program instance in the
above code, the value of ``f[index]`` needs to be able to store a different
value of ``Foo::a`` for each program instance. However, a ``varying Foo``
still has only a single ``a`` member, since ``a`` was declared with
``uniform`` variability in the declaration of ``Foo``. Therefore, the
indexing operation in the last line results in an error.
Declarations and Initializers
-----------------------------
@@ -3824,12 +3901,12 @@ equivalents of them.) For example, given a structure in ``ispc``:
// ispc code
struct Node {
uniform int count;
uniform float pos[3];
int count;
float pos[3];
};
If the ``Node`` structure is used in the parameters to an ``export`` ed
function, then the header file generated by the ``ispc`` compiler will
If a ``uniform Node`` structure is used in the parameters to an ``export``
ed function, then the header file generated by the ``ispc`` compiler will
have a declaration like:
::
@@ -3970,7 +4047,7 @@ this:
::
export void length(Vector vectors[1024], uniform float len[]) {
export void length(uniform Vector vectors[1024], uniform float len[]) {
foreach (index = 0 ... 1024) {
float x = vectors[index].x;
float y = vectors[index].y;
@@ -4038,7 +4115,7 @@ then an inner loop that peels off values from the element members:
::
#define N_VEC (1024/16)
export void length(Vector16 v[N_VEC], uniform float len[]) {
export void length(uniform Vector16 v[N_VEC], uniform float len[]) {
foreach (i = 0 ... N_VEC, j = 0 ... 16) {
float x = v[i].x[j];
float y = v[i].y[j];
@@ -4075,7 +4152,7 @@ elements to work with and then proceeds with the computation.
::
#define N_VEC (1024/4)
export void length(Vector4 v[N_VEC], uniform float len[]) {
export void length(uniform Vector4 v[N_VEC], uniform float len[]) {
for (uniform int i = 0; i < N_VEC; i += programCount / 4) {
float x, y, z;
for (uniform int j = 0; j < programCount / 4; ++j) {