There's now a SOA variability class (in addition to uniform,
varying, and unbound variability); the SOA factor must be a
positive power of 2.
When applied to a type, the leaf elements of the type (i.e.
atomic types, pointer types, and enum types) are widened out
into arrays of the given SOA factor. For example, given
struct Point { float x, y, z; };
Then "soa<8> Point" has a memory layout of "float x[8], y[8],
z[8]".
Furthermore, array indexing syntax has been augmented so that
when indexing into arrays of SOA-variability data, the two-stage
indexing (first into the array of soa<> elements and then into
the leaf arrays of SOA data) is performed automatically.
Previously, we uniqued AtomicTypes, so that they could be compared
by pointer equality, but with forthcoming SOA variability changes,
this would become too unwieldy (lacking a more general / ubiquitous
type uniquing implementation.)
Now, if rate qualifiers aren't used to specify otherwise, varying
pointers point to uniform types by default. As before, uniform
pointers point to varying types by default.
float *foo; // varying pointer to uniform float
float * uniform foo; // uniform pointer to varying float
These defaults seem to require the least amount of explicit
uniform/varying qualifiers for most common cases, though TBD if it
would be easier to have a single rule that e.g. the pointed-to type
is always uniform by default.
As part of this, function declarations are no longer scoped (this is permitted
by the C standard, as it turns out.) So code like:
void foo() { void bar(); }
void bat() { bar(); }
Compiles correctly; the declaration of bar() in foo() is still available in the
definition of bar().
Fixes issue #129.
Now, when a type is declared without an explicit "uniform" or "varying"
qualifier, its variability is unbound; depending on the context of the
declaration, the variability is later finalized.
Currently, in almost all cases, types with unbound variability are
resolved to varying types; the one exception is typecasts like:
"(int)1"; in this case, the fact that (int) has unbound variability
carries through to the TypeCastExpr, which in turn notices that the
expression being type cast has uniform type and in turn will resolve
(int) to (uniform int).
Fixes issue #127.
Specifically, stmts and exprs are no longer responsible for first recursively
optimizing their children before doing their own optimization (this turned
out to be error-prone, with children sometimes being forgotten.) They now
are just responsible for their own optimization, when appropriate.
Allow atomic types to be initialized with single-element expression lists:
int x = { 5 };
Issue an error if a storage class is provided with a function parameter.
Issue an error if two members of a struct have the same name.
Issue an error on trying to assign to a struct with a const member, even if
the struct itself isn't const.
Issue an error if a function is redefined.
Issue an error if a function overload is declared that differs only in return
type from a previously-declared function.
Issue an error if "inline" or "task" qualifiers are used outside of function
declarations.
Allow trailing ',' at the end of enumerator lists.
Multiple tests for all of the above.
Pointers can be either uniform or varying, and behave correspondingly.
e.g.: "uniform float * varying" is a varying pointer to uniform float
data in memory, and "float * uniform" is a uniform pointer to varying
data in memory. Like other types, pointers are varying by default.
Pointer-based expressions, & and *, sizeof, ->, pointer arithmetic,
and the array/pointer duality all bahave as in C. Array arguments
to functions are converted to pointers, also like C.
There is a built-in NULL for a null pointer value; conversion from
compile-time constant 0 values to NULL still needs to be implemented.
Other changes:
- Syntax for references has been updated to be C++ style; a useful
warning is now issued if the "reference" keyword is used.
- It is now illegal to pass a varying lvalue as a reference parameter
to a function; references are essentially uniform pointers.
This case had previously been handled via special case call by value
return code. That path has been removed, now that varying pointers
are available to handle this use case (and much more).
- Some stdlib routines have been updated to take pointers as
arguments where appropriate (e.g. prefetch and the atomics).
A number of others still need attention.
- All of the examples have been updated
- Many new tests
TODO: documentation
Added support for resolving dimensions of multi-dimensional unsized arrays
from their initializer exprerssions (previously, only the first dimension
would be resolved.)
Added checks to make sure that no unsized array dimensions remain after
doing this (except for the first dimensision of array parameters to
functions.)
Substantial improvements and generalizations to the parsing and
declaration handling code to properly parse declarations involving
pointers. (No change to user-visible functionality, but this
lays groundwork for supporting a more general pointer model.)
Both uniform and varying function pointers are supported; when a function
is called through a varying function pointer, each unique function pointer
value across the running program instances is called once for the set of
active program instances that want to call it.
The stuff in decl.h/decl.cpp is messy, largely due to its close mapping
to C-style variable declarations. This checkin has updated code throughout
all of the declaration statement, variable, and function code that operates
on symbols and types directly. Thus, Decl* related stuff is now localized
to decl.h/decl.cpp and the parser.
Issue #13.