Skip to content

Commit ea9b2be

Browse files
NHDalykpamnany
andauthored
Add Base.isprecompilable (JuliaLang#58805) (#246)
Alternative to JuliaLang#58146. We want to compile a subset of the possible specializations of a function. To this end, we have a number of manually written `precompile` statements. Creating this list is, unfortunately, error-prone, and the list is also liable to going stale. Thus we'd like to validate each `precompile` statement in the list. The simple answer is, of course, to actually run the `precompile`s, and we naturally do so, but this takes time. We would like a relatively quick way to check the validity of a `precompile` statement. This is a dev-loop optimization, to allow us to check "is-precompilable" in unit tests. We can't use `hasmethod` as it has both false positives (too loose): ```julia julia> hasmethod(sum, (AbstractVector,)) true julia> precompile(sum, (AbstractVector,)) false julia> Base.isprecompilable(sum, (AbstractVector,)) # <- this PR false ``` and also false negatives (too strict): ```julia julia> bar(@nospecialize(x::AbstractVector{Int})) = 42 bar (generic function with 1 method) julia> hasmethod(bar, (AbstractVector,)) false julia> precompile(bar, (AbstractVector,)) true julia> Base.isprecompilable(bar, (AbstractVector,)) # <- this PR true ``` We can't use `hasmethod && isconcretetype` as it has false negatives (too strict): ```julia julia> has_concrete_method(f, argtypes) = all(isconcretetype, argtypes) && hasmethod(f, argtypes) has_concrete_method (generic function with 1 method) julia> has_concrete_method(bar, (AbstractVector,)) false julia> has_concrete_method(convert, (Type{Int}, Int32)) false julia> precompile(convert, (Type{Int}, Int32)) true julia> Base.isprecompilable(convert, (Type{Int}, Int32)) # <- this PR true ``` `Base.isprecompilable` is essentially `precompile` without the actual compilation. Co-authored-by: Kiran Pamnany <[email protected]>
1 parent 37cdbd8 commit ea9b2be

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

base/loading.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3209,6 +3209,20 @@ macro __DIR__()
32093209
return isempty(_dirname) ? pwd() : abspath(_dirname)
32103210
end
32113211

3212+
"""
3213+
isprecompilable(f, argtypes::Tuple{Vararg{Any}})
3214+
3215+
Check, as far as is possible without actually compiling, if the given
3216+
function `f` can be compiled for the argument tuple (of types) `argtypes`.
3217+
"""
3218+
function isprecompilable(@nospecialize(f), @nospecialize(argtypes::Tuple))
3219+
isprecompilable(Tuple{Core.Typeof(f), argtypes...})
3220+
end
3221+
3222+
function isprecompilable(@nospecialize(argt::Type))
3223+
ccall(:jl_is_compilable, Int32, (Any,), argt) != 0
3224+
end
3225+
32123226
"""
32133227
precompile(f, argtypes::Tuple{Vararg{Any}})
32143228

src/gf.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,6 +2929,15 @@ JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tuplet
29292929
}
29302930
}
29312931

2932+
JL_DLLEXPORT int jl_is_compilable(jl_tupletype_t *types)
2933+
{
2934+
size_t world = jl_atomic_load_acquire(&jl_world_counter);
2935+
size_t min_valid = 0;
2936+
size_t max_valid = ~(size_t)0;
2937+
jl_method_instance_t *mi = jl_get_compile_hint_specialization(types, world, &min_valid, &max_valid, 1);
2938+
return mi == NULL ? 0 : 1;
2939+
}
2940+
29322941
JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types)
29332942
{
29342943
size_t world = jl_atomic_load_acquire(&jl_world_counter);

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@
286286
XX(jl_istopmod) \
287287
XX(jl_is_binding_deprecated) \
288288
XX(jl_is_char_signed) \
289+
XX(jl_is_compilable) \
289290
XX(jl_is_const) \
290291
XX(jl_is_debugbuild) \
291292
XX(jl_is_foreign_type) \

0 commit comments

Comments
 (0)