从程序员的角度来看,"新"处理器中的"新"是什么

Vai*_*ari 0 x86 x86-64 processor cpu-architecture micro-architecture

我最近对理解低级计算很感兴趣.据我所知,今天广泛使用的计算机遵循x86/x86-64架构.

据我所知,架构,更具体地说,指令集架构(ISA)是程序员能够向CPU发出的指令集.

第一个问题,ISA是不断发展还是保持不变?

我认为它不断发展(意味着新指令不断被添加/先前的指令被修改?)但是旧的处理器如何能够执行用新指令编写的代码?(它不知道新的指令,但应该能够执行代码,因为它具有x86架构).编译器是处理这个东西还是处理器?基本上,相同的指令集如何能够在所有处理器上运行,无论是旧的还是新的?

最后,除了微体系结构,这不是程序员的关注(如果我错了,请纠正我),程序员在处理新处理器时会看到哪些变化?由于微体系结构的变化,旧的指令可能因为有效的实现而快速运行.但是,是否引入了新的指令以允许以前无法完成的操作?或者之前可以用一堆指令做什么,但现在可以通过硬件的变化来完成一个?新的寄存器?还要别的吗?

它是否完成了 - 如果处理器支持这个新的强大指令以加快执行速度,那么使用新指令,否则回退到较慢的旧指令.如果是,谁实现了这个if - else子句?编译器?如果不是,那会发生什么?

Pet*_*des 6

像大多数ISA一样,x86正在不断发展.

一些国际检索单位通过重新定义现有的操作码(例如MIPS64r6这样做)来打破后退,但这种情况有点罕见.例如,MIPS32r6/MIPS64r6就是一个例子:https://en.wikipedia.org/wiki/MIPS_architecture#MIPS32/MIPS64_Release_6 重新定义了几种编码,并删除了一些指令.

x86 从未打破过倒计时:Ryzen或Skylake-X仍然可以启动并运行在8086上运行的机器代码.这是x86 CPU意味着什么:参见x86的开始:Intel 8080 vs Intel 8086?.(我们只讨论机器代码,但是如果你在传统BIOS模式下启动PC而不是UEFI,即使I/O设备也会模拟,因此像早期DOS这样早期8086 PC OS可能实际上是本机运行的.)

英特尔和AMD认为这样的极端情况是,在当前CPU的16位和32位模式下仍然支持像SALC 这样的未记录的 8086指令(类似sbb al,al但没有更新FLAGS),耗尽了宝贵的操作码编码空间,可以用于更短的编码新的指示.

但使用新insn的SW仅适用于新硬件.新软件将在当前和未来的硬件和旧硬件上运行,因为它选择与之兼容.(例如,在32位代码中,您可能会避免使用cmovPentium Pro新增的其他指令,因此您的代码可以在P5(i586)Pentium/PMMX上运行.)

x86-64设置一个包含SSE2和PPro指令的新基线cmov.幸运的是,64位代码不必担心与没有这些东西的旧CPU竞争,x86-64需要它们.

包括AVX2,FMA和BMI2(例如Haswell)的新基线将非常好.BMI1/BMI2尤其是最有用的,如果你的编译器可以在您的代码在任何地方使用它们,以便更有效的变量数移位指令等等,不只是一对夫妇的热循环就像SIMD指令.但英特尔仍在销售没有BMI2的新CPU(例如Penla/Celeron版本的Skylake/Coffee Lake).

如果不是,那会发生什么?

CPU不支持的指令通常会出现#UD(UnDefined)错误.在类Unix操作系统上,您的进程将收到SIGILL(非法指令信号).

制作一个利用新指令但不会在旧CPU上触发非法指令错误的二进制文件的唯一方法是进行运行时CPU检测和动态调度.有些编译器可以帮到你.

新指令可能具有(在旧CPU上)看起来像是不同指令的冗余前缀的编码.例如lzcnt,在不支持它的CPU上将解码为rep bsr,只运行bsr.并给出了不同的结果lzcnt!

(英特尔的文档明确指出,未来的CPU不能保证以与当前CPU相同的方式解码具有无意义前缀的指令.这使得他们有空间以这种方式进行ISA扩展.)

有时,旧CPU上无意义的REP前缀的静默忽略对ISA扩展很有用.例如pauserep nop.它在旧CPU上无害地解码非常有用,允许它在没有检查的情况下放置在旋转循环中.类似地,硬件锁定椭圆(事务存储器)解码为仍然在旧CPU上工作的代码,实际上执行原子操作而不是开始事务.


另见:https://www.agner.org/optimize/blog/read.php?i = 25停止指令集战争,由Agner Fog提供.英特尔的一些历史拧过AMD通过不释放为即将到来的ISA扩展的细节,所以AMD最终发展自己的不兼容的,并采取更多年增加了一个新的扩展自己的CPU的支持.(例如,在Bulldozer之前的AMD CPU上没有SSSE3,这意味着即使是需要新计算机的游戏也不需要它作为基线多年.)


但是,是否引入了新的指令以允许以前无法完成的操作?

是的,SIMD是最重要的例子之一.MMX,然后是SSE/SSE2,然后是SSE4.x. 然后AVX为两倍宽的矢量.并行处理16或32字节数据的整个向量可以为类似strlenmemcmp相对于一次一个字节的循环提供巨大的加速.对很多数组的东西也非常有帮助.

AVX2什么是基于面具打包左边最有效的方法?是一个有趣的新指令集启用新技巧的例子.例如AVX512内置此操作,而AVX2 + BMI2允许使用pdep/ pext以前无法实现的技巧.

SSSE3 pshufb是第一个可变控制shuffle指令,从查找表加载shuffle-control允许以前不可能有效的事情.例如,从字符串中获取IPv4地址的最快方法.

如何使用SIMD实现atoi?还显示了一些使用x86 pmaddubsw/ pmaddwd整数乘法+水平加法指令可以做的漂亮的事情,乘以十进制的地方值.


8086之后添加的新指令的早期历史记录在旧版本的NASM手册中很好地记录在附录中.本附录的当前版本删除了每条指令的文本描述,以便为SIMD指令腾出空间.(他们中有很多.)

A.77 IMUL: Signed Integer Multiply
IMUL r/m8                     ; F6 /5                [8086] 
IMUL r/m16                    ; o16 F7 /5            [8086] 
IMUL r/m32                    ; o32 F7 /5            [386]
IMUL reg16,r/m16              ; o16 0F AF /r         [386] 
IMUL reg32,r/m32              ; o32 0F AF /r         [386]
IMUL reg16,imm8               ; o16 6B /r ib         [286] 
IMUL reg16,imm16              ; o16 69 /r iw         [286] 
IMUL reg32,imm8               ; o32 6B /r ib         [386] 
IMUL reg32,imm32              ; o32 69 /r id         [386]
IMUL reg16,r/m16,imm8         ; o16 6B /r ib         [286] 
IMUL reg16,r/m16,imm16        ; o16 69 /r iw         [286] 
IMUL reg32,r/m32,imm8         ; o32 6B /r ib         [386] 
IMUL reg32,r/m32,imm32        ; o32 69 /r id         [386]
Run Code Online (Sandbox Code Playgroud)

当然,对于32位扩展,任何reg32指令都需要386,但请注意,imul-immediate在286(imul cx, [bx], 123)中是新的,而2操作数imul在386(imul cx, [bx])中是新的,允许乘法而不破坏DX:AX,使得AX不那么"特殊" ".

其他386条指令相似movsx并且movzx也使得寄存器更加正交,让您可以有效地对任何寄存器进行符号扩展.在此之前,您必须将数据导入AL并使用cbw,或者进入AX cwd以签署扩展到DX:AX.