计算 MIPS 表达式的有效方法
Efficient way to compute MIPS expression
我正在为嵌入式计算机编写程序,但只有很少的内存和处理能力可以使用。
y 和 a 是存储在浮点寄存器中的双精度值,而 x 是双精度数组。在 MIPS 中编写此表达式的最有效方法是什么?
y = y + a * x[i];
我不精通 MIPS 汇编程序,所以我不会为实际的 MIPS 指令操心,我会在 z80/x86 TASM 的中途使用类似简单英语的东西,希望你能明白。
而且我假设您想添加整个数组,而不仅仅是这一行,因为这会改变任务的所有内容。
如果您真的只想优化这一行,那么就没有什么花哨的余地了。只需加载 x[i],将其乘以 a,并将结果添加到 y。
如果您谈论的是一些固定大小的数组(如矩阵中的大小 4),可能有一些直接展开的方法比我的以下方法更快。
如果我们谈论的是 some 数组,那是不同的(但你应该这样发布),你可以节省很多 (n-1) 先对 x 数组求和的乘法:
load r1, x_array_pointer
load r2, x_array_end_pointer
load fpr0, zero_value
:loop_sum_x_array
add fpr0,[r1]
add r1,size_of_double
cmp r1,r2
jump_less loop_sum_x_array ; till whole array is summed
mul fpr0, *a* ; now multiply sum{x} by "a"
add fpr0, *y* ; and add initial "y" value
; fpr0 contains result
"Algorithm": y + a*x0 + a*x1 + a*x2 + ... = y + a*(x0 + x1 + x2 + ...) (如果你在 SO 发帖之前没有自己想出这个,你要么没有尝试过,要么你已经 8 岁了,或者你应该认真地做一些思考和基本的数学练习,因为这很明显。嘿,实际上,在这种难度下它纯粹是有趣的,为什么你让其他人在 SO 过 你的 乐趣?你很慷慨,先生。 : ) )
内存:这不使用任何额外的内存,只使用输入 y、a 和 x,你需要一些临时寄存器(r1,r2,fpr0)(所以只要你不做8位CPU练习,你应该有足够的备用寄存器)。
处理能力:算法的复杂度为 O(n)(并且由于您必须从 x 数组中添加每个值,所以您无法击败它)。内部循环使用非常基本的指令:一个浮点加法、从内存中加载双精度值、地址递增、比较和条件跳转。然后它需要 one 浮点乘法和一个 fp 加法。 x 数组是按顺序访问的,因此内存缓存未命中应该最少。
如果您的 CPU 有任何专门的指令,例如 MMX,使用这些指令可能会更快地写入大型数组的总和。但是在用于大型阵列的现代 CPU+RAM 上,您将主要受到内存缓存速度的限制,因为对于 GHz CPU 来说,内部循环就像不存在一样(当然,从内存加载值除外)。
编辑:正如 Michael 指出的那样,使用 C 编译器是正确的方法,我只是为了编写一些伪汇编程序的乐趣而做我的回答。我不确定您的平台是什么,但如果它有价值,则必须有用于 PC 的交叉编译器以及将二进制结果获取到目标的方法。
我正在为嵌入式计算机编写程序,但只有很少的内存和处理能力可以使用。
y 和 a 是存储在浮点寄存器中的双精度值,而 x 是双精度数组。在 MIPS 中编写此表达式的最有效方法是什么?
y = y + a * x[i];
我不精通 MIPS 汇编程序,所以我不会为实际的 MIPS 指令操心,我会在 z80/x86 TASM 的中途使用类似简单英语的东西,希望你能明白。
而且我假设您想添加整个数组,而不仅仅是这一行,因为这会改变任务的所有内容。
如果您真的只想优化这一行,那么就没有什么花哨的余地了。只需加载 x[i],将其乘以 a,并将结果添加到 y。
如果您谈论的是一些固定大小的数组(如矩阵中的大小 4),可能有一些直接展开的方法比我的以下方法更快。
如果我们谈论的是 some 数组,那是不同的(但你应该这样发布),你可以节省很多 (n-1) 先对 x 数组求和的乘法:
load r1, x_array_pointer
load r2, x_array_end_pointer
load fpr0, zero_value
:loop_sum_x_array
add fpr0,[r1]
add r1,size_of_double
cmp r1,r2
jump_less loop_sum_x_array ; till whole array is summed
mul fpr0, *a* ; now multiply sum{x} by "a"
add fpr0, *y* ; and add initial "y" value
; fpr0 contains result
"Algorithm": y + a*x0 + a*x1 + a*x2 + ... = y + a*(x0 + x1 + x2 + ...) (如果你在 SO 发帖之前没有自己想出这个,你要么没有尝试过,要么你已经 8 岁了,或者你应该认真地做一些思考和基本的数学练习,因为这很明显。嘿,实际上,在这种难度下它纯粹是有趣的,为什么你让其他人在 SO 过 你的 乐趣?你很慷慨,先生。 : ) )
内存:这不使用任何额外的内存,只使用输入 y、a 和 x,你需要一些临时寄存器(r1,r2,fpr0)(所以只要你不做8位CPU练习,你应该有足够的备用寄存器)。
处理能力:算法的复杂度为 O(n)(并且由于您必须从 x 数组中添加每个值,所以您无法击败它)。内部循环使用非常基本的指令:一个浮点加法、从内存中加载双精度值、地址递增、比较和条件跳转。然后它需要 one 浮点乘法和一个 fp 加法。 x 数组是按顺序访问的,因此内存缓存未命中应该最少。
如果您的 CPU 有任何专门的指令,例如 MMX,使用这些指令可能会更快地写入大型数组的总和。但是在用于大型阵列的现代 CPU+RAM 上,您将主要受到内存缓存速度的限制,因为对于 GHz CPU 来说,内部循环就像不存在一样(当然,从内存加载值除外)。
编辑:正如 Michael 指出的那样,使用 C 编译器是正确的方法,我只是为了编写一些伪汇编程序的乐趣而做我的回答。我不确定您的平台是什么,但如果它有价值,则必须有用于 PC 的交叉编译器以及将二进制结果获取到目标的方法。