diff --git a/am/bootstrap.am b/am/bootstrap.am
index a71946958..00f677e4f 100644
--- a/am/bootstrap.am
+++ b/am/bootstrap.am
@@ -1,4 +1,4 @@
-## Copyright (C) 2009-2023 Free Software Foundation, Inc.
+## Copyright (C) 2009-2024 Free Software Foundation, Inc.
##
## This file is part of GNU Guile.
##
@@ -73,6 +73,7 @@ SOURCES = \
language/tree-il/compile-cps.scm \
language/tree-il/cps-primitives.scm \
language/tree-il/debug.scm \
+ language/tree-il/demux-lambda.scm \
language/tree-il/effects.scm \
language/tree-il/eta-expand.scm \
language/tree-il/fix-letrec.scm \
diff --git a/module/language/tree-il/demux-lambda.scm b/module/language/tree-il/demux-lambda.scm
new file mode 100644
index 000000000..661ce7962
--- /dev/null
+++ b/module/language/tree-il/demux-lambda.scm
@@ -0,0 +1,124 @@
+;;; Expand case-lambda and lambda* into simple dispatchers
+;;; Copyright (C) 2024 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 program. If not, see
+;;; .
+
+;;; Commentary:
+;;;
+;;; We can partition lambdas into simple and complex. A simple lambda
+;;; has just one clause and no optional, rest, or keyword arguments.
+;;; Any other lambda is complex. This pass aims to facilitate reduction
+;;; of complex lambdas to simple lambdas. It does so by eta-expanding
+;;; lexically-bound complex lambdas into simple dispatchers that
+;;; tail-call simple lambda body procedures. This will allow peval to
+;;; elide the complex lambdas in many cases.
+;;;
+;;; Code:
+
+(define-module (language tree-il demux-lambda)
+ #:use-module (srfi srfi-1)
+ #:use-module (ice-9 match)
+ #:use-module (language tree-il)
+ #:export (demux-lambda))
+
+(define (make-binding name sym val) (vector name sym val))
+
+(define (demux-clause func-name clause)
+ (match clause
+ (#f (values '() clause))
+ (($ src req opt rest kw inits gensyms body alternate)
+ (call-with-values (lambda () (demux-clause func-name alternate))
+ (lambda (bindings alternate)
+ (define simple-req
+ (append req (or opt '()) (if rest (list rest) '())
+ (match kw
+ ((aok? (kw name sym) ...) name)
+ (#f '()))))
+ (define simple-clause
+ (make-lambda-case src simple-req '() #f #f '() gensyms body #f))
+ (define simple-func (make-lambda src '() simple-clause))
+ (define simple-sym (gensym "demuxed"))
+ (define simple-binding
+ (make-binding func-name simple-sym simple-func))
+
+ (define renamed-syms
+ (map (lambda (_) (gensym "demux")) gensyms))
+ (define rename-sym
+ (let ((renamed (map cons gensyms renamed-syms)))
+ (lambda (sym) (or (assq-ref renamed sym) sym))))
+ (define renamed-kw
+ (match kw
+ ((aok? (kw name sym) ...)
+ (cons aok? (map list kw name (map rename-sym sym))))
+ (#f #f)))
+ (define renamed-inits
+ (map (lambda (init)
+ (post-order
+ (lambda (exp)
+ (match exp
+ (($ src name sym)
+ (make-lexical-ref src name (rename-sym sym)))
+ (($ src name sym exp)
+ (make-lexical-set src name (rename-sym sym) exp))
+ (_ exp)))
+ init))
+ inits))
+ (define dispatch-call
+ (make-call src (make-lexical-ref src func-name simple-sym)
+ (map (lambda (name sym)
+ (make-lexical-ref src name sym))
+ simple-req renamed-syms)))
+ (define dispatch-clause
+ (make-lambda-case src req opt rest renamed-kw renamed-inits
+ renamed-syms dispatch-call alternate))
+
+ (values (cons simple-binding bindings)
+ dispatch-clause))))))
+
+(define (demux-lambda exp)
+ (define (complex-lambda? val)
+ (match val
+ (($ src meta
+ ($ src req opt rest kw inits gensyms body alternate))
+ (or (pair? opt) rest (pair? kw) alternate))
+ (_ #f)))
+
+ (define (demux-binding name gensym val)
+ (if (complex-lambda? val)
+ (match val
+ (($ src meta clause)
+ (call-with-values (lambda () (demux-clause name clause))
+ (lambda (extra-bindings clause)
+ (let ((val (make-lambda src meta clause)))
+ (append extra-bindings
+ (list (make-binding name gensym val))))))))
+ (list (make-binding name gensym val))))
+
+ (define (demux-lexically-bound-complex-lambdas exp)
+ (match exp
+ (($ src in-order? names gensyms vals body)
+ (match (append-map demux-binding names gensyms vals)
+ ((#(name gensym val) ...)
+ (make-letrec src in-order? name gensym val body))))
+
+ (($ src names gensyms vals body)
+ (if (or-map lambda? vals)
+ (demux-lexically-bound-complex-lambdas
+ (make-letrec src #f names gensyms vals body))
+ exp))
+
+ (_ exp)))
+
+ (post-order demux-lexically-bound-complex-lambdas exp))
diff --git a/module/language/tree-il/optimize.scm b/module/language/tree-il/optimize.scm
index b1d8b8294..11e0470be 100644
--- a/module/language/tree-il/optimize.scm
+++ b/module/language/tree-il/optimize.scm
@@ -1,6 +1,6 @@
;;; Tree-il optimizer
-;; Copyright (C) 2009, 2010-2015, 2018-2021 Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2010-2015, 2018-2021, 2024 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
@@ -45,6 +45,7 @@
(letrectify (lookup #:letrectify? letrectify))
(seal? (assq-ref opts #:seal-private-bindings?))
(xinline? (assq-ref opts #:cross-module-inlining?))
+ (demux (lookup #:demux-lambda? demux-lambda))
(peval (lookup #:partial-eval? peval))
(eta-expand (lookup #:eta-expand? eta-expand))
(inlinables (lookup #:inlinable-exports? inlinable-exports)))
@@ -56,6 +57,7 @@
(run-pass! (resolve exp env))
(run-pass! (expand exp))
(run-pass! (letrectify exp #:seal-private-bindings? seal?))
+ (run-pass! (demux exp))
(run-pass! (fix-letrec exp))
(run-pass! (peval exp env #:cross-module-inlining? xinline?))
(run-pass! (eta-expand exp))
diff --git a/module/system/base/optimize.scm b/module/system/base/optimize.scm
index 8c36cca07..2152041c3 100644
--- a/module/system/base/optimize.scm
+++ b/module/system/base/optimize.scm
@@ -1,6 +1,6 @@
;;; Optimization flags
-;; Copyright (C) 2018, 2020-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2018,2020-2022,2024 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
@@ -32,6 +32,7 @@
(#:resolve-primitives? 1)
(#:expand-primitives? 1)
(#:letrectify? 2)
+ (#:demux-lambda? 2)
(#:seal-private-bindings? 3)
(#:partial-eval? 1)
(#:eta-expand? 2)