Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

egal_tfunc bugfix #29838

Merged
merged 3 commits into from
Oct 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, spvals::SimpleVector
atyp = argextype(ex.args[3], src, spvals, slottypes)
return isknowntype(atyp) ? 4 : params.inline_nonleaf_penalty
end
fidx = findfirst(x->x===f, T_FFUNC_KEY)
fidx = find_tfunc(f)
if fidx === nothing
# unknown/unhandled builtin or anonymous function
# Use the generic cost of a direct function call
Expand Down
115 changes: 64 additions & 51 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ const T_IFUNC_COST = Vector{Int}(undef, N_IFUNC)
const T_FFUNC_KEY = Vector{Any}()
const T_FFUNC_VAL = Vector{Tuple{Int, Int, Any}}()
const T_FFUNC_COST = Vector{Int}()
function find_tfunc(@nospecialize f)
for i = 1:length(T_FFUNC_KEY)
if T_FFUNC_KEY[i] === f
return i
end
end
end

const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name)
const DATATYPE_PARAMETERS_FIELDINDEX = fieldindex(DataType, :parameters)
Expand Down Expand Up @@ -198,33 +205,36 @@ cglobal_tfunc(@nospecialize(fptr)) = Ptr{Cvoid}
cglobal_tfunc(@nospecialize(fptr), @nospecialize(t)) = (isType(t) ? Ptr{t.parameters[1]} : Ptr)
cglobal_tfunc(@nospecialize(fptr), t::Const) = (isa(t.val, Type) ? Ptr{t.val} : Ptr)
add_tfunc(Core.Intrinsics.cglobal, 1, 2, cglobal_tfunc, 5)
add_tfunc(ifelse, 3, 3,
function (@nospecialize(cnd), @nospecialize(x), @nospecialize(y))
if isa(cnd, Const)
if cnd.val === true
return x
elseif cnd.val === false
return y
else
return Bottom
end
elseif isa(cnd, Conditional)
# optimized (if applicable) in abstract_call
elseif !(Bool ⊑ cnd)

function ifelse_tfunc(@nospecialize(cnd), @nospecialize(x), @nospecialize(y))
if isa(cnd, Const)
if cnd.val === true
return x
elseif cnd.val === false
return y
else
return Bottom
end
return tmerge(x, y)
end, 1)
elseif isa(cnd, Conditional)
# optimized (if applicable) in abstract_call
elseif !(Bool ⊑ cnd)
return Bottom
end
return tmerge(x, y)
end
add_tfunc(ifelse, 3, 3, ifelse_tfunc, 1)

function egal_tfunc(@nospecialize(x), @nospecialize(y))
xx = maybe_widen_conditional(x)
yy = maybe_widen_conditional(y)
if isa(x, Conditional) && isa(yy, Const)
yy.val === false && return Conditional(x.var, x.elsetype, x.vtype)
yy.val === true && return x
return x
return Const(false)
elseif isa(y, Conditional) && isa(xx, Const)
xx.val === false && return Conditional(y.var, y.elsetype, y.vtype)
xx.val === true && return y
return Const(false)
elseif isa(xx, Const) && isa(yy, Const)
return Const(xx.val === yy.val)
elseif typeintersect(widenconst(xx), widenconst(yy)) === Bottom
Expand All @@ -236,6 +246,7 @@ function egal_tfunc(@nospecialize(x), @nospecialize(y))
return Bool
end
add_tfunc(===, 2, 2, egal_tfunc, 1)

function isdefined_nothrow(argtypes::Array{Any, 1})
length(argtypes) == 2 || return false
return typeintersect(widenconst(argtypes[1]), Module) === Union{} ?
Expand Down Expand Up @@ -435,23 +446,24 @@ function typeof_tfunc(@nospecialize(t))
end
end
add_tfunc(typeof, 1, 1, typeof_tfunc, 0)
add_tfunc(typeassert, 2, 2,
function (@nospecialize(v), @nospecialize(t))
t = instanceof_tfunc(t)[1]
t === Any && return v
if isa(v, Const)
if !has_free_typevars(t) && !isa(v.val, t)
return Bottom
end
return v
elseif isa(v, Conditional)
if !(Bool <: t)
return Bottom
end
return v
end
return typeintersect(widenconst(v), t)
end, 4)

function typeassert_tfunc(@nospecialize(v), @nospecialize(t))
t = instanceof_tfunc(t)[1]
t === Any && return v
if isa(v, Const)
if !has_free_typevars(t) && !isa(v.val, t)
return Bottom
end
return v
elseif isa(v, Conditional)
if !(Bool <: t)
return Bottom
end
return v
end
return typeintersect(widenconst(v), t)
end
add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4)

function isa_tfunc(@nospecialize(v), @nospecialize(tt))
t, isexact = instanceof_tfunc(tt)
Expand Down Expand Up @@ -487,23 +499,24 @@ function isa_tfunc(@nospecialize(v), @nospecialize(tt))
return Bool
end
add_tfunc(isa, 2, 2, isa_tfunc, 0)
add_tfunc(<:, 2, 2,
function (@nospecialize(a), @nospecialize(b))
a, isexact_a = instanceof_tfunc(a)
b, isexact_b = instanceof_tfunc(b)
if !has_free_typevars(a) && !has_free_typevars(b)
if a <: b
if isexact_b || a === Bottom
return Const(true)
end
else
if isexact_a || (b !== Bottom && typeintersect(a, b) === Union{})
return Const(false)
end
end
end
return Bool
end, 0)

function subtype_tfunc(@nospecialize(a), @nospecialize(b))
a, isexact_a = instanceof_tfunc(a)
b, isexact_b = instanceof_tfunc(b)
if !has_free_typevars(a) && !has_free_typevars(b)
if a <: b
if isexact_b || a === Bottom
return Const(true)
end
else
if isexact_a || (b !== Bottom && typeintersect(a, b) === Union{})
return Const(false)
end
end
end
return Bool
end
add_tfunc(<:, 2, 2, subtype_tfunc, 0)

function const_datatype_getfield_tfunc(@nospecialize(sv), fld::Int)
if (fld == DATATYPE_NAME_FIELDINDEX ||
Expand Down Expand Up @@ -1248,7 +1261,7 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
end
tf = T_IFUNC[iidx]
else
fidx = findfirst(x->x===f, T_FFUNC_KEY)
fidx = find_tfunc(f)
if fidx === nothing
# unknown/unhandled builtin function
return Any
Expand Down
74 changes: 67 additions & 7 deletions test/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1205,8 +1205,7 @@ isdefined_f3(x) = isdefined(x, 3)
@test @inferred(isdefined_f3(())) == false
@test find_call(first(code_typed(isdefined_f3, Tuple{Tuple{Vararg{Int}}})[1]), isdefined, 3)

let isa_tfunc = Core.Compiler.T_FFUNC_VAL[
findfirst(x->x===isa, Core.Compiler.T_FFUNC_KEY)][3]
let isa_tfunc = Core.Compiler.isa_tfunc
@test isa_tfunc(Array, Const(AbstractArray)) === Const(true)
@test isa_tfunc(Array, Type{AbstractArray}) === Const(true)
@test isa_tfunc(Array, Type{AbstractArray{Int}}) == Bool
Expand All @@ -1220,10 +1219,10 @@ let isa_tfunc = Core.Compiler.T_FFUNC_VAL[
@test isa_tfunc(UnionAll, Const(Type{Array})) === Bool
@test isa_tfunc(Union, Const(Union{Float32, Float64})) === Bool
@test isa_tfunc(Union, Type{Union}) === Const(true)
@test isa_tfunc(typeof(Union{}), Const(Int)) === Const(false) # any result is ok
@test isa_tfunc(typeof(Union{}), Const(Int)) === Const(false)
@test isa_tfunc(typeof(Union{}), Const(Union{})) === Const(false)
@test isa_tfunc(typeof(Union{}), typeof(Union{})) === Const(false)
@test isa_tfunc(typeof(Union{}), Union{}) === Union{}
@test isa_tfunc(typeof(Union{}), Union{}) === Union{} # any result is ok
@test isa_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true)
@test isa_tfunc(typeof(Union{}), Const(typeof(Union{}))) === Const(true)
let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{}))
Expand All @@ -1238,15 +1237,14 @@ let isa_tfunc = Core.Compiler.T_FFUNC_VAL[
@test isa_tfunc(Val{1}, Type{Val{T}} where T) === Bool
@test isa_tfunc(Val{1}, DataType) === Bool
@test isa_tfunc(Any, Const(Any)) === Const(true)
@test isa_tfunc(Any, Union{}) === Union{}
@test isa_tfunc(Any, Union{}) === Union{} # any result is ok
@test isa_tfunc(Any, Type{Union{}}) === Const(false)
@test isa_tfunc(Union{Int64, Float64}, Type{Real}) === Const(true)
@test isa_tfunc(Union{Int64, Float64}, Type{Integer}) === Bool
@test isa_tfunc(Union{Int64, Float64}, Type{AbstractArray}) === Const(false)
end

let subtype_tfunc = Core.Compiler.T_FFUNC_VAL[
findfirst(x->x===(<:), Core.Compiler.T_FFUNC_KEY)][3]
let subtype_tfunc = Core.Compiler.subtype_tfunc
@test subtype_tfunc(Type{<:Array}, Const(AbstractArray)) === Const(true)
@test subtype_tfunc(Type{<:Array}, Type{AbstractArray}) === Const(true)
@test subtype_tfunc(Type{<:Array}, Type{AbstractArray{Int}}) == Bool
Expand Down Expand Up @@ -1296,6 +1294,68 @@ let subtype_tfunc = Core.Compiler.T_FFUNC_VAL[
@test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{AbstractArray}) === Const(false)
end

let egal_tfunc
function egal_tfunc(a, b)
r = Core.Compiler.egal_tfunc(a, b)
@test r === Core.Compiler.egal_tfunc(b, a)
return r
end
@test egal_tfunc(Const(12345.12345), Const(12344.12345 + 1)) == Const(true)
@test egal_tfunc(Array, Const(Array)) === Const(false)
@test egal_tfunc(Array, Type{Array}) === Const(false)
@test egal_tfunc(Int, Int) == Bool
@test egal_tfunc(Array, Array) == Bool
@test egal_tfunc(Array, AbstractArray{Int}) == Bool
@test egal_tfunc(Array{Real}, AbstractArray{Int}) === Const(false)
@test egal_tfunc(Array{Real, 2}, AbstractArray{Real, 2}) === Bool
@test egal_tfunc(Array{Real, 2}, AbstractArray{Int, 2}) === Const(false)
@test egal_tfunc(DataType, Int) === Const(false)
@test egal_tfunc(DataType, Const(Int)) === Bool
@test egal_tfunc(DataType, Const(Array)) === Const(false)
@test egal_tfunc(UnionAll, Const(Int)) === Const(false)
@test egal_tfunc(UnionAll, Const(Array)) === Bool
@test egal_tfunc(Union, Const(Union{Float32, Float64})) === Bool
@test egal_tfunc(Const(Union{Float32, Float64}), Const(Union{Float32, Float64})) === Const(true)
@test egal_tfunc(Type{Union{Float32, Float64}}, Type{Union{Float32, Float64}}) === Bool
@test egal_tfunc(typeof(Union{}), typeof(Union{})) === Bool # could be improved
@test egal_tfunc(Const(typeof(Union{})), Const(typeof(Union{}))) === Const(true)
let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{}))
@test egal_tfunc(c, Const(Bool)) === Const(false)
@test egal_tfunc(c, Type{Bool}) === Const(false)
@test egal_tfunc(c, Const(Real)) === Const(false)
@test egal_tfunc(c, Type{Real}) === Const(false)
@test egal_tfunc(c, Const(Signed)) === Const(false)
@test egal_tfunc(c, Type{Complex}) === Const(false)
@test egal_tfunc(c, Type{Complex{T}} where T) === Const(false)
@test egal_tfunc(c, Bool) === Bool
@test egal_tfunc(c, Any) === Bool
end
let c = Conditional(Core.SlotNumber(0), Union{}, Const(Union{})) # === Const(false)
@test egal_tfunc(c, Const(false)) === Conditional(c.var, c.elsetype, Union{})
@test egal_tfunc(c, Const(true)) === Conditional(c.var, Union{}, c.elsetype)
@test egal_tfunc(c, Const(nothing)) === Const(false)
@test egal_tfunc(c, Int) === Const(false)
@test egal_tfunc(c, Bool) === Bool
@test egal_tfunc(c, Any) === Bool
end
let c = Conditional(Core.SlotNumber(0), Const(Union{}), Union{}) # === Const(true)
@test egal_tfunc(c, Const(false)) === Conditional(c.var, Union{}, c.vtype)
@test egal_tfunc(c, Const(true)) === Conditional(c.var, c.vtype, Union{})
@test egal_tfunc(c, Const(nothing)) === Const(false)
@test egal_tfunc(c, Int) === Const(false)
@test egal_tfunc(c, Bool) === Bool
@test egal_tfunc(c, Any) === Bool
end
@test egal_tfunc(Type{Val{1}}, Type{Val{T}} where T) === Bool
@test egal_tfunc(Type{Val{1}}, DataType) === Bool
@test egal_tfunc(Const(Any), Const(Any)) === Const(true)
@test egal_tfunc(Any, Union{}) === Const(false) # any result is ok
@test egal_tfunc(Type{Any}, Type{Union{}}) === Const(false)
@test egal_tfunc(Union{Int64, Float64}, Real) === Bool
@test egal_tfunc(Union{Int64, Float64}, Integer) === Bool
@test egal_tfunc(Union{Int64, Float64}, AbstractArray) === Const(false)
end

function f23024(::Type{T}, ::Int) where T
1 + 1
end
Expand Down