Language agnostic 递归处理器或编程语言/编译器或两者的函数的能力?

Language agnostic 递归处理器或编程语言/编译器或两者的函数的能力?,language-agnostic,recursion,processor,Language Agnostic,Recursion,Processor,递归调用函数的能力是处理器或编程语言/编译器固有的能力。也许,两者都需要元素来支持递归 我一直认为递归调用函数的能力完全是在编程语言中实现的,以及它如何安排运行时堆栈,直到何时何地返回。我的假设正确吗?或者处理器有允许递归的特定逻辑吗?处理器只是在代码告诉它的地方跳转。递归绝对是一种语言功能 它也是一个编译器函数,因为编译器必须实现该语言。但是如果没有,我们会认为它坏了。 最后,操作的负担当然由处理器承担:它必须将上下文和变量推送到堆栈帧上,跳转到例程的入口点,执行指令,返回。。。你知道,处理器

递归调用函数的能力是处理器或编程语言/编译器固有的能力。也许,两者都需要元素来支持递归


我一直认为递归调用函数的能力完全是在编程语言中实现的,以及它如何安排运行时堆栈,直到何时何地返回。我的假设正确吗?或者处理器有允许递归的特定逻辑吗?

处理器只是在代码告诉它的地方跳转。递归绝对是一种语言功能

它也是一个编译器函数,因为编译器必须实现该语言。但是如果没有,我们会认为它坏了。 最后,操作的负担当然由处理器承担:它必须将上下文和变量推送到堆栈帧上,跳转到例程的入口点,执行指令,返回。。。你知道,处理器所做的事情。

语言


您甚至不总是需要堆栈来递归。有关不需要堆栈的递归类型的示例,请参阅。

所有现代处理器都能够递归,因为它们具有基于堆栈的函数调用和返回指令


早期的计算机经历了一段非常艰难的时期。例如,IBM360对代码进行了布局,使函数的返回值和局部变量与代码并排。递归调用会破坏上一个调用的值。

正如Carl Smotricz所说,CPU只是遵循指令流中出现的分支指令。我们倾向于调用递归只不过是普通的函数调用,其中被调用的函数恰好与当前执行的函数相同,这在较高的层次上有一些非常有趣的效果。

即使在具有堆栈寻址模式的现代处理器上,您有时仍然希望在堆上分配调用帧,就像在OS/360这样的系统上所做的那样。例如,在Scheme中,可以捕获一个延续(基本上是一个调用帧加上活动局部变量绑定的表示)并保持它。如果您在函数内的全局变量中捕获一个continuation,然后从该函数返回,则无法清除活动调用帧。一旦不再有对它的任何引用,垃圾收集器将在某个时候清理它,但与此同时,如果调用帧是在堆栈上分配的,则需要将它复制到其他地方(堆)。这与尾部调用优化有点相反,在尾部调用优化中,您可以证明不需要为递归调用分配堆栈帧。对于延续,您需要分配调用帧并使其及其关联的环境无限期地挂起。

堆栈和递归调用不需要明确的硬件支持,但处理器确实需要某些功能。我认为在基于寄存器的机器上,以下内容就足够了:

  • 您可以将存储值写入程序计数器,例如使用跳转指令。这是需要返回的
  • 您可以使用一个寄存器来存储自己的堆栈指针
  • 中断不会把事情搞得太糟(尽管在中断上下文中可能没有堆栈,即使有堆栈,您也可以接受)
引导代码必须分配一个内存区域作为堆栈使用,然后就可以开始了


我想有些处理器不提供这种功能。大多数处理器都明确支持堆栈指针和链接指针,以及有助于标准调用约定的指令。但是您可以发明并实现自己的调用约定。

一些OS/360语言支持递归,特别是PL/I、Algol和LISP。这不是硬件,而是语言实现。考虑在8080 /Z80 .@ Load Mead上处理堆栈变量是多么困难:尽管有可能支持IBM 360或370上的递归,但硬件在这方面还是相当有限的。我不知道这是否是真的,但很长一段时间以来,当你对一个进行递归时,它从堆中分配堆栈帧。早期的Cray也没有对堆栈的任何硬件支持……您假设的是基于堆栈的CPU体系结构。在无堆栈CPU上,递归函数更难实现。但是基于堆栈的CPU处理递归就像处理任何其他函数调用一样。否则,是的,堆栈必须由程序本身模拟。一些可能被视为处理器的芯片对于递归来说不够灵活。您需要一个足够灵活的内存模型来实现堆栈和用于返回的间接跳转。例如,较旧的GPU无法递归。感谢大家给出的好答案!