X86 处理器如何处理条件?

X86 处理器如何处理条件?,x86,conditional-statements,X86,Conditional Statements,那么,超低级IF()看起来像什么,x86处理器如何处理它?处理器有“分支IF”指令,当满足某个条件时,它会分支,否则它会继续执行下一条指令 所以 将成为 load A into register 0 if the zero flag is set (ie, register 0 contains 0x00) then jump to endcondition) dosomething endcondition: 更复杂的条件(if(A | | B&&C))变成一系列指令,使寄存器处于0或非零状

那么,超低级IF()看起来像什么,x86处理器如何处理它?

处理器有“分支IF”指令,当满足某个条件时,它会分支,否则它会继续执行下一条指令

所以

将成为

load A into register 0
if the zero flag is set (ie, register 0 contains 0x00) then jump to endcondition)
dosomething
endcondition:
更复杂的条件(
if(A | | B&&C)
)变成一系列指令,使寄存器处于0或非零状态,因此branchif指令可以根据条件标志跳转或不跳转

有许多条件标志(零、进位、负、溢出等),一些branchif指令也在更复杂的条件下运行(即,它实际上可能检查一个寄存器是否等于另一个寄存器,而不是简单地查看标志)。每种体系结构都是不同的,都会进行折衷,因此指令集是完整的,但同时也是快速和紧凑的

正如moocha在评论中指出的那样,某些体系结构允许您将条件应用于某些、许多甚至所有指令,因此您可能不仅有“branch if”指令,还有“and if”、“add if”、“move if”等指令

一旦您进入流水线、无序执行、缓存、微码和所有其他高级主题,x86就非常、非常、非常复杂,超出了这个简单的解释。在大多数情况下,上述解释就足够了。但是,如果您正在编写一个手工制作的非常紧密的算法,那么您必须考虑这些因素,以获得最大的性能和吞吐量

但这是另一个问题的主题


-亚当基本上,你有一束电子在你的CPU内的不同原子之间传递。由于CPU中硅原子的结构,电子遵循某些路径,这决定了计算机将遵循的执行分支

编辑:看来我应该解释得不那么含糊一点。恕我直言,我的专业是计算机科学,而不是电气工程,所以我对这些东西的理解不是很深刻:

你的CPU是由一种叫做“半导体”的材料制成的,通常是硅。半导体的一个伟大之处是,通过“掺杂”,或使用在材料上形成负或正“电荷载流子”区域的杂质,可以很容易地改变它们的电气特性。这些区域连接在一起的线路被称为“交叉点”,电流从一个方向流过这些交叉点要比从另一个方向流过容易得多。这种特性被用来制造二极管和晶体管,二极管只允许电流沿一个方向流动,晶体管可以被认为是微小的开关,允许一个电流控制另一个电流。这些晶体管和二极管以多种方式组合在一起,以创建CPU的逻辑门


CPU内部的许多逻辑门专用于作为“控制单元”,负责检索和解码指令,告诉CPU的其余部分该做什么,并最终获得下一条指令。在x86上,控制单元实际上正在运行“微码”,它告诉控制单元如何处理分支、流水线等。要了解x86 ISA是如何在特定的微体系结构上实现的,您确实需要非常具体地了解特定的处理器系列。

这是一条分支指令,取决于特定的机器体系结构。它指出了如何设置内存位置或寄存器来测试特定的低级别条件,如分支不相等或分支不为零该测试然后跳转(如果条件失败,则不跳)到内存的另一部分。显然,如果您有一个复杂的条件,它可能需要评估许多不同的条件,并且可能涉及多个分支指令。

通常CPU有一个所谓的指令寄存器,它保存下一步要执行的当前机器语言操作码的内存地址。。。和许多其他寄存器来保存数据

通常,cpu在执行指令寄存器中的每个操作码后,只需将其递增1,即可移动到内存中的下一个位置,该位置应在编译程序应用程序中具有下一个操作码

一个操作码(实际上可能有几个)允许cpu通过“比较”其他两个cpu寄存器中的值来“分支”,如果一个大于另一个,则将一个内存地址复制到指令寄存器中,而如果另一个最大,则复制第二个,将不同的内存地址放入指令寄存器


这大概是“低”水平,因为它可以把它与继电器和晶体管无关

使用C编译器的输出(使用gcc上的
-s
开关)来查看编译时给定的C代码片段将生成什么输出是相当容易的。但在玩具程序上使用优化时要小心。如果你不小心的话,乐观主义者通常会优化掉那些总是以某种方式出现的条件句(请参阅以获得更详细的解释)

例如,一个普通的C程序:

#include <stdio.h>

int main (int argc, char **argv) {
    int ii = 10;
    int jj = 20;
    if (jj > ii) {
        puts ("jj > ii \n");
    }
    return 0;
}
对于正在发生的事情的简要剖析:

  • 第一部分(
    .rodata
    )用字符串“
    jj>ii\n
    ”声明一个常量

  • 第二部分是初始化堆栈上
    ii
    jj
    变量的内容

  • 来自
    cmpl-8(%ebp),%eax
    的位正在进行实际比较;
    jle
    指令跳过对“
    put
    ”的调用,这实际上是“
    if
    ”语句的逻辑颠倒了

  • 在标签“
    .L2
    ”之后,系统将整理堆栈顶部并从调用返回


这里有一个关于这些结构如何在x86 architec上编译的非常好的概述
#include <stdio.h>

int main (int argc, char **argv) {
    int ii = 10;
    int jj = 20;
    if (jj > ii) {
        puts ("jj > ii \n");
    }
    return 0;
}
    .file   "foo.c"
    .section    .rodata
.LC0:
    .string "jj > ii \n"
    .text
.globl main
    .type   main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %ecx
    subl    $20, %esp
    movl    $10, -8(%ebp)
    movl    $20, -12(%ebp)
    movl    -12(%ebp), %eax
    cmpl    -8(%ebp), %eax
    jle .L2
    movl    $.LC0, (%esp)
    call    puts
.L2:
    movl    $0, %eax
    addl    $20, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.3.2-1ubuntu12) 4.3.2"
    .section    .note.GNU-stack,"",@progbits
if (a==0) {
    b= 1;
}
cmp    0, eax
cmovzl ebx, 1
int x;

if ( y < 5 )
  x = 5;
else
  x = y;
y -= 5
int r = y < 0; // r is 1 if y < 5, 0 otherwise
r -= 1         // r is 0x00000000 if y < 5, 0xffffffff otherwise
x = y & r      // x is 0 if y < 5, (y-5) otherwise 
x += 5;        // x is 5 if y < 5, y otherwise