具体实施方式
仅通过示例的方式来描述本发明的实施例。这些示例表示当前对于申请人来说已知的实践本发明的最佳方式,尽管这些示例并不是唯一的实现本发明的方式。本说明阐述了示例的功能以及用户构建和运行示例的步骤的顺序。然而,可以通过不同的示例而实现相同或等同的功能和顺序。
堆栈是通常用于提供临时存储区域以供程序使用的数据结构,并且堆栈被实现为后进先出(LIFO)数据结构(其可以替代地被称为先进后出FILO数据结构)从而使得严格以数据被添加到堆栈的相反次序将数据从堆栈中移除。堆栈可以被认为从堆栈原点向上或向下生长;然而,在任何情况下,由堆栈指针来标识堆栈的顶端(其是被最新添加到堆栈的元素),该堆栈指针通常指向下一个非使用的条目。堆栈指针值可以被存储在处理器内的硬件寄存器中。当向堆栈添加(或“推入”)值时,该值被写入到堆栈指针所指向的位置并且例如通过将指针增加4(即,4字节=32比特)来更新堆栈指针值(从而使得该堆栈指针指向下一个非使用条目)。当随后将数据元素从堆栈中移除(或“弹出”)时,移除数据元素并且更新堆栈指针以指向变得更小的堆栈上的下一个未使用的条目。
为了下文描述的目的,堆栈被认为向下生长,从而使得当数据被推入堆栈时堆栈指针值减少,当数据被从堆栈弹出时堆栈指针值增加。然而,将会理解的是,如果堆栈被认为向上生长(其中当数据被推入堆栈时堆栈指针值增加,而当数据被从堆栈弹出时堆栈指针值减小),则本文中所描述的方法同样可以应用。
下文描述的是用于预测堆栈指针值的方法,该方法被设计从而使得其不会做出错误预测。该方法(其存储之前的堆栈指针寄存器ID)被设置为做出正确预测或根本不做预测。这排除了当发现预测错误时不得不随后清除该预测的效果的可能性。该方法使用新的数据结构,在该数据结构中,每次更新堆栈指针都存储针对堆栈指针的物理寄存器分配(其中使用了寄存器重命名)。当更新了堆栈指针时,存储保持有更新之前的堆栈指针值的物理寄存器的标识符(ID)并且存储堆栈增大的尺寸值(其等同于堆栈指针的变化)。新的堆栈指针值(在更新之后)被存储在不同的物理寄存器中。如果堆栈增大了特定的量(例如,在进入函数时)并且随后缩小了相同的量(例如,在退出相同的函数时),堆栈指针的映射可以被更新为之前所存储的物理寄存器ID。这节省了ALU(算法逻辑单元)操作,这是由于不需要计算新的堆栈指针值(该新的、堆栈缩小后的值已经被存储在对应于所存储的寄存器ID的物理寄存器中)。
本文中所描述的方法可以是尤其有用的,并且导致客观的效率,其中主函数调用许多其它较小的函数并且因此可以节省很多ALU操作;然而,本方法并不限于仅在这样的情况下使用。
尽管参考堆栈指针并且特别是在使用寄存器重命名的处理器中描述了本方法,但是如在下文中更加详细描述的,本文中所描述的方法还可以应用于没有使用寄存器重命名以及任何可逆函数的情况。
图1示出了堆栈指针值预测的示例方法的流程图,该示例方法可以参考图2(其为堆栈200的示意图)而描述。如图2所示,堆栈200具有原点202并且为了本描述被认为是从堆栈原点202向下生长的目的。
当出现增大堆栈的指令时(块102),存储当前保持有堆栈指针值(在增大堆栈之前)的物理寄存器的寄存器ID并且存储堆栈的增大的尺寸值(块104)。寄存器ID和尺寸值可以被存储(在块104中)在新的数据结构中,该新的数据结构可以被设置为保持N对值(其中,N为设计选择)。该数据结构还可以采取堆栈的形式(即,LIFO或FILO数据结构),其中严格按照条目被添加到堆栈中的相反次序来移除这些条目,并且这些条目在本文中可以被称为“预测堆栈”以区别于图1的块102和106中的所出现的指令所指代的主堆栈(例如,如图2所示)。
在示例中,增大堆栈的指令(如在块102中所出现的)可以是函数调用(即,进入函数)的结果,并且该函数可以例如采取这样的形式:
SUB P8 P2 16
其中,P8是被分配给堆栈指针值的新的物理寄存器的ID,并且其中该新的堆栈指针值要被存储,P2是当前被分配给堆栈指针的物理寄存器的ID(并且因此保持有在向堆栈添加数据之前的堆栈指针值),并且16是堆栈尺寸的增加。
参考图2中所示的示例堆栈200,物理寄存器P2保持有对应于箭头204的堆栈指针值,而对应于箭头208的新的堆栈指针值被存储在物理寄存器P8,这使得数据(在该示例中,四个变量208中的每个由32比特宽)能够被添加到堆栈200。
如果该数据结构(或预测堆栈)原本为空,则随着上述示例指令之后,该数据结构的内容可以为:
第一栏包含寄存器ID而第二栏包括尺寸值(字节)。尽管该数据结构可以存储为16的尺寸值(其正好对应于增大堆栈的指令中的尺寸值,其在该示例中为32比特(4字节)),但是指令中的尺寸值将永远是4的倍数(并且因此尺寸值的比特的子集将是常数并且不需要被存储)。在该示例中,N=4,这是由于在该数据结构中存在四个条目的空间。将会理解的是仅以示例的方式来提供该数据结构的尺寸和格式,并且在其它示例中该数据结构可以被不同地设置而仍然保持有同样的数据对(寄存器ID和尺寸值)。
该数据结构所需要的存储空间(例如,存储器或触发器(flip-flop))的量取决于N的值以及存储寄存器ID(例如,4或6比特)和尺寸值(例如,4或6比特)所需要的比特数。在一些示例中,N=1,导致仅需要非常小量的存储空间的数据结构。然而,在如下文所述的其它示例中,N>1,例如以允许嵌套函数。
继出现增大堆栈的指令(在块102中)之后,可以出现缩小堆栈的指令(块106),缩小堆栈的指令可以例如采用这样的形式:
ADD P9 P8 16
其中P9是被分配给堆栈指针值的新的物理寄存器的ID,并且其中该新的堆栈指针值要被存储,P8是当前被分配给堆栈指针的物理寄存器的ID(并且因此保持有在从堆栈移除数据之前的堆栈指针值),并且16是堆栈尺寸的减少。
响应于检测到缩小堆栈的指令(在块106中),将该指令中的尺寸值与存储在数据结构中的尺寸值进行比较(块108)。为了当前说明的目的,将该指令中的尺寸值与该数据结构中的顶端条目中的尺寸值(即,该数据结构中最新添加的条目)进行比较。
重新参考上文所示的示例数据结构,可以看出在该示例中,尺寸值确实对应(块108中的“是”),这是由于所存储的值4对应于堆栈尺寸的变化16(由于上文所述的原因,通过将堆栈尺寸的变化除以4而给出在该示例中的数据结构中所存储的值)。响应于检测到对应或匹配(块108中的“是”),寄存器重命名表被更新以示出被分配给堆栈指针值的新的物理寄存器对应于所存储的寄存器ID(块110)(例如,上文示例中的P2),并且并不使用在缩小堆栈的指令中所标识的物理寄存器(上文示例中的P9)。因此,并不一定要执行运算以计算新的堆栈指针值(这是由于其已经被存储在数据结构中所标识的物理寄存器中,例如上文示例中的P2),这节省了ALU运算并且打破了RAW危害(其允许更大的乱序执行)。另外,在缩小堆栈指令中所标识的物理寄存器(例如,上文示例中的P9)可以用于另一个目的(例如,其可以保留在空闲寄存器列表上,其中保持有这样的列表)将来自数据结构的包含有对应的尺寸值的条目从数据结构中移除(块112),在上文示例中,这留下了空的数据结构。
在上文的示例中,缩小堆栈的指令(其被标识在块106中)包含有对应于数据结构中的顶端条目的尺寸值(块108中的“是”)。然而,如果缩小堆栈的指令为例如:
ADD P9 P8 24
则尺寸值并不对应(块108中的“否”,这是由于24/4=6并且6≠4)。在没有对应的情况下,清除数据结构中的所有条目并且以常规方式来执行缩小堆栈的指令。
如能够从上文描述中看出的,在数据结构中的条目之间执行的比较以及缩小堆栈的指令确保了仅在预测正确的情况下(即,尺寸值对应的情况下)做出预测,并且确保在其它情况下(即,尺寸值不对应的情况下)不对堆栈指针值进行预测。
在刚刚描述的示例中,将缩小堆栈的指令与数据结构中的顶端条目进行比较,然而在下文描述的其它示例中,比较还可以涉及数据结构中的其它条目。
在各个示例中,可以使用对物理寄存器的低级别控制以确保原始的物理寄存器(其在预测堆栈中被引用)并没有失效而同时在预测堆栈中被引用。一种示例方法为传递具有堆栈增大指令的边带(sideband)从而使得之后释放/使无效物理寄存器的逻辑并不释放/使无效在预测堆栈中所引用的保持有堆栈指针的物理寄存器。在另一个示例方法中,保持预测堆栈的逻辑(例如,图4中的堆栈指针值预测模块)发信号示意哪些寄存器正在使用从而使得释放/使无效逻辑并不释放/使无效这些寄存器。一旦将包含有特定寄存器ID的条目从预测堆栈中清除,物理寄存器就可以被无效/重新使用等。
由于预测堆栈中所引用的物理寄存器没有被无效,可以需要额外的物理寄存器,其中物理寄存器的最小数量对应于虚拟寄存器的总数加一,可以在预测堆栈中引用物理寄存器的最大次数(其等于N)。然而,通常处理器可以具有远多于该最小值的物理寄存器。
在上文所述的示例中,缩小堆栈的指令(块106中所出现的)跟随在增大堆栈的指令(块102中所出现的)之后而在两者之间没有添加和/或移除其它数据。然而,在一些示例中,例如对于嵌套函数,在将任何数据从堆栈中移除之前,数据可以多于一次被添加到堆栈中并且这可以在能够参考图3所描述的另一个示例中描述。
在该示例中,出现第一增大堆栈的指令(块102):
SUB P8 P2 16
所以如上文所述,存储有堆栈指针的寄存器ID(P2)以及尺寸值(16/4=4)被存储在数据结构中(在块104中):
如图3中的第一示例堆栈301所示,四个数据项被添加到堆栈(如箭头31所表明)并且将堆栈指针从对应于箭头306的原始值(存储在物理寄存器P2中)更新为对应于箭头308的新值(其存储在物理寄存器P8中)。
所出现的操作堆栈(即,增大或缩小)的下一个指令可以是例如另一个增大堆栈的指令,如由图1中的从块104到块102的虚线箭头所表明。在该示例中,增大堆栈的第二指令可以是:
SUB P4 P8 8
所以如上文所述,当前堆栈指针的寄存器ID(P8)以及尺寸值(8/4=2)被存储在数据结构中(在块104中):
该新的条目现在被认为是数据结构中的顶端条目。如图3中的第二示例堆栈302所示,两个数据项被添加到堆栈(如由箭头32所表明)并且将堆栈指针从对应于箭头308的值(存储在物理寄存器P8中)更新为对应于箭头310的新值(其存储在物理寄存器P4中)。
之后可以出现缩小堆栈的指令(在块106中):
ADD P3 P4 8
将该指令中的尺寸值(8)与数据结构中的顶端条目中的尺寸值进行比较(在块108中)并且从该示例中可以看出存在对应(块108中的“是”,由于8/4=2并且2=2)。因此存储有堆栈指针的物理寄存器的映射被更新为数据结构中的顶端条目中的寄存器ID(P8)(在块110中)并且将顶端条目从数据结构中移除(在块112中),这留下:
如图3中的第三示例堆栈303所示,将两个数据项从堆栈中移除(如由箭头33所表明),并且将堆栈指针从对应于箭头310的值(存储在物理寄存器P4中)更新为对应于箭头308的值(其之前存储在物理寄存器P8中)。
所出现的操作堆栈(即,增大或缩小)的下一个指令可以是例如另一个缩小堆栈的指令,如由图1中的从块112到块106的虚线箭头所表明。在该示例中,增大堆栈的第二指令可以是:
ADD P7 P8 16
将该指令中的尺寸值(16)与数据结构中的顶端条目中的尺寸值进行比较(在块108中)并且从该示例中可以看出存在对应(块108中的“是”,由于16/4=4并且4=4)。因此存储有堆栈指针的物理寄存器的映射被更新为数据结构中的顶端条目中的寄存器ID(P2)(在块110中)并且将顶端条目从数据结构中移除(在块112中),这留下空的数据结构。
如图3中的第四示例堆栈304所示,将四个数据项从堆栈中移除(如由箭头34所表明),并且将堆栈指针从对应于箭头308的值(存储在物理寄存器P8中)更新为对应于箭头306的值(其之前存储在物理寄存器P2中)。
在该示例中,存在多个增大堆栈的指令并且跟随着多个缩小堆栈的指令。该示例可以例如对应于嵌套函数,例如其中在指令的顺序方面:
SUB P8 P2 16
SUB P4 P8 8
ADD P3 P4 8
ADD P7 P8 16
外部指令对对应于第一函数而内部指令对对应于第二函数,该第二函数为第一函数内部的嵌套函数。
当在其它函数中存在许多嵌套函数的情况下,本文中所描述的方法仍然适用;然而,这些方法可能需要更大的N值(即,更大的数据结构深度)从而使得可以存储更多的条目而不会空间不足。在上文所述的示例中,所需的N值等于或超过2以便使得该数据结构不会溢出。
在函数调用被足够深地嵌套以使得预测堆栈溢出(例如,对于所使用的嵌套程度来说N太小)的示例中,则预测堆栈中最老的信息将会丢失(并且它们的对应物将不会被预测);然而,最新的数据将得以留存并且所做出的预测将继续为正确的。
图4是示例乱序处理器400示意图,其中可以实现本文中所描述的方法。在该示例中,处理器400为单线程处理器,然而本文中的方法还可以用应用于多线程处理器(其中每个线程都会使用单独的堆栈指针而维持单独的堆栈)。
处理器400包括提取平台(stage)402、解码和重命名平台404、重排序缓冲区406、提交平台408、一个或多个功能单元410、412,其中每个单元包括一个或多个执行流水线和缓存/存储器414。处理器400进一步包括寄存器堆(RF)416和寄存器重命名映射418,寄存器重命名映射418由解码和重命名平台404维持(或由解码和重命名平台404内的寄存器重命名模块来维持)。
提取平台402被配置为由程序计数器(PC)指示而从程序中(以程序次序)提取指令。一旦提取到指令,该指令就被提供给解码和重命名平台404,解码和重命名平台404被设置为翻译该指令并且执行寄存器重命名。特别地,每个指令可以包括寄存器写入操作;一个或多个寄存器读出操作;和/或算术运算或逻辑运算。寄存器写入操作向目的寄存器进行写入而寄存器读出操作从源寄存器进行读出。在寄存器重命名期间,用物理寄存器替代指令中提及的每个虚拟寄存器(例如,源寄存器和目的寄存器)。
对于寄存器写入操作,为所提及的虚拟寄存器(例如,目的寄存器)分配未使用的(或可用的)物理寄存器。可以将任何分配存储在寄存器重命名表418中,其中寄存器重命名表418是示出了每个虚拟寄存器与被分配给程序流中的指令的物理寄存器之间的映射的数据结构。对于寄存器读取操作,针对特定虚拟寄存器(例如,源寄存器)的正确的物理寄存器可以从由该虚拟寄存器所索引的寄存器重命名表418中的条目来确定。
上文参考图1-3所描述的方法可以在解码和重命名平台404内实现,并且例如,解码和重命名平台404可以包括执行图3中所示的以及上文所述的方法的堆栈指针值预测模块420。如上所述,该模块420(或解码和重命名平台404)维持在本文中被称为预测堆栈422的数据结构。
在指令通过解码和重命名平台404之后,该指令被插入到记录器缓冲区406(ROB)并且被派送到功能单元410、412以进行执行。指令被派送到的功能单元410、412可以基于指令的类型。重排序缓冲区406是使得指令能够被以乱序执行而顺序地提交的缓冲区。重排序缓冲区406保持有被以程序次序插入重排序缓冲区406的指令,但是可以又功能单元410、412来乱序地执行ROB 406内的指令。在一些示例中,重排序缓冲区406可以形成为环形缓冲区,该环形缓冲区具有指向ROB 406中的最老的指令的头,以及指向ROB 406中的最新的指令的尾。以程序次序将指令从重排序缓冲区406输出到提交平台408。换句话说,当指令已被执行时,将该指令从ROB 406的头输出,并且该头被增加到ROB 406中的下一个指令。从重排序缓冲区406输出的指令被提供给提交平台408,提交平台408将指令的结果提交给寄存器/存储器。
每个功能单元410、420负责指令指令并且可以被配置为执行特定类型的指令。例如,加载-存储单元412在图4中示出并且其它功能单元410可以包括整数单元、浮点单元(FPU)、数字信号处理器(DSP)/单指令多数据(SIMD)单元、或乘法累加(MAC)单元中的一个或多个。加载-存储单元412向L1缓存和除此之外的存储器读数据并且从L1缓存和除此之外的存储器写数据。在一些实例中,加载-存储单元可以计算地址并且其可以(或可以不)包含L1缓存并且执行数据/标签RAM查找。整数单元执行整数指令、FPU执行浮点指令、DSP/SIMD单元具有多个处理元件,该多个处理元件同时执行关于多个数据点的相同操作、并且MAC单元计算两个数的乘积并且将该乘积添加到加法器。功能单元内的执行流水线可以具有不同的长度和/或复杂度。例如,FPU流水线通常比整数执行流水线更长,这是因为FPU流水线一般来说执行更复杂的操作。
虽然执行从解码和重命名平台404接收到的指令,但是每个功能单元410、420向一个或多个共享寄存器堆416中的物理寄存器执行读出和写入。
处理器400还包括除了图4中所示的那些元件之外的功能元件。例如,处理器可以进一步包括分支预测器,分支预测器被配置为在已知指令要引起可能的流程变化的情况下预测程序流程将采取哪个方向。分支预测是有用的,这是由于在得知分支指令的结果之前使得能够由处理器400推测性地执行指令。当分支预测器准确地预测出程序流程时,这提改进了处理器400的性能。然而,如果分支预测器并没有正确地预测分支方向,则发生误预测,需要在程序能够执行之前来纠正该误预测。为了纠正误预测,放弃发送到ROB 406的推测性的指令,并且提取平台402开始从正确的程序分支提取指令。
将理解的是,其它处理器可以不包括图4中所示的所有功能元件(即,可以省略图4中所示的功能元件中的一个或多个),并且在一些示例中,其它处理器包括图4中未示出的额外功能元件。
除了由解码和重命名平台404所维持的预测堆栈422之外,在一些示例中,还可以存在有加载-存储单元412所维持的心的数据结构。该新的数据结构(其在本文中还可以称为堆栈指针缓存)存储堆栈指针物理寄存器ID以及实际的堆栈指针值(存储在对应的物理寄存器中)。在各个示例中,堆栈指针缓存存储最后M个堆栈指针物理寄存器ID以及对应的堆栈指针值,并且在一些实例中,M=N。
图5是由加载-存储单元412所实现的用于堆栈指针值缓存的示例方法的流程图,图5中的方法可以结合由解码和重命名平台404所实现的图1中所示的方法而使用,或者可以独立于图1中所示的方法而使用。如图5所示,当例如由解码和重命名平台404检测到堆栈指针发生变化时(块502)(其中解码和重命名平台404通知加载-存储单元412),将当前堆栈指针物理寄存器ID以及该堆栈指针的值存储在堆栈指针缓存中(块508)。将立即的是,这可以以多种不同方式而实现,例如,可以紧随堆栈指针发生变化之后而立即存储新的物理寄存器ID和值或者可以紧接在变化之前立即存储老的物理寄存器ID和值。在各个示例中,存储物理寄存器ID可以使用存储器的6比特而存储堆栈指针值可以使用32比特。
在堆栈指针缓存的大小有限的情况下,其可以被设置为存储M个数据对(其中该对包括物理寄存器ID和堆栈指针值)。在该大小有限时,在没有空间存储新的值的情况下(块504中的“是”),存储新的数据对可以需要丢弃最老的存储的值对(块506)。
当物理寄存器ID被移到“空闲寄存器列表”(例如,解码和重命名平台404)时,移除堆栈指针缓存中对应的条目(块510)。
通过存储物理寄存器ID和值,当堆栈指针接收到用于使用地址中对应的物理寄存器来进行加载/存储的指令时,加载-存储单元已经知道该堆栈指针的值,并且这消除了执行寄存器堆读取的需要(其需要寄存器堆读取端口)。通过缓存堆栈指针值,计算地址(通常是堆栈指针加上立即数偏移)而不需要读取端口是可能的。这意味着可以针对这些计算而使用有限的ALU,并且这释放了其它功能但与以用于其它操作。
可以通过将新的栏添加到堆栈指针缓存以保持偏移值来扩展图5的方法。该偏移会是距离堆栈指针的偏移(由于存储在存储器中的变量被存储在距离该堆栈指针的固定偏移处)。在这种情况下,如果用于加载/存储的地址为堆栈指针值加上偏移(例如,LD P20[P2+8]),则物理寄存器和偏移可以用于查询并且检测全部32位是否都被缓存在堆栈指针缓存中。
在上文描述的该示例中,所述比较(图1中的块108)将指令(在块106中出现)中的尺寸值与预测堆栈中的顶端条目进行比较。然而,在其它示例中,所述比较可以涉及预测堆栈中多于一个条目。例如,如果操作堆栈的两个连续指令都向堆栈添加数据:
SUB P8 P2 16
SUB P9 P8 8
这导致两个条目中的该结果被存储在预测堆栈中:
如果出现随后的缩小堆栈的指令(在块106中):
ADD P7 P9 24
则与预测堆栈中的顶端条目的比较(在块108中)不会导致发现对应(6≠2);然而,与顶端的两个条目的比较会导致对应(6=4+2)并且因此,如图6所示,比较操作(在块108中)可以涉及着眼于多于一个条目。
图6是实现比较操作(在图1的块108中)的实例方法的流程图,其中存在可以在尺寸比较中使用的条目数量的阈值T。如果缩小堆栈的指令中的尺寸(在块106中出现)仅要与预测堆栈中的顶端条目相比较,则T=1;然而,比较可以涉及预测堆栈中的多于一个条目,则T>1。如图6所示,该比较始于变量x=1并且将缩小指令中的尺寸(来自块106)与预测堆栈中的顶端条目进行比较(在块602的第一次迭代中)。对于T=1,方法如上文所述进行并且如果不存在对应,则清除堆栈中的所有条目(在块114中)。然而如果T>1,则还存在一个或多个比较的迭代,其中将缩小指令中的尺寸(来自块106)与来自堆栈中逐渐增加的数量的条目(在每次迭代中增加一个条目)的尺寸总和进行比较,直到存在对应(当方法进行到图1中的块110)、或达到阈值而未对应(当方法进行到图1中的块114)、或已使用了预测堆栈中的所有条目而未发现对应(当方法再一次到达图1中的块114)。
在比较操作(块108中)中使用预测表中的多个条目的情况下,例如如图6所示,使用在比较操作中所使用的所有条目中的最早添加的(即,最老)条目(即,x个条目中的最老的条目,该x个条目用于实现对应)来更新堆栈指针的映射,并且将用于实现对应的所有条目(即,导致块602中的“是”的所有x个条目)从预测堆栈中移除(在块112)。
还可以更新该方法以处理这样的情况:其中缩小堆栈的指令并没有完全撤销预测堆栈中的固定数量的条目的操作,如图7所示。图7为迭代方法并且可以指定迭代的最大次数。例如,如果两个连续的操作堆栈的指令都向堆栈添加数据:
SUB P8 P2 16
SUB P9 P8 8
则这导致两个条目中的该结果被存储在预测堆栈中:
如果出现随后的缩小堆栈的指令(在块106中):
ADD P7 P9 12
则与顶端条目的比较不会导致发现对应(在块108中的“否”,这是由于12/4=3并且3≠2),但是(假设还没达到迭代的最大次数,块707中的“否”)由于与值对应的尺寸大于所存储的尺寸(块701中的“是”,由于3>2),所以移除预测堆栈中的顶端条目(块703),并且缩小操作的尺寸减少2(即,减少了刚刚移除的条目的尺寸)以在该示例中给出为1的缩小的尺寸。
在本方法的第二迭代中(再次假设还未达到迭代的最大次数并且堆栈中还有更多的条目,块707中的“否”),在缩小操作的尺寸(在之前迭代的块703中所减少的,在该示例中为1)与所存储的尺寸(在该示例中为4)之间执行另一个比较(在块701中)。在该示例中,由于更新后的缩小指令的尺寸小于所存储的尺寸(块701中的“否”,由于1<4),所以将允许缩小指令正常运行(从而使得在该特定示例中,计算新的堆栈指针并且存储在P7中),并且新的顶端条目中的尺寸将减少缩小指令的尺寸(块705,例如在该示例中缩小1,这是由于所移除的条目包含值2并且3-2=1)以给出为3的条目尺寸。这导致一个条目被留在预测堆栈:
如果出现随后的缩小堆栈的指令(在块106中):
ADD P6 P7 12
则与顶对条目的比较现在会导致发现对应(由于12/4=3并且3=3)。所以,存储有堆栈指针的物理寄存器的映射被更新(块110中)为数据结构中的顶端条目中的寄存器ID(P2)并且将该顶端条目从数据结构中移除(在块112),留下空的数据结构。该缩小堆栈的指令会不需要执行。
在处理器动态地分配存储器的情境中,可以存在作为动态分配的结果而将数据添加到堆栈(导致堆栈指针中发生变化),以及作为函数调用的结果而将数据添加到堆栈(如上所述)并且因此上文参考图1所描述的方法可以被修改并且在图8和图9中示出了两个变型。
在第一个示例变型中,如图8所示,条目仍然被存储在预测堆栈中,其为存储器的动态分配的结果(而非函数调用),该存储器的动态分配在预测堆栈中被标记出(在块104中)。这种指令的示例(例如,如块102中所出现的)为SUB SP SP R5,而非SUB SP SP 8。
在示例中,如果存在将数据添加到堆栈(其作为函数调用的结果)的两个指令,并且其后跟随着将数据添加到堆栈(其作为存储器的动态分配的结果)的一个或多个指令,则预测堆栈可以看起来像是这样:
在该示例中,仅指令序列(其将数据添加到堆栈并且其为存储器的动态分配的结果)中的第一个被存储在预测堆栈中(在块104)。
如果随后出现缩小堆栈的指令(在块106中),例如:
ADD P7 P9 16
则尺寸的比较(在块807中)关注在具有与指令中所标识的相同的堆栈指针寄存器ID(例如,本例中的P9)的一个条目之前的条目。在该示例中,存在对应(块“807”中的“是”,由于在包含有P9的条目之前的条目为P8,4,16/4=4并且4=4)并且因此,将堆栈指针的映射更新为寄存器ID P8(在块110中)。然后,将从预测堆栈的顶端处直到并且包括在具有与指令中所标识的相同的堆栈指针寄存器ID(例如,上例中的P8)的一个条目之前的所有条目移除(块811)。在上例中,则该预测堆栈会仅包含单个条目:
第二示例变型,如图9所示,涉及检测与帧指针有关的指令(其表明存储器分配是动态执行的)。在存储器被动态地分配的情况下,可以使用堆栈指针和帧指针两者。不同于当数据被添加堆栈到或从堆栈移除时值发生变化(并且因此在当程序在存储器被动态分配的情况下运行时可以发生变化)的堆栈指针,帧指针可以用于指向堆栈中的固定位置(在程序运行期间,如果动态存储器分配需要堆栈指针)。该固定位置可以是例如如果在函数内并不使用动态位置则堆栈指针将会指向的位置(即,在最后静态分配的存储器区段之后的存储器位置)。
如图9所示,在第二示例变型中,以与参考图所描述的相同方式将条目添加到预测堆栈(在块102和104);然而,如果出现基于堆栈指针值而设置帧指针的指令(块905),例如:
MOV FP SP
其可以用被分配给SP的物理寄存器(本实例中的P9)来更新针对FP的重命名映射条目,则在预测堆栈中添加新的条目(块906)。在示例中,在检测到与帧指针有关的指令之前的预测堆栈可包括:
随着检测到基于堆栈指针而设置帧指针的指令(在块905),该预测堆栈可以包括:
其中,该预测堆栈中的顶端条目包括被分配给堆栈指针的当前物理寄存器(本示例中的P9)以及为零的尺寸值(由于堆栈还没有增大)。该指令MOVFP SP可以被认为是很快将会有动态分配的指示(而非尝试检测动态分配自身)。
本方法接着以与参考图8所描述的类似的方式进行。例如,如果存在增大堆栈的多个后续指令,则预测堆栈可以包括:
P2 |
4 |
P8 |
4 |
P9 |
0 |
P10 |
4 |
P11 |
4 |
预测堆栈中的最新的条目可以来自静态分配,该静态分配来自嵌套函数内。可以以通常的方式来移除这些条目,留下如下的预测堆栈:
这时,如果出现将堆栈从P9中的值缩小4的缩小指令,例如:
ADD P12 P9 16
则可以将堆栈指针重映射到P8(由于P9是完成SUB P9 P8 16之后的SP)、可以放弃该指令、并且可以从预测堆栈中移除至少2个条目(在块811中)以留下仅一个条目。
将会理解的是,尽管图8-9的描述仅指代与预测堆栈中的单个条目的比较,但是这些变型可以与参考图6-7所描述的变型相结合,例如从而使得可以将缩小堆栈的指令中的尺寸(如块106中所出现的)与预测堆栈中的多于一个条目进行比较(在块108或807中)。
在图8和图9的进一步变型中,可以使用标记(在预测堆栈中的每个条目中)以表明是否作为函数调用的结果而添加了指令。在这样的示例中,修改块811从而使得在预测堆栈顶端处的所有被标记的条目被移除。
图10为当检测到中断(块1002)时所使用的方法的流程图,并且本方法可以结合之前描述的任何方法而使用。当发生中断时,堆栈指针被存储在存储器中并且接着在退出中断时恢复。由于中断可以已经操作了堆栈指针的值,所以存储在堆栈指针中的条目可以不再有效并且因此清除预测堆栈以移除所有条目(块1004)。这可以扩展到包括检测到从存储器加载了堆栈指针值的任何情况。
上文描述的方法关于使用寄存器重命名的处理器。在不适用寄存器重命名的情况下该方法也是可应用的;然而在这样的应用中,预测堆栈存储当前堆栈指针值(在堆栈增大之前的堆栈指针值)以及堆栈增大的尺寸值(在块1104中),如图11所示。这比使用寄存器ID效率更低,这是因为堆栈增大需要更多的存储空间(例如,其可以为32比特的值)。该方法接着如图1所示并且如上文所述而进行,除了不更新堆栈指针的映射(在块110中),如果在缩小指令的尺寸(在块110中出现)与预测堆栈中所存储的条目(或多个条目)之间的存在对应(块108中的“是”),则堆栈指针其自身更新为所存储的值(块1110)。将会理解的是,上文参考图1所描述的变型(例如,如图6-9所示)也可以应用于图11中所示的方法。
在上例中,存储有堆栈指针寄存器ID和堆栈的增大的尺寸值的数据结构被描述为FILO。然而将会理解,其可以替换地使用缓存结构而实现。
尽管上文所述的方法关于对堆栈指针值的预测,但是所描述的技术还可以用于检测被预测为可逆的任何指令,并且如果随后出现该指令的逆转,则可以使用老的物理寄存器。在这样的示例中,所使用的数据结构可以使用缓存结构而非FILO以存储关于可能可逆的所有函数的数据。由于针对可能可逆的每个操作都存储了数据(例如,物理寄存器ID和常数值,尽管根据特定的操作还可以有其它字段),而不是仅有在随后被逆转的指令,所以有必要着眼于数据结构中的非最新存储的条目。
本文中描述的方法可以结合具有与C类似的调用惯例的编程语言(这覆盖了大多数语言)而使用,其中这样的编程语言在存储器中使用堆栈以用于在程序范围的该部分内进行存储。可以修改本文中的方法以供结合其它语言使用。
本文中所使用的术语“处理器”和“计算机”指代具有处理能力从而使得其能够执行指令的任何设备、或其部分。术语“处理器”可以例如包括中央处理单元(CPU)、图形处理单元(GPU或VPU)、物理处理单元(PPU)、数字信号处理器(DSP)、通用处理器(例如,通用GPU)、微处理器、被设计为加速任务的CPU外部的任何处理单元等。本领域技术人员将意识到这样的处理能力被包括在许多不同的设备中并且因此术语“计算机”包括机顶盒、媒体播放机、数字无线电设备、PC、服务器、移动电话、个人数字助理和许多其它设备。
本领域技术人员将认识到,所利用的用于存储程序指令的存储设备可以跨网络分布。例如,远程计算机可以存储被描述为软件的过程的示例。本地或终端计算机可以访问远程计算机并且下载该软件的一部分或全部以运行该程序。或者,本地计算机可以根据需要而下载软件的一些部分、或在本地终端处执行一些软件指令并在远程计算机(或计算机网络)处执行一些软件指令。本领域技术人员还将意识到通过利用本领域技术人员已知的传统技术,可以由专用电路(例如,DSP、可编程逻辑阵列等)来执行软件指令的一部分。
存储有用于实现所公开的方面的机器可执行数据的存储器可以是非瞬时性介质。非瞬时性介质可以是易失性或非易失性的。易失性非瞬时介质的示例包括基于半导体的存储器,例如SRAM或DRAM。可以用于实现非易失性存储器的技术的示例包括光和磁存储器技术、闪速存储器、相变存储器、电阻式RAM。
对“逻辑”的特别引用指代执行功能或多个功能的结构。逻辑的示例包括被设计为执行那些功能的电路。例如,这样的电路可以包括晶体管和/或在制造过程方面可行的其它硬件元件。这样的晶体管和/或其它元件可以用于形成实现和/或包含存储器的电路或结构,通过示例的方式,该存储器可以是例如,寄存器、触发器、或锁存器、逻辑运算器(例如,布尔运算)、数学运算器(例如,加法器、乘法器、或移位寄存器)、以及互连。这样的元件可以被提供为定制电路或标准单元库、宏、或其它级别的抽象。可以在特定的设置中将这样的元件互连。逻辑可以包括为固定函数的电路而电路可以被编程以执行方法或多个方法;可以从固件或软件更新或控制机制来提供这样的编程。所标识的用于执行一个功能的逻辑还可以包括实现组成性函数或子过程的逻辑。在示例中,硬件逻辑具有实现固定函数操作、或运算、状态机或过程的电路。
如将对本领域技术人员显而易见的是,本文中所给出的任何范围或设备值可以被扩展或改变而不会失去所寻求的效果。
将会理解上文所述的益处和优点可以关于一个实施例或可以关于几个实施例。实施例并不限于解决所陈述的问题中的任意或全部问题的那些实施例或者具有所陈述的益处和优点中的任意或全部优点的那些实施例。
对“一个”的任意引用指代那些物品中的一个或多个。本文中使用“包含”以意味着包括所标识的方法块或元件,但是这样的块或元件并不包括排他性列表并且装置可以包含额外的块或元件并且方法可以包含额外的操作或元件。此外,块、元件和操作它们自身并不是隐含地封闭的。
可以以任何合适的次序来执行本文中所描述的方法的步骤,或在合适的情况下同时来执行本文中所描述的方法的步骤。图中的框之间的箭头表示方法步骤的一个示例顺序但是并不是要排除其它顺序或并行执行多个步骤。另外,可以从任意方法中删除单独的块而不背离本文中所描述的主题的精神和范围。上述的任何示例的方面可以与所描述的任何其它示例的方面相结合以形成另外的示例而不失去所寻求的效果。在示出了由箭头来连接图的元件的情况下,将会理解这些箭头仅表示元件之间的一个示例通信流(包括数据和控制消息)。元件之间的流可以在任一方向或两个方向。
将理解的是,仅通过示例的方式而给出对优选实施例的上述描述并且可以由本领域技术人员进行各种修改。尽管上文使用一定程度的特定性或参考一个或多个单独的实施例而描述了各个实施例,本领域技术人员能够对所公开的实施例进行多种变化而不背离本发明的精神或范围。