繁体   English   中英

为8位处理器优化一行C代码

[英]optimizing a line of C code for 8 bit processor

我正在使用8位处理器,并且已经在C编译器中编写代码,现在超过140行代码只占用1200字节,而这条单行占用的字节超过200字节。 eeprom_read()是一个函数,这个1000和100和10乘法应该有问题。

romAddr = eeprom_read(146)*1000 + eeprom_read(147)*100 +
          eeprom_read(148)*10 + eeprom_read(149);

处理器是8位, romAddr数据类型是int 有没有办法以更优化的方式编写这一行?

使用最多空间的东西可能是乘法的使用。 如果您的处理器缺少执行乘法的指令,则编译器必须逐步使用软件来执行此操作,这可能需要相当多的代码。

很难说,因为您没有指定目标处理器(或您正在使用的编译器)的任何内容。

一种方法可能是以某种方式尝试减少内联,因此可以重复使用乘以10的代码(在所有四个术语中使用)。

要知道是否属于这种情况,必须检查机器代码。 顺便说一下,使用十进制常量进行地址计算实际上很奇怪。

有时可以将乘法编译成一系列加法,是的。 您可以通过使用左移运算符来优化它。

A*1000 = A*512 + A*256 + A*128 + A*64 + A*32 + A*8

或者同样的事情:

A<<9 + A<<8 + A<<7 + A<<6 + A<<5 + A<<3

这仍然比单个“乘法”指令长一些,但是你的处理器显然没有它,所以这可能是下一个最好的事情。

你关注的是空间,而不是时间,对吧? 你有四个函数调用,每个函数都传递一个整数参数,然后乘以一个常量,然后加上。 就像第一个猜测一样,那可能是

  1. 将整数常量加载到寄存器中(6个字节)
  2. 推送寄存器(2个字节,
  3. 调用eeprom_read (6个字节)
  4. 调整堆栈(4个字节)
  5. 将整数乘法器加载到寄存器中(6个字节)
  6. 推两个寄存器(4个字节),
  7. 调用乘法例程(6个字节)
  8. 调整堆栈(4个字节)
  9. 将临时总和加载到寄存器中(6个字节)
  10. 添加到该寄存器的乘法结果(2个字节)
  11. 存储回临时总和(6个字节)。

让我们看看,6 + 2 + 6 + 4 + 6 + 4 + 6 + 4 + 6 + 2 + 6 =每次调用eeprom_read约52个字节。 最后一次调用会更短,因为它不会成倍增加。

我会尝试不使用像146这样的参数来调用eeprom_read ,而是使用(unsigned char)146 ,并且乘以1000而不是(unsigned short)1000 这样,您可以使编译器使用更短的指令,并且可能使用乘法指令而不是乘法函数调用。 此外,对eeprom_read的调用可能会被宏观化为直接内存提取,从而节省了参数的推送,函数的调用以及堆栈调整。

另一个技巧可能是将四个产品中的每一个存储在一个局部变量中,并在最后将它们全部加在一起。 这可能会产生更少的代码。 所有这些可能性也会使它更快,更小,尽管你可能不需要关心它。

节省空间的另一种可能是使用循环,如下所示:

static unsigned short powerOf10[] = {1000, 100, 10, 1};
unsigned short i;
romAddr = 0;
for (i = 146; i < 150; i++){
  romAddr += powerOf10[i-146] * eeprom_read(i);
}

这应该通过调用和乘法仅一次,加上循环指令而不是四个副本来节省空间。

在任何情况下,都可以使用编译器生成的汇编语言。

它非常非常依赖于编译器,但我建议你至少通过这种方式简化乘法:

romAddr = ((eeprom_read(146)*10 + eeprom_read(147))*10 +
          eeprom_read(148))*10 + eeprom_read(149);

你可以把它放在一个循环中:

uint8_t i = 146;
romAddr = eeprom_read(i);
for (i = 147; i < 150; i++)
    romAddr = romAddr * 10 + eeprom_read(i);

希望编译器应该认识到将16位值乘以10会更简单,而单独实现乘法1000和100则相比。

不过,我并不完全依赖编译器来有效地处理循环。

也许:

uint8_t hi, lo;
hi = (uint8_t)eeprom_read(146) * (uint8_t)10 + (uint8_t)eeprom_read(147);
lo = (uint8_t)eeprom_read(148) * (uint8_t)10 + (uint8_t)eeprom_read(149);
romAddr = hi * (uint8_t)100 + lo;

所有这些都是未经测试的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM