Skip to content

Commit 4ae311c

Browse files
committed
git lecture 9 init
1 parent 62e0790 commit 4ae311c

22 files changed

+2613
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using MacroTools
2+
using IRTools
3+
4+
using IRTools: branches, block, empty!, evalir, func, branch!, block, IR, @dynamo, xcall
5+
6+
function _mark(label, ex)
7+
label isa Symbol || error("label has to be a Symbol")
8+
return Expr(
9+
:block,
10+
Expr(:meta, :begin_optional, label),
11+
esc(ex),
12+
Expr(:meta, :end_optional, label),
13+
)
14+
end
15+
16+
macro mark(label, ex)
17+
_mark(label, ex)
18+
end
19+
20+
21+
foo(x) = bar(baz(x))
22+
23+
function bar(x)
24+
@mark print iseven(x) && println("The input is even.")
25+
x
26+
end
27+
28+
function baz(x)
29+
@mark print x<0 && println("The input is negative.")
30+
x
31+
end
32+
33+
34+
35+
isbegin(e::Expr) = Meta.isexpr(e,:meta) && e.args[1]===:begin_optional
36+
isend(e::Expr) = Meta.isexpr(e,:meta) && e.args[1]===:end_optional
37+
38+
39+
skip(f::Core.IntrinsicFunction, args...) = f(args...)
40+
skip(f::Core.Builtin, args...) = f(args...)
41+
42+
@dynamo function skip(args...)
43+
ir = IR(args...)
44+
delete_line = false
45+
local orig
46+
47+
for (x,st) in ir
48+
is_begin = isbegin(st.expr)
49+
is_end = isend(st.expr)
50+
51+
if is_begin
52+
delete_line = true
53+
end
54+
55+
if is_begin
56+
orig = block(ir,x)
57+
elseif is_end
58+
dest = block(ir,x)
59+
if orig != dest
60+
empty!(branches(orig))
61+
branch!(orig,dest)
62+
end
63+
end
64+
65+
if delete_line
66+
delete!(ir,x)
67+
end
68+
69+
if is_end
70+
delete_line = false
71+
end
72+
73+
if haskey(ir,x) && Meta.isexpr(st.expr,:call)
74+
ir[x] = IRTools.xcall(skip, st.expr.args...)
75+
end
76+
end
77+
return ir
78+
end
79+
80+
function skip(ex::Expr)
81+
end
82+
83+
macro skip(ex)
84+
ex.head == :call || error("Input expression has to be a `:call`.")
85+
return xcall(skip, ex.args...)
86+
end
87+
88+
display(@code_ir foo(-2))
89+
display(@code_ir skip(foo,-2))
90+
display(foo(-2))
91+
@skip foo(-2)
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Dictionaries
2+
include("loggingprofiler.jl")
3+
4+
function retrieve_code_info(sigtypes, world = Base.get_world_counter())
5+
S = Tuple{map(s -> Core.Compiler.has_free_typevars(s) ? typeof(s.parameters[1]) : s, sigtypes)...}
6+
_methods = Base._methods_by_ftype(S, -1, world)
7+
if isempty(_methods)
8+
@info("method $(sigtypes) does not exist")
9+
return(nothing)
10+
end
11+
type_signature, raw_static_params, method = _methods[1]
12+
mi = Core.Compiler.specialize_method(method, type_signature, raw_static_params, false)
13+
ci = Base.isgenerated(mi) ? Core.Compiler.get_staged(mi) : Base.uncompressed_ast(method)
14+
Base.Meta.partially_inline!(ci.code, [], method.sig, Any[raw_static_params...], 0, 0, :propagate)
15+
ci
16+
end
17+
18+
function overdubbable(ex::Expr)
19+
ex.head != :call && return(false)
20+
length(ex.args) < 2 && return(false)
21+
return(overdubbable(ex.args[1]))
22+
end
23+
overdubbable(gr::Core.GlobalRef) = gr.name [:overdub, :record_start, :record_end, :promote, :convert, :tuple]
24+
# overdubbable(gr::Symbol) =
25+
overdubbable(ex) = false
26+
timable(ex) = overdubbable(ex)
27+
28+
#
29+
remap(ex::Expr, maps) = Expr(ex.head, remap(ex.args, maps)...)
30+
remap(args::AbstractArray, maps) = map(a -> remap(a, maps), args)
31+
remap(c::Core.GotoNode, maps) = Core.GotoNode(maps.goto[c.label])
32+
remap(c::Core.GotoIfNot, maps) = Core.GotoIfNot(remap(c.cond, maps), maps.goto[c.dest])
33+
remap(r::Core.ReturnNode, maps) = Core.ReturnNode(remap(r.val, maps))
34+
remap(a::Core.SlotNumber, maps) = maps.slots[a.id]
35+
remap(a::Core.SSAValue, maps) = Core.SSAValue(maps.ssa[a.id])
36+
remap(a::Core.NewvarNode, maps) = Core.NewvarNode(maps.slots[a.slot.id])
37+
remap(a::GlobalRef, maps) = a
38+
remap(a::QuoteNode, maps) = a
39+
remap(ex, maps) = ex
40+
41+
exportname(ex::GlobalRef) = QuoteNode(ex.name)
42+
exportname(ex::Symbol) = QuoteNode(ex)
43+
exportname(ex::Expr) = exportname(ex.args[1])
44+
exportname(i::Int) = QuoteNode(Symbol("Int(",i,")"))
45+
46+
dummy() = return
47+
function empty_codeinfo()
48+
new_ci = code_lowered(dummy, Tuple{})[1]
49+
empty!(new_ci.code)
50+
empty!(new_ci.slotnames)
51+
empty!(new_ci.linetable)
52+
empty!(new_ci.codelocs)
53+
new_ci
54+
end
55+
56+
overdub(f::Core.IntrinsicFunction, args...) = f(args...)
57+
overdub(f::Core.Builtin, args...) = f(args...)
58+
59+
@generated function overdub(f::F, args...) where {F}
60+
ci = retrieve_code_info((F, args...))
61+
if ci === nothing
62+
return(Expr(:call, :f, [:(args[$(i)]) for i in 1:length(args)]...))
63+
end
64+
65+
new_ci = empty_codeinfo()
66+
new_ci.slotnames = vcat([Symbol("#self#"), :f, :args], ci.slotnames[2:end])
67+
new_ci.slotflags = vcat([0x00, 0x00, 0x00], ci.slotflags[2:end])
68+
foreach(s -> push!(new_ci.linetable, s), ci.linetable)
69+
70+
maps = (
71+
ssa = Dict{Int, Int}(),
72+
slots = Dict{Int, Any}(),
73+
goto = Dict{Int,Int}(),
74+
)
75+
76+
#we need to map indexes of slot-variables from ci to their new values.
77+
# except the first one, we just remap them
78+
maps.slots[1] = Core.SlotNumber(1)
79+
foreach(i -> maps.slots[i] = Core.SlotNumber(i + 2), 2:length(ci.slotnames)) # they are shifted by 2 accomondating inserted `f` and `args`
80+
81+
#if somewhere the original parameters of the functions will be used
82+
#they needs to be remapped to an SSAValue from here, since the overdubbed
83+
# function has signatures overdub(f, args...) instead of f(x,y,z...)
84+
newci_no = 0
85+
for i in 1:length(args)
86+
newci_no +=1
87+
push!(new_ci.code, Expr(:call, Base.getindex, Core.SlotNumber(3), i))
88+
maps.slots[i+1] = Core.SSAValue(newci_no)
89+
push!(new_ci.codelocs, ci.codelocs[1])
90+
end
91+
92+
for (ci_no, ex) in enumerate(ci.code)
93+
if timable(ex)
94+
fname = exportname(ex)
95+
push!(new_ci.code, Expr(:call, GlobalRef(LoggingProfiler, :record_start), fname))
96+
push!(new_ci.codelocs, ci.codelocs[ci_no])
97+
newci_no += 1
98+
maps.goto[ci_no] = newci_no
99+
# if overdubbable(ex)
100+
# ex = Expr(:call, GlobalRef(Main, :overdub), ex.args...)
101+
# end
102+
push!(new_ci.code, ex)
103+
push!(new_ci.codelocs, ci.codelocs[ci_no])
104+
newci_no += 1
105+
maps.ssa[ci_no] = newci_no
106+
push!(new_ci.code, Expr(:call, GlobalRef(LoggingProfiler, :record_end), fname))
107+
push!(new_ci.codelocs, ci.codelocs[ci_no])
108+
newci_no += 1
109+
else
110+
push!(new_ci.code, ex)
111+
push!(new_ci.codelocs, ci.codelocs[ci_no])
112+
newci_no += 1
113+
maps.ssa[ci_no] = newci_no
114+
end
115+
end
116+
117+
for i in length(args)+1:length(new_ci.code)
118+
new_ci.code[i] = remap(new_ci.code[i], maps)
119+
end
120+
new_ci
121+
new_ci.inferred = false
122+
new_ci.ssavaluetypes = length(new_ci.code)
123+
# new_ci
124+
return(new_ci)
125+
end
126+
127+
LoggingProfiler.reset!()
128+
new_ci = overdub(sin, 1.0)
129+
LoggingProfiler.to
130+
131+
function foo(x, y)
132+
z = x * y
133+
z + sin(y)
134+
end
135+
136+
137+
LoggingProfiler.reset!()
138+
overdub(foo, 1.0, 1.0)
139+
LoggingProfiler.to
140+
141+
macro record(ex)
142+
Expr(:call, :overdub, ex.args...)
143+
end
144+
145+
LoggingProfiler.reset!()
146+
@record foo(1.0, 1.0)
147+
LoggingProfiler.to

0 commit comments

Comments
 (0)