GCC ARM 汇编预处理器宏

2024-04-18

我正在尝试使用汇编(ARM)宏进行定点乘法:

    #define MULT(a,b) __asm__ __volatile__ ( \
        "SMULL r2, r3, %0, %1\n\t" \
        "ADD r2, r2, #0x8000\n\t" \
        "ADC r3, r3, #0\n\t" \
        "MOV %0, r2, ASR#16\n\t" \
        "ORR %0, %0, r3, ASL#16" \
        : "=r" (a) : "0"(a), "1"(b) : "r2", "r3" );

但是当尝试编译时,我收到错误:expected expression before 'asm'

(如果您珍惜时间,您可以忽略下面的所有内容,但如果您看一下它会很好,这里的主要问题是如何使上述工作正常进行)

我试过这个:

    static inline GLfixed MULT(GLfixed a, GLfixed b){
       asm volatile(
        "SMULL r2, r3, %[a], %[b]\n"
        "ADD r2, r2, #0x8000\n"
        "ADC r3, r3, #0\n"
        "MOV %[a], r2, ASR#16\n"
        "ORR %[a], %[a], r3, ASL#16\n"
        : "=r" (a)
        : [a] "r" (a), [b] "r" (b)
        : "r2", "r3");
     return a; }

这可以编译,但似乎有一个问题,因为当我使用常量时,例如:MULT(65536,65536) 它可以工作,但是当我使用变量时,它似乎搞砸了:

GLfixed m[16];
m[0]=costab[player_ry];//1(65536 integer representation)
m[5]=costab[player_rx];//1(65536 integer representation)
m[6]=-sintab[player_rx];//0
m[8]=-sintab[player_ry];//0
LOG("%i,%i,%i",m[6],m[8],MULT(m[6],m[8]));
m[1]=MULT(m[6],m[8]);
m[2]=MULT(m[5],-m[8]);
m[9]=MULT(-m[6],m[0]);
m[10]=MULT(m[5],m[0]);
m[12]=MULT(m[0],0)+MULT(m[8],0);
m[13]=MULT(m[1],0)+MULT(m[5],0)+MULT(m[9],0);
m[14]=MULT(m[2],0)+MULT(m[6],0)+MULT(m[10],0);
m[15]=0x00010000;//1(65536 integer representation)

int i=0;
while(i<16)
{
    LOG("%i,%i,%i,%i",m[i],m[i+1],m[i+2],m[i+3]);
    i+=4;
}

上面的代码将打印(LOG就像这里的printf):

0,0,-1411346156
65536,65536,65536,440
-2134820096,65536,0,-1345274311
0,65536,22,220
65536,196608,131072,65536

当正确的结果是(显然上面有很多垃圾):

0,0,0
65536,0,0,0
0,65536,0,0
0,0,65536,0
0,0,0,65536

第一部分很简单:问题是__asm__block 是一个语句,而不是一个表达式。

您可以使用 GCC语句表达式 http://gcc.gnu.org/onlinedocs/gcc-4.6.0/gcc/Statement-Exprs.html扩展来实现你想要的 - 像这样:

#define MULT(a,b) \
  ({ \
    __asm__ __volatile__ ( \
      /* ... asm stuff here ... */
    ); \
    a; \
  })

第二部分是由于输入和输出操作数规范的问题。这里有两个不同的版本,而且都是错误的。在宏观版本中,您说过:

: "=r" (a) : "0"(a), "1"(b) : "r2", "r3"

哪些限制

  • 输出a到寄存器(这是操作数 0);
  • 输入a与操作数 0 相同,即相同的寄存器(这是操作数 1);
  • 输入b与操作数 1 相同,即再次相同(这是操作数 2)。

你需要"r"(b)在这里,可以将其称为%2.

在内联版本中,您说过:

: "=r" (a) : [a] "r" (a), [b] "r" (b) : "r2", "r3"

这限制了输出a和输入a and b到寄存器,但是

  • 它不声明它们之间的任何关系;
  • asm 从未明确引用输出操作数(您没有给输出操作数命名,并且 asm 代码不引用%0).

您应该能够使用以下方法修复原始版本:

: "=r" (a) : "0" (a), "r" (b) : "r2", "r3"

并参考a作为任一%0 or %1, and b as %2.

内联版本可以这样修复:

: [a] "=r" (a) : "[a]" (a), [b] "r" (b) : "r2", "r3"

并将操作数称为%[a] and %[b].

如果你想在宏版本中使用名称,你将需要类似的东西

: [arg_a] "=r" (a) : "[arg_a]" (a), [arg_b] "r" (b) : "r2", "r3"

(并参考%[arg_a] and %[arg_b])因为否则预处理器将扩展a and b inside [a] and [b].

请注意命名参数情况中的微妙之处:当为参数指定名称时(如输出中所示)a) 你写[a]- 没有引号 - 但是当您引用另一个已经命名的操作数的名称时(如输入中所示)a)你需要把它放在引号内:"[a]".

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC ARM 汇编预处理器宏 的相关文章

随机推荐