PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/register-allocation.scm

http://github.com/theoria/maeve
Scheme | 381 lines | 291 code | 15 blank | 75 comment | 0 complexity | 663d0673e27c28019aec475e2b17d0cc MD5 | raw file
  1. (define-module maeve.compiler.register-allocation
  2. (use gauche.array)
  3. (use util.combinations)
  4. (use maeve.compiler.intermediate-language-util)
  5. (use maeve.compiler.intermediate-language-instance)
  6. (use maeve.compiler.data-flow-analysis)
  7. (export-all))
  8. (select-module maeve.compiler.register-allocation)
  9. (define *sp* (make-svar :type 'sp))
  10. (define *fp* (make-svar :type 'fp))
  11. (define-values (ref-stack-by-sp/const ref-stack-by-fp/const)
  12. (let1 gen
  13. (lambda (base offset)
  14. (unless (integer? offset) (error "mem offset must be ingeter :" offset))
  15. (make-mem :base base :offset (* (variable-size) offset)))
  16. (values (cut gen *sp* <>) (cut gen *fp* <>))))
  17. (define (proc-parameter-allocation:stack type xs)
  18. (let* ((n 0)
  19. (ys
  20. (map1-with-index
  21. (lambda (i _)
  22. (inc! n)
  23. (case type
  24. ((lmd) (ref-stack-by-fp/const i))
  25. ((call) (ref-stack-by-sp/const i))
  26. (else (error "invalid procparam type :" type))))
  27. xs)))
  28. (values ys (* (variable-size) n))))
  29. (define (%paramalloca-regs xs type regs)
  30. (let* ((%num-of-regs (length regs))
  31. (n 0)
  32. (ys
  33. (map1-with-index
  34. (lambda (i _)
  35. (if (> %num-of-regs i)
  36. (case type
  37. ((lmd call) (make-register :num (pop! regs)))
  38. (else (error "invalid procparam type :" type)))
  39. (begin
  40. (inc! n)
  41. (case type
  42. ((lmd) (ref-stack-by-fp/const i))
  43. ((call) (ref-stack-by-sp/const i))
  44. (else (error "invalid procparam type :" type))))))
  45. xs)))
  46. (values ys (* (variable-size) n))))
  47. (define (proc-parameter-allocation:x86-64 type xs)
  48. (unless (eq? type 'call)
  49. (error "proc-parameter-allocation:x86-64 type-error :" type))
  50. (%paramalloca-regs
  51. xs type
  52. (map rregister->regnum '(rdi rsi rdx rcx r8 r9))))
  53. (define (proc-parameter-allocation:register type xs)
  54. (%paramalloca-regs
  55. xs type
  56. (map rregister->regnum (vector->list (registers)))))
  57. (define (register-allocation:stack paramalloca e)
  58. (let ((lva-table (make-hash-table 'eq?))
  59. (cur-table (make-hash-table 'eq?)))
  60. (define cur-default (cut make-vector (num-of-registers) #f))
  61. (mir-traverse
  62. (target e)
  63. (type no-update)
  64. (handler
  65. (lmd
  66. (let-values (((cur) (cur-default))
  67. ((dists arg-size) (paramalloca 'lmd param)))
  68. (for-each
  69. (lambda (lv e)
  70. (hash-table-put! lva-table lv e)
  71. (when (register? e) (vector-set! cur (register:num-of e) #t)))
  72. param dists)
  73. (when-debug:regalloca
  74. (format #t "cur ~s : ~s ~s ~s\n"
  75. id (filter-map register:num-of* dists) cur (eq-hash cur)))
  76. (hash-table-put! cur-table *self* cur)
  77. (for-each-with-index
  78. (lambda (i lv)
  79. (hash-table-put!
  80. lva-table lv (ref-stack-by-fp/const (- (+ 1 i)))))
  81. local-vars)))))
  82. (when-debug:regalloca (hash-table-dump lva-table))
  83. (make-register-allocation-result
  84. :compute-using-register
  85. (lambda (xs) (hash-table-get* cur-table (find lmd? xs) (cur-default)))
  86. :lvar-allocation (lambda (_ lv) (hash-table-get lva-table lv)))))
  87. (define (pp-dim2-array dim1 dim2 a)
  88. (define (dim2-array? a)
  89. (let1 s (array-shape a)
  90. (= 2 (array-length s 0) (array-length s 1))))
  91. (unless (dim2-array? a)
  92. (error "Dimension of array is not 2. That's shape :" (shape a)))
  93. (let ((start1 (array-start a 0))
  94. (start2 (array-start a 1))
  95. (cmax 0))
  96. (define (%update x)
  97. (cond
  98. ((string-length (write-to-string x))
  99. (cut < cmax <>)
  100. => (lambda (l) (set! cmax l)))))
  101. (vector-for-each (lambda (_ e) (%update e)) dim1)
  102. (vector-for-each (lambda (_ e) (%update e)) dim2)
  103. (array-for-each-index
  104. a
  105. (lambda (i j) (%update (array-ref a i j))))
  106. (let1 out (cut format #t #`"~,|cmax|@a " <>)
  107. (array-for-each-index
  108. a
  109. (lambda (i j)
  110. (when (= start2 j)
  111. (when (= start1 i)
  112. (out "")
  113. (vector-for-each
  114. (lambda (_ e) (out e))
  115. dim2))
  116. (newline)
  117. (out (vector-ref dim1 (- i start1))))
  118. (let1 x (array-ref a i j)
  119. (out (if x x "")))))))
  120. (newline))
  121. (define (matrix-size matrix)
  122. (let ((e1 (array-end matrix 1))
  123. (e2 (array-end matrix 1)))
  124. (if (= e1 e2) e1
  125. (error "interference matrix required, but got :" matrix))))
  126. (define (matrix->graphviz i->v matrix)
  127. (print "digraph cfg {")
  128. (print " node [shape = \"plaintext\", fontsize = \"10\"];")
  129. (dotimes (i (matrix-size matrix))
  130. (format #t " ~a [label = \"~a ~a\"];\n" i i (i->v i)))
  131. (format #t " edge [dir = none]\n\n")
  132. (array-for-each-index
  133. matrix
  134. (lambda (i j)
  135. (when (and (array-ref matrix i j)
  136. (< i j))
  137. (format #t " ~s -> ~s;\n" i j))))
  138. (print "}"))
  139. (define (register-allocation:primitive-approximation paramalloca e)
  140. (define lva-table (make-hash-table 'eq?))
  141. (define cur-table (make-hash-table 'eq?))
  142. (define cur-default (cut make-vector (num-of-registers) #f))
  143. (define (make-interference-graph slive)
  144. (define (%make-interference-graph live-rights)
  145. (let* ((vars
  146. (sort
  147. (fold (lambda (e p) (lset-union eqv? e p))
  148. '() live-rights)
  149. il<?))
  150. (vlen (length vars))
  151. (v->i (alist->hash-table (map1-with-index xcons vars) 'eqv?))
  152. (matrix (make-array (shape 0 vlen 0 vlen) #f))
  153. (index (vector 0 0)))
  154. (for-each
  155. (lambda (inf)
  156. (combinations-for-each
  157. (lambda (x)
  158. (let ((ai (hash-table-get v->i (car x)))
  159. (bi (hash-table-get v->i (cadr x))))
  160. (array-set! matrix ai bi #t)
  161. (array-set! matrix bi ai #t)))
  162. inf 2))
  163. live-rights)
  164. (values
  165. matrix
  166. (cut hash-table-get v->i <> #f)
  167. (let1 i->v (alist->hash-table (map1-with-index cons vars) 'eqv?)
  168. (cut hash-table-get i->v <> #f))
  169. (let1 x (list->vector (map il:id vars))
  170. (cut pp-dim2-array x x matrix)))))
  171. (%make-interference-graph
  172. (hash-table-map slive (compose (map$ live-elm:var-of) second-value))))
  173. (mir-traverse
  174. (target e) (type no-update)
  175. (handler
  176. (lmd
  177. (when-debug:regalloca
  178. (format #t " ** register-allocation ~s\n" id))
  179. (let*-values
  180. (((%slive) (live *self*))
  181. (_ (when-debug:regalloca
  182. (hash-table-dump*
  183. %slive :pre-key-filter il:id :value-filter
  184. (map$ (lambda (x)
  185. (if (live-elm:end?-of x)
  186. (list (live-elm:var-of x) (live-elm:end?-of x))
  187. (live-elm:var-of x)))))))
  188. ((matrix v->i i->v p) (make-interference-graph %slive))
  189. ((dists arg-size) (paramalloca 'lmd param))
  190. ((msize) (matrix-size matrix))
  191. ((kill-table) (make-vector msize #f))
  192. ((index-sum) 0)
  193. ((%num-of-regs) (num-of-registers))
  194. ((stack) '())
  195. ((result) (make-vector msize #f))
  196. ((registers) (list-ec (: i 0 %num-of-regs) i)))
  197. (define (degree vindex)
  198. (let ((c 0) (edge-to '()))
  199. (dotimes (i msize)
  200. (when (array-ref matrix vindex i)
  201. (push! edge-to i)
  202. (unless (kill? i) (inc! c))))
  203. (values c edge-to)))
  204. (define kill? (cut vector-ref kill-table <>))
  205. (define (kill vindex)
  206. (vector-set! kill-table vindex #t)
  207. ;; (dotimes (i msize)
  208. ;; (array-set! matrix vindex i #f)
  209. ;; (array-set! matrix i vindex #f))
  210. (inc! index-sum))
  211. (when-debug:regalloca (print " ** interference matrix") (p))
  212. (for-each
  213. (lambda (lv e)
  214. (hash-table-put! lva-table lv e)
  215. (cond ((v->i lv)
  216. => (lambda (i)
  217. (kill i)
  218. (vector-set! result i (or (register:num-of* e) e))))))
  219. param dists)
  220. (until (= index-sum msize)
  221. (push!
  222. stack
  223. (rlet*-last
  224. ((i 0) (r #f))
  225. (while (and (> msize i)
  226. (or
  227. (kill? i)
  228. (cond ((degree i)
  229. (lambda (deg _) (> %num-of-regs deg))
  230. => (lambda (deg edge-to)
  231. (set! r (cons i edge-to))
  232. #f))
  233. (else #t))))
  234. (inc! i))
  235. (if r
  236. (kill (car r))
  237. (error "unsupport spill.")))))
  238. (for-each
  239. (lambda (vs)
  240. (unless (vector-ref result (car vs))
  241. (vector-set!
  242. result (car vs)
  243. (car
  244. (lset-difference
  245. = registers
  246. (filter-map1
  247. (lambda (x)
  248. (cond
  249. ((vector-ref result x) integer? => identity)
  250. (else #f)))
  251. (cdr vs)))))))
  252. stack)
  253. (when-debug:regalloca
  254. (format #t "slv-result ~s : ~s ~s\n" id result stack))
  255. (let1 cur (cur-default)
  256. (vector-for-each
  257. (lambda (i e)
  258. (when (integer? e)
  259. (vector-set! cur e #t)
  260. (hash-table-put! lva-table (i->v i) (make-register :num e))))
  261. result)
  262. (hash-table-put! cur-table *self* cur))
  263. (hash-table-update-all!
  264. %slive
  265. (lambda (k elms _)
  266. (rlet1
  267. cur (cur-default)
  268. (for-each
  269. (lambda (v)
  270. (and-let* ((x (vector-ref result (v->i (live-elm:var-of v))))
  271. (_ (integer? x)))
  272. (if (live-elm:end?-of v)
  273. (vector-set! cur x 'end)
  274. (vector-set! cur x #t))))
  275. elms)
  276. (when-debug:regalloca
  277. (format #t "cur ~s : ~s ~s ~s\n"
  278. (il:id k)
  279. (map
  280. (lambda (v)
  281. (vector-ref result (v->i (live-elm:var-of v))))
  282. elms)
  283. cur (eq-hash cur)))))
  284. :dist cur-table)))))
  285. ;;(with-output-to-file "./interference-graph.dot"
  286. ;; (cut matrix->graphviz i->v m))
  287. ;; (hash-table-dump* lva-table :pre-key-filter il:id)
  288. ;; (hash-table-dump* cur-table :pre-key-filter il:id
  289. ;; :value-filter (lambda (v) (cons (eq-hash v) v)))
  290. (make-register-allocation-result
  291. :lvar-allocation (lambda (_ lv) (hash-table-get lva-table lv))
  292. :compute-using-register
  293. (lambda (xs)
  294. (cond
  295. ((find-and-value
  296. (lambda (x) (hash-table-get cur-table x #f))
  297. xs) => identity)
  298. (else (error "compute-using-register not found :" xs))))))
  299. ;; (receive (%make-set! %make-set!-vls %make-opr2)
  300. ;; (let1 lv (make-hash-table 'eq?)
  301. ;; (define (make-one x)
  302. ;; (case/pred
  303. ;; x
  304. ;; (symbol?
  305. ;; (cond
  306. ;; ((hash-table-get lv x #f) => identity)
  307. ;; (else (rlet1 r (make-lvar :name x) (hash-table-put! lv x r)))))
  308. ;; (il? x)
  309. ;; (else (make-const :v x))))
  310. ;; (values
  311. ;; (lambda (d s)
  312. ;; (make-set! :dist (make-one d) :src (make-one s)))
  313. ;; (lambda (ds s)
  314. ;; (make-set!-vls :dists (map make-one ds) :src (make-one s)))
  315. ;; (lambda (op v1 v2)
  316. ;; (make-opr2 :opr op :v1 (make-one v1) :v2 (make-one v2)))))
  317. ;; (let* ((b6 (%make-block '()))
  318. ;; (b5 (%make-block
  319. ;; (%make-set! 'i 2)
  320. ;; b6))
  321. ;; (b4 (%make-block
  322. ;; (%make-set! 'j (%make-opr2 '/ 'i 2))
  323. ;; b5))
  324. ;; (b3 (%make-block
  325. ;; (list
  326. ;; (%make-set! 'j (%make-opr2 '- 'j 1))
  327. ;; (%make-set!-vls (list 'k 'l) 30))
  328. ;; b4))
  329. ;; (b2 (%make-block
  330. ;; (%make-set!-vls
  331. ;; (list 'i 'k)
  332. ;; (make-vls :es (list (%make-opr2 '+ 'i 1)
  333. ;; (%make-opr2 '- 'j 'i))))
  334. ;; b3))
  335. ;; (b1 (%make-block
  336. ;; (list
  337. ;; (%make-set! 'j 10)
  338. ;; (%make-set! 'i -8))
  339. ;; b2)))
  340. ;; (%block:opt-succ-set!
  341. ;; b3 b2 (%make-opr2 '!= 'j 0))
  342. ;; (%block:opt-succ-set!
  343. ;; b4 b6 (%make-opr2 '< 'i 8))
  344. ;; (%block:default-succ-set! b6 b2)
  345. ;; (let1 x (make-seq :es (list b1 b2 b3 b4 b5 b6))
  346. ;; (print " ** reach")
  347. ;; (hash-table-dump*
  348. ;; (reach x)
  349. ;; :pre-key-filter il:id
  350. ;; :value-filter
  351. ;; (lambda (x)
  352. ;; (hash-table-map
  353. ;; x (lambda (k vs)
  354. ;; (cons
  355. ;; (lvar:name-of* k)
  356. ;; (map
  357. ;; (lambda (v) (list (il:id (rd-elm:src-of v)) (rd-elm:num-of v)))
  358. ;; vs))))))
  359. ;; (print " ** live")
  360. ;; (hash-table-dump*
  361. ;; (live x)
  362. ;; :pre-key-filter il:id
  363. ;; :value-filter (map$ lvar:name-of*))
  364. ;; (il->graphviz* "nak" x)
  365. ;; (process-wait-any #t))))
  366. (provide "maeve/compiler/register-allocation")