所以我一直在阅读有关处理器工作原理的文章。现在我正在研究指令(SSE、SSE2 等)。(这很有趣)。
我有很多问题(我一直在维基百科上阅读这些内容):
我看到了 SSE 上添加的一些指令的名称,但是没有关于它们的任何解释(也许是 SSE4?它们甚至没有在 Wikipedia 上列出)。我在哪里可以阅读它们的作用?
我怎么知道正在使用其中的哪一个指令?
如果我们确实知道正在使用哪些,假设我正在进行比较,(这可能是我问过的最愚蠢的问题,但我不知道汇编)是否可以直接在汇编代码上使用该指令?(我一直在看这个:http://asm.inightmare.org/opcodelst/index.php?op=CMP)
处理器如何解释指令?
如果我有一个没有任何 SSE 指令的处理器,会发生什么情况?(我想如果我们想要进行比较,我们就无法做到,对吧?)
答案1
我看到了我们在 SSE 上添加的一些指令的名称,但是没有对它们全部进行解释(也许是 SSE4?它们甚至没有在 Wikipedia 上列出)。我在哪里可以阅读它们的作用?
最好的信息来源是直接来自设计扩展的人:英特尔。权威的参考资料是英特尔® 64 和 IA-32 架构软件开发人员手册;我建议您下载合并的 1 至 3C 卷(该页面上的第一个下载链接)。您可能想看看Vol. 1, Ch. 12
- 使用 SSE3、SSSE3、SSE4 和 AESNI 进行编程。要参考具体说明,请参阅Vol. 2, Ch. 3-4
。(附录 B 也很有帮助)
我怎么知道正在使用其中的哪一个指令?
只有当您运行的程序实际使用它们时,这些指令才会被使用(即调用与各种 SSE4 指令相对应的字节码)。要找出程序使用的指令,您需要使用反汇编程序。
如果我们确实知道正在使用哪些,假设我正在进行比较,(这可能是我做过的最愚蠢的问题,但我不知道汇编)是否可以直接在汇编代码上使用该指令?(我一直在看这个: http://asm.inightmare.org/opcodelst/index.php?op=CMP)
处理器如何解释指令?
你可能想看看我对这个问题的回答,“CPU 如何“知道”命令和指令的实际含义?“。当您手写汇编代码以制作可执行文件时,您会将“人类可读的”汇编代码传递给汇编程序,汇编程序将指令转换为处理器执行的实际 0 和 1。
如果我有一个没有任何 SSE 指令的处理器,会发生什么?(我想如果我们想进行比较,我们就做不到,对吗?)
由于您的计算机图灵完备,如果没有专用硬件,它可以使用软件算法执行任意数学函数。显然,在硬件中执行密集的并行或矩阵数学运算比在软件中快得多(需要许多指令循环),因此这会导致最终用户的速度变慢。根据程序的创建方式,它可能的它可能需要一个特定的指令(即来自 SSE4 集合的指令),尽管可以在软件中执行同样的事情(从而可以在更多处理器上使用),但这种做法很少见。
举个例子,你可能还记得处理器首次推出时MMX指令集扩展。假设我们想将两个 8 元素、有符号的 8 位向量相加(因此每个向量都是 64 位,等于一个 MMX 寄存器),换句话说,A + B = C
。这可以通过以下方式完成单个 MMX 指令称为paddsb
。为简洁起见,我们假设我们的向量保存在内存位置A
、B
和C
。我们的等效汇编代码将是:
movq MM0, [A]
paddsb MM0, [B]
movq [C], MM0
但是,这个操作也可以很容易地用软件完成。例如,以下 C 代码执行等效操作(因为 achar
是 8 位宽):
#define LEN 8
char A[LEN], B[LEN], C[LEN];
/* Code to initialize vectors A and B... */
for (i = 0; i < LEN; i++)
{
C[i] = A[i] + B[i];
}
您可能已经猜出上述循环的汇编代码是什么样子,但很明显它将包含更多指令(因为我们现在需要一个循环来处理添加向量),因此,我们需要执行更多次提取。这类似于处理器的字长如何影响计算机的性能(MMX/SSEx 的目的是提供更大的寄存器,以及执行对多条数据执行相同的指令)。
答案2
按与问题相同的顺序回答您:
- 最简单的方法是访问英特尔网站并下载白皮书。即使处理器的 SDK 手册也会包含所有必需的详细信息。这里就是这样一个链接。这里是 SSE 指令集助记符和解释的另一个链接。
- 您究竟指的是正在使用这些指令中的哪一条?您是在寻找有关处理器或特定应用程序的信息吗?
对于处理器,我不知道 Windows 的情况,但在 Linux 上,您只需读取它的处理器标志。通过命令更容易完成# lshw
。
另一方面,对于特定于应用程序的,我不太确定,您总是可以反汇编可执行文件,并检查正在使用的指令。由于大多数应用程序都是为大众编写的,因此它们将仅使用通用 x86 指令集。要使用更多特定于处理器的指令,您应该在系统上手动编译应用程序。 - 您始终可以运行模拟器。如果您想在编程项目中使用汇编代码,可以使用 C 和 C++ 来实现。我只在 C 中使用过 ASM 代码,所以不知道是否有其他语言支持它。有关使用内联 ASM 的帮助,请参阅此那么问题来了。
- 这个问题很大程度上存在于计算机架构领域。虽然我可以在这里解释它,但这并不容易。还有另一个SU 问题,讨论了这一主题。
- 回答你的具体问题,SSE 指令集于 1999 年才问世,而 CMP 指令早在那之前就已经存在了。它也是 8080 指令集的一部分。无论如何,由于我们的机器是图灵完备的,即使是较旧的微处理器也可以进行比较。只是,如果没有明确的指令,执行这些操作会更加困难。每个指令集都只是一种更快、更简单、更优化的方式来执行某些指令,它几乎没有增加新功能,因为图灵完备的机器总是可以
compute everything that is computable
答案3
我看到了在 SSE 上添加的一些指令的名称,但是没有关于它们的任何解释(可能是 SSE4?它们甚至没有在维基百科上列出)。
那是不对的。维基百科上有一份列表关于每一个x86 指令,甚至包括已弃用和未记录的指令
我可以在哪里阅读有关他们所做的事情?
要了解任何 CPU,您需要阅读其制造商手册。在这种情况下英特尔或者可能AMD。对于紧凑的指令汇编,这两个是可靠的来源
如果我们确实知道正在使用哪些,假设我正在进行比较,(这可能是我问过的最愚蠢的问题,但我不知道汇编)是否可以直接在汇编代码上使用该指令?(我一直在看这个:http://asm.inightmare.org/opcodelst/index.php?op=CMP)
Assembly 只是机器码。您看到的名称是汇编指令的助记符,因此当然它们一直在汇编中直接使用
如果我有一个没有任何 SSE 指令的处理器,会发生什么情况?(我想如果我们想要进行比较,我们就无法做到,对吧?)
实际上,现在几乎找不到不支持 SSE 的 x86 CPU,因为它自 20 年前 Pentium III 开始就已推出。但通常情况下,如果 CPU 发现无效指令/操作码,它会引发例外。通常情况下,操作系统只是宣布错误,然后终止程序。但如果需要,应用程序可以捕获该异常并在软件中处理指令。这将导致极低的效率,因为状态在程序和异常处理程序之间切换,但程序无需修改即可运行。
过去,当某些 CPU 没有内置 FPU 且浮点运算在单独的协处理器中完成时,曾使用过这种方法。在这种情况下,如果未连接协处理器,则浮点指令将引发异常,异常处理程序将在软件中计算运算,然后再将其传输回程序。请参阅MS-DOS 中 x87 浮点仿真的协议是什么?
它也被一些 Hackintosh 补丁使用,使 MacOS X(需要 SSE2/3 或更高版本)能够在仅具有 SSE 的旧 CPU 上运行
答案4
仅回答第 5 个问题。假设您在半兼容机器上运行机器代码。因此 CPU 最终可能会遇到无效指令。
有一种协议,现代操作系统和 CPU 会协同遵循,以处理此类情况。CPU 会存储有关刚刚发生的事情的信息,并跳转到操作系统代码中寻求帮助,因此操作系统能够正确评估情况,并且很可能终止被误导的进程(即,它将进程从就绪队列中删除并回收相关数据结构)。
在 UNIX 系统上,非法指令对应于 SIGILL,进程可能已为该信号注册了信号处理程序例程。如果已注册,则不会终止该信号,而是调用相应的信号处理程序。否则,会在磁盘上写入核心转储。您可以在此阅读有关此内容的文章信号(7)或 Rochkind,《高级 UNIX 编程》,第 9.1 章。