cps.scm 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
  2. ;;;
  3. ;;; Port Author: Andrew Whatson
  4. ;;;
  5. ;;; Original Authors: Richard Kelsey
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/front/cps.scm
  8. ;;;
  9. ;;; (cps-call <primop> <exits> <first-arg-index> <args> <cps>) ->
  10. ;;; <call-node> + <top-call-node> + <bottom-lambda-node>
  11. ;;;
  12. ;;; (cps-sequence <nodes> <cps>) -> <last-node> + <top-call> + <bottom-lambda>
  13. ;;;
  14. ;;; (<cps> <node>) -> <value-node> + <top-call-node> + <bottom-lambda-node>
  15. (define-module (ps-compiler front cps)
  16. #:use-module (srfi srfi-9)
  17. #:use-module (prescheme scheme48)
  18. #:use-module (ps-compiler node arch)
  19. #:use-module (ps-compiler node node)
  20. #:use-module (ps-compiler node node-util)
  21. #:use-module (ps-compiler node primop)
  22. #:use-module (ps-compiler node variable)
  23. #:use-module (ps-compiler util util)
  24. #:export (cps-call cps-sequence))
  25. (define (cps-call primop exits first-arg-index args cps)
  26. (let ((call (make-call-node primop
  27. (+ (length args) first-arg-index)
  28. exits))
  29. (arguments (make-arg-nodes args first-arg-index cps)))
  30. (let loop ((args arguments) (first #f) (last #f))
  31. (if (null? args)
  32. (values call first last)
  33. (let ((arg (car args)))
  34. (attach call (arg-index arg) (arg-value arg))
  35. (if (and last (arg-first arg))
  36. (attach-body last (arg-first arg)))
  37. (loop (cdr args)
  38. (or first (arg-first arg))
  39. (or (arg-last arg) last)))))))
  40. ;; Record to hold information about arguments to calls.
  41. (define-record-type :arg
  42. (make-arg index rank value first last)
  43. arg?
  44. (index arg-index) ;; The index of this argument in the call.
  45. (rank arg-rank) ;; The estimated cost of executing this node at run time.
  46. (value arg-value) ;; What CPS returned for this argument.
  47. (first arg-first)
  48. (last arg-last))
  49. ;; Convert the elements of EXP into nodes (if they aren't already) and put
  50. ;; them into an ARG record. Returns the list of ARG records sorted
  51. ;; by ARG-RANK.
  52. (define (make-arg-nodes exp start cps)
  53. (do ((index start (+ index 1))
  54. (args exp (cdr args))
  55. (vals '() (cons (receive (value first last)
  56. (cps (car args))
  57. (make-arg index (node-rank first) value first last))
  58. vals)))
  59. ((null? args)
  60. (sort-list vals
  61. (lambda (v1 v2)
  62. (> (arg-rank v1) (arg-rank v2)))))))
  63. ;; Complexity analysis used to order argument evaluation. More complex
  64. ;; arguments are to be evaluated first. This just counts reference nodes.
  65. ;; It is almost certainly a waste of time.
  66. (define (node-rank first)
  67. (if (not first)
  68. 0
  69. (complexity-analyze-vector (call-args first))))
  70. (define (complexity-analyze node)
  71. (cond ((empty? node)
  72. 0)
  73. ((reference-node? node)
  74. 1)
  75. ((lambda-node? node)
  76. (if (not (empty? (lambda-body node)))
  77. (complexity-analyze-vector (call-args (lambda-body node)))
  78. 0))
  79. ((call-node? node)
  80. (complexity-analyze-vector (call-args node)))
  81. (else
  82. 0)))
  83. (define (complexity-analyze-vector vec)
  84. (do ((i 0 (+ i 1))
  85. (q 0 (+ q (complexity-analyze (vector-ref vec i)))))
  86. ((>= i (vector-length vec))
  87. q)))
  88. ;;----------------------------------------------------------------
  89. ;; (cps-sequence <nodes> <values-cps>) ->
  90. ;; <last-node> + <top-call> + <bottom-lambda>
  91. ;; <values-cps> is the same as the <cps> used above, except that it returns
  92. ;; a list of value nodes instead of exactly one.
  93. (define (cps-sequence nodes values-cps)
  94. (if (null? nodes)
  95. (bug "CPS: empty sequence"))
  96. (let loop ((nodes nodes) (first #f) (last #f))
  97. (if (null? (cdr nodes))
  98. (values (car nodes) first last)
  99. (receive (exp-first exp-last)
  100. (cps-sequent (car nodes) values-cps)
  101. (if (and last exp-first)
  102. (attach-body last exp-first))
  103. (loop (cdr nodes) (or first exp-first) (or exp-last last))))))
  104. (define (cps-sequent node values-cps)
  105. (receive (vals exp-first exp-last)
  106. (values-cps node)
  107. (receive (calls other)
  108. (partition-list call-node? vals)
  109. (map erase other)
  110. (if (null? calls)
  111. (values exp-first exp-last)
  112. (insert-let calls exp-first exp-last)))))
  113. (define (insert-let calls exp-first exp-last)
  114. (let* ((vars (map (lambda (call)
  115. (make-variable 'v (trivial-call-return-type call)))
  116. calls))
  117. (cont (make-lambda-node 'c 'cont vars))
  118. (call (make-call-node (get-primop (enum primop-enum let))
  119. (+ 1 (length calls))
  120. 1)))
  121. (attach-call-args call (cons cont calls))
  122. (cond (exp-first
  123. (attach-body exp-last call)
  124. (values exp-first cont))
  125. (else
  126. (values call cont)))))