cps.scm 4.0 KB

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