我正在使用RISC-V汇编语言实现33矩阵和31矩阵乘法,使用GNU C内联asm。
// description: matrix multiply with two-level for loop
#include<stdio.h>
int main()
{
int f,i=0;
int h[9]={0}, x[3]={0}, y[3]={0};
FILE *input = fopen("../input/3.txt","r");
for(i = 0; i<9; i++) fscanf(input, "%d", &h[i]);
for(i = 0; i<3; i++) fscanf(input, "%d", &x[i]);
for(i = 0; i<3; i++) fscanf(input, "%d", &y[i]);
fclose(input);
int *p_x = &x[0] ;
int *p_h = &h[0] ;
int *p_y = &y[0] ;
for (i = 0 ; i < 3; i++)
{
p_x = &x[0] ;
/*
for (f = 0 ; f < 3; f++)
*p_y += *p_h++ * *p_x++ ;
*/
for (f = 0 ; f < 3; f++){
asm volatile (
"addi t0, zero, 2\n\t"
"bne t0, %[f], Multi\n\t"
"mul t1, %[sp_h], %[sp_x]\n\t"
"add %[sp_y], %[sp_y], t1\n\t"
"addi %[p_h], %[p_h], 4\n\t"
"addi %[p_x], %[p_x], 4\n\t"
"addi %[p_y], %[p_y], 4\n\t"
"beq zero, zero, Exit\n\t"
"Multi: \n\t"
"mul t1, %[sp_h], %[sp_x]\n\t"
"add %[sp_y], %[sp_y], t1\n\t"
"addi %[p_h], %[p_h], 4\n\t"
"addi %[p_x], %[p_x], 4\n\t"
"Exit: \n\t"
:[p_y] "+&r"(p_y),
[p_x] "+&r"(p_x),
[p_h] "+&r"(p_h),
[sp_y] "+&r"(*p_y)
:[sp_h] "r"(*p_h),
[sp_x] "r"(*p_x),
[f] "r"(f)
:"t0","t1"
);
printf("x value=%d, h value=%d, y value=%d, y address=%d\n", *p_x, *p_h, *p_y, p_y);
}
}
p_y = &y[0];
for(i = 0; i<3; i++)
printf("%d \n", *p_y++);
return(0) ;
}
我想把这个评论转过来
for (f = 0 ; f < 3; f++)
*p_y += *p_h++ * *p_x++ ;
p_y++;
到asm volatile(...),但是在asm上面的代码中我遇到了这个问题:my problem看起来p_y
地址加对了,我的乘法是对的,但是我的值存储到内存中是错误的。它会存储到内存中太快,现在我的答案加上前面的答案在一起。上面的代码答案是5 28 69
有人能帮我吗?我已经编辑了"+r"
到"+&r"
,并添加了clobbers到代码中,但它不起作用
顺便说一下,我从这段代码中得到了正确的答案:
for (f = 0 ; f < 3; f++)
asm volatile ("mul %[tmp], %[sp_h], %[sp_x]\n\t"
"add %[sp_y], %[sp_y], %[tmp]\n\t"
"addi %[p_x], %[p_x], 4\n\t"
"addi %[p_h], %[p_h], 4\n\t"
:[tmp] "=r"(tmp),
[p_x] "+r"(p_x),
[p_h] "+r"(p_h),
[sp_y] "+r"(*p_y)
:[sp_h] "r"(*p_h),
[sp_x] "r"(*p_x)
);
p_y++;
我希望
14
32
50
答案。这里是输入数据:
1条答案
按热度按时间8wigbo561#
你的
[sp_y] "+&r"(*p_y)
输入/输出使用原始的p_y
来读取输入,但它使用asm语句更新的p_y
(在f==2
的情况下)来存储结果。编译器从gcc -O1 -Wall
(在Godbolt上)生成的asm很好地展示了这一点:GCC's docs没有提到当一个输出修改一个C变量时会发生什么,这个C变量也是另一个输出的左值表达式的一部分,至少我没有注意到。**我假设输出是无序的,**在这种情况下,它是类似于
x = ++x + ++x;
的未定义行为,或者至少没有具体说明会发生什么。不要在内部循环中有条件地递增
p_y
,所以根本不要将p_y
作为内部循环asm语句的输出(或输入)。我不认为有任何方法可以使其完全良好定义,尽管
"=r"(p_y[f == 2 ? -1 : 0])
和"0"(*p_y)
这样的匹配约束可能总是使用来自另一个输出寄存器的更新后的p_y
。但是您需要在C中手动执行偏移量以平衡asm的操作,完全违背了目的。所以在内部循环外使用一个单独的asm
语句来在外部循环中执行指针递增。一个单独的
int sum = *p_y;
变量对于这类事情来说是正常的,但是在递增p_y
之前,你仍然需要赋值*p_y = sum;
,所以你仍然不能在内部循环asm语句中这样做。你不希望编译器在内部循环中对sw
/lw
求和,就像你鼓励它对*p_y
做的那样。这样看起来就像
或者在asm中编写整个外循环体(包括内循环和
p_y++
),包括您自己的lw
和sw
,这样您就可以手动将addi %[p_y], %[p_y], 4
* 放在使用%[p_y]
的sw
之后。(Don对于一个带有指针输入的asm语句,不要忘记a
"memory"
clobber,它读/写不是"m"
约束的内存。)