pp-cps.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Mike Sperber
  3. ; Pretty-printing the node tree
  4. ; Sample output:
  5. ; 34 (F_12 (C_11 UNIT_0)
  6. ; (SET-CONTENTS 1 C_11 UNIT_0 UNIT '0 ^F_14))
  7. ;
  8. ; 35 (F_14 (C_13 N_1)
  9. ; 36 (LET* (((LOOP_73) (CONS CELL '0))
  10. ; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34))
  11. ; 38 ((V_77) (CONTENTS LOOP_73 CELL '0)))
  12. ; (V_77 1 C_13 N_1 '1)))
  13. ;
  14. ; 39 (F_34 (C_33 I_9 R_7)
  15. ; 40 (LET* (((V_61) (CONTENTS UNIT_0 UNIT '3))
  16. ; 41 ((V_63) (V_61 I_9 '0)))
  17. ; (TRUE? 2 ^C_58 ^C_41 V_63)))
  18. ;
  19. ; 42 (C_58 ()
  20. ; (C_33 0 R_7))
  21. ;
  22. ; 43 (C_41 ()
  23. ; 44 (LET* (((V_46) (CONTENTS UNIT_0 UNIT '2))
  24. ; 45 ((V_56) (V_46 I_9 R_7))
  25. ; 46 ((V_44) (CONTENTS UNIT_0 UNIT '1))
  26. ; 47 ((V_54) (V_44 I_9 '1))
  27. ; 48 ((V_52) (CONTENTS LOOP_73 CELL '0)))
  28. ; (V_52 1 C_33 V_54 V_56)))
  29. ; What it means:
  30. ; Variables `<name>_<id>' V_61
  31. ; Primops `<primop name>' CONTENTS
  32. ; Lambdas `^<self variable>' ^F_34
  33. ; Literals `'<value>' '0
  34. ; 35 (F_14 (C_13 N_1)
  35. ; This is the header for a lambda node. `35' is the object hash of the node.
  36. ; `F_14' is the LAMBDA-NAME and LAMBDA-ID, `(C_13 N_1)' is the variable list. The
  37. ; start of this line (not counting the object hash) is indented one column
  38. ; more than the start of the lexically superior lambda.
  39. ; 36 (LET* (((LOOP_73) (CONS CELL '0))
  40. ; 37 (() (SET-CONTENTS LOOP_73 CELL '0 ^F_34))
  41. ; 38 ((V_77) (CONTENTS LOOP_73 CELL '0)))
  42. ; (V_77 1 C_13 N_1 '1)))
  43. ; This is the body of the lambda. It is a block consisting of three simple
  44. ; calls and then a tail recursive call. The simple calls are in the form
  45. ; of a LET* that allows multiple value returns. The actual body of the
  46. ; lambda is the call `(CONS CELL '0)'. The continuation to this call is
  47. ; a lambda node `(LAMBDA (LOOP_73) (SET-CONTENTS ...))'. `36' is the
  48. ; object hash of this continuation lambda.
  49. ; After the block any lambdas in the block are printed. This lambda is
  50. ; followed by `F_34'.
  51. ; (PP-CPS node . port)
  52. ;---------------------------------------------------------------------------
  53. ; Print CPS node tree in linear form. Port defaults to the current output port.
  54. ; This just dispatches on the type of NODE.
  55. (define (pp-cps node . port)
  56. (let* ((port (if (null? port) (current-output-port) (car port)))
  57. (port (if (current-column port)
  58. port
  59. (make-tracking-output-port port))))
  60. (set! *rereadable?* #f)
  61. (cond ((lambda-node? node)
  62. (pp-cps-lambda node 4 port))
  63. ((call-node? node)
  64. (write-non-simple-call node port))
  65. (else
  66. (write-node-value node port)))
  67. (newline port)
  68. ((structure-ref i/o force-output) port)))
  69. (define (rereadable-pp-cps node port)
  70. (set! *rereadable?* #t)
  71. (pp-cps-lambda node 4 port)
  72. (values))
  73. (define (indent port count)
  74. (let ((count (cond ((<= (current-column port) count)
  75. (- count (current-column port)))
  76. (else
  77. (newline port)
  78. count))))
  79. (do ((count count (- count 1)))
  80. ((>= 0 count))
  81. (writec port #\space))))
  82. (define *rereadable?* #f)
  83. (define *next-pp-id* 0)
  84. (define (reset-pp-cps)
  85. (set! *next-pp-id* 0))
  86. (define (next-pp-id)
  87. (let ((id *next-pp-id*))
  88. (set! *next-pp-id* (+ *next-pp-id* 1))
  89. id))
  90. ; Print a lambda node by printing its identifiers, then its call, and finally
  91. ; any other lambdas that it includes.
  92. (define (pp-cps-lambda node indent-to port)
  93. (format port "~&~%")
  94. (cond ((not *rereadable?*)
  95. (node-hash node)
  96. (format port "~D" (lambda-id node))))
  97. (indent port indent-to)
  98. (write-lambda-header node port)
  99. (let ((internal (pp-cps-body (lambda-body node) indent-to port)))
  100. (writec port #\))
  101. (for-each (lambda (n)
  102. (pp-cps-lambda n (+ indent-to 1) port))
  103. internal)))
  104. (define (write-lambda-header node port)
  105. (writec port '#\()
  106. (writec port (case (lambda-type node)
  107. ((proc known-proc) #\P)
  108. ((cont) #\C)
  109. ((jump) #\J)
  110. ((escape) #\E)))
  111. (writec port #\space)
  112. (print-lambda-name node port)
  113. (writec port #\space)
  114. (write-lambda-vars node port))
  115. (define (write-lambda-vars node port)
  116. (let ((vars (lambda-variables node)))
  117. (cond ((not (null? vars))
  118. (writec port '#\()
  119. (print-variable-name (car vars) port)
  120. (do ((v (cdr vars) (cdr v)))
  121. ((null? v))
  122. (writec port '#\space)
  123. (print-variable-name (car v) port))
  124. (writec port '#\)))
  125. (else
  126. (format port "()")))))
  127. ; Print the body of a lambda node. A simple call is one that has exactly
  128. ; one exit. They and calls to lambda nodes are printed as a LET*.
  129. (define (pp-cps-body call indent-to port)
  130. (newline port)
  131. (cond ((or (simple-call? call)
  132. (let-call? call))
  133. (write-let* call indent-to port))
  134. (else
  135. (indent port (+ '2 indent-to))
  136. (write-non-simple-call call port))))
  137. ; Write out a series of calls as a LET*. The LET* ends when a call is reached
  138. ; that is neither a simple call or a call to a lambda.
  139. (define (write-let* call indent-to port)
  140. (cond ((not *rereadable?*)
  141. (node-hash (call-arg call 0))
  142. (format port "~D" (lambda-id (call-arg call '0)))))
  143. (indent port (+ '2 indent-to))
  144. (writec port '#\()
  145. (format port "LET* ")
  146. (writec port '#\()
  147. (let loop ((call (next-call call))
  148. (ns (write-simple-call call indent-to port)))
  149. (cond ((or (simple-call? call)
  150. (let-call? call))
  151. (newline port)
  152. (cond ((not *rereadable?*)
  153. (format port "~D" (lambda-id (call-arg call '0)))
  154. (node-hash (call-arg call 0))))
  155. (indent port (+ '9 indent-to))
  156. (loop (next-call call)
  157. (append (write-simple-call call indent-to port) ns)))
  158. (else
  159. (writec port '#\))
  160. (newline port)
  161. (indent port (+ '4 indent-to))
  162. (let ((ns (append (write-non-simple-call call port) ns)))
  163. (writec port '#\))
  164. ns)))))
  165. (define (simple-call? call)
  166. (= '1 (call-exits call)))
  167. (define (let-call? call)
  168. (calls-this-primop? call 'let))
  169. ; Get the call that follows CALL in a LET*.
  170. (define (next-call call)
  171. (lambda-body (call-arg call '0)))
  172. ; Write out one line of a LET*.
  173. (define (write-simple-call call indent-to port)
  174. (if (let-call? call)
  175. (write-let-call call indent-to port)
  176. (really-write-simple-call call indent-to port)))
  177. ; Write the variables bound by the continuation and then the primop and
  178. ; non-continuation arguments of the call.
  179. (define (really-write-simple-call call indent-to port)
  180. (writec port '#\()
  181. (write-lambda-vars (call-arg call '0) port)
  182. (indent port (+ indent-to '21))
  183. (writec port '#\()
  184. (format port "~S" (primop-id (call-primop call)))
  185. (write-call-args call '1 port)
  186. (writec port '#\))
  187. (find-lambda-nodes call 1))
  188. ; Write the variables of the lambda and then the values of the arguments.
  189. (define (write-let-call call indent-to port)
  190. (writec port '#\()
  191. (write-lambda-vars (call-arg call '0) port)
  192. (cond ((= '1 (vector-length (call-args call)))
  193. (writec port '#\))
  194. '())
  195. (else
  196. (writec port #\*)
  197. (indent port (+ indent-to '21))
  198. (write-node-value (call-arg call '1) port)
  199. (write-call-args call '2 port)
  200. (find-lambda-nodes call 1))))
  201. (define (find-lambda-nodes call start)
  202. (reverse (let label ((call call) (start start) (ls '()))
  203. (do ((i start (+ i 1))
  204. (ls ls (let ((arg (call-arg call i)))
  205. (cond ((call-node? arg)
  206. (label arg 0 ls))
  207. ((lambda-node? arg)
  208. (cons arg ls))
  209. (else ls)))))
  210. ((>= i (call-arg-count call))
  211. ls)))))
  212. ; Write out a call that ends a LET* block.
  213. (define (write-non-simple-call call port)
  214. (writec port '#\()
  215. (format port "~A ~D" (primop-id (call-primop call)) (call-exits call))
  216. (write-call-args call '0 port)
  217. (find-lambda-nodes call 0))
  218. ; Write out the arguments of CALL starting with START.
  219. (define (write-call-args call start port)
  220. (let* ((vec (call-args call))
  221. (len (vector-length vec)))
  222. (do ((i start (+ i '1)))
  223. ((>= i len))
  224. (writec port '#\space)
  225. (write-node-value (vector-ref vec i) port))
  226. (writec port '#\))))
  227. ; Print out a literal value.
  228. (define (cps-print-literal value port)
  229. (format port "'~S" value))
  230. ; Dispatch on the type of NODE to get the appropriate printing method.
  231. (define (write-node-value node port)
  232. (cond ((not (node? node))
  233. (format port "{not a node}"))
  234. ((lambda-node? node)
  235. (writec port '#\^)
  236. (print-lambda-name node port))
  237. ((call-node? node)
  238. (format port "(~S" (primop-id (call-primop node)))
  239. (write-call-args node '0 port))
  240. ((literal-node? node)
  241. (cps-print-literal (literal-value node) port))
  242. ((reference-node? node)
  243. (print-variable-name (reference-variable node) port))
  244. (else
  245. (bug "WRITE-NODE-VALUE got funny node ~S" node))))
  246. ; Printing variables and lambda nodes
  247. ; #T if variables are supposed to print as the name of the register containing
  248. ; them instead of their name.
  249. (define *pp-register-names?* '#f)
  250. ; A whole bunch of different entry points for printing variables in slightly
  251. ; different ways.
  252. (define (print-variable-name var port)
  253. (cond ((not var)
  254. (format port "#f"))
  255. ; ((and *pp-register-names?*
  256. ; (reg? (variable-register var)))
  257. ; (format port "~S" (reg-name (variable-register var))))
  258. (else
  259. (let ((id (cond ((not *rereadable?*)
  260. (variable-id var))
  261. ((variable-flag var)
  262. => identity)
  263. (else
  264. (let ((id (next-pp-id)))
  265. (set-variable-flag! var id)
  266. id)))))
  267. (format port "~S_~S" (variable-name var) id)))))
  268. ; Same as the above without the check for a register.
  269. (define (print-variable-plain-name var port)
  270. (cond ((not var)
  271. (format port "#f"))
  272. (else
  273. (format port "~S_~D" (variable-name var) (variable-id var)))))
  274. ; Return the name as a string.
  275. (define (variable-print-name var)
  276. (print-variable-name var '#f))
  277. ; Return the name as a symbol.
  278. (define (variable-unique-name var)
  279. (string->symbol (variable-print-name var)))
  280. ; Printing lambda-nodes as variables
  281. (define (print-lambda-name lnode port)
  282. (let ((id (cond ((not *rereadable?*)
  283. (lambda-id lnode))
  284. ((node-flag lnode)
  285. => identity)
  286. (else
  287. (let ((id (next-pp-id)))
  288. (set-node-flag! lnode id)
  289. id)))))
  290. (format port "~S_~D" (lambda-name lnode) id)))
  291. (define (lambda-print-name lnode)
  292. (print-lambda-name lnode '#f))
  293. (define (lambda-unique-name lnode)
  294. (string->symbol (lambda-print-name lnode)))