如何在 x86-64 程序集中交换二维数组的 2 个值
how to swap 2 values of a two dimensional array in x86-64 assembly
我正在用汇编 x86-64 编写一个程序,该程序根据 c
中的以下函数转置矩阵
void transpose_matrix_by_naive(int **matrix, const int matrixSize){
int i, j, auxValue;
for (i = 0; i < matrixSize; i++){
for (j = 0; j < matrixSize; j++){
if (i < j){
auxValue = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = auxValue;
}
}
}
}
创建矩阵我使用以下函数
void create_matrix(int ***matrix, const int matrixSize){
int i;
*matrix = (int **)malloc(matrixSize * sizeof(int *));
for (i = 0; i < matrixSize; i++){
(*matrix)[i] = (int *)malloc(matrixSize * sizeof(int));
}
}
asm中的程序是
;extern void transpose_matrix_by_naive_in_asm(int **matrix, int matrixSize);
; RDI RSI
section .text
global transpose_matrix_by_naive_in_asm
transpose_matrix_by_naive_in_asm:
mov RAX, 0
mov RBX, 0
loop_for_i:
loop_for_j:
cmp RAX, RBX
jl conditional_if
return:
inc RBX
cmp RBX, RSI
jne loop_for_j
inc RAX
cmp RAX, RSI
jne loop_for_i
conditional_if:
;here I have to make a swap
jmp return
我的问题是“如何交换矩阵 [i] [j] 和矩阵 [j] [i] 的值?”。值得一提的是,我只使用方矩阵。
在 x86 汇编程序中,内存中的两个值可以简单地交换
mov eax, [rdi]
mov ebx, [rsi]
mov [rdi], ebx
mov [rsi], eax
其中rdi
、rsi
是两个32位整数的内存地址。
地址计算通常应该通过计算 步幅 或偏移量来加快,为了使第 N 个元素正确或向下。
汇编程序中的整个矩阵转置可能最好由编译器生成。
OTOH 编译器在将操作分解为 4x4 子矩阵块时可能无法使用 SIMD 指令:
for (y = 0; y < size/4; y++) {
for (x = 0; x < y; x++) {
if (y == x) {
transposeSubBlock(matrix, y);
} else if (y < x) {
transposeSubBlock(matrix, y, x);
}
}
}
现在,通过加载 4 个 SIMD 寄存器(从相邻的行和相邻的列)、转置寄存器并回写,可以在矩阵对角线上转置单个 4x4 块。
__m128i a[4];
a[0] = _mm_loadu_si128(row + 0 * stride);
a[1] = _mm_loadu_si128(row + 1 * stride);
a[2] = _mm_loadu_si128(row + 2 * stride);
a[3] = _mm_loadu_si128(row + 3 *stride);
transpose(a[0],a[1],a[2],a[3]);
_mm_storeu_si128(row + 0 * stride, a[0]);
_mm_storeu_si128(row + 1 * stride, a[1]);
_mm_storeu_si128(row + 2 * stride, a[2]);
_mm_storeu_si128(row + 3 * stride, a[3]);
其他块通过加载两个 4x4 块来处理,将两个块转置到寄存器中,然后写入相反的目标。
__m128i a[4], b[4];
load4vectors(a, src0, stride);
load4vectors(b, src1, stride);
transpose(a[0],a[1],a[2],a[3]);
transpose(b[0],b[1],b[2],b[3]);
store4vectors(src0, b[0],b[1],b[2],b[3]);
store4vectors(src1, a[0],a[1],a[2],a[3]);
转置 int[4][4] 矩阵的一种可能方法是将每个元素转换为 __m128
应用 MM_TRANSPOSE_PS(a,b,c,d);
宏并将每个元素转换回 __m128i
。
剩下的任务是处理多余的元素,它们不是 4 的倍数。
我正在用汇编 x86-64 编写一个程序,该程序根据 c
中的以下函数转置矩阵void transpose_matrix_by_naive(int **matrix, const int matrixSize){
int i, j, auxValue;
for (i = 0; i < matrixSize; i++){
for (j = 0; j < matrixSize; j++){
if (i < j){
auxValue = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = auxValue;
}
}
}
}
创建矩阵我使用以下函数
void create_matrix(int ***matrix, const int matrixSize){
int i;
*matrix = (int **)malloc(matrixSize * sizeof(int *));
for (i = 0; i < matrixSize; i++){
(*matrix)[i] = (int *)malloc(matrixSize * sizeof(int));
}
}
asm中的程序是
;extern void transpose_matrix_by_naive_in_asm(int **matrix, int matrixSize);
; RDI RSI
section .text
global transpose_matrix_by_naive_in_asm
transpose_matrix_by_naive_in_asm:
mov RAX, 0
mov RBX, 0
loop_for_i:
loop_for_j:
cmp RAX, RBX
jl conditional_if
return:
inc RBX
cmp RBX, RSI
jne loop_for_j
inc RAX
cmp RAX, RSI
jne loop_for_i
conditional_if:
;here I have to make a swap
jmp return
我的问题是“如何交换矩阵 [i] [j] 和矩阵 [j] [i] 的值?”。值得一提的是,我只使用方矩阵。
在 x86 汇编程序中,内存中的两个值可以简单地交换
mov eax, [rdi]
mov ebx, [rsi]
mov [rdi], ebx
mov [rsi], eax
其中rdi
、rsi
是两个32位整数的内存地址。
地址计算通常应该通过计算 步幅 或偏移量来加快,为了使第 N 个元素正确或向下。
汇编程序中的整个矩阵转置可能最好由编译器生成。 OTOH 编译器在将操作分解为 4x4 子矩阵块时可能无法使用 SIMD 指令:
for (y = 0; y < size/4; y++) {
for (x = 0; x < y; x++) {
if (y == x) {
transposeSubBlock(matrix, y);
} else if (y < x) {
transposeSubBlock(matrix, y, x);
}
}
}
现在,通过加载 4 个 SIMD 寄存器(从相邻的行和相邻的列)、转置寄存器并回写,可以在矩阵对角线上转置单个 4x4 块。
__m128i a[4];
a[0] = _mm_loadu_si128(row + 0 * stride);
a[1] = _mm_loadu_si128(row + 1 * stride);
a[2] = _mm_loadu_si128(row + 2 * stride);
a[3] = _mm_loadu_si128(row + 3 *stride);
transpose(a[0],a[1],a[2],a[3]);
_mm_storeu_si128(row + 0 * stride, a[0]);
_mm_storeu_si128(row + 1 * stride, a[1]);
_mm_storeu_si128(row + 2 * stride, a[2]);
_mm_storeu_si128(row + 3 * stride, a[3]);
其他块通过加载两个 4x4 块来处理,将两个块转置到寄存器中,然后写入相反的目标。
__m128i a[4], b[4];
load4vectors(a, src0, stride);
load4vectors(b, src1, stride);
transpose(a[0],a[1],a[2],a[3]);
transpose(b[0],b[1],b[2],b[3]);
store4vectors(src0, b[0],b[1],b[2],b[3]);
store4vectors(src1, a[0],a[1],a[2],a[3]);
转置 int[4][4] 矩阵的一种可能方法是将每个元素转换为 __m128
应用 MM_TRANSPOSE_PS(a,b,c,d);
宏并将每个元素转换回 __m128i
。
剩下的任务是处理多余的元素,它们不是 4 的倍数。