Skip to content

Instantly share code, notes, and snippets.

@willtebbutt
Last active November 27, 2024 14:57
Show Gist options
  • Save willtebbutt/19de1b203439469942b2b5134cdf99b4 to your computer and use it in GitHub Desktop.
Save willtebbutt/19de1b203439469942b2b5134cdf99b4 to your computer and use it in GitHub Desktop.
#=
Goal: multiple any `SSAValue`s that go into :call / :invoke expressions by 5 before passing them in. So something like
```julia
Expr(:call, *, %5, 3)
```
would become
```julia
%tmp = Expr(:call, *, 5, %5)
Expr(:call, *, %tmp, 3)
```
The point is to demonstrate how a simple task which requires insertions into the IR can be done using BBCode.
=#
using Mooncake
import Core.Compiler as CC
# Define simple function.
function test_function(x)
y = sin(x)
z = cos(y)
a = y * z
return a
end
# Grab the IRCode.
ir = Base.code_ircode_by_type(Tuple{typeof(test_function), Float64})[1][1]
# Translate it into Mooncake's BBCode. The printing for BBCode is crap, so you should always
# just call `IRCode` in it if you want to print it out.
bb_ir = Mooncake.BBCode(ir)
# We're going to construct a completely new BBCode object.
# Iterate through each basic block.
new_blocks = map(bb_ir.blocks) do block
# Iterate through each statment in the current basic block. Each statement will be
# transformed into 1 or more new statments.
new_stmts = map(1:length(block)) do n
# Get the nth statement, and its associated ID.
inst = block.insts[n]
stmt = inst.stmt
id = block.inst_ids[n]
# If the statement is one that we're interested in transform it.
if Meta.isexpr(stmt, :invoke) || Meta.isexpr(stmt, :call)
# If we have an invoke, drop the method instance.
args = Meta.isexpr(stmt, :invoke) ? stmt.args[2:end] : stmt.args
# For each argument in the :invoke / :call, construct a statment which
# multiplies it by 5. If not statement should be added, return nothing.
# Return the ID which should be places in the original instruction.
extra_stmts = map(args) do arg
if arg isa Mooncake.ID
new_inst_id = Mooncake.ID()
inst_id_pair = (new_inst_id, Mooncake.new_inst(Expr(:call, *, 5, arg)))
return (inst_id_pair, new_inst_id)
else
return ((Mooncake.ID(), Mooncake.new_inst(nothing)), arg)
end
end
multiplying_stmts = map(first, extra_stmts)
new_args = map(last, extra_stmts)
return vcat(multiplying_stmts, (id, Mooncake.new_inst(Expr(:call, new_args...))))
else
# Since this statment shouldn't be transformed, return the primal id / stmt.
return (id, inst)::Tuple{Mooncake.ID, CC.NewInstruction}
end
end
# Just concatenate the new statements. Keep the block id the same.
return Mooncake.BBlock(block.id, reduce(vcat, new_stmts))
end
# Construct a new `BBCode` which is the same as the old one, just with different blocks.
new_bb_ir = Mooncake.BBCode(bb_ir, new_blocks)
# Convert the BBCode into an equivalent IRCode.
new_ir = CC.IRCode(new_bb_ir)
# Run a standard Julia optimisation pass on the IRCode to get rid of redundancies.
optimised_ir = Mooncake.optimise_ir!(new_ir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment