make tests green again
This commit is contained in:
parent
11022fea1b
commit
1b0372c6e9
1 changed files with 80 additions and 49 deletions
|
|
@ -188,6 +188,35 @@ proc isHarmlessVar*(s: PSym; c: Con): bool =
|
||||||
discard "we do not perform an abstract interpretation yet"
|
discard "we do not perform an abstract interpretation yet"
|
||||||
result = usages <= 1
|
result = usages <= 1
|
||||||
|
|
||||||
|
proc isLastRead(s: PSym; c: var Con; pc, comesFrom: int): int =
|
||||||
|
var pc = pc
|
||||||
|
while pc < c.g.len:
|
||||||
|
case c.g[pc].kind
|
||||||
|
of def:
|
||||||
|
if c.g[pc].sym == s:
|
||||||
|
# the path lead to a redefinition of 's' --> abandon it.
|
||||||
|
return pc
|
||||||
|
inc pc
|
||||||
|
of use:
|
||||||
|
if c.g[pc].sym == s:
|
||||||
|
c.otherRead = c.g[pc].n
|
||||||
|
return -1
|
||||||
|
inc pc
|
||||||
|
of goto:
|
||||||
|
pc = pc + c.g[pc].dest
|
||||||
|
of fork:
|
||||||
|
# every branch must lead to the last read of the location:
|
||||||
|
let variantA = isLastRead(s, c, pc+1, pc)
|
||||||
|
if variantA < 0: return -1
|
||||||
|
let variantB = isLastRead(s, c, pc + c.g[pc].dest, pc)
|
||||||
|
if variantB < 0: return -1
|
||||||
|
pc = variantA+1
|
||||||
|
of InstrKind.join:
|
||||||
|
let dest = pc + c.g[pc].dest
|
||||||
|
if dest == comesFrom: return pc
|
||||||
|
inc pc
|
||||||
|
return pc
|
||||||
|
|
||||||
proc isLastRead(n: PNode; c: var Con): bool =
|
proc isLastRead(n: PNode; c: var Con): bool =
|
||||||
# first we need to search for the instruction that belongs to 'n':
|
# first we need to search for the instruction that belongs to 'n':
|
||||||
doAssert n.kind == nkSym
|
doAssert n.kind == nkSym
|
||||||
|
|
@ -195,61 +224,63 @@ proc isLastRead(n: PNode; c: var Con): bool =
|
||||||
var instr = -1
|
var instr = -1
|
||||||
for i in 0..<c.g.len:
|
for i in 0..<c.g.len:
|
||||||
if c.g[i].n == n:
|
if c.g[i].n == n:
|
||||||
if instr < 0: instr = i
|
if instr < 0:
|
||||||
else:
|
instr = i
|
||||||
# eh, we found two positions that belong to 'n'?
|
break
|
||||||
# better return 'false' then:
|
|
||||||
return false
|
|
||||||
if instr < 0: return false
|
if instr < 0: return false
|
||||||
# we go through all paths beginning from 'instr+1' and need to
|
# we go through all paths beginning from 'instr+1' and need to
|
||||||
# ensure that we don't find another 'use X' instruction.
|
# ensure that we don't find another 'use X' instruction.
|
||||||
if instr+1 >= c.g.len: return true
|
if instr+1 >= c.g.len: return true
|
||||||
let s = n.sym
|
when false:
|
||||||
var pcs: seq[int] = @[instr+1]
|
result = isLastRead(n.sym, c, 0, -1) >= 0
|
||||||
var takenGotos: IntSet
|
else:
|
||||||
var takenForks = initIntSet()
|
let s = n.sym
|
||||||
while pcs.len > 0:
|
var pcs: seq[int] = @[instr+1]
|
||||||
var pc = pcs.pop
|
var takenGotos: IntSet
|
||||||
|
var takenForks = initIntSet()
|
||||||
|
while pcs.len > 0:
|
||||||
|
var pc = pcs.pop
|
||||||
|
|
||||||
takenGotos = initIntSet()
|
takenGotos = initIntSet()
|
||||||
while pc < c.g.len:
|
while pc < c.g.len:
|
||||||
case c.g[pc].kind
|
case c.g[pc].kind
|
||||||
of def:
|
of def:
|
||||||
if c.g[pc].sym == s:
|
if c.g[pc].sym == s:
|
||||||
# the path lead to a redefinition of 's' --> abandon it.
|
# the path lead to a redefinition of 's' --> abandon it.
|
||||||
when false:
|
when false:
|
||||||
# Too complex thinking ahead: In reality it is enough to find
|
# Too complex thinking ahead: In reality it is enough to find
|
||||||
# the 'def x' here on the current path to make the 'use x' valid.
|
# the 'def x' here on the current path to make the 'use x' valid.
|
||||||
# but for this the definition needs to dominate the usage:
|
# but for this the definition needs to dominate the usage:
|
||||||
var dominates = true
|
var dominates = true
|
||||||
for j in pc+1 .. instr:
|
for j in pc+1 .. instr:
|
||||||
# not within the same basic block?
|
# not within the same basic block?
|
||||||
if c.g[j].kind in {goto, fork} and (j + c.g[j].dest) in (pc+1 .. instr):
|
if c.g[j].kind in {goto, fork} and (j + c.g[j].dest) in (pc+1 .. instr):
|
||||||
#if j in c.jumpTargets:
|
#if j in c.jumpTargets:
|
||||||
dominates = false
|
dominates = false
|
||||||
if dominates: break
|
if dominates: break
|
||||||
break
|
break
|
||||||
inc pc
|
|
||||||
of use:
|
|
||||||
if c.g[pc].sym == s:
|
|
||||||
c.otherRead = c.g[pc].n
|
|
||||||
return false
|
|
||||||
inc pc
|
|
||||||
of goto:
|
|
||||||
# we must leave endless loops eventually:
|
|
||||||
if not takenGotos.containsOrIncl(pc):
|
|
||||||
pc = pc + c.g[pc].dest
|
|
||||||
else:
|
|
||||||
inc pc
|
inc pc
|
||||||
of fork:
|
of use:
|
||||||
# we follow the next instruction but push the dest onto our "work" stack:
|
if c.g[pc].sym == s:
|
||||||
if not takenForks.containsOrIncl(pc):
|
c.otherRead = c.g[pc].n
|
||||||
pcs.add pc + c.g[pc].dest
|
return false
|
||||||
inc pc
|
inc pc
|
||||||
of InstrKind.join:
|
of goto:
|
||||||
inc pc
|
# we must leave endless loops eventually:
|
||||||
#echo c.graph.config $ n.info, " last read here!"
|
if not takenGotos.containsOrIncl(pc):
|
||||||
return true
|
pc = pc + c.g[pc].dest
|
||||||
|
else:
|
||||||
|
inc pc
|
||||||
|
of fork:
|
||||||
|
# we follow the next instruction but push the dest onto our "work" stack:
|
||||||
|
if not takenForks.containsOrIncl(pc):
|
||||||
|
pcs.add pc + c.g[pc].dest
|
||||||
|
inc pc
|
||||||
|
of InstrKind.join:
|
||||||
|
inc pc
|
||||||
|
#echo c.graph.config $ n.info, " last read here!"
|
||||||
|
return true
|
||||||
|
|
||||||
template interestingSym(s: PSym): bool =
|
template interestingSym(s: PSym): bool =
|
||||||
s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
|
s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue