Line | Exclusive | Inclusive | Code |
---|---|---|---|
1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
2 | |||
3 | """ | ||
4 | Determine whether a statement is side-effect-free, i.e. may be removed if it has no uses. | ||
5 | """ | ||
6 |
1 (2.70%) samples spent in stmt_effect_free
function stmt_effect_free(@nospecialize(stmt), @nospecialize(rt), src, spvals::SimpleVector)
1 (100.00%) (ex.), 1 (100.00%) (incl.) when called from maybe_erase_unused! line 903 |
||
7 | 1 (2.70%) | 1 (2.70%) | isa(stmt, Union{PiNode, PhiNode}) && return true |
8 | isa(stmt, Union{ReturnNode, GotoNode, GotoIfNot}) && return false | ||
9 | isa(stmt, GlobalRef) && return isdefined(stmt.mod, stmt.name) | ||
10 | isa(stmt, Slot) && return false # Slots shouldn't occur in the IR at this point, but let's be defensive here | ||
11 | if isa(stmt, Expr) | ||
12 | e = stmt::Expr | ||
13 | head = e.head | ||
14 | if head === :static_parameter | ||
15 | etyp = sparam_type(spvals[e.args[1]]) | ||
16 | # if we aren't certain enough about the type, it might be an UndefVarError at runtime | ||
17 | return isa(etyp, Const) || issingletontype(widenconst(etyp)) | ||
18 | end | ||
19 | ea = e.args | ||
20 | if head === :call | ||
21 | f = argextype(ea[1], src, spvals) | ||
22 | f = isa(f, Const) ? f.val : isType(f) ? f.parameters[1] : return false | ||
23 | f === return_type && return true | ||
24 | contains_is(_PURE_BUILTINS, f) && return true | ||
25 | contains_is(_PURE_OR_ERROR_BUILTINS, f) || return false | ||
26 | rt === Bottom && return false | ||
27 | return _builtin_nothrow(f, Any[argextype(ea[i], src, spvals) for i = 2:length(ea)], rt) | ||
28 | elseif head === :new | ||
29 | a = ea[1] | ||
30 | typ = argextype(a, src, spvals) | ||
31 | # `Expr(:new)` of unknown type could raise arbitrary TypeError. | ||
32 | typ, isexact = instanceof_tfunc(typ) | ||
33 | isexact || return false | ||
34 | isconcretedispatch(typ) || return false | ||
35 | typ = typ::DataType | ||
36 | fieldcount(typ) >= length(ea) - 1 || return false | ||
37 | for fld_idx in 1:(length(ea) - 1) | ||
38 | eT = argextype(ea[fld_idx + 1], src, spvals) | ||
39 | fT = fieldtype(typ, fld_idx) | ||
40 | eT ⊑ fT || return false | ||
41 | end | ||
42 | return true | ||
43 | elseif head === :isdefined || head === :the_exception || head === :copyast || head === :inbounds || head === :boundscheck | ||
44 | return true | ||
45 | else | ||
46 | # e.g. :simdloop | ||
47 | return false | ||
48 | end | ||
49 | end | ||
50 | return true | ||
51 | end | ||
52 | |||
53 | function abstract_eval_ssavalue(s::SSAValue, src::IRCode) | ||
54 | return types(src)[s] | ||
55 | end | ||
56 | |||
57 | function abstract_eval_ssavalue(s::SSAValue, src::IncrementalCompact) | ||
58 | return types(src)[s] | ||
59 | end | ||
60 | |||
61 | function compact_exprtype(compact::IncrementalCompact, @nospecialize(value)) | ||
62 | if isa(value, AnySSAValue) | ||
63 | return types(compact)[value] | ||
64 | elseif isa(value, Argument) | ||
65 | return compact.ir.argtypes[value.n] | ||
66 | end | ||
67 | return argextype(value, compact.ir, compact.ir.spvals) | ||
68 | end | ||
69 | |||
70 | is_tuple_call(ir::IRCode, @nospecialize(def)) = isa(def, Expr) && is_known_call(def, tuple, ir, ir.spvals) | ||
71 | is_tuple_call(compact::IncrementalCompact, @nospecialize(def)) = isa(def, Expr) && is_known_call(def, tuple, compact) | ||
72 | function is_known_call(e::Expr, @nospecialize(func), src::IncrementalCompact) | ||
73 | if e.head !== :call | ||
74 | return false | ||
75 | end | ||
76 | f = compact_exprtype(src, e.args[1]) | ||
77 | return isa(f, Const) && f.val === func | ||
78 | end |