首页 > 解决方案 > 在 IRTools 发电机中提取自己的 IR

问题描述

我正在尝试编写一个IRTools发电机,它将在内部使用调用它的方法的 IR。作为一个简化的例子,keep_ir(f, args...)应该返回(f(args...), IR(f, args...)).

我尝试了以下方法:

IRTools.@dynamo function keep_ir(f, args...)
    old_ir = IRTools.IR(f, args...)
    new_ir = IRTools.empty(old_ir)
    foreach(arg -> IRTools.argument!(new_ir), IRTools.arguments(old_ir))
    foreach(((v, stmt),) -> push!(new_ir, stmt.expr), old_ir)

    arg_types = [IRTools.xcall(Core, :Typeof, arg) for arg in IRTools.arguments(old_ir)]
    original_ir = push!(new_ir, IRTools.xcall(IRTools, :IR,
                                              IRTools.xcall(IRTools, :meta,
                                                            IRTools.xcall(Core, :apply_type,
                                                                          :(Base.Tuple),
                                                                          arg_types...))))
    old_rv = IRTools.branches(IRTools.block(old_ir, 1))[end]
    new_rv = push!(new_ir, IRTools.xcall(:tuple, old_rv.args[1], original_ir))
    IRTools.return!(new_ir, new_rv)
    @show new_ir # for debugging
    return new_ir
end

但它失败了一个模糊的错误:

julia> ff(x, y) = 4x + y^2, x
ff (generic function with 1 method)

julia> keep_ir(ff, 1, 20)
new_ir = 1: (%1, %2, %3)
  %4 = 4 * %2
  %5 = Core.apply_type(Base.Val, 2)
  %6 = (%5)()
  %7 = Base.literal_pow(Main.:^, %3, %6)
  %8 = %4 + %7
  %9 = Core.tuple(%8, %2)
  %10 = Base.Tuple
  %11 = Core.Typeof(%1)
  %12 = Core.Typeof(%2)
  %13 = Core.Typeof(%3)
  %14 = Core.apply_type(%10, %11, %12, %13)
  %15 = IRTools.meta(%14)
  %16 = IRTools.IR(%15)
  %17 = Base.tuple(%9, %16)
  return %17

ERROR: error compiling keep_ir: unsupported or misplaced expression "." in function keep_ir
Stacktrace:
 [1] top-level scope at REPL[76]:1
caused by [exception 1]
unsupported or misplaced expression "." in function keep_ir
Stacktrace:
 [1] top-level scope at REPL[76]:1

不过,它构建的 IR 对我来说看起来不错……

标签: compilationjulia

解决方案


您可以在编译时将其拼接为一个值,而不是尝试在运行时重建 IR:

using IRTools
using IRTools: @dynamo, IR, returnvalue, block, xcall, return!

@dynamo function keepir(args...)
  ir = IR(args...)
  ir2 = copy(ir)
  ret = push!(ir, xcall(:tuple, returnvalue(block(ir, 1)), ir2))
  return!(ir, ret)
  return ir
end

ff(x, y) = 4x + y^2, x

keepir(ff, 2, 3) # => ((17, 2), IR(...))

FWIW,您看到的错误可能来自:(Base.Tuple)您在 IR 中输入的表达式。如果您改用它应该可以工作GlobalRef(Base, :Tuple)


推荐阅读