【问题标题】:Why are conditionally executed instructions not present in later ARM instruction sets?为什么后来的 ARM 指令集中没有条件执行指令?
【发布时间】:2014-04-05 19:31:07
【问题描述】:

天真地,有条件执行的指令对我来说似乎是个好主意。

当我阅读更多关于 ARM(和类似 ARM)指令集(Thumb2、Unicore、AArch64)的信息时,我发现它们都缺少条件执行位。

为什么每个都缺少条件执行?

当时的条件执行是一个错误,还是后续的更改使其成为昂贵的指令位浪费?

【问题讨论】:

    标签: assembly arm computer-architecture conditional-execution


    【解决方案1】:

    一般声称现代系统具有更好的分支预测器,编译器也更先进,因此它们在指令编码空间上的成本是不合理的。

    这是来自ARMv8 Instruction Set Overview

    A64 指令集不包含谓词或 有条件的执行。 基准测试表明,现代分支 预测器工作得很好,可以预测指令的执行 没有提供足够的好处来证明其大量使用 操作码空间,以及它的高级实现成本 实现。

    它还在继续

    一组非常小的“条件数据处理”指令是 假如。这些指令是无条件执行的,但使用 条件标志作为指令的额外输入。这套有 在条件分支的情况下被证明是有益的 预测不佳,或者效率低下。

    另一篇名为Trading Conditional Execution for More Registers on ARM Processors 的论文声称:

    ...条件执行占用了宝贵的指令空间 每个条件都被编码成一个 4 位的条件代码选择器 32 位 ARM 指令。此外,只有一小部分 指令实际上在现代嵌入式中是有条件的 应用程序,条件执行甚至可能不会导致 现代嵌入式处理器的性能改进。

    【讨论】:

    • 另外,谓词在乱序执行时效果不佳:它可能需要四个个数据流源操作数(谓词,目标寄存器的当前值[needed if predicate is false] 和两个源寄存器值),必须检查可用性。 AArch64 的谓词指令只需要三个源(这更有可能得到 OoO 机制的支持[例如,支持 FMA],并且对破解成 2 源微操作更友好[就像 Alpha 21264 对 CMOV 所做的那样])。跨度>
    • 我什至找不到条件分支来注册或条件返回,也没有条件加载。
    • @Ant6n 条件加载特别棘手,因为您无法轻松地将它们拆分为多个微操作。
    【解决方案2】:

    条件执行是执行许多辅助或位旋转例程的不错选择,例如排序、列表或树操作、数字到字符串的转换、sqrt 或长除法。我们可以在路由器中添加 UART 驱动程序并提取位域。那些分支与非分支的比率很高,而且不可预测性也很高。

    然而,一旦你超越了最低级别的服务(或通过使用更高级别的语言来增加抽象级别),代码看起来就完全不同了:不同条件分支内的代码块更多地包含移动数据和调用子例行公事。在这里,那些额外的 4 位的好处迅速消失。这不仅是个人发展,而且是文化:文化编程已经从非结构化(Basic、Fortran、Assembler)发展为结构化。在不同的指令集架构中也能更好地支持不同的编程范例。

    技术上的妥协可能是将五位“cond.S”字段压缩为四个或三个最常用使用的组合。


    • 一篇关于profile guided mode selection 的论文,为流行的 SA-110 thumb/ARM 编译例程提供功耗、周期时间、代码大小和指令计数基准。一些例程在 ARM 模式下效果更好,而另一些在 Thumb 模式下效果更好。这取决于算法,最终取决于代码/编译器。

    【讨论】:

    • “这不仅是个人发展,还有文化。” - 什么?
    • @OJFord:我相信这意味着你的个人发展管道与流行的管道。 OOP 倾向于在没有内联的情况下到处乱跳。 IPA 可以对较新的语言进行相当显着的优化。我认为对于母语不是英语的人来说这是一个公平的观点。
    【解决方案3】:

    其中一个原因是因为指令编码。

    thumb 中,您不能在紧凑的 16 位空间中再挤 4 位,而寄存器操作数的 3 个高位甚至没有足够的空间,它们必须减少到只有 8 个寄存器的子集。请注意,在 thumb2 中,您有一个单独的 IT(E) 指令用于 selecting the conditions for the next 4 instructions。但是,由于上述原因,您不能将条件存储在同一条指令中。

    对于 AArch64,与 32 位 ARM 相比,寄存器的数量增加了一倍,但是对于新的 3 个高位寄存器,您没有任何剩余位。如果要使用旧编码,则必须从窄的 12 位立即数或 4 位条件“借用”。与 MIPS 等其他 RISC 架构相比,12 位已经太小了,减少数量会使一切变得更糟,因此删除条件是更好的选择。因为分支预测已经变得越来越先进,所以不会有太大问题。它还使实现乱序执行变得更容易,因为现在需要重命名和关心的事情就更少了

    【讨论】:

    • AArch64 确实包含一系列不错的谓词指令,例如比 x86 的 CMOV 更强大的条件递增和选择。在适当的情况下,它绝对仍然是为高效的无分支代码而设计的。但它们只是 ALU 指令,而不是谓词存储或谓词加载,它们可以让您从可能无效的指针无分支地执行条件加载或存储。
    • 是的,这比每条指令的条件执行要好
    【解决方案4】:

    就像 mips 中的延迟槽是一个技巧(当时),arm 中的条件执行是一个技巧(当时),就像 pc 提前两条指令一样。现在他们有多大的影响? ARM 分支预测器是否真的会产生如此大的差异,或者是他们需要在 32 位指令字中更多位的真正答案,并且像拇指一样,首先最容易摆脱的是条件位。

    做一些性能测试来看看分支预测器到底有多好或多好并不难,我在 arm11 上尝试了无条件分支,当然这是一个旧架构,但仍在广泛使用。很难让分支预测显示出任何改进,而且它在任何形式或形式上都无法与条件执行竞争。我没有在 cortex-a 家族的任何东西上重复这些经验。

    【讨论】:

    • 但在某些情况下,您可以通过某种方式对代码或数据进行按摩,以更好地进行分支预测。您可以设计更好的算法/代码。你可以帮助编译器。您可以对数据进行排序,这样预测就不会面临随机性。那么所有这些都与 ISA 核心的设计选择相比吗?我可以同情设计师。
    • 我在汇编中这样做,编译器没有参与,我给了处理器一切机会。基本上是一堆带有被测指令的nop,首先更改循环中项目的对齐方式和数量,以找到最后条件分支的最佳点和循环顶部的入口点(基于显着的性能差异在这些位置上)然后调整被测指令在循环内的位置。用条件执行重复了类似的测试。
    • 正如 Aki 所说,您不必查看太多已编译的代码即可意识到编译器通常无法利用条件执行,并且无论如何都必须分支。每条指令 4 位对于我们可能不会使用的东西来说是非常昂贵的空间。每条指令 3 位立即使三个操作数指令的可能寄存器数量增加一倍,我宁愿寄存器数量是条件执行的两倍。
    【解决方案5】:

    在旧的 ARM v4 上,条件指令仅在它们最终被执行的可能性很高,或者概率约为 50% 时,如果在一个指令中只有 2 到 4 个,则可以节省时间。排。如果它们没有被执行,那么必须通过它们来获取它们是在浪费周期,而不是使用分支来通过它们的开销。如果它们正在执行,则将获取分支但不执行。

    一个小麻烦是,在调试时,在条件指令上设置中断总是会导致该指令中断,无论条件如何(除非我的公司没有一些非常智能的调试器)。

    【讨论】:

      【解决方案6】:

      说 ARMv8 中不存在条件执行有点误导。 问题是要了解为什么您不想执行某些指令。 也许在早期的 ARM 时代,指令的实际不执行很重要(对于电源或其他什么),但今天这个特性的意义在于它允许您避免小的愚蠢跳转的分支,例如像这样的代码 a=(b>0?1:2)。这种事情比你想象的更常见 --- 从概念上讲,它是诸如 MAX/MIN 或 ABS 之类的东西(尽管对于某些 CPU,可能有执行这些特定任务的指令)。

      在 ARMv8 中,虽然没有一般的条件执行指令,但有一些指令可以执行我所描述的特定任务,即允许您避免为短暂的哑跳转而进行分支; CSEL 是最明显的例子,尽管还有其他情况(例如条件的条件设置)来处理其他常见模式(在这种情况下是 C 短路表达式评估的模式)。

      恕我直言,ARM 在这里所做的才是最有意义的。他们提取了在现代 CPU 上仍然有价值的条件执行功能(避免许多分支),同时更改了实现细节以匹配现代 CPU 的微架构。

      【讨论】:

        【解决方案7】:

        “为什么条件执行的指令不存在......” “当时的条件执行是一个错误,还是后来的更改导致了对指令位的昂贵浪费?”

        维基百科关于“Predication - Disadvantages”的文章提供了一些信息:

        "缺点
        Predication 的主要缺点是增加了编码空间。在典型的实现中,每条指令都为谓词保留一个位域,指定该指令在什么条件下应该生效。当可用内存有限时,例如在嵌入式设备上,这种空间成本可能会令人望而却步。但是,某些架构(例如 Thumb-2)能够避免此问题(见下文)。其他不利因素如下:

        • 预测通过向关键路径添加逻辑级别使硬件复杂化,并可能降低时钟速度。
        • 谓词块包括所有操作的循环,因此较短的路径可能需要更长的时间并受到惩罚。

        当路径平衡或最长路径执行最频繁时,预测最有效,但在编译时确定这样的路径非常困难,即使存在分析信息也是如此。

        ...

        在 ARM 架构中,原始 32 位指令集提供了一种称为条件执行的功能,该功能允许大多数指令由 13 个谓词中的一个来判断,这些谓词基于前一条指令设置的四个条件代码的某种组合。 ARM 的 Thumb 指令集 (1994) 放弃了条件执行以减少指令的大小,因此它们可以容纳在 16 位中,但它的继任者 Thumb-2 (2003) 通过使用除了提供之外没有任何作用的特殊指令克服了这个问题以下四个指令的谓词。 ARMv8-A (2011) 中引入的 64 位指令集将条件执行替换为条件选择指令。”。

        在“Embedded Computing: A VLIW Approach to Architecture, Compilers and Tools”中,作者 Joseph A. Fisher、Paolo Faraboschi 和 Cliff Young,第 172 页:

        "... 完全预测使硬件、ISA 和编译器复杂化。与有利于更深的管道和更快的时钟的推测不同,预测向关键路径添加逻辑级别并可能降低时钟速度。预测操作数使用珍贵的编码所有指令中的位,并且使用谓词操作数绕过操作使转发逻辑相当复杂。谓词对非循环或“面向控制”的代码的好处一直是激烈的学术和商业辩论的主题,陪审团仍然没有决定是否使用谓词的好处预测证明支持完整预测的大量硬件成本是合理的。

        完全谓词和部分谓词之间的争论更加微妙。完全谓词更具表现力,并允许编译器谓词包含任何操作组合的块。部分预测需要积极的推测并嵌入一些内在限制(例如,它不能预测包含调用操作的块)。在实现复杂性方面,如前所述,完全预测对指令编码和微体系结构的要求要高得多,而带有选择操作的部分预测非常适合大多数微体系结构和数据路径,并且对复杂性、面积或速度没有影响.

        嵌入式域中的预测
        在嵌入式领域,很难证明大量谓词寄存器的代码大小损失是合理的。完全谓词意味着“预先支付”理念,其中无论使用频率如何,都需要支付谓词机器的成本。例如,添加 6 个谓词位来处理 64 个谓词有助于将 IPF 编码推至 42 位每次操作——这种方法对于嵌入式处理器来说过于昂贵。..."。

        成本、TDP 和专利,甚至开发竞争产品所需的技术水平都会发挥作用。在这种情况下,这是从更新的编码技术中实现的成本效益,被认为需要的东西并没有真正使用,或者至少没有有效地使用(就其实施成本而言)。

        正如在另一个答案中解释的那样,ARM 手册几乎没有说明原因,比 RISC 手册所做的要少,这是 ARM 在“ARMv8 指令集概述”的第 8 页上所说的:

        "3 A64 概述
        A64 指令集提供与 AArch32 或 ARMv7 中的 A32 和 T32 指令集类似的功能。然而,正如将 32 位指令添加到 T32 指令集使一些 ARM ISA 合理化一样 行为,A64 指令集包括进一步的合理化。新指令集的亮点如下:

        • ...

        • 减少条件。更少的指令可以设置条件标志。只有条件分支和少数数据处理指令读取条件标志。没有提供条件或谓词执行,也没有等效于 T32 的 IT 指令(参见第 3.2 节)。

        ...

        3.2 条件指令
        A64 指令集不包括谓词或条件执行的概念。基准测试表明,现代分支预测器工作得很好,以至于指令的预测执行并没有提供足够的好处来证明它对操作码空间的大量使用以及它在高级实现中的实现成本。

        提供了一组非常小的“条件数据处理”指令。这些指令是无条件执行的,但使用条件标志作为指令的额外输入。该集合已被证明在条件分支预测不佳或效率低下的情况下是有益的。

        “4.3 条件代码”部分提供了更多信息,但并未说明如何做出决定。

        RISC-V ISA(最近设计的一个不相关的 ISA)的设计者解释了(http://riscv.org/spec/riscv-spec-v2.0.pdf 在第 23 页)设计处理器的一些内容:

        “条件分支被设计为包括两个寄存器之间的算术比较操作(在 PA-RISC、Xtensa 和 MIPS R6 中也是如此),而不是使用条件代码(x86、ARM、SPARC、PowerPC),或者仅比较一个寄存器与零(Alpha,MIPS)或两个寄存器仅用于相等(MIPS)。这种设计的动机是观察到组合的比较和分支指令适合常规流水线,避免额外的条件代码状态或使用临时寄存器,并减少静态代码大小和动态指令获取流量。

        ...

        条件移动和谓词指令都增加了乱序微架构的复杂性,如果谓词为假,则需要将目标架构寄存器的原始值复制到重命名的目标物理寄存器中,从而添加隐式第三个源操作数.此外,使用预测而不是分支的静态编译时决策可能会导致编译器训练集中未包含的输入的性能降低,尤其是考虑到不可预测的分支很少见,并且随着分支预测技术的改进而变得越来越少。

        我们注意到,存在各种微架构技术来动态地将不可预测的短前向分支转换为内部预测代码,以避免在分支错误预测时刷新管道的成本 [6、10、9],并且已在商业处理器 [17] 中实现。

        最简单的技术只是通过只刷新分支影子中的指令而不是整个提取流水线,或者通过使用宽指令提取或空闲指令提取槽从两侧提取指令来减少从错误预测的短前向分支中恢复的损失。更复杂的无序核心技术在分支影子中的指令上添加内部谓词,内部谓词值由分支指令写入,允许分支和后续指令以推测性和无序方式执行其他代码 [17]。

        [6] Timothy H. Heil 和 James E. Smith。选择性双路径执行。技术报告,统一 威斯康星大学 - 麦迪逊分校,1996 年 11 月。

        [9] Hyesoon Kim、Onur Mutlu、Jared Stark 和 Yale N. Patt。 Wish 分支:结合条件分支和谓词进行自适应谓词执行。在第 38 届年度 IEEE/ACM 微架构国际研讨会论文集上,MICRO 38,第 43-54 页,2005 年。

        [10] A. Klauser、T. Austin、D. Grunwald 和 B. Calder。非谓词指令集架构的动态吊床谓词。在 1998 年并行架构和编译技术国际会议论文集上,PACT '98,华盛顿特区,美国,​​1998 年。

        [17] Balaram Sinharoy, R. Kalla, WJ Starke, HQ Le, R. Cargnoni, JA Van Norstrand, BJ Ronchetti, J. Stuecheli, J. Leenstra, GL Guthrie, DQ Nguyen, B. Blaner, CF Marino 、E. Retter 和 P. 威廉姆斯。 IBM POWER7 多核服务器处理器。 IBM 研发杂志,55(3):1–1,2011 年。

        删除 64 位 ARM 上的谓词指令可以在每条指令的编码中释放 4 位,这允许向每个寄存器字段添加一位,从而使寄存器数量增加一倍。

        在我看来,在固定到 Fabric 的服务器处理器中省略 elison 功能是错误的,但需要进行权衡。这不是一个错误(拥有它,很好地实施),它很昂贵,这不是浪费(这些位很聪明,并且注意自己的事情)。条件是一个更容易/更好的选择。

        就像任何 CPU 扩展,或添加 GPU;如果你能熟练地使用你的工具,那么你很好,否则就轻装上阵。

        维基百科引述:“根据不同的基准,TSX 可以在特定工作负载中提供大约 40% 的应用程序执行速度,以及每秒 4-5 倍的数据库事务 (TPS)。”。

        它是“昂贵的”(在某些情况下),但对当前的编程风格很重要,或者更悲观地说,这是在综合基准测试中获得更高分数的一种手段。

        有一天它会像乐高一样简单,您将能够要求“它”自行组装并完成您的任务;在那之前,处理器必须支持程序员(和编译器编写者)的懒惰——因此可以在 GPU 上运行的程序很少见(但我们已经到了那里)。

        因此,移除被认为不需要或没有以具有成本效益和竞争力的方式实施的(伟大的)功能。

        因此,目前 TSX 规则;但 ARM CPU 的 Fabric 也需要花哨的线程。

        网址参考:

        AMD:https://en.wikipedia.org/wiki/Advanced_Synchronization_Facility

        英特尔:https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions

        .

        【讨论】:

          猜你喜欢
          • 2014-07-28
          • 2012-05-25
          • 1970-01-01
          • 2013-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-29
          相关资源
          最近更新 更多