Feldspar / feldspar-compiler

This is the compiler for the Feldspar Language.
Other
22 stars 5 forks source link

Storing non-storable types #202

Open emilaxelsson opened 9 years ago

emilaxelsson commented 9 years ago

(Copied from #144@feldspar-language.)

It is currently possible to e.g. make an array of references, but this doesn't do the right thing when generating code. The array will contain the values of the references, not the references themselves.

Example:

import qualified Prelude

import Feldspar
import Feldspar.Mutable
import Feldspar.Compiler
import Feldspar.SimpleVector

test x = runMutable $ do
    r1 <- newRef 1
    r2 <- newRef 2
    let arr :: Vector (Ref (Data Int32))
        arr = save $ indexed x $ \i -> (i<1) ? r1 $ r2
    setRef (arr ! 0) 33
    getRef $ arr ! 0

Generated code:

void test(uint32_t v0, int32_t * out)
{
  int32_t v1;
  int32_t v2;
  int32_t v7;
  struct array * e8 = NULL;

  v1 = 1;
  v2 = 2;
  e8 = initArray(e8, sizeof(int32_t), v0);
  for (uint32_t v3 = 0; v3 < v0; v3 += 1)
  {
    if ((v3 < 1))
    {
      at(int32_t,e8,v3) = v1;
    }
    else
    {
      at(int32_t,e8,v3) = v2;
    }
  }
  v7 = at(int32_t,e8,0);
  v7 = 33;
  *out = v7;
  freeArray(e8);
}

The assignment v7 = 33 doesn't update the original reference v1.

emwap commented 9 years ago

The code generator (wrongly?) assumes that references and arrays can be treated as imperative variables inside a runMutable. Obviously, that assumption does not hold when references are stored or returned outside the context.

pjonsson commented 9 years ago

Having slept on this I think the code appears fishy in more than one way. The storage in the array should be at(int32_t,e8,v3) = &v1. Are we missing a AddrOf somewhere in fromCore?

emwap commented 9 years ago

A Ref is treated as an imperative variable and not as a pointer. If you compile with

icompileWith defaultOptions{useNativeArrays = True} test

you get

void test(uint32_t v0, int32_t * out)
{
  int32_t v1;
  int32_t v2;
  int32_t v7;
  int32_t e8[4294967295] = { };

  v1 = 1;
  v2 = 2;
  for (uint32_t v3 = 0; v3 < v0; v3 += 1)
  {
    if ((v3 < 1))
    {
      e8[v3] = v1;
    }
    else
    {
      e8[v3] = v2;
    }
  }
  v7 = e8[0];
  v7 = 33;
  *out = v7;
}

The variable e8 is an array of int32_t and not int32_t*.

However, it is not straightforward to change the type. We need to be careful that references does not escape the mutable context. Maybe it is time to change Mut from IO to ST s.