New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible workaround for unsupported nested structs #993

Open
rossant opened this Issue Feb 15, 2015 · 9 comments

Comments

Projects
None yet
3 participants
@rossant

rossant commented Feb 15, 2015

I'm playing around with Numba and emscripten, taking the LLVM IR code generated by Numba on a function in nopython mode, and translating it to JavaScript with emscripten. I've run into an issue. PNaCl, which emscripten relies on, has a problem with nested structs. The error message is:

LLVM ERROR: ExpandStructRegs does not handle nested structs

This is a problem when working with NumPy arrays, because AFAIU, an array is stored in a struct like { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }. The shape and strides are contained in an array within a struct, which makes emscripten unhappy.

I can get around the issue by manually editing the LLVM IR, replacing e.g.:

  %agg6.fca.5.0.extract = extractvalue { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %agg6, 5, 0

by

  %agg6.fca.5.extract = extractvalue { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %agg6, 5
  %agg6.fca.5.0.extract = extractvalue [1 x i64] %agg6.fca.5.extract, 0

This is equivalent to the original statement, but it makes emscripten happier.

Until the bug is fixed in PNaCl, what should I tweak in Numba's LLVM code generation to implement this change?

@gmarkall

This comment has been minimized.

Show comment
Hide comment
@gmarkall

gmarkall Feb 16, 2015

Contributor

That particular pattern seems to be generated as part of an optimisation pass, rather than anything emitted explicitly by Numba - if you run with NUMBA_DEBUG=1 you can confirm if this is the case for your particular code by comparing the "LLVM DUMP" and "OPTIMIZED DUMP" sections of the output. If this turns out not to be the case and Numba is emitting that code directly, if you could provide a sample of the source code you're using that would help to work out the necessary changes.

One possible workaround is to set NUMBA_OPT=0 in order to prevent optimisation occurring.

At a guess, I think the instruction combining pass might be responsible for making this transformation - I'm not sure if there are ways to switch on and off specific passes from within Numba, but someone else may be able to shed more light on this.

Contributor

gmarkall commented Feb 16, 2015

That particular pattern seems to be generated as part of an optimisation pass, rather than anything emitted explicitly by Numba - if you run with NUMBA_DEBUG=1 you can confirm if this is the case for your particular code by comparing the "LLVM DUMP" and "OPTIMIZED DUMP" sections of the output. If this turns out not to be the case and Numba is emitting that code directly, if you could provide a sample of the source code you're using that would help to work out the necessary changes.

One possible workaround is to set NUMBA_OPT=0 in order to prevent optimisation occurring.

At a guess, I think the instruction combining pass might be responsible for making this transformation - I'm not sure if there are ways to switch on and off specific passes from within Numba, but someone else may be able to shed more light on this.

@rossant

This comment has been minimized.

Show comment
Hide comment
@rossant

rossant Feb 16, 2015

I'm testing this on:

@jit(int32(int32[:]), nopython=True)
def f(x):
    return x[0] + x[1]

Using NUMBA_DEBUG=1 it does look like this pattern is generated as part of an optimization pass (it seems to first appear in the FUNCTION OPTIMIZED DUMP section).

I'll see if emscripten works with NUMBA_OPT=0.

rossant commented Feb 16, 2015

I'm testing this on:

@jit(int32(int32[:]), nopython=True)
def f(x):
    return x[0] + x[1]

Using NUMBA_DEBUG=1 it does look like this pattern is generated as part of an optimization pass (it seems to first appear in the FUNCTION OPTIMIZED DUMP section).

I'll see if emscripten works with NUMBA_OPT=0.

@rossant

This comment has been minimized.

Show comment
Hide comment
@rossant

rossant Feb 16, 2015

OK without optimization I have another error message with emscripten:

Value:   %.15 = load [1 x i64]* %.14
LLVM ERROR: Unrecognized struct value

This time I'm not sure what's happening...

Here is the code just before that failing instruction (same function example f as before):

B0:                                               ; preds = %entry
  %.6 = load { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr
  store { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %.6, { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr.1
  store i32 0, i32* %"$const0.2"
  %.9 = load { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr.1
  %.10 = load i32* %"$const0.2"
  %.11 = sext i32 %.10 to i64
  store { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %.9, { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %.12
  %.14 = getelementptr { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %.12, i32 0, i32 4
  %.15 = load [1 x i64]* %.14

rossant commented Feb 16, 2015

OK without optimization I have another error message with emscripten:

Value:   %.15 = load [1 x i64]* %.14
LLVM ERROR: Unrecognized struct value

This time I'm not sure what's happening...

Here is the code just before that failing instruction (same function example f as before):

B0:                                               ; preds = %entry
  %.6 = load { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr
  store { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %.6, { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr.1
  store i32 0, i32* %"$const0.2"
  %.9 = load { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %arr.1
  %.10 = load i32* %"$const0.2"
  %.11 = sext i32 %.10 to i64
  store { i8*, i64, i64, i32*, [1 x i64], [1 x i64] } %.9, { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %.12
  %.14 = getelementptr { i8*, i64, i64, i32*, [1 x i64], [1 x i64] }* %.12, i32 0, i32 4
  %.15 = load [1 x i64]* %.14
@gmarkall

This comment has been minimized.

Show comment
Hide comment
@gmarkall

gmarkall Feb 16, 2015

Contributor

What version of LLVM does emscripten use? I am wondering if there are some differences in semantics between the versions used in Numba and emscripten. (Numba presently uses LLVM 3.5).

Contributor

gmarkall commented Feb 16, 2015

What version of LLVM does emscripten use? I am wondering if there are some differences in semantics between the versions used in Numba and emscripten. (Numba presently uses LLVM 3.5).

@rossant

This comment has been minimized.

Show comment
Hide comment
@rossant

rossant Feb 16, 2015

That's also what I thought. I originally tested with the latest stable version, which uses LLVM 3.4 as far as I can tell. Then I updated to WIP branches with LLVM 3.5, and I got the same problems.

FWIW I've found a similar bug report here: http://code.google.com/p/nativeclient/issues/detail?id=3932

I'm wondering whether this would be better solved in Numba or in emscripten/PNaCl. I've sent an e-mail to the emscripten mailing list: https://groups.google.com/forum/#!topic/emscripten-discuss/eWwyFw-YYPo

rossant commented Feb 16, 2015

That's also what I thought. I originally tested with the latest stable version, which uses LLVM 3.4 as far as I can tell. Then I updated to WIP branches with LLVM 3.5, and I got the same problems.

FWIW I've found a similar bug report here: http://code.google.com/p/nativeclient/issues/detail?id=3932

I'm wondering whether this would be better solved in Numba or in emscripten/PNaCl. I've sent an e-mail to the emscripten mailing list: https://groups.google.com/forum/#!topic/emscripten-discuss/eWwyFw-YYPo

@rossant

This comment has been minimized.

Show comment
Hide comment
@rossant

rossant Feb 17, 2015

I got around these two problems with NUMBA_OPT=0 and the following fixes that were made for Rust (it also looks like Julia has similar problems):

I'll let you know once I have something working...

rossant commented Feb 17, 2015

I got around these two problems with NUMBA_OPT=0 and the following fixes that were made for Rust (it also looks like Julia has similar problems):

I'll let you know once I have something working...

@seibert

This comment has been minimized.

Show comment
Hide comment
@seibert

seibert Feb 17, 2015

Contributor

BTW, this sounds very interesting. Definitely let us know how things work out!

Contributor

seibert commented Feb 17, 2015

BTW, this sounds very interesting. Definitely let us know how things work out!

@rossant

This comment has been minimized.

Show comment
Hide comment
@rossant

rossant Feb 18, 2015

BTW, this sounds very interesting. Definitely let us know how things work out!

Here you go: http://cyrille.rossant.net/numpy-browser-llvm/ :)

rossant commented Feb 18, 2015

BTW, this sounds very interesting. Definitely let us know how things work out!

Here you go: http://cyrille.rossant.net/numpy-browser-llvm/ :)

@seibert

This comment has been minimized.

Show comment
Hide comment
@seibert

seibert Feb 19, 2015

Contributor

Wow, that's amazing! I am impressed you got that all working.

Contributor

seibert commented Feb 19, 2015

Wow, that's amazing! I am impressed you got that all working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment