为ARMv5优化一个读取1..4字节长的小端整数的函数

为ARMv5优化一个读取1..4字节长的小端整数的函数,arm,Arm,x86的代码可以做到这一点(n只能是1到4,编译时未知): 对于没有未对齐的32位little endian负载的体系结构,我有两种变体: static uint32_t get_unaligned_le_v1(const void *p, uint32_t n) { const uint8_t *b = (const uint8_t *)p; uint32_t ret; ret = b[0]; if (n > 1) { ret |= b[1] << 8

x86的代码可以做到这一点(n只能是1到4,编译时未知):

对于没有未对齐的32位little endian负载的体系结构,我有两种变体:

static uint32_t get_unaligned_le_v1(const void *p, uint32_t n) {
  const uint8_t *b = (const uint8_t *)p;
  uint32_t ret;
  ret = b[0];
  if (n > 1) {
    ret |= b[1] << 8;
    if (n > 2) {
      ret |= b[2] << 16;
      if (n > 3) {
        ret |= b[3] << 24;
      }
    }
  }
  return ret;
}

static uint32_t get_unaligned_le_v2(const void *p, uint32_t n) {
  const uint8_t *b = (const uint8_t *)p;
  uint32_t ret = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
  ret &= wordmask[n];
  return ret;
}
static uint32\u t get\u unaligned\u le\u v1(const void*p,uint32\u n){
const uint8_t*b=(const uint8_t*)p;
uint32_t ret;
ret=b[0];
如果(n>1){
ret |=b[1]2){
ret |=b[2]3){

ret |=b[3]您需要对这些进行测试。很难说,这不仅取决于处理器体系结构,还取决于编译器、编译标志和目标系统

下面是另一个可以消除分支和表查找(未经测试的代码)的想法/技巧:

我想尝试的另一件事是重写第二个函数,如下所示:

  if (n > 1) {
    ret |= b[1] << 8;
  }
  if (n > 2) {
    ret |= b[2] << 16;
  }
  if (n > 3) {
    ret |= b[3] << 24;
  }
if(n>1){
ret |=b[1]2){
ret |=b[2]3){

ret |=b[3]您需要对这些进行测试。很难说,这不仅取决于处理器体系结构,还取决于编译器、编译标志和目标系统

下面是另一个可以消除分支和表查找(未经测试的代码)的想法/技巧:

我想尝试的另一件事是重写第二个函数,如下所示:

  if (n > 1) {
    ret |= b[1] << 8;
  }
  if (n > 2) {
    ret |= b[2] << 16;
  }
  if (n > 3) {
    ret |= b[3] << 24;
  }
if(n>1){
ret |=b[1]2){
ret |=b[2]3){

ret |=b[3]ARM上的条件执行是提高性能的最佳选择。ARM上的表查找(掩码)速度肯定会较慢。以下是我的ARMv5实现:

// When called from C, r0 = first parameter, r1 = second parameter
// r0-r3 and r12 can get trashed by C functions
unaligned_read:
  ldrb r2,[r0],#1      ; byte 0 is always read (n=1..4)
  cmp r1,#2
  ldrgeb r3,[r0],#1   ; byte 1, n >= 2
  ldrgtb r12,[r0],#1  ; byte 2, n > 2
  orrge r2,r2,r3,LSL #8
  orrgt r2,r2,r12,LSL #16
  cmp r1,#4
  ldreqb r3,[r0],#1   ; byte 3, n == 4
  movne r0,r2         ; recoup wasted cycle
  orreq r0,r2,r3,LSL #24
  mov pc,lr           ; or "bx lr" for thumb compatibility
更新:将ldreqb固定为ldrgeb


更新2:在ARM上的最后一次ldr/orr之间插入一条指令,从而缩短了另一个周期,这是提高性能的最佳选择。ARM上的表查找(掩码)速度肯定会较慢。以下是我的ARMv5实现:

// When called from C, r0 = first parameter, r1 = second parameter
// r0-r3 and r12 can get trashed by C functions
unaligned_read:
  ldrb r2,[r0],#1      ; byte 0 is always read (n=1..4)
  cmp r1,#2
  ldrgeb r3,[r0],#1   ; byte 1, n >= 2
  ldrgtb r12,[r0],#1  ; byte 2, n > 2
  orrge r2,r2,r3,LSL #8
  orrgt r2,r2,r12,LSL #16
  cmp r1,#4
  ldreqb r3,[r0],#1   ; byte 3, n == 4
  movne r0,r2         ; recoup wasted cycle
  orreq r0,r2,r3,LSL #24
  mov pc,lr           ; or "bx lr" for thumb compatibility
更新:将ldreqb固定为ldrgeb


更新2:在最后一个ldr/orr之间插入一条指令,从而缩短了另一个周期

GCC没有自己执行条件执行,两个版本都没有。我说的是“更好的机会”。我见过gcc在某些代码中这样做,你在使用'-O3'?gcc的哪个版本?gcc没有自己执行条件执行,两个版本都没有。我确实说过“更好的机会”。我见过gcc在某些代码中这样做,你在使用'-O3'?gcc的哪个版本?我将第一行的操作码更改为“ldrb”,并将出口切换为“bx lr”对于thumbarm兼容性,它确实比任何其他版本都快得多。感谢您发现了打字错误;我在没有测试的情况下直接键入了它。很高兴知道它快得多。我做了很多ARMv5优化,始终发现表查找比x86上的慢。条件执行,桶ifter和3个操作数指令是ARM的优势。我忘了问:我可以在3条款BSD许可证下使用你的代码吗?这是谷歌Snappy压缩库的一个端口(他们只支持x86和ARMv7)。我假设任何发布到StackOverflow的内容都是免费的。如果不是,我允许您将代码用于任何目的。@BitBank:我想是CC-BY-SAI将第一行的操作码更改为“ldrb”,并将出口切换为“bx lr”对于thumbarm兼容性,它确实比任何其他版本都快得多。感谢您发现了打字错误;我在没有测试的情况下直接键入了它。很高兴知道它快得多。我做了很多ARMv5优化,始终发现表查找比x86上的慢。条件执行,桶ifter和3个操作数指令是ARM的优势。我忘了问:我可以在3条款BSD许可证下使用你的代码吗?这是谷歌Snappy压缩库的一个端口(他们只支持x86和ARMv7)。我假设任何发布到StackOverflow的内容都可以免费使用。如果不是,我允许您将该代码用于任何目的。@BitBank:我想这是CC-BY-SA
// When called from C, r0 = first parameter, r1 = second parameter
// r0-r3 and r12 can get trashed by C functions
unaligned_read:
  ldrb r2,[r0],#1      ; byte 0 is always read (n=1..4)
  cmp r1,#2
  ldrgeb r3,[r0],#1   ; byte 1, n >= 2
  ldrgtb r12,[r0],#1  ; byte 2, n > 2
  orrge r2,r2,r3,LSL #8
  orrgt r2,r2,r12,LSL #16
  cmp r1,#4
  ldreqb r3,[r0],#1   ; byte 3, n == 4
  movne r0,r2         ; recoup wasted cycle
  orreq r0,r2,r3,LSL #24
  mov pc,lr           ; or "bx lr" for thumb compatibility