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:
73
ctx.cpp
73
ctx.cpp
@@ -1169,7 +1169,7 @@ FunctionEmitContext::CurrentLanesReturned(Expr *expr, bool doCoherenceCheck) {
|
|||||||
// values from other lanes that may have executed return
|
// values from other lanes that may have executed return
|
||||||
// statements previously.
|
// statements previously.
|
||||||
StoreInst(retVal, returnValuePtr, GetInternalMask(),
|
StoreInst(retVal, returnValuePtr, GetInternalMask(),
|
||||||
PointerType::GetUniform(returnType));
|
returnType, PointerType::GetUniform(returnType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2303,9 +2303,9 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr,
|
|||||||
llvm::Value *eltValue = ExtractInst(value, i, "value_member");
|
llvm::Value *eltValue = ExtractInst(value, i, "value_member");
|
||||||
llvm::Value *eltPtr =
|
llvm::Value *eltPtr =
|
||||||
AddElementOffset(ptr, i, ptrType, "struct_ptr_ptr");
|
AddElementOffset(ptr, i, ptrType, "struct_ptr_ptr");
|
||||||
const Type *eltPtrType =
|
const Type *eltType = collectionType->GetElementType(i);
|
||||||
PointerType::GetUniform(collectionType->GetElementType(i));
|
const Type *eltPtrType = PointerType::GetUniform(eltType);
|
||||||
StoreInst(eltValue, eltPtr, mask, eltPtrType);
|
StoreInst(eltValue, eltPtr, mask, eltType, eltPtrType);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2391,25 +2391,61 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr,
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
FunctionEmitContext::scatter(llvm::Value *value, llvm::Value *ptr,
|
FunctionEmitContext::scatter(llvm::Value *value, llvm::Value *ptr,
|
||||||
const Type *ptrType, llvm::Value *mask) {
|
const Type *valueType, const Type *ptrType,
|
||||||
|
llvm::Value *mask) {
|
||||||
Assert(dynamic_cast<const PointerType *>(ptrType) != NULL);
|
Assert(dynamic_cast<const PointerType *>(ptrType) != NULL);
|
||||||
Assert(ptrType->IsVaryingType());
|
Assert(ptrType->IsVaryingType());
|
||||||
|
|
||||||
const Type *valueType = ptrType->GetBaseType();
|
|
||||||
|
|
||||||
// I think this should be impossible
|
// I think this should be impossible
|
||||||
Assert(dynamic_cast<const ArrayType *>(valueType) == NULL);
|
Assert(dynamic_cast<const ArrayType *>(valueType) == NULL);
|
||||||
|
|
||||||
const CollectionType *collectionType = dynamic_cast<const CollectionType *>(valueType);
|
const CollectionType *srcCollectionType =
|
||||||
if (collectionType != NULL) {
|
dynamic_cast<const CollectionType *>(valueType);
|
||||||
|
if (srcCollectionType != NULL) {
|
||||||
|
// We're scattering a collection type--we need to keep track of the
|
||||||
|
// source type (the type of the data values to be stored) and the
|
||||||
|
// destination type (the type of objects in memory that will be
|
||||||
|
// stored into) separately. This is necessary so that we can get
|
||||||
|
// all of the addressing calculations right if we're scattering
|
||||||
|
// from a varying struct to an array of uniform instances of the
|
||||||
|
// same struct type, versus scattering into an array of varying
|
||||||
|
// instances of the struct type, etc.
|
||||||
|
const CollectionType *dstCollectionType =
|
||||||
|
dynamic_cast<const CollectionType *>(ptrType->GetBaseType());
|
||||||
|
Assert(dstCollectionType != NULL);
|
||||||
|
|
||||||
// Scatter the collection elements individually
|
// Scatter the collection elements individually
|
||||||
for (int i = 0; i < collectionType->GetElementCount(); ++i) {
|
for (int i = 0; i < srcCollectionType->GetElementCount(); ++i) {
|
||||||
llvm::Value *eltPtr = AddElementOffset(ptr, i, ptrType);
|
// First, get the values for the current element out of the
|
||||||
|
// source.
|
||||||
llvm::Value *eltValue = ExtractInst(value, i);
|
llvm::Value *eltValue = ExtractInst(value, i);
|
||||||
const Type *eltPtrType =
|
const Type *srcEltType = srcCollectionType->GetElementType(i);
|
||||||
PointerType::GetVarying(collectionType->GetElementType(i));
|
|
||||||
eltPtr = addVaryingOffsetsIfNeeded(eltPtr, eltPtrType);
|
// We may be scattering a uniform atomic element; in this case
|
||||||
scatter(eltValue, eltPtr, eltPtrType, mask);
|
// we'll smear it out to be varying before making the recursive
|
||||||
|
// scatter() call below.
|
||||||
|
if (srcEltType->IsUniformType() &&
|
||||||
|
dynamic_cast<const AtomicType *>(srcEltType) != NULL) {
|
||||||
|
eltValue = SmearUniform(eltValue, "to_varying");
|
||||||
|
srcEltType = srcEltType->GetAsVaryingType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the (varying) pointer to the i'th element of the target
|
||||||
|
// collection
|
||||||
|
llvm::Value *eltPtr = AddElementOffset(ptr, i, ptrType);
|
||||||
|
|
||||||
|
// The destination element type may be uniform (e.g. if we're
|
||||||
|
// scattering to an array of uniform structs). Thus, we need
|
||||||
|
// to be careful about passing the correct type to
|
||||||
|
// addVaryingOffsetsIfNeeded() here.
|
||||||
|
const Type *dstEltType = dstCollectionType->GetElementType(i);
|
||||||
|
const Type *dstEltPtrType = PointerType::GetVarying(dstEltType);
|
||||||
|
eltPtr = addVaryingOffsetsIfNeeded(eltPtr, dstEltPtrType);
|
||||||
|
|
||||||
|
// And recursively scatter() until we hit an atomic or pointer
|
||||||
|
// type, at which point the actual memory operations can be
|
||||||
|
// performed...
|
||||||
|
scatter(eltValue, eltPtr, srcEltType, dstEltPtrType, mask);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2483,7 +2519,8 @@ FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr,
|
FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr,
|
||||||
llvm::Value *mask, const Type *ptrType) {
|
llvm::Value *mask, const Type *valueType,
|
||||||
|
const Type *ptrType) {
|
||||||
if (value == NULL || ptr == NULL) {
|
if (value == NULL || ptr == NULL) {
|
||||||
// may happen due to error elsewhere
|
// may happen due to error elsewhere
|
||||||
Assert(m->errorCount > 0);
|
Assert(m->errorCount > 0);
|
||||||
@@ -2509,7 +2546,7 @@ FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr,
|
|||||||
Assert(ptrType->IsVaryingType());
|
Assert(ptrType->IsVaryingType());
|
||||||
// We have a varying ptr (an array of pointers), so it's time to
|
// We have a varying ptr (an array of pointers), so it's time to
|
||||||
// scatter
|
// scatter
|
||||||
scatter(value, ptr, ptrType, GetFullMask());
|
scatter(value, ptr, valueType, ptrType, GetFullMask());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2791,7 +2828,7 @@ FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType *funcType,
|
|||||||
// accumulate the result using the call mask.
|
// accumulate the result using the call mask.
|
||||||
if (callResult != NULL) {
|
if (callResult != NULL) {
|
||||||
Assert(resultPtr != NULL);
|
Assert(resultPtr != NULL);
|
||||||
StoreInst(callResult, resultPtr, callMask,
|
StoreInst(callResult, resultPtr, callMask, returnType,
|
||||||
PointerType::GetUniform(returnType));
|
PointerType::GetUniform(returnType));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
7
ctx.h
7
ctx.h
@@ -443,7 +443,8 @@ public:
|
|||||||
varying, the given storeMask is used to mask the stores so that
|
varying, the given storeMask is used to mask the stores so that
|
||||||
they only execute for the active program instances. */
|
they only execute for the active program instances. */
|
||||||
void StoreInst(llvm::Value *value, llvm::Value *ptr,
|
void StoreInst(llvm::Value *value, llvm::Value *ptr,
|
||||||
llvm::Value *storeMask, const Type *ptrType);
|
llvm::Value *storeMask, const Type *valueType,
|
||||||
|
const Type *ptrType);
|
||||||
|
|
||||||
/** Copy count bytes of memory from the location pointed to by src to
|
/** Copy count bytes of memory from the location pointed to by src to
|
||||||
the location pointed to by dest. (src and dest must not be
|
the location pointed to by dest. (src and dest must not be
|
||||||
@@ -652,8 +653,8 @@ private:
|
|||||||
|
|
||||||
CFInfo *popCFState();
|
CFInfo *popCFState();
|
||||||
|
|
||||||
void scatter(llvm::Value *value, llvm::Value *ptr, const Type *ptrType,
|
void scatter(llvm::Value *value, llvm::Value *ptr, const Type *valueType,
|
||||||
llvm::Value *mask);
|
const Type *ptrType, llvm::Value *mask);
|
||||||
void maskedStore(llvm::Value *value, llvm::Value *ptr, const Type *ptrType,
|
void maskedStore(llvm::Value *value, llvm::Value *ptr, const Type *ptrType,
|
||||||
llvm::Value *mask);
|
llvm::Value *mask);
|
||||||
llvm::Value *gather(llvm::Value *ptr, const Type *ptrType, llvm::Value *mask,
|
llvm::Value *gather(llvm::Value *ptr, const Type *ptrType, llvm::Value *mask,
|
||||||
|
|||||||
113
docs/ispc.rst
113
docs/ispc.rst
@@ -92,7 +92,8 @@ Contents:
|
|||||||
* `Reference Types`_
|
* `Reference Types`_
|
||||||
* `Enumeration Types`_
|
* `Enumeration Types`_
|
||||||
* `Short Vector Types`_
|
* `Short Vector Types`_
|
||||||
* `Struct and Array Types`_
|
* `Array Types`_
|
||||||
|
* `Struct Types`_
|
||||||
|
|
||||||
+ `Declarations and Initializers`_
|
+ `Declarations and Initializers`_
|
||||||
+ `Expressions`_
|
+ `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
|
single value that is shared across the entire gang. (In contrast, the
|
||||||
default variability qualifier for variables in ``ispc``, ``varying``,
|
default variability qualifier for variables in ``ispc``, ``varying``,
|
||||||
represents a variable that has a distinct storage location for each program
|
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``
|
It is an error to try to assign a ``varying`` value to a ``uniform``
|
||||||
variable, though ``uniform`` values can be assigned to ``uniform``
|
variable, though ``uniform`` values can be assigned to ``uniform``
|
||||||
@@ -1832,20 +1835,19 @@ expressions:
|
|||||||
int8<2> bar = ...;
|
int8<2> bar = ...;
|
||||||
foo.yz = bar; // Error: can't assign to left-hand side of expression
|
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 a[10];
|
||||||
float time;
|
uniform int * varying b[20];
|
||||||
int flags[10];
|
|
||||||
};
|
|
||||||
|
|
||||||
Like in C, multidimensional arrays can be specified; the following declares
|
Multidimensional arrays can be specified as arrays of arrays; the following
|
||||||
an array of 5 arrays of 15 floats.
|
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);
|
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
|
As in C++, after a ``struct`` is declared, an instance can be created using
|
||||||
the ``struct``'s name:
|
the ``struct``'s name:
|
||||||
|
|
||||||
@@ -1873,6 +1896,60 @@ Alternatively, ``struct`` can be used before the structure name:
|
|||||||
|
|
||||||
struct Foo f;
|
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
|
Declarations and Initializers
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -3824,12 +3901,12 @@ equivalents of them.) For example, given a structure in ``ispc``:
|
|||||||
|
|
||||||
// ispc code
|
// ispc code
|
||||||
struct Node {
|
struct Node {
|
||||||
uniform int count;
|
int count;
|
||||||
uniform float pos[3];
|
float pos[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
If the ``Node`` structure is used in the parameters to an ``export`` ed
|
If a ``uniform Node`` structure is used in the parameters to an ``export``
|
||||||
function, then the header file generated by the ``ispc`` compiler will
|
ed function, then the header file generated by the ``ispc`` compiler will
|
||||||
have a declaration like:
|
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) {
|
foreach (index = 0 ... 1024) {
|
||||||
float x = vectors[index].x;
|
float x = vectors[index].x;
|
||||||
float y = vectors[index].y;
|
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)
|
#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) {
|
foreach (i = 0 ... N_VEC, j = 0 ... 16) {
|
||||||
float x = v[i].x[j];
|
float x = v[i].x[j];
|
||||||
float y = v[i].y[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)
|
#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) {
|
for (uniform int i = 0; i < N_VEC; i += programCount / 4) {
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
for (uniform int j = 0; j < programCount / 4; ++j) {
|
for (uniform int j = 0; j < programCount / 4; ++j) {
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ struct Isect {
|
|||||||
struct Sphere {
|
struct Sphere {
|
||||||
vec center;
|
vec center;
|
||||||
float radius;
|
float radius;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Plane {
|
struct Plane {
|
||||||
@@ -83,7 +82,7 @@ static inline void vnormalize(vec &v) {
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ray_plane_intersect(Isect &isect, Ray &ray, Plane &plane) {
|
ray_plane_intersect(Isect &isect, Ray &ray, uniform Plane &plane) {
|
||||||
float d = -dot(plane.p, plane.n);
|
float d = -dot(plane.p, plane.n);
|
||||||
float v = dot(ray.dir, plane.n);
|
float v = dot(ray.dir, plane.n);
|
||||||
|
|
||||||
@@ -103,7 +102,7 @@ ray_plane_intersect(Isect &isect, Ray &ray, Plane &plane) {
|
|||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ray_sphere_intersect(Isect &isect, Ray &ray, Sphere &sphere) {
|
ray_sphere_intersect(Isect &isect, Ray &ray, uniform Sphere &sphere) {
|
||||||
vec rs = ray.org - sphere.center;
|
vec rs = ray.org - sphere.center;
|
||||||
|
|
||||||
float B = dot(rs, ray.dir);
|
float B = dot(rs, ray.dir);
|
||||||
@@ -148,7 +147,7 @@ orthoBasis(vec basis[3], vec n) {
|
|||||||
|
|
||||||
|
|
||||||
static float
|
static float
|
||||||
ambient_occlusion(Isect &isect, Plane &plane, Sphere spheres[3],
|
ambient_occlusion(Isect &isect, uniform Plane &plane, uniform Sphere spheres[3],
|
||||||
RNGState &rngstate) {
|
RNGState &rngstate) {
|
||||||
float eps = 0.0001f;
|
float eps = 0.0001f;
|
||||||
vec p, n;
|
vec p, n;
|
||||||
@@ -204,8 +203,8 @@ ambient_occlusion(Isect &isect, Plane &plane, Sphere spheres[3],
|
|||||||
static void ao_scanlines(uniform int y0, uniform int y1, uniform int w,
|
static void ao_scanlines(uniform int y0, uniform int y1, uniform int w,
|
||||||
uniform int h, uniform int nsubsamples,
|
uniform int h, uniform int nsubsamples,
|
||||||
uniform float image[]) {
|
uniform float image[]) {
|
||||||
static Plane plane = { { 0.0f, -0.5f, 0.0f }, { 0.f, 1.f, 0.f } };
|
static uniform Plane plane = { { 0.0f, -0.5f, 0.0f }, { 0.f, 1.f, 0.f } };
|
||||||
static Sphere spheres[3] = {
|
static uniform Sphere spheres[3] = {
|
||||||
{ { -2.0f, 0.0f, -3.5f }, 0.5f },
|
{ { -2.0f, 0.0f, -3.5f }, 0.5f },
|
||||||
{ { -0.5f, 0.0f, -3.0f }, 0.5f },
|
{ { -0.5f, 0.0f, -3.0f }, 0.5f },
|
||||||
{ { 1.0f, 0.0f, -2.2f }, 0.5f } };
|
{ { 1.0f, 0.0f, -2.2f }, 0.5f } };
|
||||||
|
|||||||
@@ -35,35 +35,35 @@
|
|||||||
|
|
||||||
struct InputDataArrays
|
struct InputDataArrays
|
||||||
{
|
{
|
||||||
uniform float * uniform zBuffer;
|
uniform float *zBuffer;
|
||||||
uniform unsigned int16 * uniform normalEncoded_x; // half float
|
uniform unsigned int16 *normalEncoded_x; // half float
|
||||||
uniform unsigned int16 * uniform normalEncoded_y; // half float
|
uniform unsigned int16 *normalEncoded_y; // half float
|
||||||
uniform unsigned int16 * uniform specularAmount; // half float
|
uniform unsigned int16 *specularAmount; // half float
|
||||||
uniform unsigned int16 * uniform specularPower; // half float
|
uniform unsigned int16 *specularPower; // half float
|
||||||
uniform unsigned int8 * uniform albedo_x; // unorm8
|
uniform unsigned int8 *albedo_x; // unorm8
|
||||||
uniform unsigned int8 * uniform albedo_y; // unorm8
|
uniform unsigned int8 *albedo_y; // unorm8
|
||||||
uniform unsigned int8 * uniform albedo_z; // unorm8
|
uniform unsigned int8 *albedo_z; // unorm8
|
||||||
uniform float * uniform lightPositionView_x;
|
uniform float *lightPositionView_x;
|
||||||
uniform float * uniform lightPositionView_y;
|
uniform float *lightPositionView_y;
|
||||||
uniform float * uniform lightPositionView_z;
|
uniform float *lightPositionView_z;
|
||||||
uniform float * uniform lightAttenuationBegin;
|
uniform float *lightAttenuationBegin;
|
||||||
uniform float * uniform lightColor_x;
|
uniform float *lightColor_x;
|
||||||
uniform float * uniform lightColor_y;
|
uniform float *lightColor_y;
|
||||||
uniform float * uniform lightColor_z;
|
uniform float *lightColor_z;
|
||||||
uniform float * uniform lightAttenuationEnd;
|
uniform float *lightAttenuationEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InputHeader
|
struct InputHeader
|
||||||
{
|
{
|
||||||
uniform float cameraProj[4][4];
|
float cameraProj[4][4];
|
||||||
uniform float cameraNear;
|
float cameraNear;
|
||||||
uniform float cameraFar;
|
float cameraFar;
|
||||||
|
|
||||||
uniform int32 framebufferWidth;
|
int32 framebufferWidth;
|
||||||
uniform int32 framebufferHeight;
|
int32 framebufferHeight;
|
||||||
uniform int32 numLights;
|
int32 numLights;
|
||||||
uniform int32 inputDataChunkSize;
|
int32 inputDataChunkSize;
|
||||||
uniform int32 inputDataArrayOffsets[idaNum];
|
int32 inputDataArrayOffsets[idaNum];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -575,8 +575,6 @@ SplitTileMinMax(
|
|||||||
uniform float light_positionView_z_array[],
|
uniform float light_positionView_z_array[],
|
||||||
uniform float light_attenuationEnd_array[],
|
uniform float light_attenuationEnd_array[],
|
||||||
// Outputs
|
// Outputs
|
||||||
// TODO: ISPC doesn't currently like multidimensionsal arrays so we'll do the
|
|
||||||
// indexing math ourselves
|
|
||||||
uniform int32 subtileIndices[],
|
uniform int32 subtileIndices[],
|
||||||
uniform int32 subtileIndicesPitch,
|
uniform int32 subtileIndicesPitch,
|
||||||
uniform int32 subtileNumLights[]
|
uniform int32 subtileNumLights[]
|
||||||
|
|||||||
@@ -43,17 +43,17 @@ struct Ray {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Triangle {
|
struct Triangle {
|
||||||
uniform float p[3][4];
|
float p[3][4];
|
||||||
uniform int id;
|
int id;
|
||||||
uniform int pad[3];
|
int pad[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LinearBVHNode {
|
struct LinearBVHNode {
|
||||||
uniform float bounds[2][3];
|
float bounds[2][3];
|
||||||
uniform unsigned int offset; // num primitives for leaf, second child for interior
|
unsigned int offset; // num primitives for leaf, second child for interior
|
||||||
uniform unsigned int8 nPrimitives;
|
unsigned int8 nPrimitives;
|
||||||
uniform unsigned int8 splitAxis;
|
unsigned int8 splitAxis;
|
||||||
uniform unsigned int16 pad;
|
unsigned int16 pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline float3 Cross(const float3 v1, const float3 v2) {
|
static inline float3 Cross(const float3 v1, const float3 v2) {
|
||||||
@@ -88,9 +88,12 @@ static void generateRay(uniform const float raster2camera[4][4],
|
|||||||
camy /= camw;
|
camy /= camw;
|
||||||
camz /= camw;
|
camz /= camw;
|
||||||
|
|
||||||
ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + camera2world[0][2] * camz;
|
ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy +
|
||||||
ray.dir.y = camera2world[1][0] * camx + camera2world[1][1] * camy + camera2world[1][2] * camz;
|
camera2world[0][2] * camz;
|
||||||
ray.dir.z = camera2world[2][0] * camx + camera2world[2][1] * camy + camera2world[2][2] * camz;
|
ray.dir.y = camera2world[1][0] * camx + camera2world[1][1] * camy +
|
||||||
|
camera2world[1][2] * camz;
|
||||||
|
ray.dir.z = camera2world[2][0] * camx + camera2world[2][1] * camy +
|
||||||
|
camera2world[2][2] * camz;
|
||||||
|
|
||||||
ray.origin.x = camera2world[0][3] / camera2world[3][3];
|
ray.origin.x = camera2world[0][3] / camera2world[3][3];
|
||||||
ray.origin.y = camera2world[1][3] / camera2world[3][3];
|
ray.origin.y = camera2world[1][3] / camera2world[3][3];
|
||||||
@@ -143,7 +146,7 @@ static bool BBoxIntersect(const uniform float bounds[2][3],
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool TriIntersect(const Triangle &tri, Ray &ray) {
|
static bool TriIntersect(const uniform Triangle &tri, Ray &ray) {
|
||||||
uniform float3 p0 = { tri.p[0][0], tri.p[0][1], tri.p[0][2] };
|
uniform float3 p0 = { tri.p[0][0], tri.p[0][1], tri.p[0][2] };
|
||||||
uniform float3 p1 = { tri.p[1][0], tri.p[1][1], tri.p[1][2] };
|
uniform float3 p1 = { tri.p[1][0], tri.p[1][1], tri.p[1][2] };
|
||||||
uniform float3 p2 = { tri.p[2][0], tri.p[2][1], tri.p[2][2] };
|
uniform float3 p2 = { tri.p[2][0], tri.p[2][1], tri.p[2][2] };
|
||||||
@@ -183,8 +186,8 @@ static bool TriIntersect(const Triangle &tri, Ray &ray) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BVHIntersect(const LinearBVHNode nodes[], const Triangle tris[],
|
bool BVHIntersect(const uniform LinearBVHNode nodes[],
|
||||||
Ray &r) {
|
const uniform Triangle tris[], Ray &r) {
|
||||||
Ray ray = r;
|
Ray ray = r;
|
||||||
bool hit = false;
|
bool hit = false;
|
||||||
// Follow ray through BVH nodes to find primitive intersections
|
// Follow ray through BVH nodes to find primitive intersections
|
||||||
@@ -193,7 +196,7 @@ bool BVHIntersect(const LinearBVHNode nodes[], const Triangle tris[],
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Check ray against BVH node
|
// Check ray against BVH node
|
||||||
LinearBVHNode node = nodes[nodeNum];
|
uniform LinearBVHNode node = nodes[nodeNum];
|
||||||
if (any(BBoxIntersect(node.bounds, ray))) {
|
if (any(BBoxIntersect(node.bounds, ray))) {
|
||||||
uniform unsigned int nPrimitives = node.nPrimitives;
|
uniform unsigned int nPrimitives = node.nPrimitives;
|
||||||
if (nPrimitives > 0) {
|
if (nPrimitives > 0) {
|
||||||
@@ -239,8 +242,8 @@ static void raytrace_tile(uniform int x0, uniform int x1,
|
|||||||
const uniform float raster2camera[4][4],
|
const uniform float raster2camera[4][4],
|
||||||
const uniform float camera2world[4][4],
|
const uniform float camera2world[4][4],
|
||||||
uniform float image[], uniform int id[],
|
uniform float image[], uniform int id[],
|
||||||
const LinearBVHNode nodes[],
|
const uniform LinearBVHNode nodes[],
|
||||||
const Triangle triangles[]) {
|
const uniform Triangle triangles[]) {
|
||||||
uniform float widthScale = (float)(baseWidth) / (float)(width);
|
uniform float widthScale = (float)(baseWidth) / (float)(width);
|
||||||
uniform float heightScale = (float)(baseHeight) / (float)(height);
|
uniform float heightScale = (float)(baseHeight) / (float)(height);
|
||||||
|
|
||||||
@@ -262,8 +265,8 @@ export void raytrace_ispc(uniform int width, uniform int height,
|
|||||||
const uniform float raster2camera[4][4],
|
const uniform float raster2camera[4][4],
|
||||||
const uniform float camera2world[4][4],
|
const uniform float camera2world[4][4],
|
||||||
uniform float image[], uniform int id[],
|
uniform float image[], uniform int id[],
|
||||||
const LinearBVHNode nodes[],
|
const uniform LinearBVHNode nodes[],
|
||||||
const Triangle triangles[]) {
|
const uniform Triangle triangles[]) {
|
||||||
raytrace_tile(0, width, 0, height, width, height, baseWidth, baseHeight,
|
raytrace_tile(0, width, 0, height, width, height, baseWidth, baseHeight,
|
||||||
raster2camera, camera2world, image,
|
raster2camera, camera2world, image,
|
||||||
id, nodes, triangles);
|
id, nodes, triangles);
|
||||||
@@ -275,8 +278,8 @@ task void raytrace_tile_task(uniform int width, uniform int height,
|
|||||||
const uniform float raster2camera[4][4],
|
const uniform float raster2camera[4][4],
|
||||||
const uniform float camera2world[4][4],
|
const uniform float camera2world[4][4],
|
||||||
uniform float image[], uniform int id[],
|
uniform float image[], uniform int id[],
|
||||||
const LinearBVHNode nodes[],
|
const uniform LinearBVHNode nodes[],
|
||||||
const Triangle triangles[]) {
|
const uniform Triangle triangles[]) {
|
||||||
uniform int dx = 16, dy = 16; // must match dx, dy below
|
uniform int dx = 16, dy = 16; // must match dx, dy below
|
||||||
uniform int xBuckets = (width + (dx-1)) / dx;
|
uniform int xBuckets = (width + (dx-1)) / dx;
|
||||||
uniform int x0 = (taskIndex % xBuckets) * dx;
|
uniform int x0 = (taskIndex % xBuckets) * dx;
|
||||||
@@ -295,8 +298,8 @@ export void raytrace_ispc_tasks(uniform int width, uniform int height,
|
|||||||
const uniform float raster2camera[4][4],
|
const uniform float raster2camera[4][4],
|
||||||
const uniform float camera2world[4][4],
|
const uniform float camera2world[4][4],
|
||||||
uniform float image[], uniform int id[],
|
uniform float image[], uniform int id[],
|
||||||
const LinearBVHNode nodes[],
|
const uniform LinearBVHNode nodes[],
|
||||||
const Triangle triangles[]) {
|
const uniform Triangle triangles[]) {
|
||||||
uniform int dx = 16, dy = 16;
|
uniform int dx = 16, dy = 16;
|
||||||
uniform int xBuckets = (width + (dx-1)) / dx;
|
uniform int xBuckets = (width + (dx-1)) / dx;
|
||||||
uniform int yBuckets = (height + (dy-1)) / dy;
|
uniform int yBuckets = (height + (dy-1)) / dy;
|
||||||
|
|||||||
@@ -123,9 +123,12 @@ static void generateRay(const float raster2camera[4][4],
|
|||||||
camy /= camw;
|
camy /= camw;
|
||||||
camz /= camw;
|
camz /= camw;
|
||||||
|
|
||||||
ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + camera2world[0][2] * camz;
|
ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy +
|
||||||
ray.dir.y = camera2world[1][0] * camx + camera2world[1][1] * camy + camera2world[1][2] * camz;
|
camera2world[0][2] * camz;
|
||||||
ray.dir.z = camera2world[2][0] * camx + camera2world[2][1] * camy + camera2world[2][2] * camz;
|
ray.dir.y = camera2world[1][0] * camx + camera2world[1][1] * camy +
|
||||||
|
camera2world[1][2] * camz;
|
||||||
|
ray.dir.z = camera2world[2][0] * camx + camera2world[2][1] * camy +
|
||||||
|
camera2world[2][2] * camz;
|
||||||
|
|
||||||
ray.origin.x = camera2world[0][3] / camera2world[3][3];
|
ray.origin.x = camera2world[0][3] / camera2world[3][3];
|
||||||
ray.origin.y = camera2world[1][3] / camera2world[3][3];
|
ray.origin.y = camera2world[1][3] / camera2world[3][3];
|
||||||
|
|||||||
215
expr.cpp
215
expr.cpp
@@ -509,6 +509,9 @@ TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase) {
|
|||||||
if (expr == NULL)
|
if (expr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
Debug(expr->pos, "type convert %s -> %s.", expr->GetType()->GetString().c_str(),
|
||||||
|
toType->GetString().c_str());
|
||||||
|
|
||||||
const Type *fromType = expr->GetType();
|
const Type *fromType = expr->GetType();
|
||||||
Expr *e = expr;
|
Expr *e = expr;
|
||||||
if (lDoTypeConv(fromType, toType, &e, false, errorMsgBase,
|
if (lDoTypeConv(fromType, toType, &e, false, errorMsgBase,
|
||||||
@@ -876,8 +879,9 @@ lMaskForSymbol(Symbol *baseSym, FunctionEmitContext *ctx) {
|
|||||||
/** Store the result of an assignment to the given location.
|
/** Store the result of an assignment to the given location.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
lStoreAssignResult(llvm::Value *value, llvm::Value *ptr, const Type *ptrType,
|
lStoreAssignResult(llvm::Value *value, llvm::Value *ptr, const Type *valueType,
|
||||||
FunctionEmitContext *ctx, Symbol *baseSym) {
|
const Type *ptrType, FunctionEmitContext *ctx,
|
||||||
|
Symbol *baseSym) {
|
||||||
Assert(baseSym == NULL ||
|
Assert(baseSym == NULL ||
|
||||||
baseSym->varyingCFDepth <= ctx->VaryingCFDepth());
|
baseSym->varyingCFDepth <= ctx->VaryingCFDepth());
|
||||||
if (!g->opt.disableMaskedStoreToStore &&
|
if (!g->opt.disableMaskedStoreToStore &&
|
||||||
@@ -895,10 +899,10 @@ lStoreAssignResult(llvm::Value *value, llvm::Value *ptr, const Type *ptrType,
|
|||||||
// never be accessed, since those lanes aren't executing, and won't
|
// never be accessed, since those lanes aren't executing, and won't
|
||||||
// be executing at this scope or any other one before the variable
|
// be executing at this scope or any other one before the variable
|
||||||
// goes out of scope.
|
// goes out of scope.
|
||||||
ctx->StoreInst(value, ptr, LLVMMaskAllOn, ptrType);
|
ctx->StoreInst(value, ptr, LLVMMaskAllOn, valueType, ptrType);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ctx->StoreInst(value, ptr, lMaskForSymbol(baseSym, ctx), ptrType);
|
ctx->StoreInst(value, ptr, lMaskForSymbol(baseSym, ctx), valueType, ptrType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +968,7 @@ lEmitPrePostIncDec(UnaryExpr::Op op, Expr *expr, SourcePos pos,
|
|||||||
|
|
||||||
// And store the result out to the lvalue
|
// And store the result out to the lvalue
|
||||||
Symbol *baseSym = expr->GetBaseSymbol();
|
Symbol *baseSym = expr->GetBaseSymbol();
|
||||||
lStoreAssignResult(binop, lvalue, lvalueType, ctx, baseSym);
|
lStoreAssignResult(binop, lvalue, type, lvalueType, ctx, baseSym);
|
||||||
|
|
||||||
// And then if it's a pre increment/decrement, return the final
|
// And then if it's a pre increment/decrement, return the final
|
||||||
// computed result; otherwise return the previously-grabbed expression
|
// computed result; otherwise return the previously-grabbed expression
|
||||||
@@ -2439,7 +2443,8 @@ lEmitOpAssign(AssignExpr::Op op, Expr *arg0, Expr *arg1, const Type *type,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const Type *lvalueType = arg0->GetLValueType();
|
const Type *lvalueType = arg0->GetLValueType();
|
||||||
if (lvalueType == NULL)
|
const Type *resultType = arg0->GetType();
|
||||||
|
if (lvalueType == NULL || resultType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Get the value on the right-hand side of the assignment+operation
|
// Get the value on the right-hand side of the assignment+operation
|
||||||
@@ -2492,7 +2497,7 @@ lEmitOpAssign(AssignExpr::Op op, Expr *arg0, Expr *arg1, const Type *type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And store the result back to the lvalue.
|
// And store the result back to the lvalue.
|
||||||
lStoreAssignResult(newValue, lv, lvalueType, ctx, baseSym);
|
lStoreAssignResult(newValue, lv, resultType, lvalueType, ctx, baseSym);
|
||||||
|
|
||||||
return newValue;
|
return newValue;
|
||||||
}
|
}
|
||||||
@@ -2517,29 +2522,30 @@ AssignExpr::GetValue(FunctionEmitContext *ctx) const {
|
|||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Assign: {
|
case Assign: {
|
||||||
llvm::Value *lv = lvalue->GetLValue(ctx);
|
llvm::Value *ptr = lvalue->GetLValue(ctx);
|
||||||
if (lv == NULL) {
|
if (ptr == NULL) {
|
||||||
Error(lvalue->pos, "Left hand side of assignment expression can't "
|
Error(lvalue->pos, "Left hand side of assignment expression can't "
|
||||||
"be assigned to.");
|
"be assigned to.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const Type *lvalueType = lvalue->GetLValueType();
|
const Type *ptrType = lvalue->GetLValueType();
|
||||||
if (lvalueType == NULL) {
|
const Type *valueType = rvalue->GetType();
|
||||||
|
if (ptrType == NULL || valueType == NULL) {
|
||||||
Assert(m->errorCount > 0);
|
Assert(m->errorCount > 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *rv = rvalue->GetValue(ctx);
|
llvm::Value *value = rvalue->GetValue(ctx);
|
||||||
if (rv == NULL) {
|
if (value == NULL) {
|
||||||
Assert(m->errorCount > 0);
|
Assert(m->errorCount > 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->SetDebugPos(pos);
|
ctx->SetDebugPos(pos);
|
||||||
|
|
||||||
lStoreAssignResult(rv, lv, lvalueType, ctx, baseSym);
|
lStoreAssignResult(value, ptr, valueType, ptrType, ctx, baseSym);
|
||||||
|
|
||||||
return rv;
|
return value;
|
||||||
}
|
}
|
||||||
case MulAssign:
|
case MulAssign:
|
||||||
case DivAssign:
|
case DivAssign:
|
||||||
@@ -2754,7 +2760,7 @@ lEmitVaryingSelect(FunctionEmitContext *ctx, llvm::Value *test,
|
|||||||
// Use masking to conditionally store the expr1 values
|
// Use masking to conditionally store the expr1 values
|
||||||
Assert(resultPtr->getType() ==
|
Assert(resultPtr->getType() ==
|
||||||
PointerType::GetUniform(type)->LLVMType(g->ctx));
|
PointerType::GetUniform(type)->LLVMType(g->ctx));
|
||||||
ctx->StoreInst(expr1, resultPtr, test, PointerType::GetUniform(type));
|
ctx->StoreInst(expr1, resultPtr, test, type, PointerType::GetUniform(type));
|
||||||
return ctx->LoadInst(resultPtr, "selectexpr_final");
|
return ctx->LoadInst(resultPtr, "selectexpr_final");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3643,11 +3649,81 @@ lAddVaryingOffsetsIfNeeded(FunctionEmitContext *ctx, llvm::Value *ptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Check to see if the given type is an array of or pointer to a varying
|
||||||
|
struct type that in turn has a member with bound 'uniform' variability.
|
||||||
|
Issue an error and return true if such a member is found.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
lVaryingStructHasUniformMember(const Type *type, SourcePos pos) {
|
||||||
|
if (dynamic_cast<const VectorType *>(type) != NULL ||
|
||||||
|
dynamic_cast<const ReferenceType *>(type) != NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const StructType *st = dynamic_cast<const StructType *>(type);
|
||||||
|
if (st == NULL) {
|
||||||
|
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
|
||||||
|
if (at != NULL)
|
||||||
|
st = dynamic_cast<const StructType *>(at->GetElementType());
|
||||||
|
else {
|
||||||
|
const PointerType *pt = dynamic_cast<const PointerType *>(type);
|
||||||
|
if (pt == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
st = dynamic_cast<const StructType *>(pt->GetBaseType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->IsVaryingType() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < st->GetElementCount(); ++i) {
|
||||||
|
const Type *eltType = st->GetElementType(i);
|
||||||
|
if (eltType == NULL) {
|
||||||
|
Assert(m->errorCount > 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dynamic_cast<const StructType *>(eltType) != NULL) {
|
||||||
|
// We know that the enclosing struct is varying at this point,
|
||||||
|
// so push that down to the enclosed struct before makign the
|
||||||
|
// recursive call.
|
||||||
|
eltType = eltType->GetAsVaryingType();
|
||||||
|
if (lVaryingStructHasUniformMember(eltType, pos))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (eltType->IsUniformType()) {
|
||||||
|
Error(pos, "Gather operation is impossible due to the presence of "
|
||||||
|
"struct member \"%s\" with uniform type \"%s\" in the "
|
||||||
|
"varying struct type \"%s\".",
|
||||||
|
st->GetElementName(i).c_str(), eltType->GetString().c_str(),
|
||||||
|
st->GetString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
llvm::Value *
|
llvm::Value *
|
||||||
IndexExpr::GetValue(FunctionEmitContext *ctx) const {
|
IndexExpr::GetValue(FunctionEmitContext *ctx) const {
|
||||||
const Type *baseExprType;
|
const Type *baseExprType, *indexType, *returnType;
|
||||||
if (baseExpr == NULL || index == NULL ||
|
if (baseExpr == NULL || index == NULL ||
|
||||||
((baseExprType = baseExpr->GetType()) == NULL))
|
((baseExprType = baseExpr->GetType()) == NULL) ||
|
||||||
|
((indexType = index->GetType()) == NULL) ||
|
||||||
|
((returnType = GetType()) == NULL)) {
|
||||||
|
Assert(m->errorCount > 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is going to be a gather, make sure that the varying return
|
||||||
|
// type can represent the result (i.e. that we don't have a bound
|
||||||
|
// 'uniform' member in a varying struct...)
|
||||||
|
if (indexType->IsVaryingType() &&
|
||||||
|
lVaryingStructHasUniformMember(returnType, pos))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ctx->SetDebugPos(pos);
|
ctx->SetDebugPos(pos);
|
||||||
@@ -3942,6 +4018,7 @@ public:
|
|||||||
SourcePos idpos, bool derefLValue);
|
SourcePos idpos, bool derefLValue);
|
||||||
|
|
||||||
const Type *GetType() const;
|
const Type *GetType() const;
|
||||||
|
const Type *GetLValueType() const;
|
||||||
int getElementNumber() const;
|
int getElementNumber() const;
|
||||||
const Type *getElementType() const;
|
const Type *getElementType() const;
|
||||||
|
|
||||||
@@ -3960,9 +4037,17 @@ const Type *
|
|||||||
StructMemberExpr::GetType() const {
|
StructMemberExpr::GetType() const {
|
||||||
// It's a struct, and the result type is the element type, possibly
|
// It's a struct, and the result type is the element type, possibly
|
||||||
// promoted to varying if the struct type / lvalue is varying.
|
// promoted to varying if the struct type / lvalue is varying.
|
||||||
const StructType *structType = getStructType();
|
const Type *exprType;
|
||||||
if (structType == NULL)
|
const StructType *structType;
|
||||||
|
if (expr == NULL ||
|
||||||
|
((exprType = expr->GetType()) == NULL) ||
|
||||||
|
((structType = getStructType()) == NULL)) {
|
||||||
|
Assert(m->errorCount > 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exprType->IsVaryingType())
|
||||||
|
structType = structType->GetAsVaryingType();
|
||||||
|
|
||||||
const Type *elementType = structType->GetElementType(identifier);
|
const Type *elementType = structType->GetElementType(identifier);
|
||||||
if (elementType == NULL) {
|
if (elementType == NULL) {
|
||||||
@@ -3973,15 +4058,37 @@ StructMemberExpr::GetType() const {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PointerType *pt = dynamic_cast<const PointerType *>(expr->GetType());
|
// If the expression we're getting the member of has an lvalue that is
|
||||||
if (structType->IsVaryingType() ||
|
// a varying pointer type, then the result type must be the varying
|
||||||
(pt != NULL && pt->IsVaryingType()))
|
// version of the element type.
|
||||||
return elementType->GetAsVaryingType();
|
if (GetLValueType()->IsVaryingType())
|
||||||
else
|
elementType = elementType->GetAsVaryingType();
|
||||||
|
|
||||||
return elementType;
|
return elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Type *
|
||||||
|
StructMemberExpr::GetLValueType() const {
|
||||||
|
if (expr == NULL) {
|
||||||
|
Assert(m->errorCount > 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *exprLValueType = dereferenceExpr ? expr->GetType() :
|
||||||
|
expr->GetLValueType();
|
||||||
|
if (exprLValueType == NULL) {
|
||||||
|
Assert(m->errorCount > 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (exprLValueType->IsUniformType() ||
|
||||||
|
dynamic_cast<const ReferenceType *>(exprLValueType) != NULL) ?
|
||||||
|
PointerType::GetUniform(getElementType()) :
|
||||||
|
PointerType::GetVarying(getElementType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
StructMemberExpr::getElementNumber() const {
|
StructMemberExpr::getElementNumber() const {
|
||||||
const StructType *structType = getStructType();
|
const StructType *structType = getStructType();
|
||||||
@@ -3994,6 +4101,7 @@ StructMemberExpr::getElementNumber() const {
|
|||||||
"Element name \"%s\" not present in struct type \"%s\".%s",
|
"Element name \"%s\" not present in struct type \"%s\".%s",
|
||||||
identifier.c_str(), structType->GetString().c_str(),
|
identifier.c_str(), structType->GetString().c_str(),
|
||||||
getCandidateNearMatches().c_str());
|
getCandidateNearMatches().c_str());
|
||||||
|
|
||||||
return elementNumber;
|
return elementNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4004,30 +4112,32 @@ StructMemberExpr::getElementType() const {
|
|||||||
if (structType == NULL)
|
if (structType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return structType->GetAsUniformType()->GetElementType(identifier);
|
return structType->GetElementType(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the type of the underlying struct that we're returning a member
|
||||||
|
of. */
|
||||||
const StructType *
|
const StructType *
|
||||||
StructMemberExpr::getStructType() const {
|
StructMemberExpr::getStructType() const {
|
||||||
const Type *exprType = expr->GetType();
|
const Type *type = dereferenceExpr ? expr->GetType() :
|
||||||
if (exprType == NULL)
|
expr->GetLValueType();
|
||||||
|
if (type == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const StructType *structType = dynamic_cast<const StructType *>(exprType);
|
const Type *structType;
|
||||||
if (structType == NULL) {
|
const ReferenceType *rt = dynamic_cast<const ReferenceType *>(type);
|
||||||
const PointerType *pt = dynamic_cast<const PointerType *>(exprType);
|
if (rt != NULL)
|
||||||
if (pt != NULL)
|
structType = rt->GetReferenceTarget();
|
||||||
structType = dynamic_cast<const StructType *>(pt->GetBaseType());
|
|
||||||
else {
|
else {
|
||||||
const ReferenceType *rt =
|
const PointerType *pt = dynamic_cast<const PointerType *>(type);
|
||||||
dynamic_cast<const ReferenceType *>(exprType);
|
Assert(pt != NULL);
|
||||||
Assert(rt != NULL);
|
structType = pt->GetBaseType();
|
||||||
structType = dynamic_cast<const StructType *>(rt->GetReferenceTarget());
|
|
||||||
}
|
}
|
||||||
Assert(structType != NULL);
|
|
||||||
}
|
const StructType *ret = dynamic_cast<const StructType *>(structType);
|
||||||
return structType;
|
Assert(ret != NULL);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4370,22 +4480,6 @@ MemberExpr::GetLValue(FunctionEmitContext *ctx) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Type *
|
|
||||||
MemberExpr::GetLValueType() const {
|
|
||||||
if (expr == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
const Type *exprLValueType = dereferenceExpr ? expr->GetType() :
|
|
||||||
expr->GetLValueType();
|
|
||||||
if (exprLValueType == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return exprLValueType->IsUniformType() ?
|
|
||||||
PointerType::GetUniform(getElementType()) :
|
|
||||||
PointerType::GetVarying(getElementType());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr *
|
Expr *
|
||||||
MemberExpr::TypeCheck() {
|
MemberExpr::TypeCheck() {
|
||||||
return expr ? this : NULL;
|
return expr ? this : NULL;
|
||||||
@@ -6428,6 +6522,9 @@ DereferenceExpr::GetValue(FunctionEmitContext *ctx) const {
|
|||||||
if (type == NULL)
|
if (type == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (lVaryingStructHasUniformMember(type, pos))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
Symbol *baseSym = expr->GetBaseSymbol();
|
Symbol *baseSym = expr->GetBaseSymbol();
|
||||||
llvm::Value *mask = baseSym ? lMaskForSymbol(baseSym, ctx) :
|
llvm::Value *mask = baseSym ? lMaskForSymbol(baseSym, ctx) :
|
||||||
ctx->GetFullMask();
|
ctx->GetFullMask();
|
||||||
@@ -7337,14 +7434,8 @@ NewExpr::NewExpr(int typeQual, const Type *t, Expr *init, Expr *count,
|
|||||||
if (allocType != NULL && allocType->HasUnboundVariability()) {
|
if (allocType != NULL && allocType->HasUnboundVariability()) {
|
||||||
Type::Variability childVariability = isVarying ?
|
Type::Variability childVariability = isVarying ?
|
||||||
Type::Uniform : Type::Varying;
|
Type::Uniform : Type::Varying;
|
||||||
if (dynamic_cast<const StructType *>(allocType) != NULL)
|
|
||||||
// FIXME: yet another place where the "structs are varying"
|
|
||||||
// wart pops up..
|
|
||||||
childVariability = Type::Varying;
|
|
||||||
|
|
||||||
allocType = allocType->ResolveUnboundVariability(childVariability);
|
allocType = allocType->ResolveUnboundVariability(childVariability);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
expr.h
1
expr.h
@@ -299,7 +299,6 @@ public:
|
|||||||
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
|
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
|
||||||
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
|
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
|
||||||
const Type *GetType() const;
|
const Type *GetType() const;
|
||||||
const Type *GetLValueType() const;
|
|
||||||
Symbol *GetBaseSymbol() const;
|
Symbol *GetBaseSymbol() const;
|
||||||
void Print() const;
|
void Print() const;
|
||||||
Expr *Optimize();
|
Expr *Optimize();
|
||||||
|
|||||||
14
module.cpp
14
module.cpp
@@ -330,21 +330,23 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Given an arbitrary type, see if it or any of the types contained in it
|
/** Given an arbitrary type, see if it or any of the leaf types contained
|
||||||
are varying. Returns true if so, false otherwise.
|
in it are varying. (Note that it's fine for the original struct or a
|
||||||
*/
|
contained struct to be varying, so long as all of its members have
|
||||||
|
bound 'uniform' variability.) Returns true if so, false otherwise. */
|
||||||
static bool
|
static bool
|
||||||
lRecursiveCheckVarying(const Type *t) {
|
lRecursiveCheckVarying(const Type *t) {
|
||||||
t = t->GetBaseType();
|
t = t->GetBaseType();
|
||||||
if (t->IsVaryingType()) return true;
|
|
||||||
|
|
||||||
const StructType *st = dynamic_cast<const StructType *>(t);
|
const StructType *st = dynamic_cast<const StructType *>(t);
|
||||||
if (st) {
|
if (st != NULL) {
|
||||||
for (int i = 0; i < st->GetElementCount(); ++i)
|
for (int i = 0; i < st->GetElementCount(); ++i)
|
||||||
if (lRecursiveCheckVarying(st->GetElementType(i)))
|
if (lRecursiveCheckVarying(st->GetElementType(i)))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return t->IsVaryingType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ struct Foo {
|
|||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
float func(uniform Foo foo[], int offset) {
|
float func(Foo foo[], int offset) {
|
||||||
return foo[offset].f;
|
return foo[offset].f;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
cfor (i = 0; i < 17; ++i)
|
cfor (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ struct Foo {
|
|||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
float func(uniform Foo foo[], int offset) {
|
float func(Foo foo[], int offset) {
|
||||||
return foo[offset].f;
|
return foo[offset].f;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
cfor (i = 0; i < 17; ++i)
|
cfor (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ struct Foo {
|
|||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
cfor (i = 0; i < 17; ++i)
|
cfor (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export void f_f(uniform float RET[], uniform float aFOO[]) {
|
|||||||
r[i].v.z = 300*i + 3*programIndex;
|
r[i].v.z = 300*i + 3*programIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray *rp = &r[programIndex/2];
|
varying Ray *rp = &r[programIndex/2];
|
||||||
RET[programIndex] = rp->v.z;
|
RET[programIndex] = rp->v.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
|
||||||
export uniform int width() { return programCount; }
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
struct Foo { uniform float x; float y; };
|
struct Foo { float x; float y; };
|
||||||
|
|
||||||
export void f_fu(uniform float ret[], uniform float aa[], uniform float b) {
|
export void f_fu(uniform float ret[], uniform float aa[], uniform float b) {
|
||||||
float a = aa[programIndex];
|
float a = aa[programIndex];
|
||||||
Foo foo[32];
|
uniform Foo foo[32];
|
||||||
for (uniform int i = 0; i < 32; ++i)
|
for (uniform int i = 0; i < 32; ++i) {
|
||||||
foo[i].x = i;
|
foo[i].x = i;
|
||||||
|
foo[i].y = -1234 + i;
|
||||||
|
}
|
||||||
varying Foo fv = foo[a];
|
varying Foo fv = foo[a];
|
||||||
fv.x += 1000;
|
fv.x += 1000;
|
||||||
//CO print("fv.x = %\n", fv.x);
|
//CO print("fv.x = %\n", fv.x);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
export uniform int width() { return programCount; }
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
struct Point {
|
struct Point {
|
||||||
uniform float x, y, z;
|
float x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ struct Point {
|
|||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Point * buf = new Point(0., b, a);
|
varying Point * buf = new varying Point(0., b, a);
|
||||||
RET[programIndex] = buf->z;
|
RET[programIndex] = buf->z;
|
||||||
delete buf;
|
delete buf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ struct Foo {
|
|||||||
uniform float b;
|
uniform float b;
|
||||||
};
|
};
|
||||||
|
|
||||||
void update(uniform Foo * varying fp) {
|
void update(varying Foo * varying fp) {
|
||||||
++fp;
|
++fp;
|
||||||
fp->a -= 1;
|
fp->a -= 1;
|
||||||
fp->b = 1;
|
fp->b = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||||
uniform Foo f[2] = { { 1234, 4321 }, { aFOO[programIndex], 5 } };
|
Foo f[2] = { { 1234, 4321 }, { aFOO[programIndex], 5 } };
|
||||||
update(f);
|
update(f);
|
||||||
RET[programIndex] = f[1].a;
|
RET[programIndex] = f[1].a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ struct Foo {
|
|||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
float func(uniform Foo foo[], int offset) {
|
float func(Foo foo[], int offset) {
|
||||||
return foo[offset].f;
|
return foo[offset].f;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
for (i = 0; i < 17; ++i)
|
for (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ struct Foo {
|
|||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
float func(uniform Foo foo[], int offset) {
|
float func(Foo foo[], int offset) {
|
||||||
return foo[offset].f;
|
return foo[offset].f;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
for (i = 0; i < 17; ++i)
|
for (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ struct Foo {
|
|||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
uniform int i;
|
uniform int i;
|
||||||
for (i = 0; i < 17; ++i)
|
for (i = 0; i < 17; ++i)
|
||||||
foo[i].f = i*a;
|
foo[i].f = i*a;
|
||||||
|
|||||||
34
tests/struct-nested-1.ispc
Normal file
34
tests/struct-nested-1.ispc
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
struct Vector { float x, y, z; };
|
||||||
|
|
||||||
|
struct Ray { Vector o; float t; Vector d; };
|
||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
void init(varying Ray rays[], uniform int count, float v) {
|
||||||
|
for (uniform int i = 0; i < count; ++i) {
|
||||||
|
rays[i].o.x = programIndex;
|
||||||
|
rays[i].o.y = v;
|
||||||
|
rays[i].o.z = -1234;
|
||||||
|
rays[i].t = 42;
|
||||||
|
rays[i].d.x = 2*v;
|
||||||
|
rays[i].d.y = 3*v;
|
||||||
|
rays[i].d.z = 4*v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_dx(Ray &r) {
|
||||||
|
r.d.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
float v = aFOO[programIndex];
|
||||||
|
Ray rays[10];
|
||||||
|
init(rays, 10, v);
|
||||||
|
zero_dx(rays[b]);
|
||||||
|
RET[programIndex] = rays[5].d.x + rays[5].d.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 3 + 3*programIndex;
|
||||||
|
}
|
||||||
34
tests/struct-nested-2.ispc
Normal file
34
tests/struct-nested-2.ispc
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
struct Vector { float x, y, z; };
|
||||||
|
|
||||||
|
struct Ray { Vector o; float t; Vector d; };
|
||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
void init(uniform Ray rays[], uniform int count, float v) {
|
||||||
|
for (uniform int i = 0; i < count; ++i) {
|
||||||
|
rays[i].o.x = i;
|
||||||
|
rays[i].o.y = 2*i;
|
||||||
|
rays[i].o.z = 3*i;
|
||||||
|
rays[i].t = 4*i;
|
||||||
|
rays[i].d.x = 5*i;
|
||||||
|
rays[i].d.y = 6*i;
|
||||||
|
rays[i].d.z = 7*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_dx(Ray &r) {
|
||||||
|
r.d.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
float v = aFOO[programIndex];
|
||||||
|
uniform Ray rays[programCount+1];
|
||||||
|
init(rays, programCount+1, v);
|
||||||
|
Ray rg = rays[v];
|
||||||
|
RET[programIndex] = rg.o.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 3 + 3*programIndex;
|
||||||
|
}
|
||||||
35
tests/struct-nested-3.ispc
Normal file
35
tests/struct-nested-3.ispc
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
struct Vector { float x, y, z; };
|
||||||
|
|
||||||
|
struct Ray { Vector o; float t; Vector d; };
|
||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
void init(uniform Ray rays[], uniform int count, float v) {
|
||||||
|
for (uniform int i = 0; i < count; ++i) {
|
||||||
|
rays[i].o.x = i;
|
||||||
|
rays[i].o.y = 2*i;
|
||||||
|
rays[i].o.z = 3*i;
|
||||||
|
rays[i].t = 4*i;
|
||||||
|
rays[i].d.x = 5*i;
|
||||||
|
rays[i].d.y = 6*i;
|
||||||
|
rays[i].d.z = 7*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_dx(Ray &r) {
|
||||||
|
r.d.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
float v = aFOO[programIndex];
|
||||||
|
uniform Ray rays[programCount+1];
|
||||||
|
init(rays, programCount+1, v);
|
||||||
|
Ray rg = rays[v];
|
||||||
|
zero_dx(rg);
|
||||||
|
RET[programIndex] = rg.o.z + rg.d.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 3 + 3*programIndex;
|
||||||
|
}
|
||||||
35
tests/struct-nested-4.ispc
Normal file
35
tests/struct-nested-4.ispc
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
struct Vector { float x, y, z; };
|
||||||
|
|
||||||
|
struct Ray { Vector o; float t; Vector d; };
|
||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
void init(uniform Ray rays[], uniform int count, float v) {
|
||||||
|
for (uniform int i = 0; i < count; ++i) {
|
||||||
|
rays[i].o.x = i;
|
||||||
|
rays[i].o.y = 2*i;
|
||||||
|
rays[i].o.z = 3*i;
|
||||||
|
rays[i].t = 4*i;
|
||||||
|
rays[i].d.x = 5*i;
|
||||||
|
rays[i].d.y = 6*i;
|
||||||
|
rays[i].d.z = 7*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_dx(Ray * uniform r) {
|
||||||
|
r->d.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
float v = aFOO[programIndex];
|
||||||
|
uniform Ray rays[programCount+1];
|
||||||
|
init(rays, programCount+1, v);
|
||||||
|
Ray rg = rays[v];
|
||||||
|
zero_dx(&rg);
|
||||||
|
RET[programIndex] = rg.o.z + rg.d.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 3 + 3*programIndex;
|
||||||
|
}
|
||||||
35
tests/struct-nested-5.ispc
Normal file
35
tests/struct-nested-5.ispc
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
struct Vector { float x, y, z; };
|
||||||
|
|
||||||
|
struct Ray { Vector o; float t; Vector d; };
|
||||||
|
|
||||||
|
export uniform int width() { return programCount; }
|
||||||
|
|
||||||
|
void init(uniform Ray rays[], uniform int count, float v) {
|
||||||
|
for (uniform int i = 0; i < count; ++i) {
|
||||||
|
rays[i].o.x = i;
|
||||||
|
rays[i].o.y = 2*i;
|
||||||
|
rays[i].o.z = 3*i;
|
||||||
|
rays[i].t = 4*i;
|
||||||
|
rays[i].d.x = 5*i;
|
||||||
|
rays[i].d.y = 6*i;
|
||||||
|
rays[i].d.z = 7*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_dx(uniform Ray * r) {
|
||||||
|
r->d.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
float v = aFOO[programIndex];
|
||||||
|
uniform Ray rays[programCount+1];
|
||||||
|
init(rays, programCount+1, v);
|
||||||
|
zero_dx(&rays[v]);
|
||||||
|
Ray rg = rays[v];
|
||||||
|
RET[programIndex] = rg.o.z + rg.d.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export void result(uniform float RET[]) {
|
||||||
|
RET[programIndex] = 3 + 3*programIndex;
|
||||||
|
}
|
||||||
@@ -5,13 +5,13 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
struct Foo { float f; };
|
struct Foo { float f; };
|
||||||
|
|
||||||
void f(uniform Foo foo[], float a) {
|
void f(Foo foo[], float a) {
|
||||||
++foo[a].f;
|
++foo[a].f;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
for (uniform int i = 0; i < 17; ++i)
|
for (uniform int i = 0; i < 17; ++i)
|
||||||
foo[i].f = a;
|
foo[i].f = a;
|
||||||
f(foo, a);
|
f(foo, a);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x;
|
varying float x;
|
||||||
uniform float f;
|
uniform float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x;
|
float x;
|
||||||
uniform float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fi(uniform float RET[], uniform float aFOO[], uniform int bFOO[]) {
|
export void f_fi(uniform float RET[], uniform float aFOO[], uniform int bFOO[]) {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ struct Foo {
|
|||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo myFoo[3] = { { -1, -2 }, {a, -3}, {-4, -5} };
|
Foo myFoo[3] = { { -1, -2 }, {a, -3}, {-4, -5} };
|
||||||
int i = aFOO[0];
|
int i = aFOO[0];
|
||||||
varying Foo barFoo = myFoo[i];
|
Foo barFoo = myFoo[i];
|
||||||
//CO print("% %\n", myFoo[i].x, barFoo.x);
|
//CO print("% %\n", myFoo[i].x, barFoo.x);
|
||||||
RET[programIndex] = barFoo.x;
|
RET[programIndex] = barFoo.x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
|||||||
varying Foo myFoo[3] = { { b, b, {b, b, b} },
|
varying Foo myFoo[3] = { { b, b, {b, b, b} },
|
||||||
{ b, b, {b, b, b} },
|
{ b, b, {b, b, b} },
|
||||||
{ b, b, {b, b, b} } };
|
{ b, b, {b, b, b} } };
|
||||||
uniform Foo barFoo;
|
Foo barFoo;
|
||||||
barFoo = myFoo[0];
|
barFoo = myFoo[0];
|
||||||
RET[programIndex] = barFoo.x + myFoo[1].i[2];
|
RET[programIndex] = barFoo.x + myFoo[1].i[2];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ struct Foo { float f; };
|
|||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform Foo foo[17];
|
Foo foo[17];
|
||||||
for (uniform int i = 0; i < 17; ++i)
|
for (uniform int i = 0; i < 17; ++i)
|
||||||
foo[i].f = a;
|
foo[i].f = a;
|
||||||
++foo[a].f;
|
++foo[a].f;
|
||||||
|
assert(programCount <= 16);
|
||||||
uniform int i[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
|
uniform int i[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
|
||||||
RET[programIndex] = foo[i[programIndex]].f;
|
RET[programIndex] = foo[i[programIndex]].f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
int i;
|
varying int i;
|
||||||
float f;
|
varying float f;
|
||||||
};
|
};
|
||||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ struct Foo {
|
|||||||
float x;
|
float x;
|
||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform struct Foo myFoo = {a,a};
|
struct Foo myFoo = {a,a};
|
||||||
RET[programIndex] = myFoo.x;
|
RET[programIndex] = myFoo.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ struct Foo {
|
|||||||
};
|
};
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform struct Foo myFoo[3] = { { a,a}, {a,a}, {a,a} };
|
struct Foo myFoo[3] = { { a,a}, {a,a}, {a,a} };
|
||||||
uniform struct Foo barFoo;
|
struct Foo barFoo;
|
||||||
barFoo = myFoo[1];
|
barFoo = myFoo[1];
|
||||||
RET[programIndex] = barFoo.x;
|
RET[programIndex] = barFoo.x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ struct Foo {
|
|||||||
float f;
|
float f;
|
||||||
int i[3];
|
int i[3];
|
||||||
};
|
};
|
||||||
float bar(uniform struct Foo f) { return f.f; }
|
|
||||||
|
float bar(struct Foo f) { return f.f; }
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
uniform struct Foo myFoo[3] = { { a, a, {a, a, a} },
|
struct Foo myFoo[3] = { { a, a, {a, a, a} },
|
||||||
{ a, a, {a, a, a} },
|
{ a, a, {a, a, a} },
|
||||||
{ a, a, {a, a, a} } };
|
{ a, a, {a, a, a} } };
|
||||||
RET[programIndex] = bar(myFoo[1]);
|
RET[programIndex] = bar(myFoo[1]);
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
float x;
|
varying float x;
|
||||||
};
|
};
|
||||||
|
|
||||||
float bar(uniform struct Foo f) { ++f.x; return f.x; }
|
float bar(uniform struct Foo f) { ++f.x; return f.x; }
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
float x;
|
varying float x;
|
||||||
};
|
};
|
||||||
float bar(uniform struct Foo * uniform f) { ++((*f).x); return (*f).x; }
|
float bar(uniform struct Foo * uniform f) { ++((*f).x); return (*f).x; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
float x;
|
varying float x;
|
||||||
};
|
};
|
||||||
void bar(uniform struct Foo * uniform f) { ++((*f).x); }
|
void bar(uniform struct Foo * uniform f) { ++((*f).x); }
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } };
|
uniform Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } };
|
||||||
int index = (a <= 2) ? 1 : 2;
|
int index = (a <= 2) ? 1 : 2;
|
||||||
varying Foo g = f[index];
|
varying Foo g = f[index];
|
||||||
RET[programIndex] = g.x;
|
RET[programIndex] = g.x;
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } };
|
uniform Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } };
|
||||||
int index = (a <= 2) ? 1 : 2;
|
int index = (a <= 2) ? 1 : 2;
|
||||||
varying Foo g = f[index];
|
varying Foo g = f[index];
|
||||||
RET[programIndex] = g.x;
|
RET[programIndex] = g.x;
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
float a = aFOO[programIndex];
|
float a = aFOO[programIndex];
|
||||||
Foo f[3] = { { b, 2*b }, { 3*b, 4*b }, { 5*b, 6*b } };
|
uniform Foo f[3] = { { b, 2*b }, { 3*b, 4*b }, { 5*b, 6*b } };
|
||||||
int index = (a <= 2) ? 1 : 2;
|
int index = (a <= 2) ? 1 : 2;
|
||||||
varying Foo g = f[index];
|
varying Foo g = f[index];
|
||||||
RET[programIndex] = g.x;
|
RET[programIndex] = g.x;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bar {
|
struct Bar {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bar {
|
struct Bar {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export uniform int width() { return programCount; }
|
|||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
uniform float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Illegal to assign to type "uniform struct Bar" in type "uniform struct Foo" due to element "a" with type "const varying int32"
|
// Illegal to assign to type "varying struct Bar" in type "varying struct Foo" due to element "a" with type "const varying int32"
|
||||||
|
|
||||||
struct Bar {
|
struct Bar {
|
||||||
const int a;
|
const int a;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Illegal to assign to type "uniform struct Foo" due to element "a" with type "const varying int32"
|
// Illegal to assign to type "varying struct Foo" due to element "a" with type "const varying int32"
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
const int a;
|
const int a;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Dereference operator "->" can't be applied to non-pointer type "uniform struct Foo"
|
// Dereference operator "->" can't be applied to non-pointer type "varying struct Foo"
|
||||||
|
|
||||||
struct Foo { int x; };
|
struct Foo { int x; };
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Can't convert from type "uniform int32 * varying" to type "uniform int32 * uniform" for return
|
// Can't convert from type "uniform int32 * varying" to type "varying int32 * uniform" for return
|
||||||
|
|
||||||
int * uniform func(int x) {
|
int * uniform func(int x) {
|
||||||
return new int[x];
|
return new int[x];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// "signed" qualifier is illegal with non-integer type "uniform struct Foo"
|
// "signed" qualifier is illegal with non-integer type "varying struct Foo"
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
float x;
|
float x;
|
||||||
|
|||||||
7
tests_errors/struct-uniform-gather-1.ispc
Normal file
7
tests_errors/struct-uniform-gather-1.ispc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Gather operation is impossible due to the presence of struct member "x" with uniform type
|
||||||
|
|
||||||
|
struct Foo { uniform int x; };
|
||||||
|
|
||||||
|
void a(uniform Foo array[], int index) {
|
||||||
|
Foo v = array[index];
|
||||||
|
}
|
||||||
7
tests_errors/struct-uniform-gather-2.ispc
Normal file
7
tests_errors/struct-uniform-gather-2.ispc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Gather operation is impossible due to the presence of struct member "x" with uniform type
|
||||||
|
|
||||||
|
struct Foo { uniform int x; };
|
||||||
|
|
||||||
|
void a(uniform Foo * uniform array, int index) {
|
||||||
|
Foo v = array[index];
|
||||||
|
}
|
||||||
7
tests_errors/struct-uniform-gather-3.ispc
Normal file
7
tests_errors/struct-uniform-gather-3.ispc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Gather operation is impossible due to the presence of struct member "x" with uniform type
|
||||||
|
|
||||||
|
struct Foo { uniform int x; };
|
||||||
|
|
||||||
|
void a(uniform Foo * varying array, int index) {
|
||||||
|
Foo v = array[index];
|
||||||
|
}
|
||||||
8
tests_errors/struct-uniform-gather-4.ispc
Normal file
8
tests_errors/struct-uniform-gather-4.ispc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Gather operation is impossible due to the presence of struct member "x" with uniform type
|
||||||
|
|
||||||
|
struct Bar { uniform int x; };
|
||||||
|
struct Foo { varying Bar b; };
|
||||||
|
|
||||||
|
void a(uniform Foo * varying array, int index) {
|
||||||
|
Foo v = array[index];
|
||||||
|
}
|
||||||
8
tests_errors/struct-uniform-gather-5.ispc
Normal file
8
tests_errors/struct-uniform-gather-5.ispc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Gather operation is impossible due to the presence of struct member "x" with uniform type
|
||||||
|
|
||||||
|
struct Bar { uniform int x; };
|
||||||
|
struct Foo { Bar b; };
|
||||||
|
|
||||||
|
void a(uniform Foo * varying array, int index) {
|
||||||
|
Foo v = array[index];
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Can't convert between different struct types "uniform struct Foo" and "uniform struct Bar"
|
// Can't convert between different struct types "varying struct Foo" and "varying struct Bar"
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
int a;
|
int a;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// "unsigned" qualifier is illegal with "uniform struct Foo" typ
|
// "unsigned" qualifier is illegal with "varying struct Foo" typ
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
float x;
|
float x;
|
||||||
|
|||||||
38
type.cpp
38
type.cpp
@@ -991,10 +991,6 @@ PointerType::ResolveUnboundVariability(Variability v) const {
|
|||||||
Variability ptrVariability = (variability == Unbound) ? v : variability;
|
Variability ptrVariability = (variability == Unbound) ? v : variability;
|
||||||
Variability childVariability = (ptrVariability == Varying) ?
|
Variability childVariability = (ptrVariability == Varying) ?
|
||||||
Uniform : Varying;
|
Uniform : Varying;
|
||||||
if (dynamic_cast<const StructType *>(baseType))
|
|
||||||
// struct members are varying by default.. (FIXME!!!)
|
|
||||||
childVariability = Varying;
|
|
||||||
|
|
||||||
return new PointerType(baseType->ResolveUnboundVariability(childVariability),
|
return new PointerType(baseType->ResolveUnboundVariability(childVariability),
|
||||||
ptrVariability, isConst);
|
ptrVariability, isConst);
|
||||||
}
|
}
|
||||||
@@ -1521,6 +1517,7 @@ SOAArrayType::GetAsUnboundVariabilityType() const {
|
|||||||
const SOAArrayType *
|
const SOAArrayType *
|
||||||
SOAArrayType::ResolveUnboundVariability(Variability v) const {
|
SOAArrayType::ResolveUnboundVariability(Variability v) const {
|
||||||
const StructType *sc = dynamic_cast<const StructType *>(child->ResolveUnboundVariability(v));
|
const StructType *sc = dynamic_cast<const StructType *>(child->ResolveUnboundVariability(v));
|
||||||
|
Assert(sc != NULL); // ???
|
||||||
return new SOAArrayType(sc, numElements, soaWidth);
|
return new SOAArrayType(sc, numElements, soaWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1916,16 +1913,13 @@ StructType::GetAsUnboundVariabilityType() const {
|
|||||||
|
|
||||||
const StructType *
|
const StructType *
|
||||||
StructType::ResolveUnboundVariability(Variability v) const {
|
StructType::ResolveUnboundVariability(Variability v) const {
|
||||||
std::vector<const Type *> et;
|
Assert(v != Unbound);
|
||||||
for (unsigned int i = 0; i < elementTypes.size(); ++i)
|
// We don't resolve the members here but leave them unbound, so that if
|
||||||
et.push_back((elementTypes[i] == NULL) ? NULL :
|
// resolve to varying but later want to get the uniform version of this
|
||||||
elementTypes[i]->ResolveUnboundVariability(v));
|
// type, for example, then we still have the information around about
|
||||||
|
// which element types were originally unbound...
|
||||||
|
|
||||||
// FIXME
|
return new StructType(name, elementTypes, elementNames, elementPositions,
|
||||||
if (v == Varying)
|
|
||||||
v = Uniform;
|
|
||||||
|
|
||||||
return new StructType(name, et, elementNames, elementPositions,
|
|
||||||
isConst, (variability != Unbound) ? variability : v,
|
isConst, (variability != Unbound) ? variability : v,
|
||||||
pos);
|
pos);
|
||||||
}
|
}
|
||||||
@@ -2009,7 +2003,7 @@ StructType::Mangle() const {
|
|||||||
ret += "_v_";
|
ret += "_v_";
|
||||||
ret += name + std::string("]<");
|
ret += name + std::string("]<");
|
||||||
for (unsigned int i = 0; i < elementTypes.size(); ++i)
|
for (unsigned int i = 0; i < elementTypes.size(); ++i)
|
||||||
ret += elementTypes[i]->Mangle();
|
ret += GetElementType(i)->Mangle();
|
||||||
ret += ">";
|
ret += ">";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2017,11 +2011,6 @@ StructType::Mangle() const {
|
|||||||
|
|
||||||
std::string
|
std::string
|
||||||
StructType::GetCDeclaration(const std::string &n) const {
|
StructType::GetCDeclaration(const std::string &n) const {
|
||||||
if (variability != Uniform) {
|
|
||||||
Assert(m->errorCount > 0);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if (isConst) ret += "const ";
|
if (isConst) ret += "const ";
|
||||||
ret += std::string("struct ") + name;
|
ret += std::string("struct ") + name;
|
||||||
@@ -2104,13 +2093,18 @@ StructType::GetDIType(llvm::DIDescriptor scope) const {
|
|||||||
|
|
||||||
const Type *
|
const Type *
|
||||||
StructType::GetElementType(int i) const {
|
StructType::GetElementType(int i) const {
|
||||||
|
Assert(variability != Unbound);
|
||||||
Assert(i < (int)elementTypes.size());
|
Assert(i < (int)elementTypes.size());
|
||||||
// If the struct is uniform qualified, then each member comes out with
|
|
||||||
// the same type as in the original source file. If it's varying, then
|
|
||||||
// all members are promoted to varying.
|
|
||||||
const Type *ret = elementTypes[i];
|
const Type *ret = elementTypes[i];
|
||||||
|
|
||||||
|
// If the element has unbound variability, resolve its variability to
|
||||||
|
// the struct type's variability
|
||||||
|
if (ret->HasUnboundVariability()) {
|
||||||
if (variability == Varying)
|
if (variability == Varying)
|
||||||
ret = ret->GetAsVaryingType();
|
ret = ret->GetAsVaryingType();
|
||||||
|
else
|
||||||
|
ret = ret->GetAsUniformType();
|
||||||
|
}
|
||||||
return isConst ? ret->GetAsConstType() : ret;
|
return isConst ? ret->GetAsConstType() : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
type.h
2
type.h
@@ -679,6 +679,8 @@ public:
|
|||||||
/** Returns the total number of elements in the structure. */
|
/** Returns the total number of elements in the structure. */
|
||||||
int GetElementCount() const { return int(elementTypes.size()); }
|
int GetElementCount() const { return int(elementTypes.size()); }
|
||||||
|
|
||||||
|
SourcePos GetElementPosition(int i) const { return elementPositions[i]; }
|
||||||
|
|
||||||
/** Returns the name of the structure type. (e.g. struct Foo -> "Foo".) */
|
/** Returns the name of the structure type. (e.g. struct Foo -> "Foo".) */
|
||||||
const std::string &GetStructName() const { return name; }
|
const std::string &GetStructName() const { return name; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user