我试图尝试内联汇编,我试图在内联汇编中添加十进制数字(不,不是整数).问题是,当我调用以下函数时:
inline double ADD(double num1, double num2) {
double res;
_asm{
push eax; push the former state of eax onto stack
mov eax, num1;
add eax, num2;
mov res, eax;
pop eax; restore the former state of eax now that we are done
} return res;}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨内联汇编中的操作数大小不合适(除了push和pop指令行之外的所有汇编行).所以我必须更改为整数类型,例如unsigned long,然后它可以工作,但当然只支持整数类型; 小数结果四舍五入.
有没有办法添加允许像8.4这样的十进制结果的汇编?
假设我有两个浮点数x和y,它们的值非常接近。
计算机上可以表示离散数量的浮点数,因此我们可以按升序枚举它们:f_1, f_2, f_3, ...。x我希望找到和在此列表中的距离y(即它们是 1、2、3、... 还是n离散步长?)
是否可以仅使用算术运算(+-*/)而不查看二进制表示来做到这一点?我主要感兴趣的是它在 x86 上的工作原理。
假设 和y > x之间x只有y几步(例如 < 100),下面的近似值是否正确?(可能不会 ...)
(y-x) / x / eps
Run Code Online (Sandbox Code Playgroud)
这里eps表示机器 epsilon。(机器 epsilon 是 1.0 和下一个最小浮点数之间的差。)
MXCSR之类的东西有哪些最佳设置?哪种舍入模式最快?什么处理器?启用信号NaN是否更快,以便在计算结果为nan时获得通知,或者这会导致非NaN计算的速度减慢?
总之,如何从紧密的内部SSE循环中获得最大速度?
任何相关的x87浮点速度建议也欢迎.
我的任务是在混合C/ASM中编写一个简单的应用程序,它必须使用数学协处理器.
有一个函数柱面(float x,float y,float z),如果给定的点位于柱面内,则返回1(柱面的底边为x = 0,y = 0,半径= 5,高度= 10),如果不是,则为0.
所以,看起来很简单.检查z是否在<0,10>范围内,然后检查x ^ 2 + y ^ 2 <25.
但是我对x87的了解是零.
这就是我写的一切.
_cylinder PROC
push ebp
mov ebp, esp
sub esp,8 ; I can't use .data in the application, so I reserve some space on the stack for numbers 10 and 25
mov [esp],10
mov [esp+4],25
finit
fldz
fld [ebp+8]
;here i get stuck
add esp, 8
pop ebp
_cylinder ENDP
Run Code Online (Sandbox Code Playgroud)
所以我卡住了.所以,我试着找到我可以在应用程序中使用的指令.在那里我卡住了,因为我在网上找到的每个教程/指令列表写得非常糟糕,我几乎无法理解任何东西.
问题是,当我从数学协处理器弹出一些东西时会发生什么?我在哪里可以找到弹出值?它如何从80位值转换为32位值(当然如果有)另一个问题是,FCOM(用于pop变体的FCOMP)如何工作?它比较什么(st0到st1或st1到st0?),在哪里可以看到值是小/等于/更大?
谢谢你的帮助!
我想在GHC Haskell编译器中实现C的uint-to- doublecast 的等价物.我们已经实现了int-到- double使用FILD或CVTSI2SD.是否有这些操作的无符号版本,或者我应该uint将转换前的最高位置零(从而丢失范围)?
回到 Intel 最初设计 8087 时,他们为什么选择将浮点寄存器组织为堆栈?从这样的设计中可以获得什么可能的优势?与允许将任意寄存器用作源和目标操作数相比,它似乎更不灵活且更难使用。
我正在反转的程序在浮点数和8字节整数之间进行简单的乘法运算:
section .data
va: dt 1.4426950408889634074
vb: dd 0x42424242
dd 0x41414141
section .text
global main
main:
fld tword[va]
fmul qword[vb]
ret
Run Code Online (Sandbox Code Playgroud)
gdb下的结果:
Breakpoint 1, 0x08048360 in main ()
(gdb) x/i $eip
0x8048360 <main>: fld TBYTE PTR ds:0x804953c
0x8048366 <main+6>: fmul QWORD PTR ds:0x8049546
0x804836c <main+12>: ret
(gdb) x/gx 0x8049546
0x8049546 <vb>: 0x4141414142424242
(gdb) si
0x08048366 in main ()
0x0804836c in main ()
(gdb) info float
=>R7: Valid 0x4014c726039c95268dc4 +3262848.902912714389
Run Code Online (Sandbox Code Playgroud)
我正在尝试在C(相同的32位环境)中重新创建此程序:
#include <stdio.h>
int main() {
unsigned long long vb = …Run Code Online (Sandbox Code Playgroud) 在我们的代码库中,我发现这个代码片段用于在x87上进行快速,向负无限1舍入:
inline int my_int(double x)
{
int r;
#ifdef _GCC_
asm ("fldl %1\n"
"fistpl %0\n"
:"=m"(r)
:"m"(x));
#else
// ...
#endif
return r;
}
Run Code Online (Sandbox Code Playgroud)
我不是非常熟悉GCC扩展汇编语法,但是从我从文档中收集到的内容:
r 必须是一个记忆位置,我在写回东西;x 必须是一个内存位置,数据来自哪里.现在,来回答我的问题:最终FPU堆栈是平衡的,但是如果所有8个位置都已经在使用并且我已经溢出呢?编译器如何知道它不能信任ST(7)它离开它的位置?应该添加一些clobber吗?
编辑我试图st(7)在clobber列表中指定它似乎影响codegen,现在我将等待对此事实的一些确认.
作为旁注:看看lrintglibc和MinGW 中的准系统的实现,我看到了类似的东西
__asm__ __volatile__ ("fistpl %0"
: "=m" (retval)
: "t" (x)
: "st");
Run Code Online (Sandbox Code Playgroud)
我们要求输入直接放在哪里ST(0)(避免这种情况无用fldl); 什么是"st"clobber?文档似乎只提到t(即堆栈的顶部).
我在从 Intel 2023 和 MSC Visual C++ 2022 移植工作数字代码时遇到一个奇怪的问题。使用 GCC 编译的代码非常准确(太准确),因为某些库调用以完整的 80 位浮点精度工作 - 特别是 sqrt、sin 和 cos。我可以通过使用 TUI 跟踪 gdb 的库调用来反汇编库代码执行来验证这一点。
它也出现在基准计时中,因为 x87 atan2、cos、exp 和 sin 都约为 100 个周期,而 sqrt 约为 80 个周期。SSE/AVX2 代码的相应时序低于 50 个周期,大部分在 20-30 个周期左右。
奇怪的是 tan、atan是使用 AVX2 编译的。但 cos、sin、sqrt 和 atan2 在 GCC 系统库中使用旧版 x87 代码。我已经在 32 位端口和 64 位版本上尝试过此操作,并且都遇到了相同的问题。我是海湾合作委员会的新手,所以我可能忽略了一些事情。我在 Windows 上使用默认的 MinGW 端口版本 13.1.0 (MinGW-W64 i686-ucrt-posix-dwarf),它可能有其自身的特点。
顺便说一句,我刚刚注意到 MSC 2022 有时会编码 x87 sqrt,即使启用了所有 gofaster 优化和 AVX2 代码,因为这也是我之前没有注意到的基准计时中的异常值。Intel 将其编译为本机 sqrtsd,因此速度要快得多。我回到 MSC x86 进行内联汇编,以确认 x87 …