Split last read and first write analysis (#17137)
* Split last read and first write analysis This improves performance by 10% for some cases. * Remove outdated comments
This commit is contained in:
parent
146beb2797
commit
6b7a6f8c54
1 changed files with 42 additions and 20 deletions
|
|
@ -82,7 +82,7 @@ proc aliasesCached(cache: var AliasCache, obj, field: PNode): AliasKind =
|
||||||
cache[key] = aliases(obj, field)
|
cache[key] = aliases(obj, field)
|
||||||
cache[key]
|
cache[key]
|
||||||
|
|
||||||
proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen: var HashSet[PNode], lastReads, potLastReads: var IntSet; pc: var int, until: int) =
|
proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, lastReads, potLastReads: var IntSet; pc: var int, until: int) =
|
||||||
template aliasesCached(obj, field: PNode): untyped =
|
template aliasesCached(obj, field: PNode): untyped =
|
||||||
aliasesCached(cache, obj, field)
|
aliasesCached(cache, obj, field)
|
||||||
while pc < until:
|
while pc < until:
|
||||||
|
|
@ -100,15 +100,6 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
|
||||||
cfg[r].n.comment = '\n' & $pc
|
cfg[r].n.comment = '\n' & $pc
|
||||||
potLastReads.excl r
|
potLastReads.excl r
|
||||||
|
|
||||||
var alreadySeenThisNode = false
|
|
||||||
for s in alreadySeen:
|
|
||||||
if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no:
|
|
||||||
alreadySeenThisNode = true; break
|
|
||||||
if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite
|
|
||||||
else: cfg[pc].n.flags.incl nfFirstWrite
|
|
||||||
|
|
||||||
alreadySeen.incl cfg[pc].n
|
|
||||||
|
|
||||||
inc pc
|
inc pc
|
||||||
of use:
|
of use:
|
||||||
let potLastReadsCopy = potLastReads
|
let potLastReadsCopy = potLastReads
|
||||||
|
|
@ -119,25 +110,19 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
|
||||||
|
|
||||||
potLastReads.incl pc
|
potLastReads.incl pc
|
||||||
|
|
||||||
alreadySeen.incl cfg[pc].n
|
|
||||||
|
|
||||||
inc pc
|
inc pc
|
||||||
of goto:
|
of goto:
|
||||||
pc += cfg[pc].dest
|
pc += cfg[pc].dest
|
||||||
of fork:
|
of fork:
|
||||||
# every branch must lead to the last read of the location:
|
|
||||||
var variantA = pc + 1
|
var variantA = pc + 1
|
||||||
var variantB = pc + cfg[pc].dest
|
var variantB = pc + cfg[pc].dest
|
||||||
var potLastReadsA, potLastReadsB = potLastReads
|
var potLastReadsA, potLastReadsB = potLastReads
|
||||||
var lastReadsA, lastReadsB: IntSet
|
var lastReadsA, lastReadsB: IntSet
|
||||||
var alreadySeenA, alreadySeenB = alreadySeen
|
|
||||||
while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until:
|
while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until:
|
||||||
if variantA < variantB:
|
if variantA < variantB:
|
||||||
collectLastReads(cfg, cache, alreadySeenA, lastReadsA, potLastReadsA, variantA, min(variantB, until))
|
collectLastReads(cfg, cache, lastReadsA, potLastReadsA, variantA, min(variantB, until))
|
||||||
else:
|
else:
|
||||||
collectLastReads(cfg, cache, alreadySeenB, lastReadsB, potLastReadsB, variantB, min(variantA, until))
|
collectLastReads(cfg, cache, lastReadsB, potLastReadsB, variantB, min(variantA, until))
|
||||||
|
|
||||||
alreadySeen.incl alreadySeenA + alreadySeenB
|
|
||||||
|
|
||||||
# Add those last reads that were turned into last reads on both branches
|
# Add those last reads that were turned into last reads on both branches
|
||||||
lastReads.incl lastReadsA * lastReadsB
|
lastReads.incl lastReadsA * lastReadsB
|
||||||
|
|
@ -157,6 +142,40 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
|
||||||
|
|
||||||
pc = min(variantA, variantB)
|
pc = min(variantA, variantB)
|
||||||
|
|
||||||
|
proc collectFirstWrites(cfg: ControlFlowGraph; alreadySeen: var HashSet[PNode]; pc: var int, until: int) =
|
||||||
|
while pc < until:
|
||||||
|
case cfg[pc].kind
|
||||||
|
of def:
|
||||||
|
var alreadySeenThisNode = false
|
||||||
|
for s in alreadySeen:
|
||||||
|
if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no:
|
||||||
|
alreadySeenThisNode = true; break
|
||||||
|
if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite
|
||||||
|
else: cfg[pc].n.flags.incl nfFirstWrite
|
||||||
|
|
||||||
|
alreadySeen.incl cfg[pc].n
|
||||||
|
|
||||||
|
inc pc
|
||||||
|
of use:
|
||||||
|
alreadySeen.incl cfg[pc].n
|
||||||
|
|
||||||
|
inc pc
|
||||||
|
of goto:
|
||||||
|
pc += cfg[pc].dest
|
||||||
|
of fork:
|
||||||
|
var variantA = pc + 1
|
||||||
|
var variantB = pc + cfg[pc].dest
|
||||||
|
var alreadySeenA, alreadySeenB = alreadySeen
|
||||||
|
while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until:
|
||||||
|
if variantA < variantB:
|
||||||
|
collectFirstWrites(cfg, alreadySeenA, variantA, min(variantB, until))
|
||||||
|
else:
|
||||||
|
collectFirstWrites(cfg, alreadySeenB, variantB, min(variantA, until))
|
||||||
|
|
||||||
|
alreadySeen.incl alreadySeenA + alreadySeenB
|
||||||
|
|
||||||
|
pc = min(variantA, variantB)
|
||||||
|
|
||||||
proc isLastRead(n: PNode; c: var Con): bool =
|
proc isLastRead(n: PNode; c: var Con): bool =
|
||||||
let m = dfa.skipConvDfa(n)
|
let m = dfa.skipConvDfa(n)
|
||||||
(m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or nfLastRead in m.flags
|
(m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or nfLastRead in m.flags
|
||||||
|
|
@ -1086,10 +1105,9 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var cache = initTable[(PNode, PNode), AliasKind]()
|
var cache = initTable[(PNode, PNode), AliasKind]()
|
||||||
var alreadySeen: HashSet[PNode]
|
|
||||||
var lastReads, potLastReads: IntSet
|
var lastReads, potLastReads: IntSet
|
||||||
var pc = 0
|
var pc = 0
|
||||||
collectLastReads(c.g, cache, alreadySeen, lastReads, potLastReads, pc, c.g.len)
|
collectLastReads(c.g, cache, lastReads, potLastReads, pc, c.g.len)
|
||||||
lastReads.incl potLastReads
|
lastReads.incl potLastReads
|
||||||
var lastReadTable: Table[PNode, seq[int]]
|
var lastReadTable: Table[PNode, seq[int]]
|
||||||
for position, node in c.g:
|
for position, node in c.g:
|
||||||
|
|
@ -1102,6 +1120,10 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
|
||||||
if allPositionsLastRead:
|
if allPositionsLastRead:
|
||||||
node.flags.incl nfLastRead
|
node.flags.incl nfLastRead
|
||||||
|
|
||||||
|
var alreadySeen: HashSet[PNode]
|
||||||
|
pc = 0
|
||||||
|
collectFirstWrites(c.g, alreadySeen, pc, c.g.len)
|
||||||
|
|
||||||
var scope: Scope
|
var scope: Scope
|
||||||
let body = p(n, c, scope, normal)
|
let body = p(n, c, scope, normal)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue