File: cluster.sml

package info (click to toggle)
smlnj 110.79-8
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 82,564 kB
  • sloc: ansic: 32,532; asm: 6,314; sh: 2,296; makefile: 1,821; perl: 1,170; pascal: 295; yacc: 190; cs: 78; python: 77; lisp: 19
file content (108 lines) | stat: -rw-r--r-- 3,380 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
(* uses a union-find data structure to compute clusters *)
(* First function in the function list must be the first function 
 * in the first cluster. This is achieved by ensuring that the first  
 * function is mapped to the smallest id in a dense enumeration. 
 * This function id will map to the smallest cluster id. 
 * The function ids are then iterated in descending order.
 *)
structure Cluster : 
  sig
     val cluster : CPS.function list -> CPS.function list list
  end = 
struct
  fun error msg = ErrorMsg.impossible ("Cluster." ^ msg)

  fun cluster funcs = let
    val numOfFuncs = length funcs

    (* mapping of function names to a dense integer range *)
    exception FuncId
    val funcToIdTbl : int IntHashTable.hash_table =
	IntHashTable.mkTable(numOfFuncs, FuncId)
    val lookup = IntHashTable.lookup funcToIdTbl 

    (* mapping of ids to functions *)
    val idToFuncTbl = Array.array(numOfFuncs, hd funcs)
    local
      val add = IntHashTable.insert funcToIdTbl
      fun mkFuncIdTbl ([], _) = ()
	| mkFuncIdTbl ((func as (_,f,_,_,_))::rest, id) = 
	    (add (f, id);  
	     Array.update(idToFuncTbl, id, func); 
	     mkFuncIdTbl(rest, id+1))
    in
      val _ = mkFuncIdTbl(funcs, 0)
    end

    (* union-find structure -- initially each function in its own cluster *)
    val trees = Array.tabulate(numOfFuncs, fn i => i)

    fun ascend u = let
      val v = Array.sub(trees, u)
    in if v = u then u else ascend(v)
    end
 
    fun union(t1, t2) = let
      val r1 = ascend t1
      val r2 = ascend t2
    in
      if r1 = r2 then ()		(* already in the same set *)
      else if r1 < r2 then Array.update(trees, r2, r1)
	   else Array.update(trees, r1, r2)
    end

    (* build union-find structure *)
    fun build [] = ()
      | build ((_,f,_,_,body)::rest) = let
          val fId = lookup f
	  fun forall []      = ()
	    | forall (e::es) = (calls e; forall es)

	  and calls (CPS.APP(CPS.LABEL l,_))  = union(fId, lookup l)
	    | calls (CPS.APP _)	 	      = ()
	    | calls (CPS.RECORD(_,_,_,e))     = calls e
	    | calls (CPS.SELECT(_,_,_,_,e))   = calls e
	    | calls (CPS.OFFSET(_,_,_,e))     = calls e
	    | calls (CPS.SWITCH(_,_,es))      = forall(es)
	    | calls (CPS.BRANCH(_,_,_,e1,e2)) = (calls e1; calls e2)
	    | calls (CPS.SETTER(_,_,e))       = calls e
	    | calls (CPS.LOOKER(_,_,_,_,e))   = calls e
	    | calls (CPS.ARITH(_,_,_,_,e))    = calls e
	    | calls (CPS.PURE(_,_,_,_,e))     = calls e
	    | calls (CPS.RCC(_,_,_,_,_,e))  = calls e
	    | calls (CPS.FIX _)               = error "calls.f:FIX"
        in 
	  calls body; build rest
	end (* build *)

    (* extract the clusters. 
     * The first func in the funcs list must be the first function
     * in the first cluster.
     *)
    fun extract() = let
      val clusters = Array.array(numOfFuncs, [])
      fun collect n = let
	val root = ascend(n)
	val func = Array.sub(idToFuncTbl, n)
	val cluster = Array.sub(clusters, root)
      in 
	Array.update(clusters, root, func::cluster); 
	collect (n-1)
      end

      fun finish(~1, acc) = acc
	| finish(n, acc) = 
	  (case Array.sub(clusters, n)
	    of [] => finish (n-1, acc)
             | cluster => finish(n-1, cluster::acc)
	   (*esac*))
    in
      collect (numOfFuncs-1) handle _ => ();
      finish (numOfFuncs-1, [])
    end
  in
    build funcs;
    extract()
  end (* cluster *)
end