I should have mentioned that I’m not writing a compiler pass I found out that surprisingly many things can be done in the “user space” by manually traversing CodeInfo
(example), while debugging is a way simpler. Even more surprisingly, the performance of this approach is on par with the normal compilation-execution pipeline, at least in the current generation of the Julia compiler. But of course it’s just my current use case, so I’m really thankful for all the answers!
@Roger-luo Regarding IRCode
, I played around with it a bit and can confirm it has much more useful details such as phi nodes, CFG, etc. But code_ircode()
also optimizes out many details that I want to control. For instance, in this simple case:
foo(x) = 2x + 1
bar(x) = foo(x ^ 2)
baz(x, y) = bar(x) * foo(y)
code_lowered(baz, (Float64, Int))
returns:
1-element Vector{CodeInfo}:
CodeInfo(
1 ─ %1 = Main.bar(x)
│ %2 = Main.foo(y)
│ %3 = %1 * %2
└── return %3
)
while code_ircode(baz, (Float64, Int))
produces:
1-element Vector{Pair{IRCode, DataType}}:
1 1 ─ %1 = Base.mul_float(_2, _2)::Float64 │╻╷╷ bar
│ %2 = Base.mul_float(2.0, %1)::Float64 ││╻╷ foo
│ %3 = Base.add_float(%2, 1.0)::Float64 │││╻ +
│ %4 = Base.mul_int(2, _3)::Int64 ││╻ *
│ %5 = Base.add_int(%4, 1)::Int64 ││╻ +
│ %6 = Base.sitofp(Float64, %5)::Float64 ││╻╷╷╷ promote
│ %7 = Base.mul_float(%3, %6)::Float64 ││╻ *
└── return %7 │
=> Float64
At the very least, bar()
and foo()
have been inlined preventing me from treating them in some special way, e.g. replacing with a different call. Assuming I don’t want to dive into custom interpreters yet, is the a way to turn off optimization as we can do in code_typed()
?