@@ -75,7 +75,22 @@ function compute_value_for_block(ir::IRCode, domtree::DomTree, allblocks::Vector
75
75
end
76
76
77
77
function compute_value_for_use (ir:: IRCode , domtree:: DomTree , allblocks:: Vector{Int} , du:: SSADefUse , phinodes:: IdDict{Int, SSAValue} , fidx:: Int , use_idx:: Int )
78
- # Find the first dominating def
78
+ def, stmtblock, curblock = find_def_for_use (ir, domtree, allblocks, du, use_idx)
79
+ if def == 0
80
+ if ! haskey (phinodes, curblock)
81
+ # If this happens, we need to search the predecessors for defs. Which
82
+ # one doesn't matter - if it did, we'd have had a phinode
83
+ return compute_value_for_block (ir, domtree, allblocks, du, phinodes, fidx, first (ir. cfg. blocks[stmtblock]. preds))
84
+ end
85
+ # The use is the phinode
86
+ return phinodes[curblock]
87
+ else
88
+ return val_for_def_expr (ir, def, fidx)
89
+ end
90
+ end
91
+
92
+ # find the first dominating def for the given use
93
+ function find_def_for_use (ir:: IRCode , domtree:: DomTree , allblocks:: Vector{Int} , du:: SSADefUse , use_idx:: Int )
79
94
stmtblock = block_for_inst (ir. cfg, use_idx)
80
95
curblock = find_curblock (domtree, allblocks, stmtblock)
81
96
local def = 0
@@ -90,17 +105,7 @@ function compute_value_for_use(ir::IRCode, domtree::DomTree, allblocks::Vector{I
90
105
end
91
106
end
92
107
end
93
- if def == 0
94
- if ! haskey (phinodes, curblock)
95
- # If this happens, we need to search the predecessors for defs. Which
96
- # one doesn't matter - if it did, we'd have had a phinode
97
- return compute_value_for_block (ir, domtree, allblocks, du, phinodes, fidx, first (ir. cfg. blocks[stmtblock]. preds))
98
- end
99
- # The use is the phinode
100
- return phinodes[curblock]
101
- else
102
- return val_for_def_expr (ir, def, fidx)
103
- end
108
+ return def, stmtblock, curblock
104
109
end
105
110
106
111
function simple_walk (compact:: IncrementalCompact , @nospecialize (defssa#= ::AnySSAValue=# ),
@@ -538,7 +543,7 @@ function perform_lifting!(compact::IncrementalCompact,
538
543
end
539
544
540
545
"""
541
- getfield_elim_pass !(ir::IRCode) -> newir::IRCode
546
+ sroa_pass !(ir::IRCode) -> newir::IRCode
542
547
543
548
`getfield` elimination pass, a.k.a. Scalar Replacements of Aggregates optimization.
544
549
@@ -555,7 +560,7 @@ its argument).
555
560
In a case when all usages are fully eliminated, `struct` allocation may also be erased as
556
561
a result of dead code elimination.
557
562
"""
558
- function getfield_elim_pass ! (ir:: IRCode )
563
+ function sroa_pass ! (ir:: IRCode )
559
564
compact = IncrementalCompact (ir)
560
565
defuses = IdDict {Int, Tuple{IdSet{Int}, SSADefUse}} ()
561
566
lifting_cache = IdDict {Pair{AnySSAValue, Any}, AnySSAValue} ()
@@ -784,7 +789,6 @@ function getfield_elim_pass!(ir::IRCode)
784
789
typ = typ:: DataType
785
790
# Partition defuses by field
786
791
fielddefuse = SSADefUse[SSADefUse () for _ = 1 : fieldcount (typ)]
787
- ok = true
788
792
for use in defuse. uses
789
793
stmt = ir[SSAValue (use)]
790
794
# We may have discovered above that this use is dead
@@ -793,47 +797,52 @@ function getfield_elim_pass!(ir::IRCode)
793
797
# the use in that case.
794
798
stmt === nothing && continue
795
799
field = try_compute_fieldidx_stmt (compact, stmt:: Expr , typ)
796
- field === nothing && (ok = false ; break )
800
+ field === nothing && @goto skip
797
801
push! (fielddefuse[field]. uses, use)
798
802
end
799
- ok || continue
800
803
for use in defuse. defs
801
804
field = try_compute_fieldidx_stmt (compact, ir[SSAValue (use)]:: Expr , typ)
802
- field === nothing && (ok = false ; break )
805
+ field === nothing && @goto skip
803
806
push! (fielddefuse[field]. defs, use)
804
807
end
805
- ok || continue
806
808
# Check that the defexpr has defined values for all the fields
807
809
# we're accessing. In the future, we may want to relax this,
808
810
# but we should come up with semantics for well defined semantics
809
811
# for uninitialized fields first.
810
- for (fidx, du) in pairs (fielddefuse)
812
+ ndefuse = length (fielddefuse)
813
+ blocks = Vector {Tuple{#=phiblocks=# Vector{Int}, #=allblocks=# Vector{Int}}} (undef, ndefuse)
814
+ for fidx in 1 : ndefuse
815
+ du = fielddefuse[fidx]
811
816
isempty (du. uses) && continue
817
+ push! (du. defs, idx)
818
+ ldu = compute_live_ins (ir. cfg, du)
819
+ phiblocks = Int[]
820
+ if ! isempty (ldu. live_in_bbs)
821
+ phiblocks = idf (ir. cfg, ldu, domtree)
822
+ end
823
+ allblocks = sort (vcat (phiblocks, ldu. def_bbs))
824
+ blocks[fidx] = phiblocks, allblocks
812
825
if fidx + 1 > length (defexpr. args)
813
- ok = false
814
- break
826
+ for use in du. uses
827
+ def = find_def_for_use (ir, domtree, allblocks, du, use)[1 ]
828
+ (def == 0 || def == idx) && @goto skip
829
+ end
815
830
end
816
831
end
817
- ok || continue
818
832
preserve_uses = IdDict {Int, Vector{Any}} ((idx=> Any[] for idx in IdSet {Int} (defuse. ccall_preserve_uses)))
819
833
# Everything accounted for. Go field by field and perform idf
820
- for (fidx, du) in pairs (fielddefuse)
834
+ for fidx in 1 : ndefuse
835
+ du = fielddefuse[fidx]
821
836
ftyp = fieldtype (typ, fidx)
822
837
if ! isempty (du. uses)
823
- push! (du. defs, idx)
824
- ldu = compute_live_ins (ir. cfg, du)
825
- phiblocks = Int[]
826
- if ! isempty (ldu. live_in_bbs)
827
- phiblocks = idf (ir. cfg, ldu, domtree)
828
- end
838
+ phiblocks, allblocks = blocks[fidx]
829
839
phinodes = IdDict {Int, SSAValue} ()
830
840
for b in phiblocks
831
841
n = PhiNode ()
832
842
phinodes[b] = insert_node! (ir, first (ir. cfg. blocks[b]. stmts),
833
843
NewInstruction (n, ftyp))
834
844
end
835
845
# Now go through all uses and rewrite them
836
- allblocks = sort (vcat (phiblocks, ldu. def_bbs))
837
846
for stmt in du. uses
838
847
ir[SSAValue (stmt)] = compute_value_for_use (ir, domtree, allblocks, du, phinodes, fidx, stmt)
839
848
end
@@ -855,7 +864,6 @@ function getfield_elim_pass!(ir::IRCode)
855
864
stmt == idx && continue
856
865
ir[SSAValue (stmt)] = nothing
857
866
end
858
- continue
859
867
end
860
868
isempty (defuse. ccall_preserve_uses) && continue
861
869
push! (intermediaries, idx)
@@ -870,6 +878,8 @@ function getfield_elim_pass!(ir::IRCode)
870
878
old_preserves... , new_preserves... )
871
879
ir[SSAValue (use)] = new_expr
872
880
end
881
+
882
+ @label skip
873
883
end
874
884
875
885
return ir
@@ -919,14 +929,14 @@ In addition to a simple DCE for unused values and allocations,
919
929
this pass also nullifies `typeassert` calls that can be proved to be no-op,
920
930
in order to allow LLVM to emit simpler code down the road.
921
931
922
- Note that this pass is more effective after SROA optimization (i.e. `getfield_elim_pass !`),
932
+ Note that this pass is more effective after SROA optimization (i.e. `sroa_pass !`),
923
933
since SROA often allows this pass to:
924
934
- eliminate allocation of object whose field references are all replaced with scalar values, and
925
935
- nullify `typeassert` call whose first operand has been replaced with a scalar value
926
936
(, which may have introduced new type information that inference did not understand)
927
937
928
- Also note that currently this pass _needs_ to run after `getfield_elim_pass !`, because
929
- the `typeassert` elimination depends on the transformation within `getfield_elim_pass !`
938
+ Also note that currently this pass _needs_ to run after `sroa_pass !`, because
939
+ the `typeassert` elimination depends on the transformation within `sroa_pass !`
930
940
which redirects references of `typeassert`ed value to the corresponding `PiNode`.
931
941
"""
932
942
function adce_pass! (ir:: IRCode )
0 commit comments