10
10
du::SSADefUse
11
11
12
12
This struct keeps track of all uses of some mutable struct allocated in the current function:
13
- - `du.uses::Vector{Int}` are all instances of `getfield` on the struct
13
+ - `du.uses::Vector{Int}` are all instances of `getfield` / `isdefined` on the struct
14
14
- `du.defs::Vector{Int}` are all instances of `setfield!` on the struct
15
15
The terminology refers to the uses/defs of the "slot bundle" that the mutable struct represents.
16
16
@@ -27,7 +27,10 @@ struct SSADefUse
27
27
end
28
28
SSADefUse () = SSADefUse (Int[], Int[], Int[])
29
29
30
- compute_live_ins (cfg:: CFG , du:: SSADefUse ) = compute_live_ins (cfg, du. defs, du. uses)
30
+ function compute_live_ins (cfg:: CFG , du:: SSADefUse )
31
+ # filter out `isdefined` usages
32
+ return compute_live_ins (cfg, du. defs, filter (> (0 ), du. uses))
33
+ end
31
34
32
35
# assume `stmt == getfield(obj, field, ...)` or `stmt == setfield!(obj, field, val, ...)`
33
36
try_compute_field_stmt (ir:: Union{IncrementalCompact,IRCode} , stmt:: Expr ) =
@@ -725,7 +728,7 @@ function sroa_pass!(ir::IRCode)
725
728
for ((_, idx), stmt) in compact
726
729
# check whether this statement is `getfield` / `setfield!` (or other "interesting" statement)
727
730
isa (stmt, Expr) || continue
728
- is_setfield = false
731
+ is_setfield = is_isdefined = false
729
732
field_ordering = :unspecified
730
733
if is_known_call (stmt, setfield!, compact)
731
734
4 <= length (stmt. args) <= 5 || continue
@@ -741,6 +744,13 @@ function sroa_pass!(ir::IRCode)
741
744
field_ordering = argextype (stmt. args[4 ], compact)
742
745
widenconst (field_ordering) === Bool && (field_ordering = :unspecified )
743
746
end
747
+ elseif is_known_call (stmt, isdefined, compact)
748
+ 3 <= length (stmt. args) <= 4 || continue
749
+ is_isdefined = true
750
+ if length (stmt. args) == 4
751
+ field_ordering = argextype (stmt. args[4 ], compact)
752
+ widenconst (field_ordering) === Bool && (field_ordering = :unspecified )
753
+ end
744
754
elseif isexpr (stmt, :foreigncall )
745
755
nccallargs = length (stmt. args[3 ]:: SimpleVector )
746
756
preserved = Int[]
@@ -795,13 +805,11 @@ function sroa_pass!(ir::IRCode)
795
805
lift_comparison! (=== , compact, idx, stmt, lifting_cache)
796
806
elseif is_known_call (stmt, isa, compact)
797
807
lift_comparison! (isa, compact, idx, stmt, lifting_cache)
798
- elseif is_known_call (stmt, isdefined, compact)
799
- lift_comparison! (isdefined, compact, idx, stmt, lifting_cache)
800
808
end
801
809
continue
802
810
end
803
811
804
- # analyze this `getfield` / `setfield!` call
812
+ # analyze this `getfield` / `isdefined` / ` setfield!` call
805
813
806
814
field = try_compute_field_stmt (compact, stmt)
807
815
field === nothing && continue
@@ -812,10 +820,15 @@ function sroa_pass!(ir::IRCode)
812
820
if isa (struct_typ, Union) && struct_typ <: Tuple
813
821
struct_typ = unswitchtupleunion (struct_typ)
814
822
end
823
+ if isa (struct_typ, Union) && is_isdefined
824
+ lift_comparison! (isdefined, compact, idx, stmt, lifting_cache)
825
+ continue
826
+ end
815
827
isa (struct_typ, DataType) || continue
816
828
817
829
struct_typ. name. atomicfields == C_NULL || continue # TODO : handle more
818
- if ! (field_ordering === :unspecified || (field_ordering isa Const && field_ordering. val === :not_atomic ))
830
+ if ! ((field_ordering === :unspecified ) ||
831
+ (field_ordering isa Const && field_ordering. val === :not_atomic ))
819
832
continue
820
833
end
821
834
@@ -836,6 +849,8 @@ function sroa_pass!(ir::IRCode)
836
849
mid, defuse = get! (defuses, def. id, (SPCSet (), SSADefUse ()))
837
850
if is_setfield
838
851
push! (defuse. defs, idx)
852
+ elseif is_isdefined
853
+ push! (defuse. uses, - idx)
839
854
else
840
855
push! (defuse. uses, idx)
841
856
end
@@ -844,6 +859,8 @@ function sroa_pass!(ir::IRCode)
844
859
continue
845
860
elseif is_setfield
846
861
continue # invalid `setfield!` call, but just ignore here
862
+ elseif is_isdefined
863
+ continue # TODO ?
847
864
end
848
865
849
866
# perform SROA on immutable structs here on
@@ -927,9 +944,9 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
927
944
typ = typ:: DataType
928
945
# Partition defuses by field
929
946
fielddefuse = SSADefUse[SSADefUse () for _ = 1 : fieldcount (typ)]
930
- all_forwarded = true
947
+ all_eliminated = all_forwarded = true
931
948
for use in defuse. uses
932
- stmt = ir[SSAValue (use)][:inst ] # == `getfield` call
949
+ stmt = ir[SSAValue (abs ( use)) ][:inst ] # == `getfield`/`isdefined ` call
933
950
# We may have discovered above that this use is dead
934
951
# after the getfield elim of immutables. In that case,
935
952
# it would have been deleted. That's fine, just ignore
@@ -969,7 +986,15 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
969
986
blocks[fidx] = phiblocks, allblocks
970
987
if fidx + 1 > length (defexpr. args)
971
988
for use in du. uses
972
- has_safe_def (ir, get_domtree (), allblocks, du, newidx, use) || @goto skip
989
+ if use > 0 # == `getfield` use
990
+ has_safe_def (ir, get_domtree (), allblocks, du, newidx, use) || @goto skip
991
+ else # == `isdefined` use
992
+ if has_safe_def (ir, get_domtree (), allblocks, du, newidx, - use)
993
+ ir[SSAValue (- use)][:inst ] = true
994
+ else
995
+ all_eliminated = false
996
+ end
997
+ end
973
998
end
974
999
end
975
1000
end
@@ -991,8 +1016,12 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
991
1016
NewInstruction (PhiNode (), ftyp))
992
1017
end
993
1018
# Now go through all uses and rewrite them
994
- for stmt in du. uses
995
- ir[SSAValue (stmt)][:inst ] = compute_value_for_use (ir, domtree, allblocks, du, phinodes, fidx, stmt)
1019
+ for use in du. uses
1020
+ if use > 0 # == `getfield` use
1021
+ ir[SSAValue (use)][:inst ] = compute_value_for_use (ir, domtree, allblocks, du, phinodes, fidx, use)
1022
+ else # == `isdefined` use
1023
+ continue # already rewritten if possible
1024
+ end
996
1025
end
997
1026
if ! isbitstype (ftyp)
998
1027
if preserve_uses != = nothing
@@ -1010,6 +1039,10 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
1010
1039
end
1011
1040
end
1012
1041
end
1042
+ all_eliminated || continue
1043
+ # all "usages" (i.e. `getfield` and `isdefined` calls) are eliminated,
1044
+ # now eliminate "definitions" (`setfield!`) calls
1045
+ # (NOTE the allocation itself will be eliminated by DCE pass later)
1013
1046
for stmt in du. defs
1014
1047
stmt == newidx && continue
1015
1048
ir[SSAValue (stmt)][:inst ] = nothing
0 commit comments