如何在Micropython汇编语言中测试浮点寄存器的符号

时间:2018-04-01 20:17:26

标签: assembly floating-point arm micropython

我正在学习MicroPython的汇编程序(用于PyBoard的ARM Thumb2指令集)。

是否有更快的方法来检查FPU寄存器(s0)的符号(正/负)?

@micropython.asm_thumb
def float_array_abs(r0, r1):
    label(LOOP)
    vldr(s0, [r0, 0])
    vmov(r2, s0)         # 1
    cmp(r2, 0)           # 2
    itt(mi)              # 3
    vneg(s0, s0)
    vstr(s0, [r0, 0])
    add(r0, 4)
    sub(r1, 1)
    bgt(LOOP)

这样可行,但它看起来并不像“正确”。解决方案(不确定r2的符号是否始终与s0的符号匹配)我怀疑它必须少于两条指令才能实现。

更新1:

基于评论(谢谢)我进一步提高了代码的速度:

@micropython.asm_thumb
def float_array_abs1(r0, r1):
    label(LOOP)
    ldr(r2, [r0, 0])
    cmp(r2, 0)         # this works for some reason
    bge(SKIP)
    vmov(s0, r2)
    vneg(s0, s0)
    vstr(s0, [r0, 0])  # this can be skipped if not negative
    label(SKIP)
    add(r0, 4)
    sub(r1, 1)
    bgt(LOOP)

但它仍然存在问题,这是一种确定FP值符号的可靠方法吗?

这里参考我系统上四个浮点值的字节表示:

-1.0 0xbf800000
-0.0 0x80000000
 0.0 0x00000000
 1.0 0x3f800000

我想如果这是依赖于硬件的那么我不应该依赖它来确定标志...

我认为这可能是“适当的”。这样做的方法(即适当的FPU比较):

def float_array_abs2(r0, r1):
    mov(r2, 0)
    vmov(s1, r2)
    label(LOOP)
    vldr(s0, [r0, 0])
    vcmp(s0, s1)
    vmrs(APSR_nzcv, FPSCR)
    itt(mi)
    vneg(s0, s0)
    vstr(s0, [r0, 0])
    add(r0, 4)
    sub(r1, 1)
    bgt(LOOP)

但是我计时了,它比上面的代码慢了11%(float_array_abs1)。因此,如果它是一个可靠的解决方案,那么使用早期的代码会很好。

更新2:

@ Ped7g提出了方法and 0x7FFFFFFF(见评论)。

我对此进行了测试,确实有效。这是代码:

@micropython.asm_thumb
def float_array_abs3(r0, r1):
    movwt(r3, 0x7FFFFFFF)
    label(LOOP)
    ldr(r2, [r0, 0])
    and_(r2, r3)
    str(r2, [r0, 0])
    add(r0, 4)
    sub(r1, 1)
    bgt(LOOP)

更正:它比float_array_abs1更快。 这似乎是最好的解决方案 ,但它是否健壮?

1 个答案:

答案 0 :(得分:1)

使用and将符号位屏蔽为0对于{75}二进制浮点格式(如floatdouble)是安全且最佳的。

它会根据需要将-Inf转换为+ Inf。它会将-NaN转换为+NaN,但它仍然是NaN。

NaN由全1指数和非零有效数表示。 Inf是全有指数,零有效数。 (https://en.wikipedia.org/wiki/Single-precision_floating-point_format

大多数代码都不关心NaN的有效负载或符号,只是它 NaN,所以清除符号位就好了。

ARM可以使用整数SIMD NEON指令一次执行4个单精度浮点数。我不知道VFP(非NEON硬件FPU)是否支持AND指令。

相关:Fastest way to compute absolute value using SSE AND也是x86的最佳方式。

BTW,在单独的循环中执行此操作可能会浪费内存带宽。在读取数组的循环中动态执行绝对值可能是最好的,除非您在写入一次后读取此数组许多次。至少如果你能在FP寄存器中进行AND操作。加载到AND的整数寄存器然后从整数移动到FP以获得数学指令会很糟糕。

通常你需要在你的循环中有更多的计算强度(从内存中为每个负载做更多的ALU工作)。