Build Status | Coverage | Documentation |
---|---|---|
] add CodeInfoTools
Note: A curated collection of tools for the discerning
Core.CodeInfo
connoisseur.The architecture of this package is based closely on the Pipe construct in IRTools.jl. Many (if not all) of the same idioms apply.
Working with Core.CodeInfo
is often not fun. E.g. when examining the untyped lowered form of the Rosenbrock function
CodeInfo(
@ /Users/mccoybecker/dev/CodeInfoTools.jl/examples/simple.jl:7 within `rosenbrock'
1 ─ a = 1.0
│ b = 100.0
│ result = 0.0
│ %4 = (length)(x)
│ %5 = (-)(%4, 1)
│ %6 = (Colon())(1, %5)
│ @_3 = (iterate)(%6)
│ %8 = (===)(@_3, nothing)
│ %9 = (Core.Intrinsics.not_int)(%8)
└── goto #4 if not %9
2 ┄ %11 = @_3
│ i = (getfield)(%11, 1)
│ %13 = (getfield)(%11, 2)
│ .
│ .
│ .
│
│ %36 = (===)(@_3, nothing)
│ %37 = (Core.Intrinsics.not_int)(%36)
└── goto #4 if not %37
3 ─ goto #2
4 ┄ return result
)
Do you ever wonder -- is there another (perhaps, any) way to work with this object? A Builder
perhaps? Where I might load my CodeInfo
into -- iterate, make local changes, and produce a new copy?
CodeInfoTools.jl
provides a Builder
abstraction which allows you to safely iterate over and manipulate Core.CodeInfo
. It also provides more advanced functionality for creating and evaluating Core.CodeInfo
-- which is a bit on the experimental side.
How might you use this in practice?
using CodeInfoTools
function f(x, y)
z = 10
if z > 10
n = 10
return x + y
else
return x + y + z
end
end
src = code_info(f, Int, Int)
function transform(src)
b = CodeInfoTools.Builder(src)
for (v, st) in b
st isa Expr || continue
st.head == :call || continue
st.args[1] == Base.:(+) || continue
b[v] = Expr(:call, Base.:(*), st.args[2:end]...)
end
return finish(b)
end
display(src)
display(transform(src))
Here, we've lowered a function directly to a Core.CodeInfo
instance and created a Builder
instance b
. You can now safely iterate over this object, perform local changes, press finish
and - (la di da!) - out comes a new Core.CodeInfo
with your changes fresh.
# Before:
CodeInfo(
1 ─ Core.NewvarNode(:(n))
│ z = 10
│ %3 = z > 10
└── goto #3 if not %3
2 ─ n = 10
│ %6 = x + y
└── return %6
3 ─ %8 = x + y + z
└── return %8
)
# After:
CodeInfo(
1 ─ Core.NewvarNode(:(n))
│ z = 10
│ %3 = (>)(z, 10)
└── goto #3 if not %3
2 ─ n = 10
│ %6 = (*)(x, y)
└── return %6
3 ─ %8 = (*)(x, y, z)
└── return %8
)