|
| 1 | +include("test/compiler/newinterp.jl") |
| 2 | + |
| 3 | +@newinterp FiniteIterateInterpreter |
| 4 | + |
| 5 | +using Core.Compiler: |
| 6 | + AbstractLattice, BaseInferenceLattice, IPOResultLattice, InferenceLattice, |
| 7 | + ConditionalsLattice, InterConditionalsLattice, PartialsLattice, ConstsLattice, |
| 8 | + SimpleInferenceLattice, |
| 9 | + widenlattice, is_valid_lattice_norec, typeinf_lattice, ipo_lattice, optimizer_lattice, |
| 10 | + widenconst, tmeet, tmerge, ⊑, ⊏, abstract_eval_special_value, widenreturn |
| 11 | + |
| 12 | +const CC = Core.Compiler |
| 13 | + |
| 14 | +struct FiniteIterateLattice{L<:AbstractLattice} <: AbstractLattice |
| 15 | + parent::L |
| 16 | +end |
| 17 | +CC.widenlattice(𝕃::FiniteIterateLattice) = 𝕃.parent |
| 18 | +CC.is_valid_lattice_norec(::FiniteIterateLattice, @nospecialize(elm)) = _is_finite_lattice(elm) |
| 19 | +_is_finite_lattice(@nospecialize t) = ( |
| 20 | + isa(t, FiniteIterate) || isa(t, FiniteState) || isa(t, TerminatingCondition)) |
| 21 | + |
| 22 | +CC.typeinf_lattice(::FiniteIterateInterpreter) = |
| 23 | + InferenceLattice(ConditionalsLattice(PartialsLattice(FiniteIterateLattice(ConstsLattice())))) |
| 24 | +CC.ipo_lattice(::FiniteIterateInterpreter) = |
| 25 | + InferenceLattice(InterConditionalsLattice(PartialsLattice(ConstsLattice()))) |
| 26 | +CC.optimizer_lattice(::FiniteIterateInterpreter) = |
| 27 | + FiniteIterateLattice(SimpleInferenceLattice.instance) |
| 28 | + |
| 29 | +struct FiniteIterate |
| 30 | + typ |
| 31 | + itr |
| 32 | + function FiniteIterate(@nospecialize(typ), @nospecialize(itr)) |
| 33 | + @assert !_is_finite_lattice(typ) "nested FiniteLattice" |
| 34 | + return new(typ, itr) |
| 35 | + end |
| 36 | +end |
| 37 | +struct FiniteState |
| 38 | + typ |
| 39 | + itr |
| 40 | + function FiniteState(@nospecialize(typ), @nospecialize(itr)) |
| 41 | + @assert !_is_finite_lattice(typ) "nested FiniteLattice" |
| 42 | + return new(typ, itr) |
| 43 | + end |
| 44 | +end |
| 45 | +struct TerminatingCondition end |
| 46 | +function CC.tmeet(𝕃::FiniteIterateLattice, @nospecialize(v), @nospecialize(t::Type)) |
| 47 | + if isa(v, FiniteIterate) |
| 48 | + error("tmeet FiniteIterate") |
| 49 | + v = v.typ |
| 50 | + elseif isa(v, FiniteState) |
| 51 | + error("tmeet FiniteState") |
| 52 | + v = v.typ |
| 53 | + elseif isa(v, TerminatingCondition) |
| 54 | + error("tmeet TerminatingCondition") |
| 55 | + if t === Bool |
| 56 | + return TerminatingCondition() |
| 57 | + end |
| 58 | + return Bool |
| 59 | + end |
| 60 | + return tmeet(widenlattice(𝕃), v, t) |
| 61 | +end |
| 62 | +function CC.tmerge(𝕃::FiniteIterateLattice, @nospecialize(x), @nospecialize(y)) |
| 63 | + if isa(x, FiniteIterate) |
| 64 | + if isa(y, FiniteIterate) && x.itr === y.itr |
| 65 | + return FiniteIterate(tmerge(widenlattice(𝕃), x.typ, y.typ), x.itr) |
| 66 | + end |
| 67 | + x = x.typ |
| 68 | + elseif isa(y, FiniteIterate) |
| 69 | + y = y.typ |
| 70 | + end |
| 71 | + if isa(x, FiniteState) |
| 72 | + if isa(y, FiniteState) && x.itr === y.itr |
| 73 | + return FiniteState(tmerge(widenlattice(𝕃), x.typ, y.typ), x.itr) |
| 74 | + end |
| 75 | + x = x.typ |
| 76 | + elseif isa(y, FiniteState) |
| 77 | + y = y.typ |
| 78 | + end |
| 79 | + if isa(x, TerminatingCondition) |
| 80 | + if isa(y, TerminatingCondition) |
| 81 | + return TerminatingCondition() |
| 82 | + end |
| 83 | + x = Bool |
| 84 | + elseif isa(y, TerminatingCondition) |
| 85 | + y = Bool |
| 86 | + end |
| 87 | + return tmerge(widenlattice(𝕃), x, y) |
| 88 | +end |
| 89 | +function CC.:⊑(𝕃::FiniteIterateLattice, @nospecialize(x), @nospecialize(y)) |
| 90 | + if isa(x, FiniteIterate) |
| 91 | + if isa(y, FiniteIterate) |
| 92 | + if x.itr === y.itr |
| 93 | + return ⊑(widenlattice(𝕃), x.typ, y.typ) |
| 94 | + end |
| 95 | + return false |
| 96 | + elseif isa(y, FiniteState) |
| 97 | + return false |
| 98 | + elseif isa(y, TerminatingCondition) |
| 99 | + return false |
| 100 | + end |
| 101 | + x = x.typ |
| 102 | + elseif isa(y, FiniteIterate) |
| 103 | + return x === Union{} |
| 104 | + end |
| 105 | + if isa(x, FiniteState) |
| 106 | + if isa(y, FiniteState) |
| 107 | + if x.itr === y.itr |
| 108 | + return ⊑(widenlattice(𝕃), x.typ, y.typ) |
| 109 | + end |
| 110 | + return false |
| 111 | + elseif isa(y, TerminatingCondition) |
| 112 | + return false |
| 113 | + end |
| 114 | + x = x.typ |
| 115 | + elseif isa(y, FiniteState) |
| 116 | + return x === Union{} |
| 117 | + end |
| 118 | + if isa(x, TerminatingCondition) |
| 119 | + return x !== Union{} |
| 120 | + elseif isa(y, TerminatingCondition) |
| 121 | + return x === Union{} |
| 122 | + end |
| 123 | + return ⊑(widenlattice(𝕃), x, y) |
| 124 | +end |
| 125 | +CC.widenconst(fi::FiniteIterate) = widenconst(fi.typ) |
| 126 | +CC.widenconst(fs::FiniteState) = widenconst(fs.typ) |
| 127 | +CC.widenconst(::TerminatingCondition) = Bool |
| 128 | +function widenfiniteiterate(@nospecialize x) |
| 129 | + if isa(x, FiniteIterate) |
| 130 | + return x.typ |
| 131 | + elseif isa(x, FiniteState) |
| 132 | + return x.typ |
| 133 | + elseif isa(x, TerminatingCondition) |
| 134 | + return Bool |
| 135 | + end |
| 136 | + return x |
| 137 | +end |
| 138 | +CC.widenreturn(𝕃::FiniteIterateLattice, @nospecialize(rt), info::CC.BestguessInfo) = |
| 139 | + CC.widenreturn(widenlattice(𝕃), widenfiniteiterate(rt), info) |
| 140 | + |
| 141 | +function CC.abstract_call_known(interp::FiniteIterateInterpreter, @nospecialize(f), |
| 142 | + arginfo::CC.ArgInfo, si::CC.StmtInfo, sv::CC.AbsIntState, |
| 143 | + max_methods::Int) |
| 144 | + res = @invoke CC.abstract_call_known(interp::CC.AbstractInterpreter, f::Any, |
| 145 | + arginfo::CC.ArgInfo, si::CC.StmtInfo, sv::CC.AbsIntState, |
| 146 | + max_methods::Int) |
| 147 | + (; fargs, argtypes) = arginfo |
| 148 | + la = length(argtypes) |
| 149 | + if la ≥ 2 && fargs !== nothing && CC.istopfunction(f, :iterate) |
| 150 | + if res.rt !== Union{} |
| 151 | + if argtypes[2] ⊑ Tuple |
| 152 | + if la == 2 |
| 153 | + res = CC.CallMeta(FiniteIterate(res.rt, fargs[2]), res.exct, res.effects, res.info) |
| 154 | + elseif la == 3 |
| 155 | + a3 = argtypes[3] |
| 156 | + if a3 isa FiniteState && a3.itr === fargs[2] |
| 157 | + res = CC.CallMeta(FiniteIterate(res.rt, a3.itr), res.exct, res.effects, res.info) |
| 158 | + end |
| 159 | + end |
| 160 | + end |
| 161 | + end |
| 162 | + end |
| 163 | + if la == 3 && CC.istopfunction(f, :(===)) |
| 164 | + if CC.widenconditional(res.rt) === Bool && argtypes[2] isa FiniteIterate |
| 165 | + return CC.CallMeta(TerminatingCondition(), res.exct, res.effects, res.info) |
| 166 | + end |
| 167 | + end |
| 168 | + return res |
| 169 | +end |
| 170 | +CC.@nospecs function CC._getfield_tfunc(𝕃::FiniteIterateLattice, s00, name, setfield::Bool) |
| 171 | + if isa(s00, FiniteIterate) |
| 172 | + if name isa Core.Const && name.val === 2 |
| 173 | + rt = CC._getfield_tfunc(widenlattice(𝕃), s00.typ, name, setfield) |
| 174 | + if rt !== Union{} |
| 175 | + return FiniteState(rt, s00.itr) |
| 176 | + end |
| 177 | + end |
| 178 | + s00 = s00.typ |
| 179 | + elseif isa(s00, FiniteState) |
| 180 | + s00 = s00.typ |
| 181 | + elseif isa(s00, TerminatingCondition) |
| 182 | + return Union{} |
| 183 | + end |
| 184 | + name = widenfiniteiterate(name) |
| 185 | + return CC._getfield_tfunc(widenlattice(𝕃), s00, name, setfield) |
| 186 | +end |
| 187 | +CC.@nospecs function CC.not_int_tfunc(𝕃::FiniteIterateLattice, x) |
| 188 | + if isa(x, TerminatingCondition) |
| 189 | + return TerminatingCondition() |
| 190 | + end |
| 191 | + return CC.not_int_tfunc(widenlattice(𝕃), x) |
| 192 | +end |
| 193 | +function CC.handle_control_backedge!(interp::FiniteIterateInterpreter, frame::CC.InferenceState, |
| 194 | + from::Int, to::Int, @nospecialize(condt)) |
| 195 | + if condt === TerminatingCondition() |
| 196 | + return nothing |
| 197 | + end |
| 198 | + @invoke CC.handle_control_backedge!(interp::CC.AbstractInterpreter, frame::CC.InferenceState, |
| 199 | + from::Int, to::Int, condt::Any) |
| 200 | +end |
| 201 | + |
| 202 | +using Test |
| 203 | +@test Base.infer_effects(; interp=FiniteIterateInterpreter()) do |
| 204 | + for i = (1,2,3) |
| 205 | + end |
| 206 | +end |> CC.is_terminates |
0 commit comments