【问题标题】:ARMv7 gcc option to force native divideARMv7 gcc 选项强制本机除法
【发布时间】:2018-10-08 18:53:53
【问题描述】:

我正在使用 GCC 为支持原生除法的 ARMv7 内核构建裸机应用程序。我已删除所有库依赖项。

GCC C 编译器有时会引用 __aeabi_uidiv()。其他时候它会选择使用硬件除法(用于无符号整数除法)。我无法找到一个编译器标志来强制它使用硬件划分(而不是 __aeabi_* lib 调用)。有人知道这样的标志吗?

编辑:我应该澄清一下,我正在适当地使用编译器标志 -mtune=cortex-a7 和 -march=armv7-a 用于 i.MX6ULL。

示例错误:

uint32_t GenerateError(uint32_t num, uint32_t den) {
    return num / den; //generates undefined reference to __aeabi_uidiv
}

【问题讨论】:

    标签: gcc arm


    【解决方案1】:

    gcc 就是这样一个编译器。

    uint8_t fun_u8 ( uint8_t a, uint8_t b )
    {
        return(a/b);
    }
    uint16_t fun_u16 ( uint16_t a, uint16_t b )
    {
        return(a/b);
    }
    uint32_t fun_u32 ( uint32_t a, uint32_t b )
    {
        return(a/b);
    }
    uint64_t fun_u64 ( uint64_t a, uint64_t b )
    {
        return(a/b);
    }
    
    int8_t fun_s8 ( int8_t a, int8_t b )
    {
        return(a/b);
    }
    int16_t fun_s16 ( int16_t a, int16_t b )
    {
        return(a/b);
    }
    int32_t fun_s32 ( int32_t a, int32_t b )
    {
        return(a/b);
    }
    int64_t fun_s64 ( int64_t a, int64_t b )
    {
        return(a/b);
    }
    

    构建

    arm-none-eabi-gcc -O2 -mcpu=cortex-a7 -c so.c -o so.o

    结果

    00000000 <fun_u8>:
       0:   e730f110    udiv    r0, r0, r1
       4:   e12fff1e    bx  lr
    
    00000008 <fun_u16>:
       8:   e730f110    udiv    r0, r0, r1
       c:   e12fff1e    bx  lr
    
    00000010 <fun_u32>:
      10:   e730f110    udiv    r0, r0, r1
      14:   e12fff1e    bx  lr
    
    00000018 <fun_u64>:
      18:   e92d4010    push    {r4, lr}
      1c:   ebfffffe    bl  0 <__aeabi_uldivmod>
      20:   e8bd8010    pop {r4, pc}
    
    00000024 <fun_s8>:
      24:   e730f110    udiv    r0, r0, r1
      28:   e12fff1e    bx  lr
    
    0000002c <fun_s16>:
      2c:   e710f110    sdiv    r0, r0, r1
      30:   e6bf0070    sxth    r0, r0
      34:   e12fff1e    bx  lr
    
    00000038 <fun_s32>:
      38:   e710f110    sdiv    r0, r0, r1
      3c:   e12fff1e    bx  lr
    
    00000040 <fun_s64>:
      40:   e92d4010    push    {r4, lr}
      44:   ebfffffe    bl  0 <__aeabi_ldivmod>
      48:   e8bd8010    pop {r4, pc}
    

    从正确的 arm 文档来看,硬件支持最多 32 位/32 位。除此之外,您必须调用一个库(乘法也是如此)以确认期望可以添加:

    uint8_t fun_m8 ( uint32_t a, uint8_t b )
    {
        return(a/b);
    }
    uint16_t fun_m16 ( uint32_t a, uint16_t b )
    {
        return(a/b);
    }
    uint32_t fun_m32 ( uint32_t a, uint32_t b )
    {
        return(a/b);
    }
    
    0000004c <fun_m8>:
      4c:   e730f110    udiv    r0, r0, r1
      50:   e6ef0070    uxtb    r0, r0
      54:   e12fff1e    bx  lr
    
    00000058 <fun_m16>:
      58:   e730f110    udiv    r0, r0, r1
      5c:   e6ff0070    uxth    r0, r0
      60:   e12fff1e    bx  lr
    
    00000064 <fun_m32>:
      64:   e730f110    udiv    r0, r0, r1
      68:   e12fff1e    bx  lr
    

    这并不奇怪。

    现在是 arm 模式,编译器通常会使用拇指模式...

    00000000 <fun_u8>:
       0:   fbb0 f0f1   udiv    r0, r0, r1
       4:   4770        bx  lr
       6:   bf00        nop
    
    00000008 <fun_u16>:
       8:   fbb0 f0f1   udiv    r0, r0, r1
       c:   4770        bx  lr
       e:   bf00        nop
    
    ...
    

    此平台上没有变化 thumb2 也支持除法,因此它大于它支持的正在编译的代码的要求,该要求指示它是否可以使用硬件指令,对于这个测试,gcc 选择了所需的硬件指令而不是一个 gcclib 调用(它可以调用)。

    如果您希望编译器使用硬件指令,则指示编译器使用您想要的指令集。并将您的代码保持在该指令集的功能范围内。并使用同样为感兴趣的指令集编译的库,并且该代码保持在该指令集的限制内。 (然后查看编译器是否使用整个指令集或至少使用感兴趣的指令,如果没有,则制作您自己的库函数用于汇编中的除法并调用它)。

    【讨论】:

    • 我想我在看到你的编辑之前使用 cortex-a7 很幸运。
    • 感谢您的详尽回答。我仍然不知道这里的幕后发生了什么。
    • arm 在 acorn、armv4、armv5...armv8 以及皮质 ms armv6m armv7m armv8m 之后有许多架构。除了 armv8,这些都是 arm 或 thumb 模式指令,但通常建立在过去的基础上。最初没有划分,所以如果你不指定核心/架构,那么你在编译器构建时获得默认值,可能是 armv4t。所以没有除法所以为了做除法gcc有它自己的内部库来覆盖指令集没有的东西所以当你的C代码有除法时使用库。
    • gcc 的 arm 后端是这样的,那些人选择在一个后端将所有这些选项都带回到橡子时代,所以你必须非常具体才能获得你所追求的指令,并且/或者你必须使用程序集。
    • 我尝试了 4.x.x、5.x.x 和 8.x.x 都产生了除法指令,而不是库调用。
    【解决方案2】:

    您正在寻找的是-march=armv7ve。这将使用硬件除法指令针对 Armv7。 -mcpu=cortex-a15cortex-a7 以该架构为目标,因此它们将生成除法指令。

    【讨论】:

      猜你喜欢
      • 2010-12-21
      • 1970-01-01
      • 2012-11-28
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      相关资源
      最近更新 更多