blob: d1a1c0bf20b8331bbae8f7e75776c14079b75365 [file] [log] [blame] [raw]
doc = """Julia wrapper.
Usage:
julia_wrapper.jl <input_code> <output_path> [--format=<fmt>] [--debuginfo=<info>] [--optimize=<opt>] [--verbose]
julia_wrapper.jl --help
Options:
-h --help Show this screen.
--format=<fmt> Set output format (One of "lowered", "typed", "warntype", "llvm", "native") [default: native]
--debuginfo=<info> Controls amount of generated metadata (One of "default", "none") [default: default]
--optimize={true*|false} Controls whether "llvm" or "typed" output should be optimized or not [default: true]
--verbose Prints some process info
"""
using InteractiveUtils
if first(ARGS) == "--"
popfirst!(ARGS)
end
format = "native"
debuginfo = :default
optimize = true
verbose = false
show_help = false
arg_parser_error = false
positional_ARGS = String[]
for x in ARGS
if startswith(x, "--format=")
global format = x[10:end]
elseif startswith(x, "--debuginfo=")
if x[13:end] == "none"
global debuginfo = :none
end
elseif startswith(x, "--optimize=")
# Do not error out if we can't parse the option
global optimize = something(tryparse(Bool, x[12:end]), true)
elseif x == "--verbose"
global verbose = true
elseif x == "--help" || x == "-h"
global show_help = true
elseif !startswith(x, "-")
push!(positional_ARGS, x)
else
global arg_parser_error = true
println("Unknown argument ", x)
end
end
if show_help
println(doc)
exit(Int(arg_parser_error)) # exit(1) if failed to parse
end
if length(positional_ARGS) != 2
arg_parser_error = true
println("Expected two position args", positional_ARGS)
end
if arg_parser_error
println(doc)
exit(1)
end
input_file = popfirst!(positional_ARGS)
output_path = popfirst!(positional_ARGS)
# Include user code into module
m = Module(:Godbolt)
Base.include(m, input_file)
# Find functions and method specializations
m_methods = Any[]
for name in names(m, all=true)
local fun = getfield(m, name)
if fun isa Function
if verbose
println("Function: ", fun)
end
for me in methods(fun)
for s in me.specializations
if s != nothing
me_types = getindex(s.specTypes.parameters, 2:length(s.specTypes.parameters))
push!(m_methods, (fun, me_types, me))
if verbose
println(" Method types: ", me_types)
end
end
end
end
end
end
# Open output file
open(output_path, "w") do io
# For all found methods
for (me_fun, me_types, me) in m_methods
io_buf = IOBuffer() # string buffer
if format == "typed"
ir, retval = InteractiveUtils.code_typed(me_fun, me_types; optimize, debuginfo)[1]
Base.IRShow.show_ir(io_buf, ir)
elseif format == "lowered"
cl = Base.code_lowered(me_fun, me_types; debuginfo)
print(io_buf, cl)
elseif format == "llvm"
InteractiveUtils.code_llvm(io_buf, me_fun, me_types; optimize, debuginfo)
elseif format == "native"
InteractiveUtils.code_native(io_buf, me_fun, me_types; debuginfo)
elseif format == "warntype"
InteractiveUtils.code_warntype(io_buf, me_fun, me_types; debuginfo)
end
code = String(take!(io_buf))
line_num = count("\n",code)
# Print first line: <[source code line] [number of output lines] [function name] [method types]>
write(io, "<")
print(io, me.line)
print(io, " ")
print(io, line_num)
print(io, " ")
print(io, me_fun)
write(io, " ")
for i in 1:length(me_types)
print(io, me_types[i])
if i < length(me_types)
write(io, ", ")
end
end
write(io, ">\n")
# Print code for this method
write(io, code)
write(io, "\n")
end
end
exit(0)