Skip to content

Commit 100666b

Browse files
committed
[NewOptimizer] manually optimize UseRefIterator allocations
eventually, we want stack-allocations to do this automatically
1 parent f09fb93 commit 100666b

File tree

1 file changed

+83
-61
lines changed

1 file changed

+83
-61
lines changed

base/compiler/ssair/ir.jl

Lines changed: 83 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,23 @@ struct NewSSAValue
190190
id::Int
191191
end
192192

193-
mutable struct UseRefIterator
193+
mutable struct UseRef
194194
stmt::Any
195+
op::Int
196+
UseRef(@nospecialize(a)) = new(a, 0)
197+
end
198+
struct UseRefIterator
199+
use::Tuple{UseRef, Nothing}
195200
relevant::Bool
196-
UseRefIterator(@nospecialize(a), relevant::Bool) = new(a, relevant)
201+
UseRefIterator(@nospecialize(a), relevant::Bool) = new((UseRef(a), nothing), relevant)
197202
end
198-
getindex(it::UseRefIterator) = it.stmt
203+
getindex(it::UseRefIterator) = it.use[1].stmt
199204

200-
struct UseRef
201-
urs::UseRefIterator
202-
use::Int
203-
end
205+
# TODO: stack-allocation
206+
#struct UseRef
207+
# urs::UseRefIterator
208+
# use::Int
209+
#end
204210

205211
struct OOBToken
206212
end
@@ -209,41 +215,43 @@ struct UndefToken
209215
end
210216

211217
function getindex(x::UseRef)
212-
stmt = x.urs.stmt
218+
stmt = x.stmt
213219
if isa(stmt, Expr) && stmt.head === :(=)
214220
rhs = stmt.args[2]
215-
if isa(rhs, Expr) && is_relevant_expr(rhs)
216-
x.use > length(rhs.args) && return OOBToken()
217-
return rhs.args[x.use]
221+
if isa(rhs, Expr)
222+
if is_relevant_expr(rhs)
223+
x.op > length(rhs.args) && return OOBToken()
224+
return rhs.args[x.op]
225+
end
218226
end
219-
x.use == 1 || return OOBToken()
227+
x.op == 1 || return OOBToken()
220228
return rhs
221-
elseif isa(stmt, Expr) && is_relevant_expr(stmt)
222-
x.use > length(stmt.args) && return OOBToken()
223-
return stmt.args[x.use]
229+
elseif isa(stmt, Expr) # @assert is_relevant_expr(stmt)
230+
x.op > length(stmt.args) && return OOBToken()
231+
return stmt.args[x.op]
224232
elseif isa(stmt, GotoIfNot)
225-
x.use == 1 || return OOBToken()
233+
x.op == 1 || return OOBToken()
226234
return stmt.cond
227235
elseif isa(stmt, ReturnNode)
228236
isdefined(stmt, :val) || return OOBToken()
229-
x.use == 1 || return OOBToken()
237+
x.op == 1 || return OOBToken()
230238
return stmt.val
231239
elseif isa(stmt, PiNode)
232240
isdefined(stmt, :val) || return OOBToken()
233-
x.use == 1 || return OOBToken()
241+
x.op == 1 || return OOBToken()
234242
return stmt.val
235243
elseif isa(stmt, UpsilonNode)
236244
isdefined(stmt, :val) || return OOBToken()
237-
x.use == 1 || return OOBToken()
245+
x.op == 1 || return OOBToken()
238246
return stmt.val
239247
elseif isa(stmt, PhiNode)
240-
x.use > length(stmt.values) && return OOBToken()
241-
isassigned(stmt.values, x.use) || return UndefToken()
242-
return stmt.values[x.use]
248+
x.op > length(stmt.values) && return OOBToken()
249+
isassigned(stmt.values, x.op) || return UndefToken()
250+
return stmt.values[x.op]
243251
elseif isa(stmt, PhiCNode)
244-
x.use > length(stmt.values) && return OOBToken()
245-
isassigned(stmt.values, x.use) || return UndefToken()
246-
return stmt.values[x.use]
252+
x.op > length(stmt.values) && return OOBToken()
253+
isassigned(stmt.values, x.op) || return UndefToken()
254+
return stmt.values[x.op]
247255
else
248256
return OOBToken()
249257
end
@@ -257,39 +265,41 @@ function is_relevant_expr(e::Expr)
257265
end
258266

259267
function setindex!(x::UseRef, @nospecialize(v))
260-
stmt = x.urs.stmt
268+
stmt = x.stmt
261269
if isa(stmt, Expr) && stmt.head === :(=)
262270
rhs = stmt.args[2]
263-
if isa(rhs, Expr) && is_relevant_expr(rhs)
264-
x.use > length(rhs.args) && throw(BoundsError())
265-
rhs.args[x.use] = v
266-
else
267-
x.use == 1 || throw(BoundsError())
268-
stmt.args[2] = v
271+
if isa(rhs, Expr)
272+
if is_relevant_expr(rhs)
273+
x.op > length(rhs.args) && throw(BoundsError())
274+
rhs.args[x.op] = v
275+
return v
276+
end
269277
end
270-
elseif isa(stmt, Expr) && is_relevant_expr(stmt)
271-
x.use > length(stmt.args) && throw(BoundsError())
272-
stmt.args[x.use] = v
278+
x.op == 1 || throw(BoundsError())
279+
stmt.args[2] = v
280+
elseif isa(stmt, Expr) # @assert is_relevant_expr(stmt)
281+
x.op > length(stmt.args) && throw(BoundsError())
282+
stmt.args[x.op] = v
273283
elseif isa(stmt, GotoIfNot)
274-
x.use == 1 || throw(BoundsError())
275-
x.urs.stmt = GotoIfNot(v, stmt.dest)
284+
x.op == 1 || throw(BoundsError())
285+
x.stmt = GotoIfNot(v, stmt.dest)
276286
elseif isa(stmt, ReturnNode)
277-
x.use == 1 || throw(BoundsError())
278-
x.urs.stmt = typeof(stmt)(v)
287+
x.op == 1 || throw(BoundsError())
288+
x.stmt = typeof(stmt)(v)
279289
elseif isa(stmt, UpsilonNode)
280-
x.use == 1 || throw(BoundsError())
281-
x.urs.stmt = typeof(stmt)(v)
290+
x.op == 1 || throw(BoundsError())
291+
x.stmt = typeof(stmt)(v)
282292
elseif isa(stmt, PiNode)
283-
x.use == 1 || throw(BoundsError())
284-
x.urs.stmt = typeof(stmt)(v, stmt.typ)
293+
x.op == 1 || throw(BoundsError())
294+
x.stmt = typeof(stmt)(v, stmt.typ)
285295
elseif isa(stmt, PhiNode)
286-
x.use > length(stmt.values) && throw(BoundsError())
287-
isassigned(stmt.values, x.use) || throw(BoundsError())
288-
stmt.values[x.use] = v
296+
x.op > length(stmt.values) && throw(BoundsError())
297+
isassigned(stmt.values, x.op) || throw(BoundsError())
298+
stmt.values[x.op] = v
289299
elseif isa(stmt, PhiCNode)
290-
x.use > length(stmt.values) && throw(BoundsError())
291-
isassigned(stmt.values, x.use) || throw(BoundsError())
292-
stmt.values[x.use] = v
300+
x.op > length(stmt.values) && throw(BoundsError())
301+
isassigned(stmt.values, x.op) || throw(BoundsError())
302+
stmt.values[x.op] = v
293303
else
294304
throw(BoundsError())
295305
end
@@ -303,19 +313,31 @@ function userefs(@nospecialize(x))
303313
return UseRefIterator(x, relevant)
304314
end
305315

306-
start(it::UseRefIterator) = 1
307-
@noinline function next(it::UseRefIterator, use::Int)
308-
while true
309-
x = UseRef(it, use)
310-
use += 1
311-
x[] === UndefToken() || return (x, use)
312-
end
313-
end
314-
@noinline function done(it::UseRefIterator, use::Int)
316+
start(it::UseRefIterator) = (it.use[1].op = 0; nothing)
317+
next(it::UseRefIterator, ::Nothing) = it.use
318+
@noinline function done(it::UseRefIterator, ::Nothing)
315319
it.relevant || return true
316-
x, _ = next(it, use)
317-
return x[] === OOBToken()
318-
end
320+
use = it.use[1]
321+
while true
322+
use.op += 1
323+
y = use[]
324+
y === OOBToken() && return true
325+
y === UndefToken() || break
326+
end
327+
return false
328+
end
329+
#iterate(it::UseRefIterator) = (it.use[1].op = 0; iterate(it, nothing))
330+
#@noinline function iterate(it::UseRefIterator, ::Nothing)
331+
# it.relevant || return nothing
332+
# use = it.use[1]
333+
# while true
334+
# use.op += 1
335+
# y = use[]
336+
# y === OOBToken() && return nothing
337+
# y === UndefToken() || break
338+
# end
339+
# return it.use
340+
#end
319341

320342
function scan_ssa_use!(used, @nospecialize(stmt))
321343
if isa(stmt, SSAValue)

0 commit comments

Comments
 (0)