这是一个确切的问题:
下面的代码转换了M x M数组的元素,其中M是#define定义的常量:
void transpose(Marray_t A) {
int i, j;
for (i = 0; i < M; i++)
for (j = 0; j < i; j++) {
int t = A[i][j];
A[i][j] = A[j][i];
A[j][i] = t;
}
}
Run Code Online (Sandbox Code Playgroud)
当使用优化级别-02进行编译时,GCC会为函数的内部循环生成以下代码:
1. .L3
2. movl (%ebx),%eax
3. movl (%esi,%ecx,4),%edx
4. movl %eax, (%esi,%ecx,4)
5. addl $1, %ecx
6. movl %edx, (%ebx)
7. addl $52,%ebx
8. cmpl %edi,%ecx
9. jl .L3
Run Code Online (Sandbox Code Playgroud)
A. M的价值是多少?
B.什么寄存器保存程序值i和j?
C.编写转置的C代码版本,该版本利用此循环中发生的优化.在代码中使用参数M而不是数字常量.
所以在我试图理解这一点时,我注意到它乘以4,这意味着它存储了4个字节的类型(可能是int或指针).然后,它增加我$ 52(我假设我),因为它是一个更大的值,因此进入下一个数组)和$ 52/4是13.所以我猜M = 13.错了吗?
对于B,我猜想%ebx包含i而%ecx包含i.
对于C,我不完全确定,因为我不完全理解所呈现的循环.让我试着通过行号来理解并告诉我哪里错了.1.显然是循环标签的开头.2.大概将i的值移到%eax中.然后3.将A [i] [j]存储到t中.但是......我真的不明白.:/ 救命??
我修复了汇编代码中的一些错误(%ecs- > %ecx和(ebx) -> (%ebx))我希望我不会无意中引入新的错误.
关于问题,你几乎在那里有了解.让我们逐行获取代码并尝试将其转换为C.
L3:
2. movl (%ebx),%eax
// We load a 32-bit value from the address stored in ebx. We can't yet deduce the type, but let's assume int for now
int *ebx = ??;
int eax = *ebx;
3. movl (%esi,%ecx,4),%edx
// As you noted we're dealing with 32-bit values, so when converting to C we divide the index by 4
int *esi = ??;
int ecx = ??;
int edx = esi[ecx];
4. movl %eax, (%esi,%ecx,4)
esi[ecx] = eax;
5. addl $1, %ecx
ecx++;
6. movl %edx, (%ebx)
*ebx = edx;
7. addl $52,%ebx
// Again we have to remember to divide by the size of the type used (4)
ebx += 13;
8. cmpl %edi,%ecx
9. jl .L3
int edi = ??;
if (ecx < edi) goto L3;
Run Code Online (Sandbox Code Playgroud)
由此我们看到我们有一些在内循环之外初始化的未知值,但我们也可以对它们是什么做出很好的猜测.
ecx每次循环迭代递增,然后用于决定是否应该继续循环:它显然j来自C代码.edi是我们j在决定是否循环时比较的值,但它在内循环中没有改变:它是i.esi使用ecx(j)逐行索引,因此它对应于&a[i][j].ebx每次循环迭代增加52(13个索引位置) - 因为您可能已经猜到13是M - 它对应于&m[j][i]并且j每次迭代移动到指向下一列的第-row行元素.现在我们可以回答这些问题:
A. M的价值是多少?
13
B.什么寄存器保存程序值i和j?
edi和ecx分别.
C.编写转置的C代码版本,该版本利用此循环中发生的优化.在代码中使用参数M而不是数字常量.
这一点应该是直截了当的.