Implement unbound varibility for struct types.

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

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

73
ctx.cpp
View File

@@ -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<const PointerType *>(ptrType) != NULL);
Assert(ptrType->IsVaryingType());
const Type *valueType = ptrType->GetBaseType();
// I think this should be impossible
Assert(dynamic_cast<const ArrayType *>(valueType) == NULL);
const CollectionType *collectionType = dynamic_cast<const CollectionType *>(valueType);
if (collectionType != NULL) {
const CollectionType *srcCollectionType =
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
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<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;
}
@@ -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

7
ctx.h
View File

@@ -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,

View File

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

View File

@@ -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 } };

View File

@@ -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[]

View File

@@ -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;

View File

@@ -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];

221
expr.cpp
View File

@@ -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<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 *
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<const PointerType *>(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<const ReferenceType *>(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<const StructType *>(exprType);
if (structType == NULL) {
const PointerType *pt = dynamic_cast<const PointerType *>(exprType);
if (pt != NULL)
structType = dynamic_cast<const StructType *>(pt->GetBaseType());
else {
const ReferenceType *rt =
dynamic_cast<const ReferenceType *>(exprType);
Assert(rt != NULL);
structType = dynamic_cast<const StructType *>(rt->GetReferenceTarget());
}
Assert(structType != NULL);
const Type *structType;
const ReferenceType *rt = dynamic_cast<const ReferenceType *>(type);
if (rt != NULL)
structType = rt->GetReferenceTarget();
else {
const PointerType *pt = dynamic_cast<const PointerType *>(type);
Assert(pt != NULL);
structType = pt->GetBaseType();
}
return structType;
const StructType *ret = dynamic_cast<const StructType *>(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<const StructType *>(allocType) != NULL)
// FIXME: yet another place where the "structs are varying"
// wart pops up..
childVariability = Type::Varying;
allocType = allocType->ResolveUnboundVariability(childVariability);
}
}

1
expr.h
View File

@@ -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();

View File

@@ -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<const StructType *>(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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -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);

View File

@@ -3,7 +3,7 @@ export uniform int width() { return programCount; }
struct Foo {
uniform float x;
varying float x;
uniform float f;
};

View File

@@ -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[]) {

View File

@@ -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;
}

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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];

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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]);
}

View File

@@ -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) {

View File

@@ -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; }

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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; };

View File

@@ -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];

View File

@@ -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;

View 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];
}

View 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];
}

View 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];
}

View 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];
}

View 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];
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -991,10 +991,6 @@ PointerType::ResolveUnboundVariability(Variability v) const {
Variability ptrVariability = (variability == Unbound) ? v : variability;
Variability childVariability = (ptrVariability == Varying) ?
Uniform : Varying;
if (dynamic_cast<const StructType *>(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<const StructType *>(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<const Type *> 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;
}

2
type.h
View File

@@ -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; }