Skip to content

Commit 16f9374

Browse files
serenity4aviateskCédric Belmant
committed
Make Cthulhu cache CodeInstance-based, continued (#628)
* adjust to JuliaLang/julia#54899 Although these code paths don’t seem to be used very often. * Update test/irutils.jl * wip: make Cthulhu cache `CodeInstance`-based * Small fixes * Fix tests * Handle Const wrapper * Use CodeInstance for Bookmark, fix Cthulhu tests * Add invokelatest around binding access * Minor cleanup * Remove special-casing for intermediate 1.12-DEV version * Get rid of `get_mi`, eagerly infer `CodeInstance` for task calls * Don't explore const-proped/semi-concrete evaled callsites * Fix version checks for 1.12-nightly * Comment out CI for Julia versions = '1' * Raise Julia compatibility requirement to 1.12 * Run IntegrationTest on 1.12-nightly --------- Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com> Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Co-authored-by: Cédric Belmant <cedric.belmant@juliahub.com>
1 parent 4750751 commit 16f9374

17 files changed

+393
-459
lines changed

.github/workflows/CI.yml

+20-20
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,30 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
include:
16-
- version: '1' # current stable
16+
# - version: '1' # current stable
17+
# os: ubuntu-latest
18+
# arch: x64
19+
- version: '1.12-nightly' # lowest version supported
1720
os: ubuntu-latest
1821
arch: x64
19-
- version: '1.10' # lowest version supported
22+
- version: '1.13-nightly' # next release
2023
os: ubuntu-latest
2124
arch: x64
22-
- version: '1.12-nightly' # next release
23-
os: ubuntu-latest
24-
arch: x64
25-
- version: 'nightly' # dev
26-
os: ubuntu-latest
27-
arch: x64
28-
- version: '1' # x86 ubuntu
29-
os: ubuntu-latest
30-
arch: x86
31-
- version: '1' # x86 windows
32-
os: windows-latest
33-
arch: x86
34-
- version: '1' # x64 windows
35-
os: windows-latest
36-
arch: x64
37-
- version: '1' # x64 macOS
38-
os: macos-latest
39-
arch: x64
25+
# - version: 'nightly' # dev
26+
# os: ubuntu-latest
27+
# arch: x64
28+
# - version: '1' # x86 ubuntu
29+
# os: ubuntu-latest
30+
# arch: x86
31+
# - version: '1' # x86 windows
32+
# os: windows-latest
33+
# arch: x86
34+
# - version: '1' # x64 windows
35+
# os: windows-latest
36+
# arch: x64
37+
# - version: '1' # x64 macOS
38+
# os: macos-latest
39+
# arch: x64
4040
steps:
4141
- uses: actions/checkout@v4
4242
- uses: julia-actions/setup-julia@v2

.github/workflows/IntegrationTest.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
julia-version: ['1']
16+
julia-version: ['1.12-nightly']
1717
os: [ubuntu-latest]
1818
package:
1919
- {user: timholy, repo: SnoopCompile.jl}

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ TypedSyntax = "1.3.0"
1616
UUIDs = "1.9"
1717
Unicode = "1.9"
1818
WidthLimitedIO = "1"
19-
julia = "1.10"
19+
julia = "1.12"
2020

2121
[deps]
2222
CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"

TypedSyntax/test/runtests.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ include("test_module.jl")
9090
)
9191
rootnode = JuliaSyntax.parsestmt(SyntaxNode, st; filename="TSN3.jl")
9292
TSN.eval(Expr(rootnode))
93-
tsn = TypedSyntaxNode(rootnode, TSN.firstfirst, (Vector{Vector{Real}},))
93+
tsn = TypedSyntaxNode(rootnode, @invokelatest(TSN.firstfirst), (Vector{Vector{Real}},))
9494
sig, body = children(tsn)
9595
@test child(body, idxsinner...).typ === nothing
9696
@test child(body, idxsouter...).typ === Vector{Real}

src/CthulhuBase.jl

+94-101
Large diffs are not rendered by default.

src/backedges.jl

-10
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,6 @@ function show_tuple_as_call(@nospecialize(highlighter), io::IO, name::Symbol, @n
3434
first = false
3535
printstyled(env_io, "::", sig[i], color=highlighter(sig[i]))
3636
end
37-
# if kwargs !== nothing
38-
# print(io, "; ")
39-
# first = true
40-
# for (k, t) in kwargs
41-
# first || print(io, ", ")
42-
# first = false
43-
# print(io, k, "::")
44-
# show(io, t)
45-
# end
46-
# end
4737
print(io, ")")
4838
Base.show_method_params(io, tv)
4939
nothing

src/callsite.jl

+54-60
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@ using Unicode
33
abstract type CallInfo end
44

55
# Call could be resolved to a singular MI
6-
struct MICallInfo <: CallInfo
7-
mi::MethodInstance
6+
struct EdgeCallInfo <: CallInfo
7+
edge::CodeInstance
88
rt
99
effects::Effects
1010
exct
11-
function MICallInfo(mi::MethodInstance, @nospecialize(rt), effects, @nospecialize(exct=nothing))
11+
function EdgeCallInfo(edge::CodeInstance, @nospecialize(rt), effects::Effects, @nospecialize(exct=nothing))
1212
if isa(rt, LimitedAccuracy)
13-
return LimitedCallInfo(new(mi, ignorelimited(rt), effects, exct))
13+
return LimitedCallInfo(new(edge, ignorelimited(rt), effects, exct))
1414
else
15-
return new(mi, rt, effects, exct)
15+
return new(edge, rt, effects, exct)
1616
end
1717
end
1818
end
19-
get_mi(ci::MICallInfo) = ci.mi
20-
get_rt(ci::MICallInfo) = ci.rt
21-
get_effects(ci::MICallInfo) = ci.effects
22-
get_exct(ci::MICallInfo) = ci.exct
19+
get_ci(ci::EdgeCallInfo) = ci.edge
20+
get_rt(ci::EdgeCallInfo) = ci.rt
21+
get_effects(ci::EdgeCallInfo) = ci.effects
22+
get_exct(ci::EdgeCallInfo) = ci.exct
2323

2424
abstract type WrappedCallInfo <: CallInfo end
2525

2626
get_wrapped(ci::WrappedCallInfo) = ci.wrapped
2727
ignorewrappers(ci::CallInfo) = ci
2828
ignorewrappers(ci::WrappedCallInfo) = ignorewrappers(get_wrapped(ci))
29-
get_mi(ci::WrappedCallInfo) = get_mi(ignorewrappers(ci))
29+
get_ci(ci::WrappedCallInfo) = get_ci(ignorewrappers(ci))
3030
get_rt(ci::WrappedCallInfo) = get_rt(ignorewrappers(ci))
3131
get_effects(ci::WrappedCallInfo) = get_effects(ignorewrappers(ci))
3232
get_exct(ci::WrappedCallInfo) = get_exct(ignorewrappers(ci))
@@ -44,22 +44,17 @@ struct RTCallInfo <: CallInfo
4444
exct
4545
end
4646
get_rt(ci::RTCallInfo) = ci.rt
47-
get_mi(ci::RTCallInfo) = nothing
47+
get_ci(ci::RTCallInfo) = nothing
4848
get_effects(ci::RTCallInfo) = Effects()
4949
get_exct(ci::RTCallInfo) = ci.exct
5050

51-
# uncached callsite, we can't recurse into this call
52-
struct UncachedCallInfo <: WrappedCallInfo
53-
wrapped::CallInfo
54-
end
55-
5651
struct PureCallInfo <: CallInfo
5752
argtypes::Vector{Any}
5853
rt
5954
PureCallInfo(argtypes::Vector{Any}, @nospecialize(rt)) =
6055
new(argtypes, rt)
6156
end
62-
get_mi(::PureCallInfo) = nothing
57+
get_ci(::PureCallInfo) = nothing
6358
get_rt(pci::PureCallInfo) = pci.rt
6459
get_effects(::PureCallInfo) = EFFECTS_TOTAL
6560
get_exct(::PureCallInfo) = Union{}
@@ -69,7 +64,7 @@ struct FailedCallInfo <: CallInfo
6964
sig
7065
rt
7166
end
72-
get_mi(ci::FailedCallInfo) = fail(ci)
67+
get_ci(ci::FailedCallInfo) = fail(ci)
7368
get_rt(ci::FailedCallInfo) = fail(ci)
7469
get_effects(ci::FailedCallInfo) = fail(ci)
7570
get_exct(ci::FailedCallInfo) = fail(ci)
@@ -83,7 +78,7 @@ struct GeneratedCallInfo <: CallInfo
8378
sig
8479
rt
8580
end
86-
get_mi(genci::GeneratedCallInfo) = fail(genci)
81+
get_ci(genci::GeneratedCallInfo) = fail(genci)
8782
get_rt(genci::GeneratedCallInfo) = fail(genci)
8883
get_effects(genci::GeneratedCallInfo) = fail(genci)
8984
get_exct(genci::GeneratedCallInfo) = fail(genci)
@@ -101,15 +96,15 @@ struct MultiCallInfo <: CallInfo
10196
@nospecialize(exct=nothing)) =
10297
new(sig, rt, exct, callinfos)
10398
end
104-
get_mi(ci::MultiCallInfo) = error("Can't extract MethodInstance from multiple call informations")
99+
get_ci(ci::MultiCallInfo) = error("Can't extract MethodInstance from multiple call informations")
105100
get_rt(ci::MultiCallInfo) = ci.rt
106101
get_effects(mci::MultiCallInfo) = mapreduce(get_effects, CC.merge_effects, mci.callinfos)
107102
get_exct(ci::MultiCallInfo) = ci.exct
108103

109104
struct TaskCallInfo <: CallInfo
110105
ci::CallInfo
111106
end
112-
get_mi(tci::TaskCallInfo) = get_mi(tci.ci)
107+
get_ci(tci::TaskCallInfo) = get_ci(tci.ci)
113108
get_rt(tci::TaskCallInfo) = get_rt(tci.ci)
114109
get_effects(tci::TaskCallInfo) = get_effects(tci.ci)
115110
get_exct(tci::TaskCallInfo) = get_exct(tci.ci)
@@ -118,7 +113,7 @@ struct InvokeCallInfo <: CallInfo
118113
ci::CallInfo
119114
InvokeCallInfo(@nospecialize ci::CallInfo) = new(ci)
120115
end
121-
get_mi(ici::InvokeCallInfo) = get_mi(ici.ci)
116+
get_ci(ici::InvokeCallInfo) = get_ci(ici.ci)
122117
get_rt(ici::InvokeCallInfo) = get_rt(ici.ci)
123118
get_effects(ici::InvokeCallInfo) = get_effects(ici.ci)
124119
get_exct(ici::InvokeCallInfo) = get_exct(ici.ci)
@@ -128,7 +123,7 @@ struct OCCallInfo <: CallInfo
128123
ci::CallInfo
129124
OCCallInfo(@nospecialize ci::CallInfo) = new(ci)
130125
end
131-
get_mi(occi::OCCallInfo) = get_mi(occi.ci)
126+
get_ci(occi::OCCallInfo) = get_ci(occi.ci)
132127
get_rt(occi::OCCallInfo) = get_rt(occi.ci)
133128
get_effects(occi::OCCallInfo) = get_effects(occi.ci)
134129
get_exct(occi::OCCallInfo) = get_exct(occi.ci)
@@ -137,52 +132,52 @@ get_exct(occi::OCCallInfo) = get_exct(occi.ci)
137132
struct ReturnTypeCallInfo <: CallInfo
138133
vmi::CallInfo # virtualized method call
139134
end
140-
get_mi((; vmi)::ReturnTypeCallInfo) = isa(vmi, FailedCallInfo) ? nothing : get_mi(vmi)
135+
get_ci((; vmi)::ReturnTypeCallInfo) = isa(vmi, FailedCallInfo) ? nothing : get_ci(vmi)
141136
get_rt((; vmi)::ReturnTypeCallInfo) = Type{isa(vmi, FailedCallInfo) ? Union{} : widenconst(get_rt(vmi))}
142137
get_effects(::ReturnTypeCallInfo) = EFFECTS_TOTAL
143138
get_exct(::ReturnTypeCallInfo) = Union{} # FIXME
144139

145140
struct ConstPropCallInfo <: CallInfo
146-
mi::CallInfo
141+
ci::CallInfo
147142
result::InferenceResult
148143
end
149-
get_mi(cpci::ConstPropCallInfo) = cpci.result.linfo
150-
get_rt(cpci::ConstPropCallInfo) = get_rt(cpci.mi)
144+
get_ci(cpci::ConstPropCallInfo) = get_ci(cpci.ci)
145+
get_rt(cpci::ConstPropCallInfo) = get_rt(cpci.ci)
151146
get_effects(cpci::ConstPropCallInfo) = get_effects(cpci.result)
152-
get_exct(cpci::ConstPropCallInfo) = get_exct(cpci.mi)
147+
get_exct(cpci::ConstPropCallInfo) = get_exct(cpci.ci)
153148

154149
struct ConcreteCallInfo <: CallInfo
155-
mi::CallInfo
150+
ci::CallInfo
156151
argtypes::ArgTypes
157152
end
158-
get_mi(ceci::ConcreteCallInfo) = get_mi(ceci.mi)
159-
get_rt(ceci::ConcreteCallInfo) = get_rt(ceci.mi)
160-
get_effects(ceci::ConcreteCallInfo) = get_effects(ceci.mi)
161-
get_exct(cici::ConcreteCallInfo) = get_exct(ceci.mi)
153+
get_ci(ceci::ConcreteCallInfo) = get_ci(ceci.ci)
154+
get_rt(ceci::ConcreteCallInfo) = get_rt(ceci.ci)
155+
get_effects(ceci::ConcreteCallInfo) = get_effects(ceci.ci)
156+
get_exct(cici::ConcreteCallInfo) = get_exct(ceci.ci)
162157

163158
struct SemiConcreteCallInfo <: CallInfo
164-
mi::CallInfo
159+
ci::CallInfo
165160
ir::IRCode
166161
end
167-
get_mi(scci::SemiConcreteCallInfo) = get_mi(scci.mi)
168-
get_rt(scci::SemiConcreteCallInfo) = get_rt(scci.mi)
169-
get_effects(scci::SemiConcreteCallInfo) = get_effects(scci.mi)
170-
get_exct(scci::SemiConcreteCallInfo) = get_exct(scci.mi)
162+
get_ci(scci::SemiConcreteCallInfo) = get_ci(scci.ci)
163+
get_rt(scci::SemiConcreteCallInfo) = get_rt(scci.ci)
164+
get_effects(scci::SemiConcreteCallInfo) = get_effects(scci.ci)
165+
get_exct(scci::SemiConcreteCallInfo) = get_exct(scci.ci)
171166

172167
# CUDA callsite
173168
struct CuCallInfo <: CallInfo
174-
cumi::MICallInfo
169+
ci::EdgeCallInfo
175170
end
176-
get_mi(gci::CuCallInfo) = get_mi(gci.cumi)
177-
get_rt(gci::CuCallInfo) = get_rt(gci.cumi)
178-
get_effects(gci::CuCallInfo) = get_effects(gci.cumi)
171+
get_ci(gci::CuCallInfo) = get_ci(gci.ci)
172+
get_rt(gci::CuCallInfo) = get_rt(gci.ci)
173+
get_effects(gci::CuCallInfo) = get_effects(gci.ci)
179174

180175
struct Callsite
181176
id::Int # ssa-id
182177
info::CallInfo
183178
head::Symbol
184179
end
185-
get_mi(c::Callsite) = get_mi(c.info)
180+
get_ci(c::Callsite) = get_ci(c.info)
186181
get_effects(c::Callsite) = get_effects(c.info)
187182

188183
# Callsite printing
@@ -277,17 +272,17 @@ function Base.show(io::IO, (;exct)::ExctWrapper)
277272
printstyled(io, "(↑::", exct, ")"; color)
278273
end
279274

280-
function show_callinfo(limiter, mici::MICallInfo)
281-
mi = mici.mi
275+
function show_callinfo(limiter, ci::EdgeCallInfo)
276+
mi = ci.edge.def
282277
tt = (Base.unwrap_unionall(mi.specTypes)::DataType).parameters[2:end]
283278
if !isa(mi.def, Method)
284279
name = ":toplevel"
285280
else
286281
name = mi.def.name
287282
end
288-
rt = get_rt(mici)
289-
exct = get_exct(mici)
290-
__show_limited(limiter, name, tt, rt, get_effects(mici), exct)
283+
rt = get_rt(ci)
284+
exct = get_exct(ci)
285+
__show_limited(limiter, name, tt, rt, get_effects(ci), exct)
291286
end
292287

293288
function show_callinfo(limiter, ci::Union{MultiCallInfo, FailedCallInfo, GeneratedCallInfo})
@@ -317,20 +312,20 @@ function show_callinfo(limiter, ci::ConstPropCallInfo)
317312
# XXX: The first argument could be const-overriden too
318313
name = ci.result.linfo.def.name
319314
tt = ci.result.argtypes[2:end]
320-
ci = ignorewrappers(ci.mi)::MICallInfo
315+
ci = ignorewrappers(ci.ci)::EdgeCallInfo
321316
__show_limited(limiter, name, tt, get_rt(ci), get_effects(ci))
322317
end
323318

324319
function show_callinfo(limiter, ci::SemiConcreteCallInfo)
325320
# XXX: The first argument could be const-overriden too
326-
name = get_mi(ci).def.name
321+
name = get_ci(ci).def.def.name
327322
tt = ci.ir.argtypes[2:end]
328323
__show_limited(limiter, name, tt, get_rt(ci), get_effects(ci))
329324
end
330325

331326
function show_callinfo(limiter, ci::ConcreteCallInfo)
332327
# XXX: The first argument could be const-overriden too
333-
name = get_mi(ci).def.name
328+
name = get_ci(ci).def.def.name
334329
tt = ci.argtypes[2:end]
335330
__show_limited(limiter, name, tt, get_rt(ci), get_effects(ci))
336331
end
@@ -435,7 +430,7 @@ function Base.show(io::IO, c::Callsite)
435430
limiter = TextWidthLimiter(io, cols)
436431
limiter.width += 1 # for the '%' character
437432
print(limiter, string(c.id))
438-
if isa(info, MICallInfo)
433+
if isa(info, EdgeCallInfo)
439434
print(limiter, optimize ? string(" = ", c.head, ' ') : " = ")
440435
show_callinfo(limiter, info)
441436
else
@@ -457,16 +452,15 @@ function wrapped_callinfo(limiter, ci::WrappedCallInfo)
457452
print(limiter, " > ")
458453
end
459454
_wrapped_callinfo(limiter, ::LimitedCallInfo) = print(limiter, "limited")
460-
_wrapped_callinfo(limiter, ::UncachedCallInfo) = print(limiter, "uncached")
461455

462456
# is_callsite returns true if `call` dispatches to `callee`
463457
# See also `maybe_callsite` below
464-
is_callsite(call::MethodInstance, callee::MethodInstance) = call === callee
465-
is_callsite(::Nothing, callee::MethodInstance) = false # for when `get_mi` returns `nothing`
458+
is_callsite(call::CodeInstance, callee::MethodInstance) = call.def === callee
459+
is_callsite(::Nothing, callee::MethodInstance) = false # for when `get_ci` returns `nothing`
466460

467461
# is_callsite for higher-level inputs
468462
is_callsite(cs::Callsite, callee::MethodInstance) = is_callsite(cs.info, callee)
469-
is_callsite(info::CallInfo, callee::MethodInstance) = is_callsite(get_mi(info), callee)
463+
is_callsite(info::CallInfo, callee::MethodInstance) = is_callsite(get_ci(info), callee)
470464
# special CallInfo cases:
471465
function is_callsite(info::MultiCallInfo, callee::MethodInstance)
472466
for csi in info.callinfos
@@ -477,7 +471,7 @@ end
477471

478472
# maybe_callsite returns true if `call` *might* dispatch to `callee`
479473
# See also `is_callsite` above
480-
function maybe_callsite(call::MethodInstance, callee::MethodInstance)
474+
function maybe_callsite(call::CodeInstance, callee::MethodInstance)
481475
# handle comparison among Varargs
482476
function generalized_va_subtype(@nospecialize(Tshort), @nospecialize(Tlong))
483477
nshort, nlong = length(Tshort.parameters), length(Tlong.parameters)
@@ -492,7 +486,7 @@ function maybe_callsite(call::MethodInstance, callee::MethodInstance)
492486
return T <: unwrapva(Tlong.parameters[end])
493487
end
494488

495-
Tcall, Tcallee = call.specTypes, callee.specTypes
489+
Tcall, Tcallee = call.def.specTypes, callee.specTypes
496490
Tcall <: Tcallee && return true
497491
# Make sure we handle Tcall = Tuple{Vararg{String}}, Tcallee = Tuple{String,Vararg{String}}
498492
if Base.isvatuple(Tcall) && Base.isvatuple(Tcallee)
@@ -507,7 +501,7 @@ end
507501
# maybe_callsite for higher-level inputs
508502
maybe_callsite(cs::Callsite, callee::MethodInstance) = maybe_callsite(cs.info, callee)
509503
maybe_callsite(cs::Callsite, @nospecialize(tt::Type)) = maybe_callsite(cs.info, tt)
510-
maybe_callsite(info::CallInfo, callee::MethodInstance) = maybe_callsite(get_mi(info), callee)
504+
maybe_callsite(info::CallInfo, callee::MethodInstance) = maybe_callsite(get_ci(info), callee)
511505
# Special CallInfo cases:
512506
function maybe_callsite(info::MultiCallInfo, callee::MethodInstance)
513507
for csi in info.callinfos
@@ -527,7 +521,7 @@ function maybe_callsite(info::RTCallInfo, @nospecialize(tt::Type))
527521
end
528522
return true
529523
end
530-
function maybe_callsite(info::MICallInfo, @nospecialize(tt::Type))
524+
function maybe_callsite(info::EdgeCallInfo, @nospecialize(tt::Type))
531525
return tt <: info.mi.specTypes
532526
end
533527

0 commit comments

Comments
 (0)