File: regionBuilder.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (205 lines) | stat: -rw-r--r-- 7,518 bytes parent folder | download | duplicates (5)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
(*
 * Partition the IR into regions according to partition criteria
 * and frequencies.  Then feed the regions into the instruction
 * scheduler.
 *
 * The partitional criteria can be:
 *   1. The maximum number of blocks
 *   2. The maximum number of instructions
 *)

functor RegionBuilder(IR : MLRISC_IR) : REGION_BUILDER =
struct
   structure IR   = IR
   structure CFG  = IR.CFG
   structure Util = IR.Util
   structure G    = Graph
   structure A    = Array
   structure PQ   = PriorityQueue
   structure DA   = DynArray

   fun error msg = MLRiscErrorMsg.error("RegionBuilder",msg)

   val view_IR = MLRiscControl.getFlag "view-IR"

   val i2s = Int.toString
 
   fun regionBuilder {maxBlocks, maxInstrs, sideEntries, minFreqRatio,
                      traceOnly, internalBackEdges, insertDummyBlocks
                     }  (IR as G.GRAPH cfg) schedule =
   let val N = #capacity cfg ()
       val G.GRAPH loop = IR.loop IR 

       (* Note: tables must be dynamic because the cfg may be changed 
        * while scheduling is being performed
        *)
       val processed = DA.array(N, false)
       fun isProcessed i = DA.sub(processed, i) 
       fun markAsProcessed i = DA.update(processed, i, true)
       val blockIdTbl = DA.array(N, 0)

       (* A queue of all the blocks ranked by priority 
        * Give loop headers extra priority
        *)
       fun freqOf(CFG.BLOCK{freq,...}) = !freq 
       fun highestFreqFirst((i,i'),(j,j')) = 
           let val f_i = freqOf i'
               val f_j = freqOf j'
           in  if f_i = f_j then #has_node loop i  
               else f_i > f_j 
           end
       val seeds = PQ.fromList highestFreqFirst (#nodes cfg ())

       (* Initialization *)
       fun initialization() =
           (app markAsProcessed (#entries cfg ());
            app markAsProcessed (#exits cfg ())
           )

       (* Locate an unprocessed seed block; raises exception if everything
        * is done.
        *)
       fun newSeed() =
       let val (i,i') = PQ.deleteMin seeds
       in  if isProcessed i then newSeed() 
           else if freqOf i' = 0 then raise PQ.EmptyPriorityQueue
           else (i,i')
       end

       (* Grow a region according to the various parameters *) 
       fun grow(seed as (s,s')) = 
       let val freq    = real(freqOf s')
           val minFreq = freq * minFreqRatio

           (* Remove non candidates *)
           fun prune(j,j') = isProcessed j orelse real(freqOf j') < minFreq 

           fun pruneEdge(w) = real(!w) < minFreq

           fun followSucc([], blocks) = blocks
             | followSucc((_,j,CFG.EDGE{w,...})::es, blocks) =
               let val j' = #node_info cfg j
               in  if pruneEdge w orelse prune(j,j') then followSucc(es, blocks)
                   else followSucc(es, (j,j')::blocks)
               end

           fun followPred([], blocks) = blocks
             | followPred((j,_,CFG.EDGE{w,...})::es, blocks) =
               let val j' = #node_info cfg j
               in  if pruneEdge w orelse prune(j,j') then followPred(es, blocks)
                   else followPred(es, (j,j')::blocks)
               end


           val queue   = PQ.fromList highestFreqFirst [seed]
           val enqueue = PQ.insert queue

           fun chooseBest [] = []
             | chooseBest ((j,j')::rest) = 
               let val w = freqOf j'
                   fun find([],j,j',w) = [(j,j')]
                     | find((k,k')::rest, j, j', w) = 
                       let val w' = freqOf k'
                       in  if w' > w then find(rest, k, k', w') 
                           else find(rest, j, j', w)
                       end
               in  find(rest, j, j', w) end

           fun add([], blocks, blockCount) = (blocks, blockCount)
             | add((j,j')::rest, blocks, blockCount) = 
               if isProcessed j then add(rest, blocks, blockCount) 
               else (markAsProcessed j; 
                     enqueue (j,j'); 
                     add(rest, j::blocks, blockCount+1)
                    )

           (* Find the region using best first search *)
           fun collect(front, back, blockCount) =
           if PQ.isEmpty queue orelse blockCount >= maxBlocks then 
               front @ rev back 
           else
           let val node as (j,j') = PQ.deleteMin queue
               val succs  = followSucc(#out_edges cfg j, [])
               val succs  = if traceOnly then chooseBest succs else succs
               val (back, blockCount) = add(succs, back, blockCount)
               (* val preds  = followPred(#in_edges cfg j, [])
               val preds  = if traceOnly then chooseBest preds else preds 
               val (front, blockCount) = add(preds, front, blockCount) *)
           in  collect(front, back, blockCount)
           end
           
           val _ = markAsProcessed s (* mark the seed block as processed *)
           val blocks = collect([s], [], 1)
           (* The blocks collected are not in linear order *)
       in  blocks
       end

       (* Create a new subgraph from the blocks *)
       fun makeSubgraph blocks =
           if traceOnly then TraceView.trace_view blocks IR
           else AcyclicSubgraphView.acyclic_view blocks IR

       (* 
        * Perform tail duplication if no side entries are allowed
        * BUG: make sure liveness information is kept up-to-date! XXX
        *)
       fun tailDuplication(root, subgraph) =
       let val {nodes, edges} = Util.tailDuplicate IR 
                                  {subgraph=subgraph, root=root}
           val ins = PQ.insert seeds
           fun newNode (b,b') = (ins(b,b'); DA.update(blockIdTbl, b, 0))
       in  (* add new nodes created as a consequence of tail duplication
            * onto the queue so that they will be properly processed later.
            *)
           app newNode nodes
       end


       (* Create a new region *) 
       fun createRegion() = 
       let val seed     = newSeed()
           val blocks   = grow seed 
           val subgraph = makeSubgraph blocks;
       in  if sideEntries then () else tailDuplication(hd blocks, subgraph);
           subgraph
       end

       (* Number of instructions *)
       fun numberOfInstructions(G.GRAPH cfg) =
       let val size = ref 0
       in  #forall_nodes cfg (fn (_,CFG.BLOCK{insns, ...}) =>
                  size := !size + length(!insns));
           !size 
       end

       fun sizeOf(G.GRAPH cfg) = #order cfg ()

       (* Main loop *) 
       fun main() =
       let val region as G.GRAPH R = createRegion()
           val size = sizeOf region
       in  if size <= 1 then ()
           else
             let val numberOfInstructions = numberOfInstructions region
             in  if numberOfInstructions <= 2 then ()
                 else
                   let val _ = 
                       (print("REGION["^i2s(#order R ())^"] ");
                        app (fn (X,_) => print(i2s X^" ")) (#nodes R ());
                        print "\n")

                   in if !view_IR then IR.viewSubgraph IR region else ();
                      schedule{ir=IR, region=region, 
                               blockIdTbl=DA.baseArray blockIdTbl,
                               numberOfInstructions=numberOfInstructions};
                      if !view_IR then IR.viewSubgraph IR region else ()
                   end
             end;
           main()
       end 
 
   in  initialization();
       main() handle PQ.EmptyPriorityQueue => ()
   end

end