580580add_tfunc (nfields, 1 , 1 , nfields_tfunc, 1 )
581581add_tfunc (Core. _expr, 1 , INT_INF, @nospecs ((𝕃:: AbstractLattice , args... )-> Expr), 100 )
582582add_tfunc (svec, 0 , INT_INF, @nospecs ((𝕃:: AbstractLattice , args... )-> SimpleVector), 20 )
583+
584+ @nospecs function _svec_len_tfunc (𝕃:: AbstractLattice , s)
585+ if isa (s, Const) && isa (s. val, SimpleVector)
586+ return Const (length (s. val))
587+ end
588+ return Int
589+ end
590+ add_tfunc (Core. _svec_len, 1 , 1 , _svec_len_tfunc, 1 )
591+
583592@nospecs function _svec_ref_tfunc (𝕃:: AbstractLattice , s, i)
584593 if isa (s, Const) && isa (i, Const)
585594 s, i = s. val, i. val
@@ -1960,15 +1969,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
19601969 # UnionAll context is missing around this.
19611970 pop! (argtypes)
19621971 end
1963- all_are_const = true
1964- for i in 1 : length (argtypes)
1965- if ! isa (argtypes[i], Const)
1966- all_are_const = false
1967- break
1968- end
1969- end
1970- if all_are_const
1971- return Const (ntuple (i:: Int -> argtypes[i]. val, length (argtypes)))
1972+ if is_all_const_arg (argtypes, 1 ) # repeated from builtin_tfunction for the benefit of callers that use this tfunc directly
1973+ return Const (tuple (collect_const_args (argtypes, 1 )... ))
19721974 end
19731975 params = Vector {Any} (undef, length (argtypes))
19741976 anyinfo = false
@@ -2334,14 +2336,17 @@ function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argt
23342336 elseif f === Core. compilerbarrier
23352337 na == 2 || return false
23362338 return compilerbarrier_nothrow (argtypes[1 ], nothing )
2339+ elseif f === Core. _svec_len
2340+ na == 1 || return false
2341+ return _svec_len_tfunc (𝕃, argtypes[1 ]) isa Const
23372342 elseif f === Core. _svec_ref
23382343 na == 2 || return false
23392344 return _svec_ref_tfunc (𝕃, argtypes[1 ], argtypes[2 ]) isa Const
23402345 end
23412346 return false
23422347end
23432348
2344- # known to be always effect-free (in particular nothrow)
2349+ # known to be always effect-free (in particular also nothrow)
23452350const _PURE_BUILTINS = Any[
23462351 tuple,
23472352 svec,
@@ -2370,6 +2375,8 @@ const _CONSISTENT_BUILTINS = Any[
23702375 donotdelete,
23712376 memoryrefnew,
23722377 memoryrefoffset,
2378+ Core. _svec_len,
2379+ Core. _svec_ref,
23732380]
23742381
23752382# known to be effect-free (but not necessarily nothrow)
@@ -2394,6 +2401,7 @@ const _EFFECT_FREE_BUILTINS = [
23942401 Core. throw_methoderror,
23952402 getglobal,
23962403 compilerbarrier,
2404+ Core. _svec_len,
23972405 Core. _svec_ref,
23982406]
23992407
@@ -2428,6 +2436,7 @@ const _ARGMEM_BUILTINS = Any[
24282436 replacefield!,
24292437 setfield!,
24302438 swapfield!,
2439+ Core. _svec_len,
24312440 Core. _svec_ref,
24322441]
24332442
@@ -2571,6 +2580,7 @@ const _EFFECTS_KNOWN_BUILTINS = Any[
25712580 # Core._primitivetype,
25722581 # Core._setsuper!,
25732582 # Core._structtype,
2583+ Core. _svec_len,
25742584 Core. _svec_ref,
25752585 # Core._typebody!,
25762586 Core. _typevar,
@@ -2675,7 +2685,7 @@ function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argty
26752685 else
26762686 if contains_is (_CONSISTENT_BUILTINS, f)
26772687 consistent = ALWAYS_TRUE
2678- elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned || f === Core. _svec_ref
2688+ elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned || f === Core. _svec_len || f === Core . _svec_ref
26792689 consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY
26802690 elseif f === Core. _typevar || f === Core. memorynew
26812691 consistent = CONSISTENT_IF_NOTRETURNED
@@ -2784,11 +2794,12 @@ end
27842794function builtin_tfunction (interp:: AbstractInterpreter , @nospecialize (f), argtypes:: Vector{Any} ,
27852795 sv:: Union{AbsIntState, Nothing} )
27862796 𝕃ᵢ = typeinf_lattice (interp)
2787- if isa (f, IntrinsicFunction)
2788- if is_pure_intrinsic_infer (f) && all (@nospecialize (a) -> isa (a, Const), argtypes)
2789- argvals = anymap (@nospecialize (a) -> (a:: Const ). val, argtypes)
2797+ # Early constant evaluation for foldable builtins with all const args
2798+ if isa (f, IntrinsicFunction) ? is_pure_intrinsic_infer (f) : (f in _PURE_BUILTINS || (f in _CONSISTENT_BUILTINS && f in _EFFECT_FREE_BUILTINS))
2799+ if is_all_const_arg (argtypes, 1 )
2800+ argvals = collect_const_args (argtypes, 1 )
27902801 try
2791- # unroll a few cases which have specialized codegen
2802+ # unroll a few common cases for better codegen
27922803 if length (argvals) == 1
27932804 return Const (f (argvals[1 ]))
27942805 elseif length (argvals) == 2
@@ -2802,6 +2813,8 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
28022813 return Bottom
28032814 end
28042815 end
2816+ end
2817+ if isa (f, IntrinsicFunction)
28052818 iidx = Int (reinterpret (Int32, f)) + 1
28062819 if iidx < 0 || iidx > length (T_IFUNC)
28072820 # unknown intrinsic
@@ -2828,6 +2841,7 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
28282841 end
28292842 tf = T_FFUNC_VAL[fidx]
28302843 end
2844+
28312845 if hasvarargtype (argtypes)
28322846 if length (argtypes) - 1 > tf[2 ]
28332847 # definitely too many arguments
0 commit comments