Skip to content
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

LLVM ERROR: Broken function found, compilation aborted! when precompiling Base.permutedims #31156

Closed
tkf opened this issue Feb 23, 2019 · 54 comments

Comments

@tkf
Copy link
Member

tkf commented Feb 23, 2019

I get LLVM ERROR: Broken function found, compilation aborted! when including Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}}) for system image compilation. I can reproduce this in Julia 1.0 to 1.2.

First I created compile.bash:

#!/bin/bash

code_print_image_file="print(unsafe_string(Base.JLOptions().image_file))"

JULIA="${JULIA:-julia}"
IMAGE="$("$JULIA" -e "$code_print_image_file")"

OUTPUT_O=sys.a

set -ex

${JULIA} --output-o="$OUTPUT_O" \
    -g1 --startup-file=no --code-coverage=none \
    --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes \
    --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes \
    --cpu-target=native --track-allocation=none --sysimage-native-code=yes \
    --sysimage="$IMAGE" \
    --compiled-modules=yes --optimize=2 \
    ./precompile_wrapper.jl

and ./precompile_wrapper.jl:

atexit_hook_copy = copy(Base.atexit_hooks) # make backup
# clean state so that any package we use can carelessly call atexit
empty!(Base.atexit_hooks)
Base.__init__()
Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
using REPL
Base.REPL_MODULE_REF[] = REPL

Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})

Base._atexit() # run all exit hooks we registered during precompile
empty!(Base.atexit_hooks) # don't serialize the exit hooks we run + added
# atexit_hook_copy should be empty, but who knows what base will do in the future
append!(Base.atexit_hooks, atexit_hook_copy)

Then run:

$ julia --version
julia version 1.1.0

$ ./compile.bash
+ julia --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/takafumi/opt/julia/julia-1.1.0/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl
ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

$ julia-1.0 --version
julia version 1.0.3

$ JULIA=julia-1.0 ./compile.bash
+ julia-1.0 --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/takafumi/opt/julia/julia-1.0.3/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl
ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

$ ~/repos/watch/julia/usr/bin/julia -E VERSION
v"1.2.0-DEV.339"

$ JULIA=~/repos/watch/julia/usr/bin/julia ./compile.bash
+ /home/takafumi/repos/watch/julia/usr/bin/julia --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/takafumi/repos/watch/julia/usr/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl
ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

(precompile_wrapper.jl is taken from run_julia_code.jl generated by PackageCompiler.jl)

@Keno
Copy link
Member

Keno commented Feb 23, 2019

I see a crash in libuv, which makes me think you're trying to print something without libuv being initialized properly.

+ /home/keno/julia/julia --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/keno/julia/usr/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl

signal (11): Segmentation fault
in expression starting at none:0
uv_write2 at /home/keno/julia/deps/srccache/libuv-2348256acf5759a544e5ca7935f638d2bc091d60/src/unix/stream.c:1434
jl_uv_write at /home/keno/julia/src/jl_uv.c:442
uv_write_async at ./stream.jl:877
uv_write at ./stream.jl:845
unsafe_write at ./stream.jl:901
macro expansion at ./gcutils.jl:87 [inlined]
write at ./strings/io.jl:177 [inlined]
print at ./strings/io.jl:179 [inlined]
#with_output_color#672 at ./util.jl:370
#with_output_color at ./tuple.jl:0 [inlined]
#printstyled#673 at ./util.jl:398 [inlined]
#printstyled at ./none:0
jl_fptr_trampoline at /home/keno/julia/src/gf.c:1895
jl_apply_generic at /home/keno/julia/src/gf.c:2250
display_error at ./client.jl:104
jl_fptr_trampoline at /home/keno/julia/src/gf.c:1895
jl_apply_generic at /home/keno/julia/src/gf.c:2250
display_error at ./client.jl:124
jl_fptr_trampoline at /home/keno/julia/src/gf.c:1895
jl_apply_generic at /home/keno/julia/src/gf.c:2250
jl_apply at /home/keno/julia/src/julia.h:1594 [inlined]
jl_f__apply at /home/keno/julia/src/builtins.c:563
jl_f__apply_latest at /home/keno/julia/src/builtins.c:601
#invokelatest#1 at ./essentials.jl:761 [inlined]
invokelatest at ./essentials.jl:760 [inlined]
exec_options at ./client.jl:309
_start at ./client.jl:476
jl_fptr_trampoline at /home/keno/julia/src/gf.c:1895
jl_apply_generic at /home/keno/julia/src/gf.c:2250
jl_apply at /home/keno/julia/ui/../src/julia.h:1594 [inlined]
true_main at /home/keno/julia/ui/repl.c:96
main at /home/keno/julia/ui/repl.c:217
__libc_start_main at /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
_start at /home/keno/julia/julia (unknown line)
Allocations: 872735 (Pool: 872287; Big: 448); GC: 1
./compile.bash: line 19: 22733 Segmentation fault      ${JULIA} --output-o="$OUTPUT_O" -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage="$IMAGE" --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl

@tkf
Copy link
Member Author

tkf commented Feb 24, 2019

I thought the error you showed me was solved by calling Base.__init__() and Sys.__init__() manually. I can get your error by commenting out them:

diff --git a/precompile_wrapper.jl b/precompile_wrapper.jl
index 9ebfb2e..a8e8554 100644
--- a/precompile_wrapper.jl
+++ b/precompile_wrapper.jl
@@ -1,8 +1,8 @@
 atexit_hook_copy = copy(Base.atexit_hooks) # make backup
 # clean state so that any package we use can carelessly call atexit
 empty!(Base.atexit_hooks)
-Base.__init__()
-Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
+# Base.__init__()
+# Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
 using REPL
 Base.REPL_MODULE_REF[] = REPL

I uploaded the scripts I'm using here: https://gist.github.com/tkf/bb020c3e2d64d049696c7e549f0120ad/ab16ec9f94598a64f9e242f5d8b7ba1a9f7fc94e They are the same as the one included in the first post but just in case I had copy-and-paste mistake. I can reproduce LLVM ERROR: Broken function found, compilation aborted! by running the following commands in an empty directory:

wget https://gist.githubusercontent.com/tkf/bb020c3e2d64d049696c7e549f0120ad/raw/ab16ec9f94598a64f9e242f5d8b7ba1a9f7fc94e/compile.bash
wget https://gist.githubusercontent.com/tkf/bb020c3e2d64d049696c7e549f0120ad/raw/ab16ec9f94598a64f9e242f5d8b7ba1a9f7fc94e/precompile_wrapper.jl
bash compile.bash

Note also that this script can generate sys.a if I comment out Base.precompile:

$ git diff
diff --git a/precompile_wrapper.jl b/precompile_wrapper.jl
index 9ebfb2e..f6789aa 100644
--- a/precompile_wrapper.jl
+++ b/precompile_wrapper.jl
@@ -6,7 +6,7 @@ Sys.__init__() #fix https://github.com/JuliaLang/julia/issues/30479
 using REPL
 Base.REPL_MODULE_REF[] = REPL

-Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})
+# Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})

 Base._atexit() # run all exit hooks we registered during precompile
 empty!(Base.atexit_hooks) # don't serialize the exit hooks we run + added

$ rm -f sys.a

$ ./compile.bash
+ julia --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/takafumi/opt/julia/julia-1.1.0/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl

$ file sys.a
sys.a: current ar archive

FYI

$ julia -e 'using InteractiveUtils; versioninfo()'
Julia Version 1.1.0
Commit 80516ca202 (2019-01-21 21:24 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

$ julia-1.0 -e 'using InteractiveUtils; versioninfo()'
Julia Version 1.0.3
Commit 099e826241 (2018-12-18 01:34 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, skylake)

$ ~/repos/watch/julia/usr/bin/julia -e 'using InteractiveUtils; versioninfo()'
Julia Version 1.2.0-DEV.339
Commit 00f257d603 (2019-02-16 01:47 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

@tkf
Copy link
Member Author

tkf commented Apr 9, 2019

Bump. I still can reproduce the bug with current master 1.2.0-DEV.669 (4671132).

@tkf
Copy link
Member Author

tkf commented Oct 18, 2019

It is still reproducible with 1.4.0-DEV.297 (a68237f).

@IanButterworth
Copy link
Member

I'm seeing this when using the new PackageCompiler on aarch64 on 1.3.1
JuliaLang/PackageCompiler.jl#295

ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

@IanButterworth
Copy link
Member

I can reproduce the error with the first example

$ julia --version
julia version 1.3.1
$ ./compile.bash
+ julia --output-o=sys.a -g1 --startup-file=no --code-coverage=none --history-file=yes --inline=yes --math-mode=ieee --handle-signals=yes --startup-file=no --warn-overwrite=no --compile=yes --depwarn=yes --cpu-target=native --track-allocation=none --sysimage-native-code=yes --sysimage=/home/ian/Documents/julia-1.3.1/lib/julia/sys.so --compiled-modules=yes --optimize=2 ./precompile_wrapper.jl
ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

@DilumAluthge
Copy link
Member

Related: https://discourse.julialang.org/t/debugging-aot-compile-errors/20829

@IanButterworth
Copy link
Member

IanButterworth commented Feb 12, 2020

Some further testing.
In the example above, each of these precompile statements fails:

Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 2}, Array{Int64, 1}})
Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})
Base.precompile(Tuple{typeof(Base.permutedims), Array{UInt8, 3}, Array{Int64, 1}})

These don't fail:

Base.precompile(Tuple{typeof(Base.permutedims), Array{Int64, 3}, Array{Int64, 1}})
Base.precompile(Tuple{typeof(Base.permutedims), Array{Float64, 3}, Array{Int64, 1}})
Base.precompile(Tuple{typeof(Base.rand), Int64}) (sanity check)

@IanButterworth
Copy link
Member

IanButterworth commented Feb 12, 2020

Stating the obvious to be complete... in the regular REPL the equivalent methods work. i.e. permutedims(rand(Bool,2,2,2), [1,3,2])

And I noticed that the blame on the permutedims functions shows no change in at least 2 years
https://github.com/JuliaLang/julia/blame/2d5741174ce3e6a394010d2e470e4269ca54607f/base/permuteddimsarray.jl

@IanButterworth
Copy link
Member

@timholy I wondered if you had any insight given you seem to have driven the permutedims approach, from the blame (I hate that name..)

Does the fact that this happens for Bool and UInt8 arrays, but not Int64 or Float64 arrays point to anything?

@IanButterworth
Copy link
Member

On MacOS I see the same as Keno:

signal (11): Segmentation fault: 11
in expression starting at none:0
uv_write2 at /workspace/srcdir/libuv/src/unix/stream.c:1397
...

@tkf
Copy link
Member Author

tkf commented Feb 13, 2020

Maybe some error happens before/during Base.__init__()? Does calling Base.reinit_stdio at the very beginning of the script help?

@KristofferC
Copy link
Member

Note that it is enough to only have a bare

Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})

in the precompile_wrapper.jl.

@IanButterworth
Copy link
Member

and Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}}) returns true in REPL

@KristofferC
Copy link
Member

Yeah, it returns true when using PackageCompiler as well. It isn't until the the code is getting written to the object file that LLVM asserts.

@DilumAluthge
Copy link
Member

What happens when you use different optimization flags? -O0 vs -O1 vs -O2 vs -O3

@IanButterworth
Copy link
Member

With Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 2}, Array{Int64, 1}}) in precompile_wrapper.jl alone:

--optimize=0 - success
--optimize=1 - segfault
--optimize=2 - ptrtoint not supported for non-integral pointers etc.
--optimize=3 - ptrtoint not supported for non-integral pointers etc.

@IanButterworth
Copy link
Member

@tkf Just out of interest, how did you figure out this was cause by Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}}) ?

I'm trying to figure out a way to narrow in on other causes of this, as it seems to not just be limited to permutedims

@IanButterworth
Copy link
Member

IanButterworth commented Feb 13, 2020

I just tried in a build of 1.3.1 with LLVM_ASSERTIONS := 1 but didn't get anything more

ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
LLVM ERROR: Broken function found, compilation aborted!

Now trying with LLVM_ASSERTIONS := 1 & LLVM_DEBUG := 1

@DilumAluthge
Copy link
Member

@ianshmean Can you do the same thing (running with -O0 vs -O1 vs -O2 vs -O3) in Julia 1.0, 1.1, 1.2, and 1.3 to see if we can figure out when this bug was introduced?

@IanButterworth
Copy link
Member

From https://discourse.julialang.org/t/debugging-aot-compile-errors/20829/2 it looks like it started in 1.1

I'll try to cover the versions

@DilumAluthge
Copy link
Member

Also, you said that this bug does occur for Array{Bool, 3} but does not occur for Array{Int64, 3}, right?

Can you see if it occurs for BitArray{1}, BitArray{2}, BitArray{3}, etc?

@IanButterworth
Copy link
Member

Indeed.
I'll test bitarrays. Any other types worth testing to narrow-in?

Bool, UInt8 = bad
Int64, Float64 = good

@IanButterworth
Copy link
Member

IanButterworth commented Feb 13, 2020

With --optimize=2

Bad

  • Array{Bool, 2-10}
  • Array{UInt8, 2-10}
  • Array{Int8, 2}

Good

  • Array{Int64, 3}
  • Array{Float64, 3}
  • BitArray{2-3}
  • Array{Int16, 2}
  • Array{Int32, 2}

@IanButterworth
Copy link
Member

And I don't see any more from LLVM with LLVM_ASSERTIONS := 1 & LLVM_DEBUG := 1

@IanButterworth
Copy link
Member

Given Bool is stored as a UInt8, it seems like an 8-bit problem

@maleadt
Copy link
Member

maleadt commented Feb 14, 2020

I dumped the bad IR, on Julia master, as well as the IR that's normally generated at run time: https://gist.github.com/maleadt/f93ba85a91ba0860e00d883ff4052a8c
Just process with opt to see the IR verifier fail with the same error.

@IanButterworth
Copy link
Member

I'm using JuliaLang/PackageCompiler.jl#333 to blacklist anything that causes this issue, and after blacklisting permutedims I'm getting the same thing for copyto!:

ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
ptrtoint not supported for non-integral pointers
inttoptr not supported for non-integral pointers
in function julia_copyto!_18518
LLVM ERROR: Broken function found, compilation aborted!

@IanButterworth
Copy link
Member

After @vtjnash suggested in slack that it could be the vectorizer optimizations, @KristofferC suggested I disable those lines and build master, so I commented out

PM->add(createSLPVectorizerPass()); // Vectorize straight-line code

PM->add(createLoopVectorizePass()); // Vectorize loops

And it worked. The example now passes with --optimize=2

@IanButterworth
Copy link
Member

Unfortunately it still hit the julia_copyto!_18518 error though when I ran PackageCompiler with the julia master build with no vectorizer.

@DilumAluthge
Copy link
Member

@ianshmean You said that this is architecture-dependent, right? Can you post which architectures it works on, and which architectures you get the error on?

@IanButterworth
Copy link
Member

The MWE in this thread errors on both aarch64 and amd64 for me. That's not platform specific.

However, the package I'm PackageCompiling only hits this error on aarch64.
Somehow there's a significant difference in the precomp statements being generated for my package between aarch64 and arm64, and the list is too long to visually parse

[ Info: Num precomp statements generated on aarch64: 6406
[ Info: Num precomp statements generated  on amd64: 6096
[ Info: Statements uniquely generated on aarch64 (not on amd64): 1537
[ Info: Statements uniquely generated on amd64 (not on aarch64): 1277

And frustratingly neither set contains a permutedims on an 8-bit array type

@IanButterworth
Copy link
Member

To summarize. My take is that there's a bug in either/both of these that fixes the permutedims 8-bit example (I haven't build julia with these independently disabled, but can do that if it's helpful):

PM->add(createSLPVectorizerPass());         // Vectorize straight-line code
PM->add(createLoopVectorizePass());         // Vectorize loops 

And another bug somewhere else that julia_copyto!_18518 is hitting.

I tried to use export JULIA_LLVM_ARGS = -print-before-all with my PackageCompiler setup, but the output text seemed never ending (over an hour) so I cancelled before it errored.

If anyone has a suggestion, I'm happy to explore

@vchuravy
Copy link
Member

I tried to use export JULIA_LLVM_ARGS = -print-before-all with my PackageCompiler setup, but the output text seemed never ending (over an hour)

Pipe it to a file instead, so that you don;t get slowed done by your terminal.

@IanButterworth
Copy link
Member

I haven't yet piped the output out..

But, I figured out the 2 out of 6406 precompile statements that were invoking the ptrtoint not supported for non-integral pointers, inttoptr not supported for non-integral pointers errors for my package:

precompile(Tuple{typeof(Base.copyto!), Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}, Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}}) 

precompile(Tuple{typeof(Base.circshift!), Array{UInt8, 2}, Array{UInt8, 2}, Tuple{Int64, Int64}})

Details on the bisector approach I used: JuliaLang/PackageCompiler.jl#295 (comment)

@IanButterworth
Copy link
Member

Of the three known:

  1. precompile(Tuple{typeof(Base.permutedims), Array{Bool, 3}, Array{Int64, 1}})
  2. precompile(Tuple{typeof(Base.copyto!), Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}, Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}})
  3. precompile(Tuple{typeof(Base.circshift!), Array{UInt8, 2}, Array{UInt8, 2}, Tuple{Int64, Int64}})

Fails on Ubuntu aarch64: [1,2,3]
Fails on MacOS: [1]

@Keno
Copy link
Member

Keno commented Feb 21, 2020

Here's a pure LLVM reproducer: https://gist.github.com/Keno/60d900bf197bfda75e2f9f72dec4411f

Reproduce with opt -loop-reduce. I'll look into patching this.

@Keno
Copy link
Member

Keno commented Feb 21, 2020

For those wondering how to do that, the steps are basically:

  1. Build LLVM with debug symbols
  2. Record the failing process with rr
  3. Run rr -a -M to find the timestamp when it prints the error
  4. Go there with rr -g
  5. Find the address of the failing instruction (call it I)
  6. watch *I (but put in the actual address for I - don't use a variable)
  7. Keep doing rc until you find the constructor of that value
  8. Set a breakpoint at the start of whatever pass you're in
  9. Use jl_write_bitcode_func to dump the module
  10. Verify that the dumped module fails under the problematic pass using opt
  11. Use llvm-extract to just get the problematic function
  12. Verify it still fails
  13. (Optional) Use llvm-reduce or bugpoint to reduce it even further

@IanButterworth
Copy link
Member

Awesome.

Also, for the precompile statements failing on aarch64, I just got IR dumps (and posted how I did each at the top). Note that each is caused by a differently numbered copyto! function:

Base.precompile(Tuple{typeof(Base.circshift!), Array{UInt8, 2}, Array{UInt8, 2}, Tuple{Int64, Int64}})

https://gist.github.com/ianshmean/18202bed7aa6ecc433f344bbce1d8dd2

Base.precompile(Tuple{typeof(Base.copyto!), Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}, Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}})

https://gist.github.com/ianshmean/79de0928d534eaee5c68edb168bb6f92

@Keno
Copy link
Member

Keno commented Feb 21, 2020

This is what comes out of bugpoint, BTW. It's usually easiest to do further debugging on the bugpoint reduced output, because it reduces the amount of code that gets executed, so debugging with rr is faster:

; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "julia"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128-ni:10:11:12:13"
target triple = "x86_64-unknown-linux-gnu"

define hidden void @"japi1_permutedims!_4259"() #0 {
top:
  br label %L42.L46_crit_edge.us

L42.L46_crit_edge.us:                             ; preds = %L82.us.us.loopexit, %top
  %value_phi11.us = phi i64 [ undef, %top ], [ %2, %L82.us.us.loopexit ]
  %0 = sub i64 %value_phi11.us, undef
  %1 = add i64 %0, undef
  %spec.select = select i1 undef, i64 undef, i64 0
  br label %L62.us.us

L82.us.us.loopexit:                               ; preds = %L62.us.us
  %2 = add i64 undef, %value_phi11.us
  br label %L42.L46_crit_edge.us

L62.us.us:                                        ; preds = %L62.us.us, %L42.L46_crit_edge.us
  %value_phi21.us.us = phi i64 [ %6, %L62.us.us ], [ %spec.select, %L42.L46_crit_edge.us ]
  %3 = add i64 %1, %value_phi21.us.us
  %4 = getelementptr inbounds i8, i8 addrspace(13)* undef, i64 %3
  %5 = load i8, i8 addrspace(13)* %4, align 1
  %6 = add i64 undef, %value_phi21.us.us
  br i1 undef, label %L82.us.us.loopexit, label %L62.us.us, !llvm.loop !1
}

attributes #0 = { "thunk" }

!llvm.module.flags = !{!0}

!0 = !{i32 1, !"Debug Info Version", i32 3}
!1 = distinct !{!1, !2}
!2 = !{!"llvm.loop.isvectorized", i32 1}

@Keno
Copy link
Member

Keno commented Feb 24, 2020

Candidate patch: https://reviews.llvm.org/D75072
Try it out and let me know if it fixes things.

Keno added a commit that referenced this issue Feb 24, 2020
This imports the patch I put up in https://reviews.llvm.org/D75072
and should fix #31156. We should probably hold off on merging this
for a few days while upstream review is ongoing. In the meantime,
this branch should be convenient to try. Make sure to remember to build
LLVM from source, not BB.
Keno added a commit that referenced this issue Feb 24, 2020
This imports the patch I put up in https://reviews.llvm.org/D75072
and should fix #31156. We should probably hold off on merging this
for a few days while upstream review is ongoing. In the meantime,
this branch should be convenient to try. Make sure to remember to build
LLVM from source, not BB.
@Keno
Copy link
Member

Keno commented Feb 24, 2020

Backport to LLVM9 is in #34860 for your trial convenience.

@IanButterworth
Copy link
Member

IanButterworth commented Feb 25, 2020

It worked! 🎉🎉🎉🎉

I built #34860 with export USE_BINARYBUILDER_LLVM=0, and ran the compile.bash example up top, with all three failing precomp statements on my aarch64 machine and it built successfully!

Thank you so much @Keno !

Notes:

  • It took about 12 hours to build julia and LLVM on this AARCH64 machine..
  • The stdlibs of the build are messed up for me. I can't install any package that has a stdlib in it (so can't test my actual PackageCompiler test case)

Test precomp statements

Base.precompile(Tuple{typeof(Base.permutedims), Array{Bool, 2}, Array{Int64, 1}})
Base.precompile(Tuple{typeof(Base.copyto!), Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}, Array{UInt8, 2}, Base.IteratorsMD.CartesianIndices{2, Tuple{Base.UnitRange{Int64}, Base.UnitRange{Int64}}}})
Base.precompile(Tuple{typeof(Base.circshift!), Array{UInt8, 2}, Array{UInt8, 2}, Tuple{Int64, Int64}})

@DilumAluthge
Copy link
Member

@ianshmean Were you able to fix the stdlib problem?

@IanButterworth
Copy link
Member

Yes. Deleting usr and rebuilding julia worked (thankfully I didn't have to rebuild LLVM so it was much faster to build).

I posted a comment over on #34860 (comment)

IanButterworth pushed a commit to IanButterworth/julia that referenced this issue Mar 11, 2020
This imports the patch I put up in https://reviews.llvm.org/D75072
and should fix JuliaLang#31156. We should probably hold off on merging this
for a few days while upstream review is ongoing. In the meantime,
this branch should be convenient to try. Make sure to remember to build
LLVM from source, not BB.
ravibitsgoa pushed a commit to ravibitsgoa/julia that referenced this issue Apr 9, 2020
* Add patch for 31156

This imports the patch I put up in https://reviews.llvm.org/D75072
and should fix JuliaLang#31156. We should probably hold off on merging this
for a few days while upstream review is ongoing. In the meantime,
this branch should be convenient to try. Make sure to remember to build
LLVM from source, not BB.

* set LLVM BB build to release 3

update LLVM checksums

delete old LLVM.v9.0.1-1 checksums

Co-authored-by: Keno Fischer <keno@juliacomputing.com>
KristofferC pushed a commit that referenced this issue Apr 11, 2020
* Add patch for 31156

This imports the patch I put up in https://reviews.llvm.org/D75072
and should fix #31156. We should probably hold off on merging this
for a few days while upstream review is ongoing. In the meantime,
this branch should be convenient to try. Make sure to remember to build
LLVM from source, not BB.

* set LLVM BB build to release 3

update LLVM checksums

delete old LLVM.v9.0.1-1 checksums

Co-authored-by: Keno Fischer <keno@juliacomputing.com>
vchuravy pushed a commit to JuliaLang/llvm-project that referenced this issue Oct 1, 2021
This fixes a case where loop-reduce introduces ptrtoint/inttoptr for
non-integral address space pointers. Over the past several years, we
have gradually improved the SCEVExpander to actually do something
sensible for non-integral pointer types. However, that obviously
relies on the expander knowing what the type of the SCEV expression is.
That is usually the case, but there is one important case where it's
not: The type of an add expression is just the type of the last operand,
so if the non-integral pointer is not the last operand, later uses of
that SCEV may not realize that the given add expression contains
non-integral pointers and may try to expand it as integers.

One interesting observation is that we do get away with this scheme in
shockingly many cases. The reason for this is that SCEV expressions
often have an `scUnknown` pointer base, which our sort order on the
operands of add expressions sort behind basically everything else,
so it usually ends up as the last operand.

One situation where this fails is included as a test case. This test
case was bugpoint-reduced from the issue reported at
JuliaLang/julia#31156. What happens here
is that the pointer base is an scAddRec from an outer loop, plus an
scUnknown integer offset. By our sort order, the scUnknown gets sorted
after the scAddRec pointer base, thus making an add expression of these
two operands have integer type. This then confuses the expander, into
attempting to expand the whole thing as integers, which will obviously
fail when reaching the non-integral pointer.

I considered a few options to solve this, but here's what I ended up
settling on: The AddExpr class gains a new subclass that explicitly
stores the type of the expression. This subclass is used whenever one
of the operands is a non-integral pointer. To reduce the impact for the
regular case (where the SCEV expression contains no non-integral
pointers), a bit flag is kept in each flag expression to indicate
whether it is of non-integral pointer type (this should give the same
answer as asking if getType() is non-integral, but performing that
query may involve a pointer chase and requires the DataLayout). For
add expressions that flag is also used to indicate whether we're using
the subclass or not. This is slightly inefficient, because it uses
the subclass even in the (not uncommon) case where the last operand
does actually accurately reflect the non-integral pointer type. However,
it didn't seem worth the extra flag bit and complexity to do this
micro-optimization.

I had hoped that we could additionally restrict mul exprs from
containing any non-integral pointers, and also require add exprs to
only have one operand containg such pointers (but not more), but this
turned out not to work. The reason for this is that SCEV wants to
form differences between pointers, which it represents as `A + B*-1`,
so we need to allow both multiplication by `-1` and addition with
multiple non-integral pointer arguments. I'm not super happy with
that situation, but I think it exposes a more general problem with
non-integral pointers in LLVM. We don't actually have a way to express
the difference between two non-integral pointers at the IR level.
In theory this is a problem for SCEV, because it means that we can't
materialize such SCEV expression. However, in practice, these
expressions generally have the same base pointer, so SCEV will
appropriately simplify them to just the integer components.
Nevertheless it is a bit unsatisfying. Perhaps we could have an
intrinsic that takes the byte difference between two pointers to the
same allocated object (in the same sense as is used in getelementptr),
which should be a sensible operation even for non-integral pointers.
However, given the practical considerations above, that's a project
for another time. For now, simply allowing the existing pointer-diff
pattern for non-integral pointers seems to work ok.

Differential Revision: https://reviews.llvm.org/D75072
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants