Skip to content

Commit

Permalink
inference: enable evaluation of pure intrinsics
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Nov 14, 2017
1 parent d042f52 commit 8d5dd0b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
42 changes: 34 additions & 8 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,12 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
return Any
end
if isa(f, IntrinsicFunction)
if is_pure_intrinsic_infer(f) && all(a -> isa(a, Const), argtypes)
argvals = anymap(a -> a.val, argtypes)
try
return Const(f(argvals...))
end
end
iidx = Int(reinterpret(Int32, f::IntrinsicFunction)) + 1
if iidx < 0 || iidx > length(t_ifunc)
# invalid intrinsic
Expand Down Expand Up @@ -2454,6 +2460,11 @@ function abstract_call(@nospecialize(f), fargs::Union{Tuple{},Vector{Any}}, argt
end
return Conditional(a, bty, aty)
end
elseif f === (Core.Inference.not_int)
aty = argtypes[2]
if isa(aty, Conditional)
return Conditional(aty.var, aty.elsetype, aty.vtype)
end
end
end
return isa(rt, TypeVar) ? rt.ub : rt
Expand Down Expand Up @@ -4219,23 +4230,38 @@ const _pure_builtins = Any[tuple, svec, fieldtype, apply_type, ===, isa, typeof,
# known effect-free calls (might not be affect-free)
const _pure_builtins_volatile = Any[getfield, arrayref, isdefined, Core.sizeof]

function is_pure_intrinsic(f::IntrinsicFunction)
# whether `f` is pure for Inference
function is_pure_intrinsic_infer(f::IntrinsicFunction)
return !(f === Intrinsics.pointerref || # this one is volatile
f === Intrinsics.pointerset || # this one is never effect-free
f === Intrinsics.llvmcall || # this one is never effect-free
f === Intrinsics.arraylen || # this one is volatile
f === Intrinsics.sqrt_llvm || # this one may differ at runtime (by a few ulps)
f === Intrinsics.cglobal) # cglobal lookup answer changes at runtime
end

# whether `f` is pure for Optimizations
function is_pure_intrinsic_optim(f::IntrinsicFunction)
return !(f === Intrinsics.pointerref || # this one is volatile
f === Intrinsics.pointerset || # this one is never effect-free
f === Intrinsics.llvmcall || # this one is never effect-free
f === Intrinsics.checked_sdiv_int ||
f === Intrinsics.arraylen || # this one is volatile
f === Intrinsics.checked_sdiv_int || # these may throw errors
f === Intrinsics.checked_udiv_int ||
f === Intrinsics.checked_srem_int ||
f === Intrinsics.checked_urem_int ||
f === Intrinsics.sqrt_llvm ||
f === Intrinsics.cglobal) # cglobal throws an error for symbol-not-found
end

function is_pure_builtin(@nospecialize(f))
return (contains_is(_pure_builtins, f) ||
contains_is(_pure_builtins_volatile, f) ||
(isa(f,IntrinsicFunction) && is_pure_intrinsic(f)) ||
f === return_type)
if isa(f, IntrinsicFunction)
return is_pure_intrinsic_optim(f)
elseif isa(f, Builtin)
return (contains_is(_pure_builtins, f) ||
contains_is(_pure_builtins_volatile, f))
else
return f === return_type
end
end

function statement_effect_free(@nospecialize(e), src::CodeInfo, mod::Module)
Expand Down Expand Up @@ -4576,7 +4602,7 @@ function inlineable(@nospecialize(f), @nospecialize(ft), e::Expr, atypes::Vector
(isbits(val) && Core.sizeof(val) <= MAX_INLINE_CONST_SIZE &&
(contains_is(_pure_builtins, f) ||
(f === getfield && effect_free(e, sv.src, sv.mod, false)) ||
(isa(f,IntrinsicFunction) && is_pure_intrinsic(f)))))
(isa(f, IntrinsicFunction) && is_pure_intrinsic_optim(f)))))
return inline_as_constant(val, argexprs, sv, nothing)
end
end
Expand Down
3 changes: 3 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1296,3 +1296,6 @@ end
f_constant(x) = convert(Int, x)
g_test_constant() = (f_constant(3) == 3 && f_constant(4) == 4 ? true : "BAD")
@test @inferred g_test_constant()

f_pure_add() = (1 + 1 == 2) ? true : "FAIL"
@test @inferred f_pure_add()

0 comments on commit 8d5dd0b

Please sign in to comment.