我尝试使用内联汇编在此函数中计算1.34 *sqrt(lght)
,但我收到的错误如下:
' _asm'未申报(首次使用此功能) 每个未声明的标识符仅针对其出现的每个功能报告一次 预期';'之前' {'令牌
我一直在研究如何解决这个问题但却无法找到更多信息。有人可以建议一种方法让它发挥作用吗?
我的代码是:
double hullSpeed(double lgth) {
_asm {
global _start
fld lght; //load lght
fld st(0); //duplicate lght on Top of stack
fsqrt;
square root of lght
fld st(0); //load square result on top of stack
fld 1.34; //load 1.34 on top of stack
fld st(i);
duplicate 1.34 on TOS
fmulp st(0), st(i); //multiply them
fst z;
save result in z
}
return z; // return result of [ 1.34 *sqrt(lght) ]
}
答案 0 :(得分:3)
看起来你正在尝试做类似的事情:
#include <stdio.h>
double hullSpeed(double lgth)
{
double result;
__asm__(
"fldl %1\n\t" //st(0)=>st(1), st(0)=lgth . FLDL means load double float
"fsqrt\n\t" //st(0) = square root st(0)
"fmulp\n\t" //Multiplies st(0) and st(1) (1.34). Result in st(0)
: "=&t" (result) : "m" (lgth), "0" (1.34));
return result;
}
int main()
{
printf ("%f\n", hullSpeed(64.0));
}
我使用的模板可以简化,但出于演示目的,它就足够了。我们使用"=&t"
约束,因为我们将结果返回到st(0)
中浮点堆栈的顶部,我们使用&符号来表示早期的clobber(我们&#39; ll使用浮点堆栈的顶部传入1.34)。我们通过约束lgth
传递带有内存引用的"m" (lgth)
地址,"0"(1.34)
约束表示我们将在与参数0相同的寄存器中传入1.34,在本例中为浮点堆栈的顶部。这些是寄存器(或内存),我们的汇编器将覆盖但不会显示为输入或输出约束。
使用内联汇编程序学习汇编语言是一种非常难以学习的方法。可以在 x86系列下找到{em> x86 特定的机器约束here。可以找到有关约束修饰符的信息here,并且可以找到有关 GCC 扩展汇编程序模板的信息here。
我只给你一个起点,因为 GCC 的内联汇编程序使用可能相当复杂,而且对于Stackoverflow答案,任何答案都可能过于宽泛。你使用带有x87浮点的内联汇编程序的事实使它变得更加复杂。
一旦掌握了约束和修饰符,编译器会产生更好的汇编程序代码的另一种机制是:
__asm__(
"fsqrt\n\t" // st(0) = square root st(0)
"fmulp\n\t" // Multiplies st(0) and st(1) (1.34). Result in st(0)
: "=t"(result) : "0"(lgth), "u" (1.34));
提示:约束"u"
在x87浮点寄存器st(1)
中放置一个值。汇编程序模板约束有效地将lgth
放在st(0)
和st(1)
中的1.34中。我们使用约束将我们的值放在浮点堆栈上。这样可以减少我们在汇编程序代码中必须完成的工作。
如果您正在开发64位应用程序,我强烈建议您至少使用SSE / SSE2进行基本浮点计算。上面的代码应该适用于32位和64位。在64位代码中,x87浮点指令通常不如SSE / SSE2有效,但它们可以工作。
如果您尝试基于x87上的4种舍入模式之一进行舍入,则可以使用以下代码:
#include <stdint.h>
#include <stdio.h>
#define RND_CTL_BIT_SHIFT 10
typedef enum {
ROUND_NEAREST_EVEN = 0 << RND_CTL_BIT_SHIFT,
ROUND_MINUS_INF = 1 << RND_CTL_BIT_SHIFT,
ROUND_PLUS_INF = 2 << RND_CTL_BIT_SHIFT,
ROUND_TOWARD_ZERO = 3 << RND_CTL_BIT_SHIFT
} RoundingMode;
double roundd (double n, RoundingMode mode)
{
uint16_t cw; /* Storage for the current x87 control register */
uint16_t newcw; /* Storage for the new value of the control register */
uint16_t dummyreg; /* Temporary dummy register used in the template */
__asm__ __volatile__ (
"fstcw %w[cw] \n\t" /* Read current x87 control register into cw*/
"fwait \n\t" /* Do an fwait after an fstcw instruction */
"mov %w[cw],%w[treg] \n\t" /* ax = value in cw variable*/
"and $0xf3ff,%w[treg] \n\t" /* Set rounding mode bits 10 and 11 of control
register to zero*/
"or %w[rmode],%w[treg] \n\t" /* Set the rounding mode bits */
"mov %w[treg],%w[newcw]\n\t" /* newcw = value for new control reg value*/
"fldcw %w[newcw] \n\t" /* Set control register to newcw */
"frndint \n\t" /* st(0) = round(st(0)) */
"fldcw %w[cw] \n\t" /* restore control reg to orig value in cw*/
: [cw]"=m"(cw),
[newcw]"=m"(newcw),
[treg]"=&r"(dummyreg), /* Register constraint with dummy variable
allows compiler to choose available register */
[n]"+t"(n) /* +t constraint passes `n` through
top of FPU stack (st0) for both input&output*/
: [rmode]"rmi"((uint16_t)mode)); /* "g" constraint same as "rmi" */
return n;
}
double hullSpeed(double lgth)
{
double result;
__asm__(
"fsqrt\n\t" // st(0) = square root st(0)
"fmulp\n\t" // Multiplies st(0) and st(1) (1.34). Result in st(0)
: "=t"(result) : "0"(lgth), "u" (1.34));
return result;
}
int main()
{
double dbHullSpeed = hullSpeed(64.0);
printf ("%f, %f\n", dbHullSpeed, roundd(dbHullSpeed, ROUND_NEAREST_EVEN));
printf ("%f, %f\n", dbHullSpeed, roundd(dbHullSpeed, ROUND_MINUS_INF));
printf ("%f, %f\n", dbHullSpeed, roundd(dbHullSpeed, ROUND_PLUS_INF));
printf ("%f, %f\n", dbHullSpeed, roundd(dbHullSpeed, ROUND_TOWARD_ZERO));
return 0;
}
正如您在评论中指出的那样,Stackoverflow answer中有相同的代码,但它使用了多个__asm__
语句,您很好奇如何编写单个__asm__
语句。< / p>
可以在Intel Architecture Document:
中找到舍入模式(0,1,2,3)舍入模式RC字段
00B圆形结果最接近无限精确结果。如果两个值相等,则结果为偶数值(即最低有效位为零的值)。默认向下舍入(向-∞)
01B圆形结果最接近但不大于无限精确结果。向上舍入(朝向+∞)
10B圆形结果最接近但不小于无限精确结果。回零(截断)
11B圆形结果的绝对值最接近但不大于无限精确的结果。
在8.1.5节(第8.1.5.3节中具体描述的舍入模式)中,有对字段的描述。 4种舍入模式在图4-8的4.8.4节中定义。