Posted to tcl by kbk at Wed Jan 08 23:32:55 GMT 2014view pretty

set vars [analyzeProgram $program db]
set vnames [dict keys $vars]

db relation seq st st2
db relation writes st v
db relation flowspast v st st2
db relation reaches v st st2
db relation uninitRead st v
db relation deadWrite st v
# db relation induction v st

proc reaching_defs {} [bdd::datalog::compileProgram db {
 
    % A false entry node (node 0) sets every variable and flows
    % to node 1. If any of its variables are reachable, those are
    % variables possibly used uninitialized in the program.

    writes(0, _).
    writes(st,v) :- writes0(st,v).
    seq(0, 1).
    seq(st,st2) :- seq0(st,st2).

    % flowspast(v,st,st2) means that control passes from the exit of st
    % to the entry of st2 without altering the value of v

    flowspast(_, st, st2) :- seq(st, st2).
    flowspast(v, st3, st2) :- flowspast(v, st3, st),
                             !writes(st, v),
                             flowspast(v, st, st2).

    % reaches(v,st,st2) means that st assigns a value to v, which
    % reaches st2, which reads the value of v : that is, st is a
    % reaching definition for the use of v at st2.

    reaches(v, st, st2) :- writes(st, v), flowspast(v, st, st2), reads(st2, v).

    % A variable read that is reachable from the entry is a read of a
    % possibly uninitialized variable

    uninitRead(st, v) :- reaches(v, 0, st).

    % A variable write that reaches nowhere else is dead code

    deadWrite(st, v) :- writes(st, v), !reaches(v, st, _).

}]

# Report which variable definitions reach statement $i
proc query1 {i} [bdd::datalog::compileProgram db {
    reaches(v, st, $i)?
} d {
    lappend ::flowsto [lindex $::vnames [dict get $d v]] [dict get $d st]
}]

# Report which variable uses flow from statement $i
proc query2 {i} [bdd::datalog::compileProgram db {
    reaches(v, $i, st)?
} d {
    lappend ::flowsfrom [lindex $::vnames [dict get $d v]] [dict get $d st]
}]
    

reaching_defs

puts [format {%-16s %2s  %-32s %-16s} PRODUCERS {} INSTRUCTIONS CONSUMERS]
set i 0
foreach stmt $program {
    set flowsto {}
    query1 $i
    set flowsfrom {}
    query2 $i
    puts [format "%-16s %2d: %-32s %-16s" \
	      [lsort -stride 2 -index 0 -ascii \
		   [lsort -stride 2 -index 1 -integer $flowsto]] \
	      $i \
	      $stmt \
	      [lsort -stride 2 -index 0 -ascii \
		   [lsort -stride 2 -index 1 -integer $flowsfrom]]]
    incr i
}