Reference

API Reference

This page provides a comprehensive reference for IRTools functionality.

Reflection

IRTools.@code_irMacro.
@code_ir f(args...)

Convenience macro similar to @code_lowered or @code_typed. Retrieves the IR for the given function call.

julia> @code_ir gcd(10, 5)
1: (%1, %2, %3)
  %4 = %2 == 0
  br 4 unless %4
2: ...
source
IRTools.metaFunction.
meta(Tuple{...})

Construct metadata for a given method signature. Metadata can then be used to construct IR or used to perform other reflection on the method.

See also @meta, typed_meta.

julia> IRTools.meta(Tuple{typeof(gcd),Int,Int})
Metadata for gcd(a::T, b::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at intfuncs.jl:31
source
IRTools.typed_metaFunction.
typed_meta(Tuple{...})

Same as @meta, but represents the method after type inference. IR constructed with typed metadata will have type annotations.

See also @typed_meta.

julia> IRTools.typed_meta(Tuple{typeof(gcd),Int,Int})
Typed metadata for gcd(a::T, b::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at intfuncs.jl:31
source
IRTools.@metaMacro.
@meta f(args...)

Convenience macro for retrieving metadata without writing a full type signature.

julia> IRTools.@meta gcd(10, 5)
Metadata for gcd(a::T, b::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at intfuncs.jl:31
source
@typed_meta f(args...)

Convenience macro for retrieving typed metadata without writing a full type signature.

julia> IRTools.@typed_meta gcd(10, 5)
Typed metadata for gcd(a::T, b::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at intfuncs.jl:31
source

IR Manipulation

IRTools.IRType.
IR()
IR(metadata; slots = false)

Represents a fragment of SSA-form code.

IR can be constructed from scratch, but more usually an existing Julia method is used as a starting point (see meta for how to get metadata for a method). The slots argument determines whether the IR preserves mutable variable slots; by default, these are converted to SSA-style variables.

As a shortcut, IR can be constructed directly from a type signature, e.g.

julia> IR(typeof(gcd), Int, Int)
1: (%1, %2, %3)
  %4 = %2 == 0
  br 4 unless %4
2: ...
source
Statement(expr; type, line)

Represents a single statement in the IR. The expr is a non-nested Julia expression (Expr). type represents the return type of the statement; in most cases this can be ignored and defaults to Any. line represents the source location of the statement; it is an integer index into the IR's line table.

As a convenience, if expr is already a statement, the new statement will inherit its type and line number.

source
Variable(N)
var(N)

Represents an SSA variable. Primarily used as an index into IR objects.

source
IRTools.argument!Function.
argument!(block, [value, type])

Create a new argument for the given block / IR fragment, and return the variable representing the argument.

julia> ir = IR();

julia> argument!(ir)
%1

julia> ir
1: (%1)

The at keyword argument can be used to specify where the new argument should go; by default it is appended to the end of the argument list.

If there are branches to this block, they will be updated to pass value (nothing by default) as an argument.

source
Base.push!Function.
push!(ir, x)

Append the statement or expression x to the IR or block ir, returning the new variable. See also pushfirst!, insert!.

julia> ir = IR();

julia> x = argument!(ir)
%1

julia> push!(ir, xcall(:*, x, x))
%2

julia> ir
1: (%1)
  %2 = %1 * %1
source
Base.pushfirst!Function.
pushfirst!(ir, x)

Insert the expression or statement x into the given IR or block at the beginning, returning the new variable. See also push!, insert!.

julia> f(x) = 3x + 2
f (generic function with 1 method)

julia> ir = @code_ir f(1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> pushfirst!(ir, :(println("hello, world")))
%5

julia> ir
1: (%1, %2)
  %5 = println("hello, world")
  %3 = 3 * %2
  %4 = %3 + 2
  return %4
source
Base.insert!Function.
insert!(ir, v, x)

Insert the expression or statement x into the given IR, just before the variable v is defined, returning the new variable for x. See also insertafter!.

julia> f(x) = 3x + 2
f (generic function with 1 method)

julia> ir = @code_ir f(1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> insert!(ir, IRTools.var(4), :(println("hello, world")))
%5

julia> ir
1: (%1, %2)
  %3 = 3 * %2
  %5 = println("hello, world")
  %4 = %3 + 2
  return %4
source
IRTools.insertafter!Function.
insertafter!(ir, v, x)

Insert the expression or statement x into the given IR, just before the variable v is defined, returning the new variable for x. See also insert!.

julia> f(x) = 3x + 2
f (generic function with 1 method)

julia> ir = @code_ir f(1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> IRTools.insertafter!(ir, IRTools.var(4), :(println("hello, world")))
%5

julia> ir
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  %5 = println("hello, world")
  return %4
source
Base.emptyFunction.
empty(ir)

Create an empty IR fragment based on the given IR. The line number table and any metadata are preserved from the original IR.

julia> ir = empty(@code_ir gcd(10, 5))
1:

julia> ir.meta
Metadata for gcd(a::T, b::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at intfuncs.jl:31
source
Base.keysFunction.
keys(ir)

Return the variable keys for all statements defined in ir.

julia> f(x) = 3x + 2;

julia> ir = @code_ir f(1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> keys(ir)
2-element Array{IRTools.Variable,1}:
 %3
 %4
source
Base.haskeyFunction.
haskey(ir, var)

Check whether the variable var was defined in ir.

julia> f(x) = 3x + 2;

julia> ir = @code_ir f(1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> haskey(ir, var(3))
true

julia> haskey(ir, var(7))
false
source
IRTools.returnvalueFunction.
returnvalue(block)

Retreive the return value of a block.

julia> f(x) = 3x + 2;

julia> IRTools.block(@code_ir(f(1)), 1)
1: (%1, %2)
  %3 = 3 * %2
  %4 = %3 + 2
  return %4

julia> IRTools.returnvalue(ans)
%4
source
IRTools.PipeType.
Pipe(ir)

In general, it is not efficient to insert statements into IR; only appending is fast, for the same reason as with Vectors.

For this reason, the Pipe construct makes it convenient to incrementally build an new IR fragment from an old one, making efficient modifications as you go.

The general pattern looks like:

pr = IRTools.Pipe(ir)
for (v, st) in pr
  # do stuff
end
ir = IRTools.finish(pr)

Iterating over pr is just like iterating over ir, except that within the loop, inserting and deleting statements in pr around v is efficient. Later, finish(pr) converts it back to a normal IR fragment (in this case just a plain copy of the original).

source