• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. Unexpected behavior with optimizeTailCall

Stats

  • Replies 2
  • Subscribers 142
  • Views 56
  • Members are here 0

Unexpected behavior with optimizeTailCall

Aurel B
Aurel B 10 hours ago
;; Below functions are used to implement left `fold` one.
;; The goal is to make sure tail-call optimization is enabled during the recursion and reverted properly afterwards.
;; 
;; See reference : Wikipedia - Fold_(higher-order_function)"

;; I made several examples but I am surprised about the results...

(inScheme
(let ()

  ;; -------------------------------------------------------
  ;; Recursive helper
  ;; -------------------------------------------------------

  (defun rec ( function init l )
    "Apply FUNCTION to INIT and the head of L.
The result of this call is used as init and applied recursively to the tail of L"
    (if l
        (rec function (funcall function init (car l)) (cdr l))
      init
      ))

  ;; -------------------------------------------------------
  ;; Safe Revert (using `errset` or `unwindProtect`)
  ;; -------------------------------------------------------

  (defglobalfun foldl1_unwind_progn ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           )
      (unwindProtect
        (progn (sstatus optimizeTailCall t) (rec function (car l) (cdr l)))
        (sstatus optimizeTailCall tail_call_opt)
        )
      ))

  (defglobalfun foldl1_unwind ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           )
      (sstatus optimizeTailCall t)
      (unwindProtect
        (rec function (car l) (cdr l))
        (sstatus optimizeTailCall tail_call_opt)
        )
      ))

  (defglobalfun foldl1_unwind_nil ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           )
      (sstatus optimizeTailCall t)
      (unwindProtect
        ;; Setting it to nil here does not seem to matter
        (progn (sstatus optimizeTailCall nil) (rec function (car l) (cdr l)))
        (sstatus optimizeTailCall tail_call_opt)
        )
      ))

  (defglobalfun foldl1_errset ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           res )
      (sstatus optimizeTailCall t)
      (setq res (errset (rec function (car l) (cdr l))))
      (sstatus optimizeTailCall tail_call_opt)
      (if res (car res) (error "foldl1_errset - error occured: %N" errset.errset))
      ))

  ;; -------------------------------------------------------
  ;; Unsafe Revert
  ;; -------------------------------------------------------

  (defglobalfun foldl1_let ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           res )
      (sstatus optimizeTailCall t)
      (setq res (rec function (car l) (cdr l)))
      (sstatus optimizeTailCall tail_call_opt)
      res))

  (defglobalfun foldl1_prog1 ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (let ( ( tail_call_opt (status optimizeTailCall) )
           )
      (sstatus optimizeTailCall t)
      (prog1 (rec function (car l) (cdr l))) (sstatus optimizeTailCall tail_call_opt)
      ))

  (defglobalfun foldl1_putpropqq ( function l )
    "Left Fold: Apply combination FUNCTION to all elments of L starting from the left."
    (setf foldl1_putpropqq.tail_call_opt (status optimizeTailCall))
    (sstatus optimizeTailCall t)
    (prog1 (rec function (car l) (cdr l)) (sstatus optimizeTailCall foldl1_putpropqq.tail_call_opt))
    )

  ));scheme closure

;; -------------------------------------------------------
;; Testing done in the CIW
;; -------------------------------------------------------

/*
(tracef rec)
(foreach fun '( foldl1_unwind_progn foldl1_unwind foldl1_errset foldl1_let foldl1_prog1 foldl1_putpropqq)
  (println fun)
  (sstatus optimizeTailCall nil)
  (println (funcall fun 'times (list 1 2 3 4)))
  )
;*/

;; The only functions where tail-call optimization is actually working are:
;; foldl1_unwind foldl1_unwind_nil foldl1_errset

;; It feels like wrapping the call inside `errset` or `unwindProtect`
;; enables the switch but when using it in the same environment it is not yet taken in account.

;; Is this normal?
;; Am I missing something?

;; Thanks
;; Aurel

  • Cancel
  • Sign in to reply
  • Andrew Beckett
    Andrew Beckett 3 hours ago

    I'm not sure it works properly if you set it on the fly in the middle of a function. If you call (sstatus optimizeTailCall t) before calling your test code (without turning it off inside the loop), it all works OK.

    It's not well documented exactly when exactly it has an effect. I'll see if I can find out more. This is probably better as a support question than on the forums (it will probably end up with me anyway), but I'll see what I can find out in the meantime.

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Aurel B
    Aurel B 3 hours ago in reply to Andrew Beckett

    Yes, I was not sure if setting it on the fly is a good practice. (I was surprised that it works specifically in some cases though)

    Although in some of my code it is a requirement, otherwise I would have to rewrite the code and make it iterative instead of recursive...

    Thanks for your answer Slight smile 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information