580
580
add_tfunc (nfields, 1 , 1 , nfields_tfunc, 1 )
581
581
add_tfunc (Core. _expr, 1 , INT_INF, @nospecs ((𝕃:: AbstractLattice , args... )-> Expr), 100 )
582
582
add_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
+
583
592
@nospecs function _svec_ref_tfunc (𝕃:: AbstractLattice , s, i)
584
593
if isa (s, Const) && isa (i, Const)
585
594
s, i = s. val, i. val
@@ -1960,15 +1969,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
1960
1969
# UnionAll context is missing around this.
1961
1970
pop! (argtypes)
1962
1971
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 )... ))
1972
1974
end
1973
1975
params = Vector {Any} (undef, length (argtypes))
1974
1976
anyinfo = false
@@ -2334,14 +2336,17 @@ function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argt
2334
2336
elseif f === Core. compilerbarrier
2335
2337
na == 2 || return false
2336
2338
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
2337
2342
elseif f === Core. _svec_ref
2338
2343
na == 2 || return false
2339
2344
return _svec_ref_tfunc (𝕃, argtypes[1 ], argtypes[2 ]) isa Const
2340
2345
end
2341
2346
return false
2342
2347
end
2343
2348
2344
- # known to be always effect-free (in particular nothrow)
2349
+ # known to be always effect-free (in particular also nothrow)
2345
2350
const _PURE_BUILTINS = Any[
2346
2351
tuple,
2347
2352
svec,
@@ -2370,6 +2375,8 @@ const _CONSISTENT_BUILTINS = Any[
2370
2375
donotdelete,
2371
2376
memoryrefnew,
2372
2377
memoryrefoffset,
2378
+ Core. _svec_len,
2379
+ Core. _svec_ref,
2373
2380
]
2374
2381
2375
2382
# known to be effect-free (but not necessarily nothrow)
@@ -2394,6 +2401,7 @@ const _EFFECT_FREE_BUILTINS = [
2394
2401
Core. throw_methoderror,
2395
2402
getglobal,
2396
2403
compilerbarrier,
2404
+ Core. _svec_len,
2397
2405
Core. _svec_ref,
2398
2406
]
2399
2407
@@ -2428,6 +2436,7 @@ const _ARGMEM_BUILTINS = Any[
2428
2436
replacefield!,
2429
2437
setfield!,
2430
2438
swapfield!,
2439
+ Core. _svec_len,
2431
2440
Core. _svec_ref,
2432
2441
]
2433
2442
@@ -2571,6 +2580,7 @@ const _EFFECTS_KNOWN_BUILTINS = Any[
2571
2580
# Core._primitivetype,
2572
2581
# Core._setsuper!,
2573
2582
# Core._structtype,
2583
+ Core. _svec_len,
2574
2584
Core. _svec_ref,
2575
2585
# Core._typebody!,
2576
2586
Core. _typevar,
@@ -2675,7 +2685,7 @@ function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argty
2675
2685
else
2676
2686
if contains_is (_CONSISTENT_BUILTINS, f)
2677
2687
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
2679
2689
consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY
2680
2690
elseif f === Core. _typevar || f === Core. memorynew
2681
2691
consistent = CONSISTENT_IF_NOTRETURNED
@@ -2784,11 +2794,12 @@ end
2784
2794
function builtin_tfunction (interp:: AbstractInterpreter , @nospecialize (f), argtypes:: Vector{Any} ,
2785
2795
sv:: Union{AbsIntState, Nothing} )
2786
2796
𝕃ᵢ = 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 )
2790
2801
try
2791
- # unroll a few cases which have specialized codegen
2802
+ # unroll a few common cases for better codegen
2792
2803
if length (argvals) == 1
2793
2804
return Const (f (argvals[1 ]))
2794
2805
elseif length (argvals) == 2
@@ -2802,6 +2813,8 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
2802
2813
return Bottom
2803
2814
end
2804
2815
end
2816
+ end
2817
+ if isa (f, IntrinsicFunction)
2805
2818
iidx = Int (reinterpret (Int32, f)) + 1
2806
2819
if iidx < 0 || iidx > length (T_IFUNC)
2807
2820
# unknown intrinsic
@@ -2828,6 +2841,7 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
2828
2841
end
2829
2842
tf = T_FFUNC_VAL[fidx]
2830
2843
end
2844
+
2831
2845
if hasvarargtype (argtypes)
2832
2846
if length (argtypes) - 1 > tf[2 ]
2833
2847
# definitely too many arguments
0 commit comments