On Fri, Sep 26, 2025 at 10:46 AM Olivier Dion <[email protected]> wrote:
>
> On Fri, 26 Sep 2025, "Thompson, David" <[email protected]> wrote:
>
> [...]
>
> > (define-syntax max
> >   (lambda (stx)
> >     (syntax-case stx ()
> >       (id
> >        (identifier? #'id)
> >        #'%max)
> >       ((_ x) #'x)
> >       ((_ x y)
> >        #'(let ((x* x)
> >                (y* y))
> >            (if (> x* y*) x* y*)))
> >       ((_ x y ...)
> >        #'(let ((x* x)
> >                (m (max y ...)))
> >            (if (> x* m) x* m))))))
>
> Why not just:
>
>        ((_ x y ...)
>         #'(max x (max y ...)))
>
> for the last case?

Yup, much better. Thanks for pointing that out! Seems obvious in hindsight. :)

I committed a refined version of this to Hoot:
https://codeberg.org/spritely/hoot/src/commit/778f22f785babcda7903d0e9094c513af3141c1b/lib/hoot/numbers.scm#L486

The blast radius of getting it wrong in Hoot is a lot less than
getting it wrong in Guile. We can battle test it in Hoot and bring it
over to Guile in the future, if that's desired.

> Also, I'm surprise that constant folding only seems to work up to 5
> parameters here:
>
>   scheme@(guile-user)> ,optimize (max 1 2 3 4 5)
>   $13 = 5
>   scheme@(guile-user)> ,optimize (max 1 2 3 4 5 6)
>   $14 = (let ((m 6)) (if (> 1 m) 1 m))
>
> There seems to be a hardcoded value in Guile preventing too much
> recursion for this optimization pas.  We can actually call ,optimize on
> the result to get down to a constant ...
>
>   scheme@(guile-user)> ,optimize (let ((m 6)) (if (> 1 m) 1 m))
>   $15 = 6
>
> Fortunatelly, it seems that compiling actually yield a constant:
>
>   scheme@(guile-user)> ,compile (max 1 2 3 4 5 6 7 8)
>   Disassembly of <unnamed function> at #xe8:
>
>      0    (instrument-entry 26)                                 at (unknown 
> file):453:9
>      2    (assert-nargs-ee/locals 1 0)    ;; 1 slot (0 args)
>      3    (make-immediate 0 34)           ;; 8                  at (unknown 
> file):453:28
>      4    (handle-interrupts)
>      5    (return-values)
>
> I guess the previous optimization is ran until a fix point is found.

I observed the same earlier. The peval pass runs at the Tree-IL layer.
It has an effort limit and it gives up eventually. That's the output
you see from ,optimize. Then, at the CPS layer, there are other
optimization passes that reduce the code to a constant, thankfully.
The compiler interface doesn't provide a good way to tune peval, but
it would be a helpful addition. In Hoot we are doing whole-program
compilation which essentially means that programs become one giant
nested blob of code, the syntax trees are significantly deeper than is
typical for separate compilation, and I've observed that cranking up
the effort limit on peval can produce faster programs (at the expense
of even longer compilation times, of course).

Thanks to Arne for nerd sniping me today. :)

- Dave

Reply via email to