@@ -263,6 +263,7 @@ function isdefined_nothrow(argtypes::Array{Any, 1})
263263 (argtypes[2 ] ⊑ Symbol || argtypes[2 ] ⊑ Int) :
264264 argtypes[2 ] ⊑ Symbol
265265end
266+ isdefined_tfunc (arg1, sym, order) = (@nospecialize ; isdefined_tfunc (arg1, sym))
266267function isdefined_tfunc (@nospecialize (arg1), @nospecialize (sym))
267268 if isa (arg1, Const)
268269 a1 = typeof (arg1. val)
@@ -316,7 +317,7 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym))
316317 end
317318 return Bool
318319end
319- add_tfunc (isdefined, 2 , 2 , isdefined_tfunc, 1 )
320+ add_tfunc (isdefined, 2 , 3 , isdefined_tfunc, 1 )
320321
321322function sizeof_nothrow (@nospecialize (x))
322323 if isa (x, Const)
@@ -470,22 +471,26 @@ add_tfunc(arraysize, 2, 2, (@nospecialize(a), @nospecialize(d))->Int, 4)
470471function pointer_eltype (@nospecialize (ptr))
471472 a = widenconst (ptr)
472473 if a <: Ptr
473- if isa (a,DataType) && isa (a. parameters[1 ],Type)
474+ if isa (a, DataType) && isa (a. parameters[1 ], Type)
474475 return a. parameters[1 ]
475- elseif isa (a,UnionAll) && ! has_free_typevars (a)
476+ elseif isa (a, UnionAll) && ! has_free_typevars (a)
476477 unw = unwrap_unionall (a)
477- if isa (unw,DataType)
478+ if isa (unw, DataType)
478479 return rewrap_unionall (unw. parameters[1 ], a)
479480 end
480481 end
481482 end
482483 return Any
483484end
484- add_tfunc (pointerref, 3 , 3 ,
485- function (@nospecialize (a), @nospecialize (i), @nospecialize (align))
486- return pointer_eltype (a)
487- end , 4 )
488- add_tfunc (pointerset, 4 , 4 , (@nospecialize (a), @nospecialize (v), @nospecialize (i), @nospecialize (align)) -> a, 5 )
485+ add_tfunc (pointerref, 3 , 3 , (a, i, align) -> (@nospecialize ; pointer_eltype (a)), 4 )
486+ add_tfunc (pointerset, 4 , 4 , (a, v, i, align) -> (@nospecialize ; a), 5 )
487+
488+ add_tfunc (atomic_fence, 1 , 1 , (order) -> (@nospecialize ; Nothing), 4 )
489+ add_tfunc (atomic_pointerref, 2 , 2 , (a, order) -> (@nospecialize ; pointer_eltype (a)), 4 )
490+ add_tfunc (atomic_pointerset, 3 , 3 , (a, v, order) -> (@nospecialize ; a), 5 )
491+ add_tfunc (atomic_pointerswap, 3 , 3 , (a, v, order) -> (@nospecialize ; pointer_eltype (a)), 5 )
492+ add_tfunc (atomic_pointermodify, 4 , 4 , (a, op, v, order) -> (@nospecialize ; T = pointer_eltype (a); Tuple{T, T}), 5 )
493+ add_tfunc (atomic_pointerreplace, 5 , 5 , (a, x, v, success_order, failure_order) -> (@nospecialize ; Tuple{pointer_eltype (a), Bool}), 5 )
489494
490495# more accurate typeof_tfunc for vararg tuples abstract only in length
491496function typeof_concrete_vararg (t:: DataType )
@@ -675,14 +680,25 @@ function try_compute_fieldidx(typ::DataType, @nospecialize(field))
675680end
676681
677682function getfield_nothrow (argtypes:: Vector{Any} )
678- 2 <= length (argtypes) <= 3 || return false
679- length (argtypes) == 2 && return getfield_nothrow (argtypes[1 ], argtypes[2 ], Const (true ))
680- return getfield_nothrow (argtypes[1 ], argtypes[2 ], argtypes[3 ])
683+ if length (argtypes) == 2
684+ boundscheck = Bool
685+ elseif length (argtypes) == 3
686+ boundscheck = argtypes[3 ]
687+ if boundscheck === Const (:not_atomic ) # TODO : this is assuming not atomic
688+ boundscheck = Bool
689+ end
690+ elseif length (argtypes) == 4
691+ boundscheck = argtypes[4 ]
692+ else
693+ return false
694+ end
695+ widenconst (boundscheck) != = Bool && return false
696+ bounds_check_disabled = isa (boundscheck, Const) && boundscheck. val === false
697+ return getfield_nothrow (argtypes[1 ], argtypes[2 ], ! bounds_check_disabled)
681698end
682- function getfield_nothrow (@nospecialize (s00), @nospecialize (name), @nospecialize (inbounds))
683- bounds_check_disabled = isa (inbounds, Const) && inbounds. val === false
684- # If we don't have invounds and don't know the field, don't even bother
685- if ! bounds_check_disabled
699+ function getfield_nothrow (@nospecialize (s00), @nospecialize (name), boundscheck:: Bool )
700+ # If we don't have boundscheck and don't know the field, don't even bother
701+ if boundscheck
686702 isa (name, Const) || return false
687703 end
688704
@@ -700,7 +716,7 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), @nospecialize
700716 end
701717 return isdefined (sv, name. val)
702718 end
703- if bounds_check_disabled && ! isa (sv, Module)
719+ if ! boundscheck && ! isa (sv, Module)
704720 # If bounds checking is disabled and all fields are assigned,
705721 # we may assume that we don't throw
706722 for i = 1 : fieldcount (typeof (sv))
@@ -714,14 +730,15 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), @nospecialize
714730 s0 = widenconst (s00)
715731 s = unwrap_unionall (s0)
716732 if isa (s, Union)
717- return getfield_nothrow (rewrap (s. a, s00), name, inbounds ) &&
718- getfield_nothrow (rewrap (s. b, s00), name, inbounds )
733+ return getfield_nothrow (rewrap (s. a, s00), name, boundscheck ) &&
734+ getfield_nothrow (rewrap (s. b, s00), name, boundscheck )
719735 elseif isa (s, DataType)
720736 # Can't say anything about abstract types
721737 s. name. abstract && return false
738+ s. name. atomicfields == C_NULL || return false # TODO : currently we're only testing for ordering == :not_atomic
722739 # If all fields are always initialized, and bounds check is disabled, we can assume
723740 # we don't throw
724- if bounds_check_disabled && ! isvatuple (s) && s. name != = NamedTuple. body. body. name && fieldcount (s) == s. ninitialized
741+ if ! boundscheck && ! isvatuple (s) && s. name != = NamedTuple. body. body. name && fieldcount (s) == s. ninitialized
725742 return true
726743 end
727744 # Else we need to know what the field is
@@ -736,8 +753,8 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), @nospecialize
736753 return false
737754end
738755
739- getfield_tfunc (@nospecialize ( s00), @nospecialize ( name), @nospecialize (inbounds)) =
740- getfield_tfunc (s00, name)
756+ getfield_tfunc (s00, name, boundscheck_or_order) = ( @nospecialize ; getfield_tfunc (s00, name))
757+ getfield_tfunc (s00, name, order, boundscheck) = ( @nospecialize ; getfield_tfunc (s00, name) )
741758function getfield_tfunc (@nospecialize (s00), @nospecialize (name))
742759 s = unwrap_unionall (s00)
743760 if isa (s, Union)
@@ -892,10 +909,25 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
892909 end
893910 return rewrap_unionall (R, s00)
894911end
895- add_tfunc (getfield, 2 , 3 , getfield_tfunc, 1 )
896- add_tfunc (setfield!, 3 , 3 , (@nospecialize (o), @nospecialize (f), @nospecialize (v)) -> v, 3 )
897- fieldtype_tfunc (@nospecialize (s0), @nospecialize (name), @nospecialize (inbounds)) =
898- fieldtype_tfunc (s0, name)
912+
913+ setfield!_tfunc (o, f, v, order) = (@nospecialize ; v)
914+ setfield!_tfunc (o, f, v) = (@nospecialize ; v)
915+
916+ swapfield!_tfunc (o, f, v, order) = (@nospecialize ; getfield_tfunc (o, f))
917+ swapfield!_tfunc (o, f, v) = (@nospecialize ; getfield_tfunc (o, f))
918+ modifyfield!_tfunc (o, f, op, v, order) = (@nospecialize ; T = getfield_tfunc (o, f); T === Bottom ? T : Tuple{T, T})
919+ modifyfield!_tfunc (o, f, op, v) = (@nospecialize ; T = getfield_tfunc (o, f); T === Bottom ? T : Tuple{T, T}) # TODO : also model op(o.f, v) call
920+ replacefield!_tfunc (o, f, x, v, success_order, failure_order) = (@nospecialize ; replacefield!_tfunc (o, f, x, v))
921+ replacefield!_tfunc (o, f, x, v, success_order) = (@nospecialize ; replacefield!_tfunc (o, f, x, v))
922+ replacefield!_tfunc (o, f, x, v) = (@nospecialize ; T = getfield_tfunc (o, f); T === Bottom ? T : Tuple{widenconst (T), Bool})
923+ # we could use tuple_tfunc instead of widenconst, but `o` is mutable, so that is unlikely to be beneficial
924+
925+ add_tfunc (getfield, 2 , 4 , getfield_tfunc, 1 )
926+ add_tfunc (setfield!, 3 , 4 , setfield!_tfunc, 3 )
927+
928+ add_tfunc (swapfield!, 3 , 4 , swapfield!_tfunc, 3 )
929+ add_tfunc (modifyfield!, 4 , 5 , modifyfield!_tfunc, 3 )
930+ add_tfunc (replacefield!, 4 , 6 , replacefield!_tfunc, 3 )
899931
900932function fieldtype_nothrow (@nospecialize (s0), @nospecialize (name))
901933 s0 === Bottom && return true # unreachable
@@ -954,6 +986,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
954986 return true
955987end
956988
989+ fieldtype_tfunc (s0, name, boundscheck) = (@nospecialize ; fieldtype_tfunc (s0, name))
957990function fieldtype_tfunc (@nospecialize (s0), @nospecialize (name))
958991 if s0 === Bottom
959992 return Bottom
0 commit comments