1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 20:00:19 +02:00
guile/module/language/cps/split-rec.scm
Andy Wingo cd5ab6377b Add $switch CPS term kind
* module/language/cps.scm ($switch): New term.
* doc/ref/compiler.texi (CPS in Guile): Add documentation.

* module/language/cps.scm (build-term, parse-cps, unparse-cps)
* module/language/cps/closure-conversion.scm (compute-non-operator-uses)
  (compute-singly-referenced-labels, rewrite-shared-closure-calls)
  (compute-free-vars, convert-one)
* module/language/cps/compile-bytecode.scm (compile-function)
* module/language/cps/contification.scm (compute-singly-referenced-labels)
  (compute-contification-candidates, apply-contification)
* module/language/cps/cse.scm (compute-truthy-expressions)
  (forward-cont, term-successors, eliminate-common-subexpressions-in-fun)
* module/language/cps/dce.scm (compute-known-allocations)
  (compute-live-code, process-eliminations)
* module/language/cps/devirtualize-integers.scm (compute-use-counts)
  (peel-trace)
* module/language/cps/effects-analysis.scm (compute-effects)
* module/language/cps/licm.scm (hoist-one, hoist-in-loop)
* module/language/cps/loop-instrumentation.scm (compute-loop-headers)
* module/language/cps/peel-loops.scm (rename-cont)
* module/language/cps/renumber.scm (sort-labels-locally, renumber)
* module/language/cps/rotate-loops.scm (rotate-loop)
  (rotate-loops-in-function)
* module/language/cps/self-references.scm (resolve-self-references)
* module/language/cps/simplify.scm (compute-singly-referenced-vars)
  (eta-reduce, compute-singly-referenced-labels, beta-reduce)
* module/language/cps/slot-allocation.scm (compute-defs-and-uses)
  (add-prompt-control-flow-edges, compute-var-representations)
* module/language/cps/specialize-numbers.scm (compute-significant-bits)
* module/language/cps/split-rec.scm (compute-free-vars)
* module/language/cps/type-fold.scm (local-type-fold)
* module/language/cps/types.scm (successor-count, infer-types)
* module/language/cps/utils.scm (compute-function-body)
  (compute-successors, compute-predecessors)
* module/language/cps/verify.scm (compute-available-definitions)
  (check-valid-var-uses, check-arities): Add support for new term.
2020-08-12 23:30:08 +02:00

178 lines
7.3 KiB
Scheme

;;; Continuation-passing style (CPS) intermediate language (IL)
;; Copyright (C) 2013-2020 Free Software Foundation, Inc.
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;; Commentary:
;;;
;;; Split functions bound in $rec expressions into strongly-connected
;;; components. The result will be that each $rec binds a
;;; strongly-connected component of mutually recursive functions.
;;;
;;; Code:
(define-module (language cps split-rec)
#:use-module (ice-9 match)
#:use-module ((srfi srfi-1) #:select (fold))
#:use-module (language cps)
#:use-module (language cps utils)
#:use-module (language cps with-cps)
#:use-module (language cps intmap)
#:use-module (language cps intset)
#:export (split-rec))
(define (compute-free-vars conts kfun)
"Compute a FUN-LABEL->FREE-VAR... map describing all free variable
references."
(define (add-def var defs) (intset-add! defs var))
(define (add-defs vars defs)
(match vars
(() defs)
((var . vars) (add-defs vars (add-def var defs)))))
(define (add-use var uses) (intset-add! uses var))
(define (add-uses vars uses)
(match vars
(() uses)
((var . vars) (add-uses vars (add-use var uses)))))
(define (visit-nested-funs body)
(intset-fold
(lambda (label out)
(match (intmap-ref conts label)
(($ $kargs _ _ ($ $continue _ _
($ $fun kfun)))
(intmap-union out (visit-fun kfun)))
(($ $kargs _ _ ($ $continue _ _
($ $rec _ _ (($ $fun kfun) ...))))
(fold (lambda (kfun out)
(intmap-union out (visit-fun kfun)))
out kfun))
(_ out)))
body
empty-intmap))
(define (visit-fun kfun)
(let* ((body (compute-function-body conts kfun))
(free (visit-nested-funs body)))
(call-with-values
(lambda ()
(intset-fold
(lambda (label defs uses)
(match (intmap-ref conts label)
(($ $kargs names vars term)
(values
(add-defs vars defs)
(match term
(($ $continue k src exp)
(match exp
((or ($ $const) ($ $prim)) uses)
(($ $fun kfun)
(intset-union (persistent-intset uses)
(intmap-ref free kfun)))
(($ $rec names vars (($ $fun kfun) ...))
(fold (lambda (kfun uses)
(intset-union (persistent-intset uses)
(intmap-ref free kfun)))
uses kfun))
(($ $values args)
(add-uses args uses))
(($ $call proc args)
(add-use proc (add-uses args uses)))
(($ $primcall name param args)
(add-uses args uses))))
(($ $branch kf kt src op param args)
(add-uses args uses))
(($ $switch kf kt* src arg)
(add-use arg uses))
(($ $prompt k kh src escape? tag)
(add-use tag uses))
(($ $throw src op param args)
(add-uses args uses)))))
(($ $kfun src meta (and self (not #f)))
(values (add-def self defs) uses))
(_ (values defs uses))))
body empty-intset empty-intset))
(lambda (defs uses)
(intmap-add free kfun (intset-subtract
(persistent-intset uses)
(persistent-intset defs)))))))
(visit-fun kfun))
(define (compute-split fns free-vars)
(define (get-free kfun)
;; It's possible for a fun to have been skipped by
;; compute-free-vars, if the fun isn't reachable. Fall back to
;; empty-intset for the fun's free vars, in that case.
(intmap-ref free-vars kfun (lambda (_) empty-intset)))
(let* ((vars (intmap-keys fns))
(edges (intmap-map
(lambda (var kfun)
(intset-intersect (get-free kfun) vars))
fns)))
(compute-sorted-strongly-connected-components edges)))
(define (intmap-acons k v map)
(intmap-add map k v))
(define (split-rec conts)
(let ((free (compute-free-vars conts 0)))
(with-fresh-name-state conts
(persistent-intmap
(intmap-fold
(lambda (label cont out)
(match cont
(($ $kargs cont-names cont-vars
($ $continue k src ($ $rec names vars (($ $fun kfuns) ...))))
(let ((fns (fold intmap-acons empty-intmap vars kfuns))
(fn-names (fold intmap-acons empty-intmap vars names)))
(match (compute-split fns free)
(()
;; Remove trivial $rec.
(with-cps out
(setk label ($kargs cont-names cont-vars
($continue k src ($values ()))))))
((_)
;; Bound functions already form a strongly-connected
;; component.
out)
(components
;; Multiple components. Split them into separate $rec
;; expressions.
(define (build-body out components)
(match components
(()
(match (intmap-ref out k)
(($ $kargs names vars term)
(with-cps (intmap-remove out k)
term))))
((vars . components)
(match (intset-fold
(lambda (var out)
(let ((name (intmap-ref fn-names var))
(fun (build-exp
($fun (intmap-ref fns var)))))
(cons (list name var fun) out)))
vars '())
(((name var fun) ...)
(with-cps out
(let$ body (build-body components))
(letk kbody ($kargs name var ,body))
(build-term
($continue kbody src ($rec name var fun)))))))))
(with-cps out
(let$ body (build-body components))
(setk label ($kargs cont-names cont-vars ,body)))))))
(_ out)))
conts
conts)))))