terralang / terra

Terra is a low-level system programming language that is embedded in and meta-programmed by the Lua programming language.
terralang.org
Other
2.73k stars 203 forks source link

Constant Arrays #152

Open brandonbloom opened 8 years ago

brandonbloom commented 8 years ago

The documentation reads:

Terra constants represent constant values used in Terra code. For instance, if you want to create a lookup table for the sin function, you might first use Lua to calculate the values and then create a constant Terra array of floating point numbers to hold the values.

The constant function seems to work just fine for integers I've tried it on. However, I can't figure out how to make this work with arrays. I'd expect this to work:

$ terra

Terra -- A low-level counterpart to Lua

Stanford University
zdevito@stanford.edu

> x = constant(terralib.types.array(int, 3), {0,1,2})
src/terralib.lua:4440: bad argument #1 to 'cast' (invalid C type)
stack traceback:
    [C]: in function 'cast'
    src/terralib.lua:4440: in function 'constant'
    [string "stdin"]:1: in main chunk

Am I missing something?

zdevito commented 8 years ago

Here is some example code to do this. I don't remember offhand why what you wrote doesn't work:

local N = 32 local tbl = terralib.new(float[N]) for i = 1,N do tbl[i-1] = math.sin( 2 * math.pi * (i-1)/N) end

local ctable = terralib.constant(tbl)

terra sintable(a : float) : float var idx = int(a / (2 * math.pi) * N)

return ctable[idx] end

sintable:disas()

print(sintable(0)) print(sintable(math.pi/4))

On Sat, Jan 16, 2016 at 4:00 PM, Brandon Bloom notifications@github.com wrote:

The documentation reads:

Terra constants represent constant values used in Terra code. For instance, if you want to create a lookup table for the sin function, you might first use Lua to calculate the values and then create a constant Terra array of floating point numbers to hold the values.

The constant function seems to work just fine for integers I've tried it on. However, I can't figure out how to make this work with arrays. I'd expect this to work:

$ terra

Terra -- A low-level counterpart to Lua

Stanford Universityzdevito@stanford.edu

x = constant(terralib.types.array(int, 3), {0,1,2}) src/terralib.lua:4440: bad argument #1 to 'cast' (invalid C type) stack traceback: [C]: in function 'cast' src/terralib.lua:4440: in function 'constant' [string "stdin"]:1: in main chunk

Am I missing something?

— Reply to this email directly or view it on GitHub https://github.com/zdevito/terra/issues/152.

brandonbloom commented 8 years ago

Thanks! I'll leave this ticket open in case you ever want to dig in to the nature of my problem.

I've got to say, this project is fantastic. I've been writing some C, doing some gnarly text-template metaprogramming, and toying with Rust every now and again. I was able to pick up Lua in one evening and Terra the next, and was instantly productive with some pretty sophisticated metaprogramming. Thanks!

Qix- commented 6 years ago

I just wasted about 30 minutes figuring out how to make constant sized arrays of a specific base type - @brandonbloom's https://github.com/zdevito/terra/issues/152#issue-127063811 taught me terralib.types.array(base_type, num_entries) and I want to cry a little. I came here to complain a little about the inability to create such types and found this thread ._.

This is off-topic a bit, but if anyone is interested in a completely ridiculous way to create a sized array type, here you go:

local function instfor(typ)
    -- evil little C trick that translates nicely into Terra
    return (`@([&typ](nil)))
end

local function sized_array_type(base_type, num_entries)
    -- this is so ridiculous, but it works: returns `base_type[num_entries]` as a type.
    local entries = {}
    for i=1,num_entries do table.insert(entries, instfor(base_type)) end
    return (`array([entries])):gettype()
end

Terra is pretty neat (:

capr commented 5 years ago

Is there any way to make a constant array directly out of a Lua array without creating the temporary cdata buffer?

elliottslaughter commented 5 years ago

On newer versions of Terra the following should work:

> =terralib.constant(`array([{1, 2, 3}]))
constant <constant> : int32[3] = array(1, 2, 3)

This is basically making a quote with the list of elements, and passing that to terralib.constant.

capr commented 5 years ago

@elliottslaughter doesn't that still use unpack() and is thus limited to some 200 args? I had that problem before.

elliottslaughter commented 5 years ago

Hm, that does seem to be the case. At least on my machine, the limit is 7999 args. Not sure why it's that exact value, but beyond that I get:

src/terralib.lua:2572: too many results to unpack
stack traceback:
    [C]: in function 'unpack'
    src/terralib.lua:2572: in function 'docheck'
    src/terralib.lua:3030: in function 'checkexp'
    src/terralib.lua:2557: in function 'checkexpressions'
    src/terralib.lua:2724: in function 'docheck'
    src/terralib.lua:3030: in function 'checkexp'
    src/terralib.lua:3323: in function 'typecheck'
    src/terralib.lua:1154: in function 'definequote'
    terra_array_constant.t:9: in main chunk

with the program:

function range(i, j)
  local result = terralib.newlist()
  for v = i, j do
    result:insert(v)
  end
  return result
end

print(terralib.constant(`array([range(1, 8000)])))

However, I'm guessing this is just an implementation detail. I don't see anything in the above code that would indicate that it has to be implemented with unpack. So in theory Terra could be fixed to lift this limitation.

elliottslaughter commented 4 years ago

In case anyone comes here looking for a workaround, I'm copying what @zdevito posted up earlier in the threat (cleaned up slightly for presentation):

local N = 8000
local t = terralib.new(float[N])
for i = 1,N do
  t[i-1] = i
end
local c = terralib.constant(t)

terra f(x : int)
  return c[x]
end
print(f(0))
print(f(1))
print(f(2))