【发布时间】:2018-07-28 23:38:54
【问题描述】:
内联汇编代码在其中一个 for 循环中替换 C++ 语句。
有时它会神奇地工作并产生正确的结果 - 使用基数排序排序的数组。另一次 Xcode 生成了一个Thread 1: EXC_BAD_ACCESS (code=1, address=0x1eccccccccd) 错误,我使用反汇编视图追溯到incq (%[count], %%rdx, 4) 行。
我的理解
反汇编视图incq (%[count], %%rdx, 4) 为incq (%rax,%rdx,4)。这可能意味着相同的寄存器用于不同的操作数(%%rax 已在movq (%[array], %%rcx, 4), %%rax 行上使用),问题出在:: [array] "r" (array), [count] "r" (count), "b" (digit), "c" (i)。
我不明白的地方
如何管理寄存器,以便我有足够多的寄存器供我使用(分配给输入操作数和稍后的正文代码)并且它们不会同时重叠。我尝试了几种组合,但都没有奏效。
void countingSort(int array[], int length, int digit) {
int i, count[10] = { };
int sorted[length];
// Store number of occurrences in count[].
// for (i = 0; i < length; i++)
// count[ (array[i] / digit) % 10 ]++;
for (i = 0; i < length; i++)
asm volatile (
"movq (%[array], %%rcx, 4), %%rax \n\t"
"xorq %%rdx, %%rdx \n\t"
"divq %%rbx \n\t"
"movq $10, %%rbx \n\t"
"xorq %%rdx, %%rdx \n\t"
"divq %%rbx \n\t"
"incq (%[count], %%rdx, 4) \n\t"
:: [array] "r" (array), [count] "r" (count), "b" (digit), "c" (i)
: "memory"
);
// ...
}
完整代码:
#include<iostream>
using namespace std;
void print(int array[], int length) {
for (int i = 0; i < length; i++)
cout << array[i] << " ";
}
int findMax(int array[], int length) {
int max = array[0];
for (int i = 1; i < length; i++)
if (array[i] > max)
max = array[i];
return max;
}
void countingSort(int array[], int length, int digit) {
int i = 0, count[10] = { };
int sorted[length];
// Store number of occurrences in count[].
// for (i = 0; i < length; i++)
// count[ (array[i] / digit) % 10 ]++;
for (i = 0; i < length; i++)
asm volatile (
"movq (%[array], %%rcx, 4), %%rax \n\t"
"xorq %%rdx, %%rdx \n\t"
"divq %%rbx \n\t"
"movq $10, %%rbx \n\t"
"xorq %%rdx, %%rdx \n\t"
"divq %%rbx \n\t"
"incq (%[count], %%rdx, 4) \n\t"
:: [array] "r" (array), [count] "r" (count), "b" (digit), "c" (i)
: "memory"
);
// Change count[i] so that count[i] now contains actual
// position of the digit in sorted[].
// for (i = 1; i < 10; i++)
// count[i] += count[i - 1];
for (i = 1; i < 10; i++)
count[i] += count[i - 1];
// Build the sorted array.
for (i = length - 1; i >= 0; i--) {
sorted[count[ (array[i] / digit) % 10 ] - 1] = array[i];
count[ (array[i] / digit) % 10 ]--;
}
// Copy the sorted array to array[].
for (i = 0; i < length; i++)
array[i] = sorted[i];
}
void radixSort(int array[], int length) {
// Maximum number helps later when counting number of digits.
int max = findMax(array, length);
// Do Counting sort for every digit.
for (int digit = 1; max / digit > 0; digit *= 10)
countingSort(array, length, digit);
}
int main() {
int array[] = { 2, 4928, 48, 72, 280, 4, 66, 3, 1, 0, 4829 };
int length = sizeof(array) / sizeof(array[0]);
radixSort(array, length);
print(array, length);
return 0;
}
【问题讨论】:
-
您忘记将被破坏的寄存器添加到被破坏的列表中。
-
@liliscent 是的,你是对的。将
"rax", "rdx"添加到破坏列表修复了错误,但以某种方式改变了循环本身。现在输出是{ 72 4928 4928 4829 4928 4928 0 4928 4829 4928 4928 },而不是排序的{ 0, 1, 2, 3, 4, 48, 66, 72, 280, 4928, 4829 }数组。您能看出发生这种情况的任何原因吗? -
你的数据大小不对,
int应该有d后缀,而不是q。尤其是第一个movq,将下一个int移动到rax的高位。 -
为什么首先要内联 asm?为什么不把它写成 C++ 并让编译器来处理呢?无论如何,它可能会生成一样好或更好的 asm(打开优化时)。
-
@liliscent : MOVSL 是移动长的字符串指令之一。您的意思是MOVSXD 将 32 位值移动到带有符号扩展名的 64 位寄存器吗?或者 MOVL 只是将 32 位数据移动到 32 位寄存器(CPU 自动零将其自动扩展到 64 位寄存器的高 32 位)
标签: sorting assembly x86 g++ inline-assembly