一般論として、例えばこんなコードがあったとして、

(defun my-for-each (fn lst)
 (when lst
  (funcall fn (car lst))
  (my-for-each fn (cdr lst))))

fn に my-for-each を定義する関数が渡されることがある。
例えば、

(my-for-each
 (lambda (a)
  (print a)
  (defun my-for-each (fn lst) nil))
 '(a b c))

このような場合、ループせずに一回目の呼び出しで終了しなきゃならない。
つまり my-for-each は末尾再帰ではなく、末尾呼出と呼ぶべきもの。
で、末尾呼出はただのジャンプ命令に変換しちゃいけない。
毎回同じ場所にジャンプできるとは限らないし、
arity の違う関数に束縛されてるかもしれないから。

一応 Common Lisp では
「関数fの呼び出し中にfの束縛が変更されないと仮定してよい」
というような規則があるので、
コンパイラによってはループに変換するかもしれない。
でもそれはコンパイラの方針によるのであって、
「賢いコンパイラなら」というのは誤り。
動的なコード変更を重視する処理系なら、このような仮定はしない。

まあ、色々あって、Common Lisp では再帰とループは使い分けるのが普通だと思う。