Code_llvm and and code_native should return their output

As it stands code_typed returns its output, but code_llvm and code_native return Nothing and instead print their output to an io stream. I would like to propose that all three have no side effects and return some kind of Julia object which displays nicely.

Examples
julia> code_typed(abs, (Int,)) |> typeof
Vector{Any} (alias for Array{Any, 1})

julia> code_llvm(abs, (Int,)) |> typeof
;  @ int.jl:170 within `abs'
define i64 @julia_abs_1497(i64 signext %0) {
top:
; ┌ @ int.jl:130 within `flipsign'
   %1 = icmp slt i64 %0, 0
   %2 = sub i64 0, %0
   %3 = select i1 %1, i64 %2, i64 %0
; └
  ret i64 %3
}
Nothing

julia> code_native(abs, (Int,)) |> typeof
        .section        __TEXT,__text,regular,pure_instructions
; ┌ @ int.jl:170 within `abs'
; │┌ @ int.jl:130 within `flipsign'
        movq    %rdi, %rax
        negq    %rax
        cmovlq  %rdi, %rax
; │└
        retq
        nopl    (%rax,%rax)
; └
Nothing

I ran into this when trying to use these functions in a Pluto.jl notebook. code_typed works just fine but the other two don’t display their output in the notebook, which is rather annoying. You can get around this by redirecting stdout or by using sprint and returning a String, but it doesn’t look nice that way.

Would the way to fix this be to have equivalents of the CodeInfo type like a LLVMInfo and NativeInfo types, that just contain a string and get displayed nicely if showed?

4 Likes

I opened an issue at Proposal: `code_llvm` and and `code_native` should return their output · Issue #41570 · JuliaLang/julia · GitHub.

As a reference, the way e.g. code_llvm work is that it calls into LLVM and llvm does the printing:

So there is no preceding Julia object that is being printed here.

1 Like

code_llvm and code_naive have an optional parameter io to redirect IO:

help?> code_llvm
search: code_llvm @code_llvm

  code_llvm([io=stdout,], f, types; raw=false, dump_module=false, optimize=true, debuginfo=:default)

  Prints the LLVM bitcodes generated for running the method matching the given generic function and type signature to io.

So if you want to get the string, you can do:

io = IOBuffer()
code_llvm(io,sin,(Float64,))
String(take!(io))

Then you get the string of output.
I admit it’s annoying, but I think you can wrap above code into a new macro to get around this problem?

3 Likes

Yeah, you can also do this with sprint. The problem is, that a Julia String does not get displayed by printing it. Instead, the raw form gets shown in the REPL, which is rather ugly.

julia> my_code_native(args...; kwargs...) = sprint() do io
           code_native(io, args...; kwargs...)
       end
my_code_native (generic function with 1 method)

julia> my_code_native(abs, (Int,))
"\t.section\t__TEXT,__text,regular,pure_instructions\n; ┌ @ int.jl:170 within `abs'\n; │┌ @ int.jl:130 within `flipsign'\n\tmovq\t%rdi, %rax\n\tnegq\t%rax\n\tcmovlq\t%rdi, %rax\n; │└\n\tretq\n\tnopl\t(%rax,%rax)\n; └\n"

So, I was proposing something more like this

import Base: show
using InteractiveUtils: code_llvm, code_native

struct CodeLLVMInfo{F <: Function, Ts <: Tuple}
    f::F
    types::Ts
end

function show(io::IO, ::MIME"text/plain", info::CodeLLVMInfo)
    code_llvm(io, info.f, info.types)
end

proposed_code_llvm(f, types) = CodeLLVMInfo(f, types)

display(proposed_code_llvm(abs, (Int,)))

Another solution would be to make all three return nothing and print their output. You could make them consistent like that, too.

1 Like

Doesn’t Pluto have a way to display strings nicely? So you would compose sprint with that?

I don’t know if Pluto has a way of showing printed strings. I tested the sprint code and it doesn’t display nicely. May be there’s some other way to do it though.

In any case, I think the three inspection functions should be consistent. So, either all should print or all should return their output.

Here’s what I tried.

### A Pluto.jl notebook ###
# v0.15.1

using Markdown
using InteractiveUtils

# ╔═╡ fd998ae0-e480-11eb-2aa1-8317fbbf5333
my_code_native(args...; kwargs...) = sprint() do io
   code_native(io, args...; kwargs...)
end

# ╔═╡ 3fa04cfe-ebd5-4a7d-885d-6a6eae4a5a53
my_code_native(abs, (Int,))

# ╔═╡ Cell order:
# ╠═fd998ae0-e480-11eb-2aa1-8317fbbf5333
# ╠═3fa04cfe-ebd5-4a7d-885d-6a6eae4a5a53

Looks like you can use Text:

bild

3 Likes

Thanks, that solves one issue.