Jon*_*han 5 macros assembly gcc preprocessor arm
我正在尝试使用汇编(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" );
Run Code Online (Sandbox Code Playgroud)
但在尝试编译时,我得到错误:' 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; }
Run Code Online (Sandbox Code Playgroud)
这编译但似乎有一个问题,因为当我使用常量ex:MULT(65536,65536)它可以工作,但当我使用变量时,似乎f**k up:
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;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码将打印(LOG就像这里的printf):
0,0,-1411346156
65536,65536,65536,440
-2134820096,65536,0,-1345274311
0,65536,22,220
65536,196608,131072,65536
Run Code Online (Sandbox Code Playgroud)
当得到正确的结果时(显然上面有很多垃圾):
0,0,0
65536,0,0,0
0,65536,0,0
0,0,65536,0
0,0,0,65536
Run Code Online (Sandbox Code Playgroud)
第一部分很简单:问题是__asm__块是一个语句,而不是表达式.
您可以使用GCC的语句表达式扩展来实现您想要的 - 如下所示:
#define MULT(a,b) \
({ \
__asm__ __volatile__ ( \
/* ... asm stuff here ... */
); \
a; \
})
Run Code Online (Sandbox Code Playgroud)
第二部分是由于输入和输出操作数规范中的问题.这里有两个不同的版本,两者都错了.在宏版本中,你说过:
: "=r" (a) : "0"(a), "1"(b) : "r2", "r3"
Run Code Online (Sandbox Code Playgroud)
哪个约束
a到寄存器(这是操作数0);a与操作数0相同,即相同的寄存器(这是操作数1);b与操作数1相同,即再次相同(这是操作数2).你需要"r"(b)在这里,并可以将其称为%2.
在内联版本中,您已经说过:
: "=r" (a) : [a] "r" (a), [b] "r" (b) : "r2", "r3"
Run Code Online (Sandbox Code Playgroud)
它限制了输出a和输入a以及b寄存器,但是
%0).您应该可以使用以下方法修复原始版本:
: "=r" (a) : "0" (a), "r" (b) : "r2", "r3"
Run Code Online (Sandbox Code Playgroud)
并将其a称为" %0或%1"和" bas" %2.
内联版本可以像这样修复:
: [a] "=r" (a) : "[a]" (a), [b] "r" (b) : "r2", "r3"
Run Code Online (Sandbox Code Playgroud)
并将操作数称为%[a]和%[b].
如果你想在宏版本中使用名字,你需要的东西是这样的
: [arg_a] "=r" (a) : "[arg_a]" (a), [arg_b] "r" (b) : "r2", "r3"
Run Code Online (Sandbox Code Playgroud)
(并参考%[arg_a]和%[arg_b])因为否则预处理器将扩展a和b内部[a]和[b].
注意命名参数情况中的细微之处:当一个名称被赋予一个参数(如在输出中a)时,你写的[a]- 没有引号 - 但是当你引用另一个已经命名的操作数的名称时(如输入中a)你需要把它放在引号内:"[a]".
您是否尝试过简单的 C 代码而不是汇编?在我的 GCC 4.5.3 系统上,编译器生成的代码至少与您手写的汇编器一样好:
int mul (int a, int b)
{
long long x = ((long long)a * b + 0x8000);
return x>>16;
}
Run Code Online (Sandbox Code Playgroud)
编译为以下 asm 代码:
# input: r0, r1
mov r3, #32768
mov r4, #0
smlal r3, r4, r0, r1
mov r0, r3, lsr #16
orr r0, r0, r4, asl #16
# result in r0
Run Code Online (Sandbox Code Playgroud)
(函数调用 Epilog 和 Prolog 已删除)
如果在单个函数中有多次乘法,代码会变得更好,因为编译器将删除冗余的 mov r3, #32768 指令。
| 归档时间: |
|
| 查看次数: |
4579 次 |
| 最近记录: |