OP2/PyOP2 — pull request #292 by FabioLuporini (2013-12-17 12:46:32+00:00)
Title: Specialize the execution model of Device-based and Host-based backends

So far, we have adopted the same identical execution model for all backends. In particular, we assumed kernels' iteration spaces had to be hoisted out at the level of the wrapper function. This is known to have benefits for device backends (it improves parallelism/data locality in cuda and opencl), but unfortunately it worsen the performance on CPUs as it leads to redundant computation and, more in general, it prevents many optimizations from being introduced, e.g. vectorisation and register tiling.

With this pull request we propose to break this execution model. PyOP2 receives an AST and transforms it suitably for the backend on which we are executing. For example, PyOP2 could receive a kernel like the following (in the form of an AST):

```
void foo (int A[3]) {
int B[3] = {...};
#pragma pyop2 itspace
for (int i = 0; i < 3; i++)
A[i] = B[i];
}
```

PyOP2 checks the backend (this is implemented by exploiting inheritance) and traverses the AST. If the backend is CUDA, the AST will be modified such that the resulting kernel is:

```
void foo(int A[1], int i) {
A[0] = B[i];
}
```

That is, PyOP2 interprets the `#pragma pyop2 itspace` as an indication that the following loop (or block of code) is fully-parallel, i.e. all of its iterations can be executed concurrently and no race condition will occur. Note that A is not indexed anymore by the iteration variable because it is a kernel variable that depends on the iteration space itself. On the other hand, B is a local read-only variable, so it has to be accessed by means of i. The IR subsystem in PyOP2 automatically does this sort of reasoning.

If the backend belongs to the class of host backends, than the iteration space is left inside the kernel, i.e. the generated code will be:

```
void foo (int A[3]) {
int B[3] = {...};
for (int i = 0; i < 3; i++)
A[i] = B[i];
}
```

This required to change the wrapper function of host backends. Now, a buffer variable is passed in to the kernel (i.e. we are no more passing in a pointer to a single entry). Once the kernel is executed, computed entries in the buffer are "scattered" to appropriate locations.

All tests have been modified to create and pass in an AST, rather than a string of C code, to PyOP2.

This has a dependency on the pull request in FFC for the branch pyop2-ir-itspace.