From f81acbfe806c1ac7b34e62c67bfb4c2f1f07e3f2 Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Mon, 20 Feb 2012 12:20:51 -0800 Subject: [PATCH] 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. --- ctx.cpp | 73 ++++-- ctx.h | 7 +- docs/ispc.rst | 113 +++++++-- examples/aobench/ao.ispc | 11 +- examples/deferred/kernels.ispc | 50 ++-- examples/rt/rt.ispc | 49 ++-- examples/rt/rt_serial.cpp | 9 +- expr.cpp | 221 ++++++++++++------ expr.h | 1 - module.cpp | 14 +- tests/cfor-struct-gather-2.ispc | 4 +- tests/cfor-struct-gather-3.ispc | 4 +- tests/cfor-struct-gather.ispc | 2 +- tests/gather-struct-vector.ispc | 2 +- tests/masked-scatter-struct.ispc | 8 +- tests/new-delete-5.ispc | 2 +- tests/new-delete-6.ispc | 2 +- tests/ptr-22.ispc | 4 +- tests/struct-gather-2.ispc | 4 +- tests/struct-gather-3.ispc | 4 +- tests/struct-gather.ispc | 2 +- tests/struct-nested-1.ispc | 34 +++ tests/struct-nested-2.ispc | 34 +++ tests/struct-nested-3.ispc | 35 +++ tests/struct-nested-4.ispc | 35 +++ tests/struct-nested-5.ispc | 35 +++ tests/struct-ref-lvalue.ispc | 4 +- tests/struct-test-115.ispc | 2 +- tests/struct-test-116.ispc | 4 +- tests/struct-test-118.ispc | 4 +- tests/struct-test-119.ispc | 2 +- tests/struct-vary-index-expr.ispc | 3 +- tests/unif-struct-test-113.ispc | 4 +- tests/unif-struct-test-117.ispc | 3 +- tests/unif-struct-test-118.ispc | 4 +- tests/unif-struct-test-120.ispc | 9 +- tests/unif-struct-test-121.ispc | 3 +- tests/unif-struct-test-122.ispc | 2 +- tests/unif-struct-test-123.ispc | 2 +- tests/varying-struct-2.ispc | 24 +- tests/varying-struct-3.ispc | 24 +- tests/varying-struct-4.ispc | 24 +- tests/varying-struct-5.ispc | 38 +-- tests/varying-struct-6.ispc | 32 +-- tests/varying-struct.ispc | 24 +- .../assign-struct-with-const-member-2.ispc | 2 +- .../assign-struct-with-const-member.ispc | 2 +- tests_errors/deref-3.ispc | 2 +- tests_errors/new-delete-6.ispc | 2 +- tests_errors/signed-struct.ispc | 2 +- tests_errors/struct-uniform-gather-1.ispc | 7 + tests_errors/struct-uniform-gather-2.ispc | 7 + tests_errors/struct-uniform-gather-3.ispc | 7 + tests_errors/struct-uniform-gather-4.ispc | 8 + tests_errors/struct-uniform-gather-5.ispc | 8 + tests_errors/struct_type_equality.ispc | 2 +- tests_errors/unsigned-struct.ispc | 2 +- type.cpp | 42 ++-- type.h | 2 + 59 files changed, 744 insertions(+), 322 deletions(-) create mode 100644 tests/struct-nested-1.ispc create mode 100644 tests/struct-nested-2.ispc create mode 100644 tests/struct-nested-3.ispc create mode 100644 tests/struct-nested-4.ispc create mode 100644 tests/struct-nested-5.ispc create mode 100644 tests_errors/struct-uniform-gather-1.ispc create mode 100644 tests_errors/struct-uniform-gather-2.ispc create mode 100644 tests_errors/struct-uniform-gather-3.ispc create mode 100644 tests_errors/struct-uniform-gather-4.ispc create mode 100644 tests_errors/struct-uniform-gather-5.ispc diff --git a/ctx.cpp b/ctx.cpp index f8dfdf36..44f49c81 100644 --- a/ctx.cpp +++ b/ctx.cpp @@ -1169,7 +1169,7 @@ FunctionEmitContext::CurrentLanesReturned(Expr *expr, bool doCoherenceCheck) { // values from other lanes that may have executed return // statements previously. 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 *eltPtr = AddElementOffset(ptr, i, ptrType, "struct_ptr_ptr"); - const Type *eltPtrType = - PointerType::GetUniform(collectionType->GetElementType(i)); - StoreInst(eltValue, eltPtr, mask, eltPtrType); + const Type *eltType = collectionType->GetElementType(i); + const Type *eltPtrType = PointerType::GetUniform(eltType); + StoreInst(eltValue, eltPtr, mask, eltType, eltPtrType); } return; } @@ -2391,25 +2391,61 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr, */ void 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(ptrType) != NULL); Assert(ptrType->IsVaryingType()); - const Type *valueType = ptrType->GetBaseType(); - // I think this should be impossible Assert(dynamic_cast(valueType) == NULL); - const CollectionType *collectionType = dynamic_cast(valueType); - if (collectionType != NULL) { + const CollectionType *srcCollectionType = + dynamic_cast(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(ptrType->GetBaseType()); + Assert(dstCollectionType != NULL); + // Scatter the collection elements individually - for (int i = 0; i < collectionType->GetElementCount(); ++i) { - llvm::Value *eltPtr = AddElementOffset(ptr, i, ptrType); + for (int i = 0; i < srcCollectionType->GetElementCount(); ++i) { + // First, get the values for the current element out of the + // source. llvm::Value *eltValue = ExtractInst(value, i); - const Type *eltPtrType = - PointerType::GetVarying(collectionType->GetElementType(i)); - eltPtr = addVaryingOffsetsIfNeeded(eltPtr, eltPtrType); - scatter(eltValue, eltPtr, eltPtrType, mask); + const Type *srcEltType = srcCollectionType->GetElementType(i); + + // We may be scattering a uniform atomic element; in this case + // we'll smear it out to be varying before making the recursive + // scatter() call below. + if (srcEltType->IsUniformType() && + dynamic_cast(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; } @@ -2483,7 +2519,8 @@ FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr) { void 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) { // may happen due to error elsewhere Assert(m->errorCount > 0); @@ -2509,7 +2546,7 @@ FunctionEmitContext::StoreInst(llvm::Value *value, llvm::Value *ptr, Assert(ptrType->IsVaryingType()); // We have a varying ptr (an array of pointers), so it's time to // 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. if (callResult != NULL) { Assert(resultPtr != NULL); - StoreInst(callResult, resultPtr, callMask, + StoreInst(callResult, resultPtr, callMask, returnType, PointerType::GetUniform(returnType)); } else diff --git a/ctx.h b/ctx.h index 97e7f08e..529cf4d7 100644 --- a/ctx.h +++ b/ctx.h @@ -443,7 +443,8 @@ public: varying, the given storeMask is used to mask the stores so that they only execute for the active program instances. */ 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 the location pointed to by dest. (src and dest must not be @@ -652,8 +653,8 @@ private: CFInfo *popCFState(); - void scatter(llvm::Value *value, llvm::Value *ptr, const Type *ptrType, - llvm::Value *mask); + void scatter(llvm::Value *value, llvm::Value *ptr, const Type *valueType, + const Type *ptrType, llvm::Value *mask); void maskedStore(llvm::Value *value, llvm::Value *ptr, const Type *ptrType, llvm::Value *mask); llvm::Value *gather(llvm::Value *ptr, const Type *ptrType, llvm::Value *mask, diff --git a/docs/ispc.rst b/docs/ispc.rst index c131497c..2dc59437 100644 --- a/docs/ispc.rst +++ b/docs/ispc.rst @@ -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) { diff --git a/examples/aobench/ao.ispc b/examples/aobench/ao.ispc index 61c2dc7d..556e4cde 100644 --- a/examples/aobench/ao.ispc +++ b/examples/aobench/ao.ispc @@ -50,7 +50,6 @@ struct Isect { struct Sphere { vec center; float radius; - }; struct Plane { @@ -83,7 +82,7 @@ static inline void vnormalize(vec &v) { 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 v = dot(ray.dir, plane.n); @@ -103,7 +102,7 @@ ray_plane_intersect(Isect &isect, Ray &ray, Plane &plane) { 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; float B = dot(rs, ray.dir); @@ -148,7 +147,7 @@ orthoBasis(vec basis[3], vec n) { static float -ambient_occlusion(Isect &isect, Plane &plane, Sphere spheres[3], +ambient_occlusion(Isect &isect, uniform Plane &plane, uniform Sphere spheres[3], RNGState &rngstate) { float eps = 0.0001f; 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, uniform int h, uniform int nsubsamples, uniform float image[]) { - static Plane plane = { { 0.0f, -0.5f, 0.0f }, { 0.f, 1.f, 0.f } }; - static Sphere spheres[3] = { + static uniform Plane plane = { { 0.0f, -0.5f, 0.0f }, { 0.f, 1.f, 0.f } }; + static uniform Sphere spheres[3] = { { { -2.0f, 0.0f, -3.5f }, 0.5f }, { { -0.5f, 0.0f, -3.0f }, 0.5f }, { { 1.0f, 0.0f, -2.2f }, 0.5f } }; diff --git a/examples/deferred/kernels.ispc b/examples/deferred/kernels.ispc index ae0542b2..ec099d88 100644 --- a/examples/deferred/kernels.ispc +++ b/examples/deferred/kernels.ispc @@ -35,35 +35,35 @@ struct InputDataArrays { - uniform float * uniform zBuffer; - uniform unsigned int16 * uniform normalEncoded_x; // half float - uniform unsigned int16 * uniform normalEncoded_y; // half float - uniform unsigned int16 * uniform specularAmount; // half float - uniform unsigned int16 * uniform specularPower; // half float - uniform unsigned int8 * uniform albedo_x; // unorm8 - uniform unsigned int8 * uniform albedo_y; // unorm8 - uniform unsigned int8 * uniform albedo_z; // unorm8 - uniform float * uniform lightPositionView_x; - uniform float * uniform lightPositionView_y; - uniform float * uniform lightPositionView_z; - uniform float * uniform lightAttenuationBegin; - uniform float * uniform lightColor_x; - uniform float * uniform lightColor_y; - uniform float * uniform lightColor_z; - uniform float * uniform lightAttenuationEnd; + uniform float *zBuffer; + uniform unsigned int16 *normalEncoded_x; // half float + uniform unsigned int16 *normalEncoded_y; // half float + uniform unsigned int16 *specularAmount; // half float + uniform unsigned int16 *specularPower; // half float + uniform unsigned int8 *albedo_x; // unorm8 + uniform unsigned int8 *albedo_y; // unorm8 + uniform unsigned int8 *albedo_z; // unorm8 + uniform float *lightPositionView_x; + uniform float *lightPositionView_y; + uniform float *lightPositionView_z; + uniform float *lightAttenuationBegin; + uniform float *lightColor_x; + uniform float *lightColor_y; + uniform float *lightColor_z; + uniform float *lightAttenuationEnd; }; struct InputHeader { - uniform float cameraProj[4][4]; - uniform float cameraNear; - uniform float cameraFar; + float cameraProj[4][4]; + float cameraNear; + float cameraFar; - uniform int32 framebufferWidth; - uniform int32 framebufferHeight; - uniform int32 numLights; - uniform int32 inputDataChunkSize; - uniform int32 inputDataArrayOffsets[idaNum]; + int32 framebufferWidth; + int32 framebufferHeight; + int32 numLights; + int32 inputDataChunkSize; + int32 inputDataArrayOffsets[idaNum]; }; @@ -575,8 +575,6 @@ SplitTileMinMax( uniform float light_positionView_z_array[], uniform float light_attenuationEnd_array[], // Outputs - // TODO: ISPC doesn't currently like multidimensionsal arrays so we'll do the - // indexing math ourselves uniform int32 subtileIndices[], uniform int32 subtileIndicesPitch, uniform int32 subtileNumLights[] diff --git a/examples/rt/rt.ispc b/examples/rt/rt.ispc index 97d63d43..490dc5c1 100644 --- a/examples/rt/rt.ispc +++ b/examples/rt/rt.ispc @@ -43,17 +43,17 @@ struct Ray { }; struct Triangle { - uniform float p[3][4]; - uniform int id; - uniform int pad[3]; + float p[3][4]; + int id; + int pad[3]; }; struct LinearBVHNode { - uniform float bounds[2][3]; - uniform unsigned int offset; // num primitives for leaf, second child for interior - uniform unsigned int8 nPrimitives; - uniform unsigned int8 splitAxis; - uniform unsigned int16 pad; + float bounds[2][3]; + unsigned int offset; // num primitives for leaf, second child for interior + unsigned int8 nPrimitives; + unsigned int8 splitAxis; + unsigned int16 pad; }; 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; camz /= camw; - ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + camera2world[0][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.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + + camera2world[0][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.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 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] }; @@ -183,8 +186,8 @@ static bool TriIntersect(const Triangle &tri, Ray &ray) { } -bool BVHIntersect(const LinearBVHNode nodes[], const Triangle tris[], - Ray &r) { +bool BVHIntersect(const uniform LinearBVHNode nodes[], + const uniform Triangle tris[], Ray &r) { Ray ray = r; bool hit = false; // Follow ray through BVH nodes to find primitive intersections @@ -193,7 +196,7 @@ bool BVHIntersect(const LinearBVHNode nodes[], const Triangle tris[], while (true) { // Check ray against BVH node - LinearBVHNode node = nodes[nodeNum]; + uniform LinearBVHNode node = nodes[nodeNum]; if (any(BBoxIntersect(node.bounds, ray))) { uniform unsigned int nPrimitives = node.nPrimitives; 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 camera2world[4][4], uniform float image[], uniform int id[], - const LinearBVHNode nodes[], - const Triangle triangles[]) { + const uniform LinearBVHNode nodes[], + const uniform Triangle triangles[]) { uniform float widthScale = (float)(baseWidth) / (float)(width); 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 camera2world[4][4], uniform float image[], uniform int id[], - const LinearBVHNode nodes[], - const Triangle triangles[]) { + const uniform LinearBVHNode nodes[], + const uniform Triangle triangles[]) { raytrace_tile(0, width, 0, height, width, height, baseWidth, baseHeight, raster2camera, camera2world, image, 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 camera2world[4][4], uniform float image[], uniform int id[], - const LinearBVHNode nodes[], - const Triangle triangles[]) { + const uniform LinearBVHNode nodes[], + const uniform Triangle triangles[]) { uniform int dx = 16, dy = 16; // must match dx, dy below uniform int xBuckets = (width + (dx-1)) / 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 camera2world[4][4], uniform float image[], uniform int id[], - const LinearBVHNode nodes[], - const Triangle triangles[]) { + const uniform LinearBVHNode nodes[], + const uniform Triangle triangles[]) { uniform int dx = 16, dy = 16; uniform int xBuckets = (width + (dx-1)) / dx; uniform int yBuckets = (height + (dy-1)) / dy; diff --git a/examples/rt/rt_serial.cpp b/examples/rt/rt_serial.cpp index cc413dea..535f25e4 100644 --- a/examples/rt/rt_serial.cpp +++ b/examples/rt/rt_serial.cpp @@ -123,9 +123,12 @@ static void generateRay(const float raster2camera[4][4], camy /= camw; camz /= camw; - ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + camera2world[0][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.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + + camera2world[0][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.y = camera2world[1][3] / camera2world[3][3]; diff --git a/expr.cpp b/expr.cpp index be69fd9b..f62d5497 100644 --- a/expr.cpp +++ b/expr.cpp @@ -509,6 +509,9 @@ TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase) { if (expr == NULL) return NULL; + Debug(expr->pos, "type convert %s -> %s.", expr->GetType()->GetString().c_str(), + toType->GetString().c_str()); + const Type *fromType = expr->GetType(); Expr *e = expr; 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. */ static void -lStoreAssignResult(llvm::Value *value, llvm::Value *ptr, const Type *ptrType, - FunctionEmitContext *ctx, Symbol *baseSym) { +lStoreAssignResult(llvm::Value *value, llvm::Value *ptr, const Type *valueType, + const Type *ptrType, FunctionEmitContext *ctx, + Symbol *baseSym) { Assert(baseSym == NULL || baseSym->varyingCFDepth <= ctx->VaryingCFDepth()); 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 // be executing at this scope or any other one before the variable // goes out of scope. - ctx->StoreInst(value, ptr, LLVMMaskAllOn, ptrType); + ctx->StoreInst(value, ptr, LLVMMaskAllOn, valueType, ptrType); } 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 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 // 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; } const Type *lvalueType = arg0->GetLValueType(); - if (lvalueType == NULL) + const Type *resultType = arg0->GetType(); + if (lvalueType == NULL || resultType == NULL) return NULL; // 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. - lStoreAssignResult(newValue, lv, lvalueType, ctx, baseSym); + lStoreAssignResult(newValue, lv, resultType, lvalueType, ctx, baseSym); return newValue; } @@ -2517,29 +2522,30 @@ AssignExpr::GetValue(FunctionEmitContext *ctx) const { switch (op) { case Assign: { - llvm::Value *lv = lvalue->GetLValue(ctx); - if (lv == NULL) { + llvm::Value *ptr = lvalue->GetLValue(ctx); + if (ptr == NULL) { Error(lvalue->pos, "Left hand side of assignment expression can't " "be assigned to."); return NULL; } - const Type *lvalueType = lvalue->GetLValueType(); - if (lvalueType == NULL) { + const Type *ptrType = lvalue->GetLValueType(); + const Type *valueType = rvalue->GetType(); + if (ptrType == NULL || valueType == NULL) { Assert(m->errorCount > 0); return NULL; } - llvm::Value *rv = rvalue->GetValue(ctx); - if (rv == NULL) { + llvm::Value *value = rvalue->GetValue(ctx); + if (value == NULL) { Assert(m->errorCount > 0); return NULL; } ctx->SetDebugPos(pos); - lStoreAssignResult(rv, lv, lvalueType, ctx, baseSym); + lStoreAssignResult(value, ptr, valueType, ptrType, ctx, baseSym); - return rv; + return value; } case MulAssign: case DivAssign: @@ -2754,7 +2760,7 @@ lEmitVaryingSelect(FunctionEmitContext *ctx, llvm::Value *test, // Use masking to conditionally store the expr1 values Assert(resultPtr->getType() == 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"); } @@ -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(type) != NULL || + dynamic_cast(type) != NULL) + return false; + + const StructType *st = dynamic_cast(type); + if (st == NULL) { + const ArrayType *at = dynamic_cast(type); + if (at != NULL) + st = dynamic_cast(at->GetElementType()); + else { + const PointerType *pt = dynamic_cast(type); + if (pt == NULL) + return false; + + st = dynamic_cast(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(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 * IndexExpr::GetValue(FunctionEmitContext *ctx) const { - const Type *baseExprType; + const Type *baseExprType, *indexType, *returnType; 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; ctx->SetDebugPos(pos); @@ -3942,6 +4018,7 @@ public: SourcePos idpos, bool derefLValue); const Type *GetType() const; + const Type *GetLValueType() const; int getElementNumber() const; const Type *getElementType() const; @@ -3960,9 +4037,17 @@ const Type * StructMemberExpr::GetType() const { // It's a struct, and the result type is the element type, possibly // promoted to varying if the struct type / lvalue is varying. - const StructType *structType = getStructType(); - if (structType == NULL) + const Type *exprType; + const StructType *structType; + if (expr == NULL || + ((exprType = expr->GetType()) == NULL) || + ((structType = getStructType()) == NULL)) { + Assert(m->errorCount > 0); return NULL; + } + + if (exprType->IsVaryingType()) + structType = structType->GetAsVaryingType(); const Type *elementType = structType->GetElementType(identifier); if (elementType == NULL) { @@ -3973,12 +4058,34 @@ StructMemberExpr::GetType() const { return NULL; } - const PointerType *pt = dynamic_cast(expr->GetType()); - if (structType->IsVaryingType() || - (pt != NULL && pt->IsVaryingType())) - return elementType->GetAsVaryingType(); - else - return elementType; + // If the expression we're getting the member of has an lvalue that is + // a varying pointer type, then the result type must be the varying + // version of the element type. + if (GetLValueType()->IsVaryingType()) + elementType = elementType->GetAsVaryingType(); + + 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(exprLValueType) != NULL) ? + PointerType::GetUniform(getElementType()) : + PointerType::GetVarying(getElementType()); } @@ -3994,6 +4101,7 @@ StructMemberExpr::getElementNumber() const { "Element name \"%s\" not present in struct type \"%s\".%s", identifier.c_str(), structType->GetString().c_str(), getCandidateNearMatches().c_str()); + return elementNumber; } @@ -4004,30 +4112,32 @@ StructMemberExpr::getElementType() const { if (structType == 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 * StructMemberExpr::getStructType() const { - const Type *exprType = expr->GetType(); - if (exprType == NULL) + const Type *type = dereferenceExpr ? expr->GetType() : + expr->GetLValueType(); + if (type == NULL) return NULL; - - const StructType *structType = dynamic_cast(exprType); - if (structType == NULL) { - const PointerType *pt = dynamic_cast(exprType); - if (pt != NULL) - structType = dynamic_cast(pt->GetBaseType()); - else { - const ReferenceType *rt = - dynamic_cast(exprType); - Assert(rt != NULL); - structType = dynamic_cast(rt->GetReferenceTarget()); - } - Assert(structType != NULL); + + const Type *structType; + const ReferenceType *rt = dynamic_cast(type); + if (rt != NULL) + structType = rt->GetReferenceTarget(); + else { + const PointerType *pt = dynamic_cast(type); + Assert(pt != NULL); + structType = pt->GetBaseType(); } - return structType; + + const StructType *ret = dynamic_cast(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 * MemberExpr::TypeCheck() { return expr ? this : NULL; @@ -6428,6 +6522,9 @@ DereferenceExpr::GetValue(FunctionEmitContext *ctx) const { if (type == NULL) return NULL; + if (lVaryingStructHasUniformMember(type, pos)) + return NULL; + Symbol *baseSym = expr->GetBaseSymbol(); llvm::Value *mask = baseSym ? lMaskForSymbol(baseSym, ctx) : ctx->GetFullMask(); @@ -7337,14 +7434,8 @@ NewExpr::NewExpr(int typeQual, const Type *t, Expr *init, Expr *count, if (allocType != NULL && allocType->HasUnboundVariability()) { Type::Variability childVariability = isVarying ? Type::Uniform : Type::Varying; - if (dynamic_cast(allocType) != NULL) - // FIXME: yet another place where the "structs are varying" - // wart pops up.. - childVariability = Type::Varying; - allocType = allocType->ResolveUnboundVariability(childVariability); } - } diff --git a/expr.h b/expr.h index 70224a7f..e0d1348c 100644 --- a/expr.h +++ b/expr.h @@ -299,7 +299,6 @@ public: llvm::Value *GetValue(FunctionEmitContext *ctx) const; llvm::Value *GetLValue(FunctionEmitContext *ctx) const; const Type *GetType() const; - const Type *GetLValueType() const; Symbol *GetBaseSymbol() const; void Print() const; Expr *Optimize(); diff --git a/module.cpp b/module.cpp index 102445cc..41a82cff 100644 --- a/module.cpp +++ b/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 - are varying. Returns true if so, false otherwise. -*/ +/** Given an arbitrary type, see if it or any of the leaf types contained + 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 lRecursiveCheckVarying(const Type *t) { t = t->GetBaseType(); - if (t->IsVaryingType()) return true; const StructType *st = dynamic_cast(t); - if (st) { + if (st != NULL) { for (int i = 0; i < st->GetElementCount(); ++i) if (lRecursiveCheckVarying(st->GetElementType(i))) return true; + return false; } - return false; + else + return t->IsVaryingType(); } diff --git a/tests/cfor-struct-gather-2.ispc b/tests/cfor-struct-gather-2.ispc index c5f5a677..7c615139 100644 --- a/tests/cfor-struct-gather-2.ispc +++ b/tests/cfor-struct-gather-2.ispc @@ -7,13 +7,13 @@ struct Foo { float f; }; -float func(uniform Foo foo[], int offset) { +float func(Foo foo[], int offset) { return foo[offset].f; } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; cfor (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/cfor-struct-gather-3.ispc b/tests/cfor-struct-gather-3.ispc index c5f5a677..7c615139 100644 --- a/tests/cfor-struct-gather-3.ispc +++ b/tests/cfor-struct-gather-3.ispc @@ -7,13 +7,13 @@ struct Foo { float f; }; -float func(uniform Foo foo[], int offset) { +float func(Foo foo[], int offset) { return foo[offset].f; } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; cfor (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/cfor-struct-gather.ispc b/tests/cfor-struct-gather.ispc index 28ac6e85..49928a6b 100644 --- a/tests/cfor-struct-gather.ispc +++ b/tests/cfor-struct-gather.ispc @@ -9,7 +9,7 @@ struct Foo { export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; cfor (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/gather-struct-vector.ispc b/tests/gather-struct-vector.ispc index d0ba704b..600f6f73 100644 --- a/tests/gather-struct-vector.ispc +++ b/tests/gather-struct-vector.ispc @@ -14,7 +14,7 @@ export void f_f(uniform float RET[], uniform float aFOO[]) { r[i].v.z = 300*i + 3*programIndex; } - Ray *rp = &r[programIndex/2]; + varying Ray *rp = &r[programIndex/2]; RET[programIndex] = rp->v.z; } diff --git a/tests/masked-scatter-struct.ispc b/tests/masked-scatter-struct.ispc index 7235b06c..bb36a60b 100644 --- a/tests/masked-scatter-struct.ispc +++ b/tests/masked-scatter-struct.ispc @@ -1,13 +1,15 @@ 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) { float a = aa[programIndex]; - Foo foo[32]; - for (uniform int i = 0; i < 32; ++i) + uniform Foo foo[32]; + for (uniform int i = 0; i < 32; ++i) { foo[i].x = i; + foo[i].y = -1234 + i; + } varying Foo fv = foo[a]; fv.x += 1000; //CO print("fv.x = %\n", fv.x); diff --git a/tests/new-delete-5.ispc b/tests/new-delete-5.ispc index ab99df2e..4fce2da7 100644 --- a/tests/new-delete-5.ispc +++ b/tests/new-delete-5.ispc @@ -2,7 +2,7 @@ export uniform int width() { return programCount; } struct Point { - uniform float x, y, z; + float x, y, z; }; export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { diff --git a/tests/new-delete-6.ispc b/tests/new-delete-6.ispc index bad82aee..1ea3f437 100644 --- a/tests/new-delete-6.ispc +++ b/tests/new-delete-6.ispc @@ -7,7 +7,7 @@ struct Point { export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { 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; delete buf; } diff --git a/tests/ptr-22.ispc b/tests/ptr-22.ispc index 0f00abec..855564b3 100644 --- a/tests/ptr-22.ispc +++ b/tests/ptr-22.ispc @@ -6,14 +6,14 @@ struct Foo { uniform float b; }; -void update(uniform Foo * varying fp) { +void update(varying Foo * varying fp) { ++fp; fp->a -= 1; fp->b = 1; } 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); RET[programIndex] = f[1].a; } diff --git a/tests/struct-gather-2.ispc b/tests/struct-gather-2.ispc index ce24aa18..cfd427b7 100644 --- a/tests/struct-gather-2.ispc +++ b/tests/struct-gather-2.ispc @@ -7,13 +7,13 @@ struct Foo { float f; }; -float func(uniform Foo foo[], int offset) { +float func(Foo foo[], int offset) { return foo[offset].f; } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; for (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/struct-gather-3.ispc b/tests/struct-gather-3.ispc index ce24aa18..cfd427b7 100644 --- a/tests/struct-gather-3.ispc +++ b/tests/struct-gather-3.ispc @@ -7,13 +7,13 @@ struct Foo { float f; }; -float func(uniform Foo foo[], int offset) { +float func(Foo foo[], int offset) { return foo[offset].f; } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; for (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/struct-gather.ispc b/tests/struct-gather.ispc index 96ecb011..efa42e1d 100644 --- a/tests/struct-gather.ispc +++ b/tests/struct-gather.ispc @@ -9,7 +9,7 @@ struct Foo { export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; uniform int i; for (i = 0; i < 17; ++i) foo[i].f = i*a; diff --git a/tests/struct-nested-1.ispc b/tests/struct-nested-1.ispc new file mode 100644 index 00000000..1496fb5b --- /dev/null +++ b/tests/struct-nested-1.ispc @@ -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; +} diff --git a/tests/struct-nested-2.ispc b/tests/struct-nested-2.ispc new file mode 100644 index 00000000..21ca0907 --- /dev/null +++ b/tests/struct-nested-2.ispc @@ -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; +} diff --git a/tests/struct-nested-3.ispc b/tests/struct-nested-3.ispc new file mode 100644 index 00000000..fe9b0d3a --- /dev/null +++ b/tests/struct-nested-3.ispc @@ -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; +} diff --git a/tests/struct-nested-4.ispc b/tests/struct-nested-4.ispc new file mode 100644 index 00000000..5c2432f8 --- /dev/null +++ b/tests/struct-nested-4.ispc @@ -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; +} diff --git a/tests/struct-nested-5.ispc b/tests/struct-nested-5.ispc new file mode 100644 index 00000000..9e00167d --- /dev/null +++ b/tests/struct-nested-5.ispc @@ -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; +} diff --git a/tests/struct-ref-lvalue.ispc b/tests/struct-ref-lvalue.ispc index cab05f25..535a1a0f 100644 --- a/tests/struct-ref-lvalue.ispc +++ b/tests/struct-ref-lvalue.ispc @@ -5,13 +5,13 @@ export uniform int width() { return programCount; } struct Foo { float f; }; -void f(uniform Foo foo[], float a) { +void f(Foo foo[], float a) { ++foo[a].f; } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; for (uniform int i = 0; i < 17; ++i) foo[i].f = a; f(foo, a); diff --git a/tests/struct-test-115.ispc b/tests/struct-test-115.ispc index ee0d9229..4f2f4f9e 100644 --- a/tests/struct-test-115.ispc +++ b/tests/struct-test-115.ispc @@ -3,7 +3,7 @@ export uniform int width() { return programCount; } struct Foo { - uniform float x; + varying float x; uniform float f; }; diff --git a/tests/struct-test-116.ispc b/tests/struct-test-116.ispc index 33357c0b..fcbc9360 100644 --- a/tests/struct-test-116.ispc +++ b/tests/struct-test-116.ispc @@ -3,8 +3,8 @@ export uniform int width() { return programCount; } struct Foo { - uniform float x; - uniform float f; + float x; + float f; }; export void f_fi(uniform float RET[], uniform float aFOO[], uniform int bFOO[]) { diff --git a/tests/struct-test-118.ispc b/tests/struct-test-118.ispc index 9fff2a38..e0d0fea7 100644 --- a/tests/struct-test-118.ispc +++ b/tests/struct-test-118.ispc @@ -9,9 +9,9 @@ struct Foo { export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { 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]; - varying Foo barFoo = myFoo[i]; + Foo barFoo = myFoo[i]; //CO print("% %\n", myFoo[i].x, barFoo.x); RET[programIndex] = barFoo.x; } diff --git a/tests/struct-test-119.ispc b/tests/struct-test-119.ispc index 1239ac4a..7e095d4e 100644 --- a/tests/struct-test-119.ispc +++ b/tests/struct-test-119.ispc @@ -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} }, { b, b, {b, b, b} }, { b, b, {b, b, b} } }; - uniform Foo barFoo; + Foo barFoo; barFoo = myFoo[0]; RET[programIndex] = barFoo.x + myFoo[1].i[2]; } diff --git a/tests/struct-vary-index-expr.ispc b/tests/struct-vary-index-expr.ispc index 11326b56..dbf8de8f 100644 --- a/tests/struct-vary-index-expr.ispc +++ b/tests/struct-vary-index-expr.ispc @@ -7,10 +7,11 @@ struct Foo { float f; }; export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform Foo foo[17]; + Foo foo[17]; for (uniform int i = 0; i < 17; ++i) foo[i].f = a; ++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 }; RET[programIndex] = foo[i[programIndex]].f; } diff --git a/tests/unif-struct-test-113.ispc b/tests/unif-struct-test-113.ispc index 4968a9c6..3b576c28 100644 --- a/tests/unif-struct-test-113.ispc +++ b/tests/unif-struct-test-113.ispc @@ -3,8 +3,8 @@ export uniform int width() { return programCount; } struct Foo { - int i; - float f; + varying int i; + varying float f; }; export void f_f(uniform float RET[], uniform float aFOO[]) { float a = aFOO[programIndex]; diff --git a/tests/unif-struct-test-117.ispc b/tests/unif-struct-test-117.ispc index c6c93122..aec05a4b 100644 --- a/tests/unif-struct-test-117.ispc +++ b/tests/unif-struct-test-117.ispc @@ -6,9 +6,10 @@ struct Foo { float x; float f; }; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform struct Foo myFoo = {a,a}; + struct Foo myFoo = {a,a}; RET[programIndex] = myFoo.x; } diff --git a/tests/unif-struct-test-118.ispc b/tests/unif-struct-test-118.ispc index e1a0c353..f92016fd 100644 --- a/tests/unif-struct-test-118.ispc +++ b/tests/unif-struct-test-118.ispc @@ -8,8 +8,8 @@ struct Foo { }; export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { float a = aFOO[programIndex]; - uniform struct Foo myFoo[3] = { { a,a}, {a,a}, {a,a} }; - uniform struct Foo barFoo; + struct Foo myFoo[3] = { { a,a}, {a,a}, {a,a} }; + struct Foo barFoo; barFoo = myFoo[1]; RET[programIndex] = barFoo.x; } diff --git a/tests/unif-struct-test-120.ispc b/tests/unif-struct-test-120.ispc index 738ae218..575b5e2e 100644 --- a/tests/unif-struct-test-120.ispc +++ b/tests/unif-struct-test-120.ispc @@ -7,12 +7,13 @@ struct Foo { float f; 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) { float a = aFOO[programIndex]; - uniform struct Foo myFoo[3] = { { a, a, {a, a, a} }, - { a, a, {a, a, a} }, - { a, a, {a, a, a} } }; + struct Foo myFoo[3] = { { a, a, {a, a, a} }, + { a, a, {a, a, a} }, + { a, a, {a, a, a} } }; RET[programIndex] = bar(myFoo[1]); } diff --git a/tests/unif-struct-test-121.ispc b/tests/unif-struct-test-121.ispc index 7d65cb0e..11e794ab 100644 --- a/tests/unif-struct-test-121.ispc +++ b/tests/unif-struct-test-121.ispc @@ -3,8 +3,9 @@ export uniform int width() { return programCount; } struct Foo { - float x; + varying float 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) { diff --git a/tests/unif-struct-test-122.ispc b/tests/unif-struct-test-122.ispc index 30e056b1..afe59983 100644 --- a/tests/unif-struct-test-122.ispc +++ b/tests/unif-struct-test-122.ispc @@ -3,7 +3,7 @@ export uniform int width() { return programCount; } struct Foo { - float x; + varying float x; }; float bar(uniform struct Foo * uniform f) { ++((*f).x); return (*f).x; } diff --git a/tests/unif-struct-test-123.ispc b/tests/unif-struct-test-123.ispc index e9fe4acf..023fc022 100644 --- a/tests/unif-struct-test-123.ispc +++ b/tests/unif-struct-test-123.ispc @@ -3,7 +3,7 @@ export uniform int width() { return programCount; } struct Foo { - float x; + varying float x; }; void bar(uniform struct Foo * uniform f) { ++((*f).x); } export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { diff --git a/tests/varying-struct-2.ispc b/tests/varying-struct-2.ispc index c0842fbb..af64878c 100644 --- a/tests/varying-struct-2.ispc +++ b/tests/varying-struct-2.ispc @@ -2,19 +2,19 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - + +struct Foo { + float x, y; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } }; - int index = (a <= 2) ? 1 : 2; - varying Foo g = f[index]; - RET[programIndex] = g.x; -} - + float a = aFOO[programIndex]; + uniform Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } }; + int index = (a <= 2) ? 1 : 2; + varying Foo g = f[index]; + RET[programIndex] = g.x; +} + export void result(uniform float RET[]) { RET[programIndex] = 15; RET[0] = RET[1] = 10; diff --git a/tests/varying-struct-3.ispc b/tests/varying-struct-3.ispc index 9d536944..1691e855 100644 --- a/tests/varying-struct-3.ispc +++ b/tests/varying-struct-3.ispc @@ -2,19 +2,19 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - + +struct Foo { + float x, y; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } }; - int index = (a <= 2) ? 1 : 2; - varying Foo g = f[index]; - RET[programIndex] = g.x; -} - + float a = aFOO[programIndex]; + uniform Foo f[3] = { { b, b }, { 2*b, 2*b }, { 3*b, 3*b } }; + int index = (a <= 2) ? 1 : 2; + varying Foo g = f[index]; + RET[programIndex] = g.x; +} + export void result(uniform float RET[4]) { RET[programIndex] = 15; RET[0] = RET[1] = 10; diff --git a/tests/varying-struct-4.ispc b/tests/varying-struct-4.ispc index fd9d6382..f0f85f86 100644 --- a/tests/varying-struct-4.ispc +++ b/tests/varying-struct-4.ispc @@ -2,19 +2,19 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - + +struct Foo { + float x, y; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - Foo f[3] = { { b, 2*b }, { 3*b, 4*b }, { 5*b, 6*b } }; - int index = (a <= 2) ? 1 : 2; - varying Foo g = f[index]; - RET[programIndex] = g.x; -} - + float a = aFOO[programIndex]; + uniform Foo f[3] = { { b, 2*b }, { 3*b, 4*b }, { 5*b, 6*b } }; + int index = (a <= 2) ? 1 : 2; + varying Foo g = f[index]; + RET[programIndex] = g.x; +} + export void result(uniform float RET[]) { RET[programIndex] = 25; RET[0] = RET[1] = 15; diff --git a/tests/varying-struct-5.ispc b/tests/varying-struct-5.ispc index c5a74605..d51d48db 100644 --- a/tests/varying-struct-5.ispc +++ b/tests/varying-struct-5.ispc @@ -2,23 +2,23 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - -struct Bar { - uniform Foo uf; - varying Foo vf; -}; - + +struct Foo { + float x, y; +}; + +struct Bar { + uniform Foo uf; + varying Foo vf; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - // Bar bar = { { b, b }, { a, a } }; - Bar bar; - bar.uf.x = b; - bar.vf.y = a; - RET[programIndex] = bar.uf.x + bar.vf.y; -} - -export void result(uniform float RET[]) { RET[programIndex] = 6+programIndex; } + float a = aFOO[programIndex]; + // Bar bar = { { b, b }, { a, a } }; + Bar bar; + bar.uf.x = b; + bar.vf.y = a; + RET[programIndex] = bar.uf.x + bar.vf.y; +} + +export void result(uniform float RET[]) { RET[programIndex] = 6+programIndex; } diff --git a/tests/varying-struct-6.ispc b/tests/varying-struct-6.ispc index 49afc339..450e76e6 100644 --- a/tests/varying-struct-6.ispc +++ b/tests/varying-struct-6.ispc @@ -2,20 +2,20 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - -struct Bar { - uniform Foo uf; - varying Foo vf; -}; - + +struct Foo { + float x, y; +}; + +struct Bar { + uniform Foo uf; + varying Foo vf; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - Bar bar = { { b, b }, { a, a } }; - RET[programIndex] = bar.uf.x + bar.vf.y; -} - -export void result(uniform float RET[4]) { RET[programIndex] = 6+programIndex; } + float a = aFOO[programIndex]; + Bar bar = { { b, b }, { a, a } }; + RET[programIndex] = bar.uf.x + bar.vf.y; +} + +export void result(uniform float RET[4]) { RET[programIndex] = 6+programIndex; } diff --git a/tests/varying-struct.ispc b/tests/varying-struct.ispc index f32663aa..6c1ed26d 100644 --- a/tests/varying-struct.ispc +++ b/tests/varying-struct.ispc @@ -2,16 +2,16 @@ export uniform int width() { return programCount; } - -struct Foo { - uniform float x, y; -}; - + +struct Foo { + float x, y; +}; + export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - varying Foo g; - g.x = a; - RET[programIndex] = g.x; -} - -export void result(uniform float RET[]) { RET[programIndex] = 1+programIndex; } + float a = aFOO[programIndex]; + varying Foo g; + g.x = a; + RET[programIndex] = g.x; +} + +export void result(uniform float RET[]) { RET[programIndex] = 1+programIndex; } diff --git a/tests_errors/assign-struct-with-const-member-2.ispc b/tests_errors/assign-struct-with-const-member-2.ispc index 7a8bae94..cceb8a5d 100644 --- a/tests_errors/assign-struct-with-const-member-2.ispc +++ b/tests_errors/assign-struct-with-const-member-2.ispc @@ -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 { const int a; diff --git a/tests_errors/assign-struct-with-const-member.ispc b/tests_errors/assign-struct-with-const-member.ispc index af85e7f3..78f933a8 100644 --- a/tests_errors/assign-struct-with-const-member.ispc +++ b/tests_errors/assign-struct-with-const-member.ispc @@ -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 { const int a; diff --git a/tests_errors/deref-3.ispc b/tests_errors/deref-3.ispc index 8e632dfb..19d4e82d 100644 --- a/tests_errors/deref-3.ispc +++ b/tests_errors/deref-3.ispc @@ -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; }; diff --git a/tests_errors/new-delete-6.ispc b/tests_errors/new-delete-6.ispc index 250441c2..0462cbca 100644 --- a/tests_errors/new-delete-6.ispc +++ b/tests_errors/new-delete-6.ispc @@ -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) { return new int[x]; diff --git a/tests_errors/signed-struct.ispc b/tests_errors/signed-struct.ispc index 4171c518..84c4d540 100644 --- a/tests_errors/signed-struct.ispc +++ b/tests_errors/signed-struct.ispc @@ -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 { float x; diff --git a/tests_errors/struct-uniform-gather-1.ispc b/tests_errors/struct-uniform-gather-1.ispc new file mode 100644 index 00000000..72031696 --- /dev/null +++ b/tests_errors/struct-uniform-gather-1.ispc @@ -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]; +} diff --git a/tests_errors/struct-uniform-gather-2.ispc b/tests_errors/struct-uniform-gather-2.ispc new file mode 100644 index 00000000..a9dcb29b --- /dev/null +++ b/tests_errors/struct-uniform-gather-2.ispc @@ -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]; +} diff --git a/tests_errors/struct-uniform-gather-3.ispc b/tests_errors/struct-uniform-gather-3.ispc new file mode 100644 index 00000000..2c9913de --- /dev/null +++ b/tests_errors/struct-uniform-gather-3.ispc @@ -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]; +} diff --git a/tests_errors/struct-uniform-gather-4.ispc b/tests_errors/struct-uniform-gather-4.ispc new file mode 100644 index 00000000..9623f17b --- /dev/null +++ b/tests_errors/struct-uniform-gather-4.ispc @@ -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]; +} diff --git a/tests_errors/struct-uniform-gather-5.ispc b/tests_errors/struct-uniform-gather-5.ispc new file mode 100644 index 00000000..845538be --- /dev/null +++ b/tests_errors/struct-uniform-gather-5.ispc @@ -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]; +} diff --git a/tests_errors/struct_type_equality.ispc b/tests_errors/struct_type_equality.ispc index 26fe80f4..21460435 100644 --- a/tests_errors/struct_type_equality.ispc +++ b/tests_errors/struct_type_equality.ispc @@ -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 { int a; diff --git a/tests_errors/unsigned-struct.ispc b/tests_errors/unsigned-struct.ispc index 107a988b..cb02ce5a 100644 --- a/tests_errors/unsigned-struct.ispc +++ b/tests_errors/unsigned-struct.ispc @@ -1,4 +1,4 @@ -// "unsigned" qualifier is illegal with "uniform struct Foo" typ +// "unsigned" qualifier is illegal with "varying struct Foo" typ struct Foo { float x; diff --git a/type.cpp b/type.cpp index a9988f4e..bdc096fd 100644 --- a/type.cpp +++ b/type.cpp @@ -991,10 +991,6 @@ PointerType::ResolveUnboundVariability(Variability v) const { Variability ptrVariability = (variability == Unbound) ? v : variability; Variability childVariability = (ptrVariability == Varying) ? Uniform : Varying; - if (dynamic_cast(baseType)) - // struct members are varying by default.. (FIXME!!!) - childVariability = Varying; - return new PointerType(baseType->ResolveUnboundVariability(childVariability), ptrVariability, isConst); } @@ -1521,6 +1517,7 @@ SOAArrayType::GetAsUnboundVariabilityType() const { const SOAArrayType * SOAArrayType::ResolveUnboundVariability(Variability v) const { const StructType *sc = dynamic_cast(child->ResolveUnboundVariability(v)); + Assert(sc != NULL); // ??? return new SOAArrayType(sc, numElements, soaWidth); } @@ -1916,16 +1913,13 @@ StructType::GetAsUnboundVariabilityType() const { const StructType * StructType::ResolveUnboundVariability(Variability v) const { - std::vector et; - for (unsigned int i = 0; i < elementTypes.size(); ++i) - et.push_back((elementTypes[i] == NULL) ? NULL : - elementTypes[i]->ResolveUnboundVariability(v)); + Assert(v != Unbound); + // We don't resolve the members here but leave them unbound, so that if + // resolve to varying but later want to get the uniform version of this + // type, for example, then we still have the information around about + // which element types were originally unbound... - // FIXME - if (v == Varying) - v = Uniform; - - return new StructType(name, et, elementNames, elementPositions, + return new StructType(name, elementTypes, elementNames, elementPositions, isConst, (variability != Unbound) ? variability : v, pos); } @@ -2009,7 +2003,7 @@ StructType::Mangle() const { ret += "_v_"; ret += name + std::string("]<"); for (unsigned int i = 0; i < elementTypes.size(); ++i) - ret += elementTypes[i]->Mangle(); + ret += GetElementType(i)->Mangle(); ret += ">"; return ret; } @@ -2017,11 +2011,6 @@ StructType::Mangle() const { std::string StructType::GetCDeclaration(const std::string &n) const { - if (variability != Uniform) { - Assert(m->errorCount > 0); - return ""; - } - std::string ret; if (isConst) ret += "const "; ret += std::string("struct ") + name; @@ -2104,13 +2093,18 @@ StructType::GetDIType(llvm::DIDescriptor scope) const { const Type * StructType::GetElementType(int i) const { + Assert(variability != Unbound); 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]; - if (variability == Varying) - ret = ret->GetAsVaryingType(); + + // If the element has unbound variability, resolve its variability to + // the struct type's variability + if (ret->HasUnboundVariability()) { + if (variability == Varying) + ret = ret->GetAsVaryingType(); + else + ret = ret->GetAsUniformType(); + } return isConst ? ret->GetAsConstType() : ret; } diff --git a/type.h b/type.h index 5b49dead..79ff5a57 100644 --- a/type.h +++ b/type.h @@ -679,6 +679,8 @@ public: /** Returns the total number of elements in the structure. */ 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".) */ const std::string &GetStructName() const { return name; }