我正在研究带有IAR编译器的STM8S微控制器。
我尝试比较d.M0.bit._5=d.M1.bit._7;
的版本,并将循环和代码内存差异写为下面的命令。
typedef union
{
struct
{
unsigned char _0 :1;
unsigned char _1 :1;
unsigned char _2 :1;
unsigned char _3 :1;
unsigned char _4 :1;
unsigned char _5 :1;
unsigned char _6 :1;
unsigned char _7 :1;
} bit;
unsigned char data;
} m;
typedef struct
{
m M0,
M1,
M2,
} dm_;
#pragma location = 0x050
dm_ d;
// original version;
d.M0.bit._5=d.M1.bit._7; // 21 byte(difference from total code memory),
// 18 cycle (PC:Programme Counter)
//--------------------------------------------------------------------------
// second version;
d.M0.bit._5=0; // 18 byte(difference from total code memory),
if(d.M1.bit._7) // 15 cycle (PC:Programme Counter)
d.M0.bit._5=1;
// third version;
d.M0.data &=~(1<<5); // 18 byte(difference from total code memory),
if(d.M1.data & 0x80) // 15 cycle (PC:Programme Counter)
d.M0.data |=(1<<5);
看来是这样,第二版和第三版比原版更平等,更有效但我不知道这是一个自信的比较吗?
在调试器模式下,我计算PC周期数并编译所有代码以检查每个代码存储器和新代码存储器的差异。
此外,它可能并不重要,但d.M0.bit._5=d.M1.bit._7;
版本代码的汇编覆盖范围有更多汇编指令。
答案 0 :(得分:1)
总的来说,最好避免使用ifs,因为除非你有条件移动指令,否则if == branch == slow。
从一个值到另一个值分配位的最短已知公式是:
r = a ^ ((a ^ b) & mask)
以下是公式的来源:https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
因此,您案件的最终结果将是:
unsigned char a = d.M0.data;
unsigned char b = (d.M1.data >> 2); // put bit 7 into 5th position
unsigned char mask = 0x20; // will assign to a the 5th bit of b
d.M0.data = a ^ ((a ^ b) & mask);
在我的Intel i5上,它比其他选项快6-13%。我预计在较慢的CPU上差异会更明显。
但它有点棘手,所以如果速度增益值得代码可读性,那取决于你......
--------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------
bits_assign 212 ns 212 ns 3288700
bits_assign_if_bit 212 ns 210 ns 3327297
bits_assign_if_data 203 ns 203 ns 3457701
bits_assign_branchless 188 ns 188 ns 3713355