重写没有分支的代码

Rewrite the code without branches

我有以下功能:

uint16_t foo(uint8_t input)
{
     uint16_t N = 38;
     if (!(input&1))
     {
       N = 0;
     }
     else 
     {
        if ((input&2) >> 1)
        {
           N = ~N;
        }
     }
     return N;
}

我想在没有 ifs 的情况下重写它,就像一个将 38 转换为 0,3865497 给定 input 的内联函数] 并且只使用标准的 C 位操作。

重点不在于编译器可以内联函数,或者函数要快,而只是为了摆脱分支并保持恒定时间,而不管 input 是什么。

第一个if很简单:

uint16_t c = ((input&1)^1)-1;
N &= c;

但是我很难找到一些简单的方法来进行条件否定。

使用 table 查找。

uint16_t foo(uint8_t input) {
    int index= input & 0x3;
    const uint16 table[4]= {0,~38,0,38};
    return table[index];
}

如果我以正确的方式阅读您的代码,它会显示以下内容:

uint16_t foo1(uint8_t input)
{
     uint16_t N = 38;

     uint16_t bit0 = input & 1;
     uint16_t nbit0 = bit0 ^ 1;
     uint16_t bit1 = (input & 2) >> 1;
     uint16_t nbit1 = bit1 ^ 1;

     N = nbit0 * ( bit1 * ~N + nbit1 * N);

     return N;
}

随意摆脱变量。它们只是为了便于阅读。

为了保证 运行-time 和平衡的代码,必须使用汇编程序。由于 MSP430 汇编程序并不那么复杂,所以这不是什么大问题。请注意,乘法之类的事情可能由具有 not 常量 运行-time.

的函数执行

避免分支没有什么意义。相反,您应该平衡执行路径,e.g.using NOP(无操作)。 MSP430 用户指南包括指令时序。请注意,时序是固定的,这与 ARM 等较大的 CPU 不同,它取决于流水线和内存时序。

一般说明:通过 CPU 个周期进行计时在大多数情况下不是一个好主意。 MSP430 等现代 MCU 提供内部定时器和与 ADC 等其他外设的连接以触发,例如转换具有高度准确的时间。它们可以生成中断,因此 CPU 可以准备下一个值或读取样本,而不用关心代码的 运行 时间(除非花费的时间太长)。

将CPU用于此类禁止实例中断,因为它们会破坏任何时序。这使得维护这样的系统成为一场噩梦。

这应该有效。

#include<stdio.h>

int main(){
    int input;
    scanf("%d", &input);
    int N = (input&1)*(((input&2)*32729)+(38+((input&2)>>1)));
    printf("%d\n", N);
}

7 次运算,没有乘法,基于 njuffa 的评论:

uint16_t bar(uint8_t input)
{
    return (0-(input&1)) & (38^(0-((input>>1)&1)));
}

Demo