biometrics / likely

A compiler intermediate representation for image recognition and heterogeneous computing.
http://www.liblikely.org
Other
78 stars 11 forks source link

Exposing Compile Time Constant Matricies #52

Closed jklontz closed 9 years ago

jklontz commented 10 years ago

This is a precursor to #20. @JordanCheney I think this is a nice feature for you to take on because a) you expressed interest in it, b) its pretty well self contained, c) it's not high on my priority list right now, and d) it should be straightforward :)

It used to be the case that expressions were lazily evaluated:

x = 2 + 2
(x); compute 2 + 2, return 4

However, it's now the case that expressions are evaluated immediately:

x = 2 + 2; x is 4
(x); return 4

This is handled by the EvaluatedExpression class, which represents a constant matrix value known at compile time (a scalar value like x is just a single-element matrix). The immediate goal is to make these matricies indexable, as discussed in #20 with the image example. Before I thought this would require patching kernelArgument, but that was before EvaluatedExpression was introduced, which is where the patch should occur (see the placeholder comments I've left in this class).

Note that there are a couple bigger picture ideas at play here:

  1. An expression is currently evaluated by compiling it into a zero-argument function and running said function. As you might imagine, this is a lot of overhead to execute what should be simple code, and we'd prefer to just run the LLVM interpreter directly on the IR to get the result instead (much faster for simple computations). I have a bug fix waiting to land in LLVM, and we'll switch over to using the interpreter when it does.
  2. EvaluatedExpression operates by embedding a hard coded pointer to the matrix in the LLVM IR. This is fine if the IR is evaluated immediately, but would of course be completely incorrect if we wanted to compile to an object file that was embedded in another program. Thus, another thing you'll need to do is check likely_offline(builder.env) and in this case copy the entire matrix data into IR instead of the hard coded pointer. I'm sure this is possible, but I don't know how.
  3. Even in the offline case, we'd still like to be able to execute any constant expressions at compile time. I think this will take some thought when we get there, as it may conflict with the previous point.
JordanCheney commented 10 years ago

Sounds good to me! Excited to play around with it

JordanCheney commented 10 years ago

Quick question- say you have a single channel 10x10 matrix image and you index into it like (index 1 3). Should this a) be an error because the matrix is not single column, b) assume a default value for column (probably 0) and return the value at that row column index, or c) return a 1x10 matrix with data equal to the third row of image?

Personally, I think c) is the most helpful solution but I'm curious about your thoughts.

jklontz commented 10 years ago

For the time being, I'd like to see d) assume row = 0, frame = 0 and index into the (potentially out of bounds) matrix. While the example I gave used indicies known at compile time, the implementation should not require this. Instead it should call builder.expression(ast) to retrieve the IR for each index value, then call builder.index(matrix, c, x, y, t) to index into the matrix.

c) is an interesting option, but I'm not at a point where I'm ready to begin reasoning about slicing. I think this will have to be a separate intrinsic function anyway.

JordanCheney commented 10 years ago

Sounds good to me!

JordanCheney commented 10 years ago

I don't believe that builder has a member called index at the moment. Is this something I need to add or am I just not looking in the right place?

jklontz commented 10 years ago

Ah, you're right. I forgot I must have inlined that code into kernelArgument::evaluateOperator. Take a look there for inspiration. There may be some shared behavior take we can factor out into the builder class.

JordanCheney commented 10 years ago

When I try and test my code in Dream with

lenna = (read "../data/misc/lenna.tiff")
index = image => (image 1 10 10 0)
(index lenna)

image is evaluated as a kernelArgument instead of as an EvaluatedExpression and an exception is thrown for to many arguments. Is there something that needs to be changed in a lookup function so that it evaluates image as an EvaluatedExpression?

jklontz commented 10 years ago

kernels are used for data-parallel operations. In this case, you are just trying to index into a single pixel, which should be expressed as:

lenna = (read "../data/misc/lenna.tiff")
(lenna 1 10 10 0)

Note that in both cases, lenna is an EvaluatedExpression, but only in my example do we use lenna as the operator.

jklontz commented 9 years ago

Closing this as partially done and partially no longer relevant.